2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
39 #include "wine/unicode.h"
42 #define REG_PROGRESS_VALUE 13200
43 #define COMPONENT_PROGRESS_VALUE 24000
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 * consts and values used
50 static const WCHAR c_colon[] = {'C',':','\\',0};
52 static const WCHAR szCreateFolders[] =
53 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
54 static const WCHAR szCostFinalize[] =
55 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
56 static const WCHAR szWriteRegistryValues[] =
57 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
58 static const WCHAR szCostInitialize[] =
59 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
60 static const WCHAR szFileCost[] =
61 {'F','i','l','e','C','o','s','t',0};
62 static const WCHAR szInstallInitialize[] =
63 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
64 static const WCHAR szInstallValidate[] =
65 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
66 static const WCHAR szLaunchConditions[] =
67 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
68 static const WCHAR szProcessComponents[] =
69 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
70 static const WCHAR szRegisterTypeLibraries[] =
71 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
72 static const WCHAR szCreateShortcuts[] =
73 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
74 static const WCHAR szPublishProduct[] =
75 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
76 static const WCHAR szWriteIniValues[] =
77 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
78 static const WCHAR szSelfRegModules[] =
79 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
80 static const WCHAR szPublishFeatures[] =
81 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
82 static const WCHAR szRegisterProduct[] =
83 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
84 static const WCHAR szInstallExecute[] =
85 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
86 static const WCHAR szInstallExecuteAgain[] =
87 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
88 static const WCHAR szInstallFinalize[] =
89 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
90 static const WCHAR szForceReboot[] =
91 {'F','o','r','c','e','R','e','b','o','o','t',0};
92 static const WCHAR szResolveSource[] =
93 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
94 static const WCHAR szAllocateRegistrySpace[] =
95 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
96 static const WCHAR szBindImage[] =
97 {'B','i','n','d','I','m','a','g','e',0};
98 static const WCHAR szDeleteServices[] =
99 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
100 static const WCHAR szDisableRollback[] =
101 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
102 static const WCHAR szExecuteAction[] =
103 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
104 static const WCHAR szInstallAdminPackage[] =
105 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
106 static const WCHAR szInstallSFPCatalogFile[] =
107 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
108 static const WCHAR szIsolateComponents[] =
109 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
110 static const WCHAR szMigrateFeatureStates[] =
111 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
112 static const WCHAR szMsiUnpublishAssemblies[] =
113 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
114 static const WCHAR szInstallODBC[] =
115 {'I','n','s','t','a','l','l','O','D','B','C',0};
116 static const WCHAR szInstallServices[] =
117 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
118 static const WCHAR szPatchFiles[] =
119 {'P','a','t','c','h','F','i','l','e','s',0};
120 static const WCHAR szPublishComponents[] =
121 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
122 static const WCHAR szRegisterComPlus[] =
123 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
124 static const WCHAR szRegisterUser[] =
125 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
126 static const WCHAR szRemoveEnvironmentStrings[] =
127 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
128 static const WCHAR szRemoveExistingProducts[] =
129 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
130 static const WCHAR szRemoveFolders[] =
131 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
132 static const WCHAR szRemoveIniValues[] =
133 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
134 static const WCHAR szRemoveODBC[] =
135 {'R','e','m','o','v','e','O','D','B','C',0};
136 static const WCHAR szRemoveRegistryValues[] =
137 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
138 static const WCHAR szRemoveShortcuts[] =
139 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
140 static const WCHAR szRMCCPSearch[] =
141 {'R','M','C','C','P','S','e','a','r','c','h',0};
142 static const WCHAR szScheduleReboot[] =
143 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
144 static const WCHAR szSelfUnregModules[] =
145 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
146 static const WCHAR szSetODBCFolders[] =
147 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
148 static const WCHAR szStartServices[] =
149 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
150 static const WCHAR szStopServices[] =
151 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
152 static const WCHAR szUnpublishComponents[] =
153 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
154 static const WCHAR szUnpublishFeatures[] =
155 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
156 static const WCHAR szUnregisterComPlus[] =
157 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
158 static const WCHAR szUnregisterTypeLibraries[] =
159 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
160 static const WCHAR szValidateProductID[] =
161 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
162 static const WCHAR szWriteEnvironmentStrings[] =
163 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
165 /********************************************************
167 ********************************************************/
169 void msi_feature_set_state( MSIPACKAGE *package, MSIFEATURE *feature, INSTALLSTATE state )
171 if (!package->ProductCode)
173 feature->ActionRequest = state;
174 feature->Action = state;
176 else if (state == INSTALLSTATE_ABSENT)
178 switch (feature->Installed)
180 case INSTALLSTATE_ABSENT:
181 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
182 feature->Action = INSTALLSTATE_UNKNOWN;
185 feature->ActionRequest = state;
186 feature->Action = state;
189 else if (state == INSTALLSTATE_SOURCE)
191 switch (feature->Installed)
193 case INSTALLSTATE_ABSENT:
194 case INSTALLSTATE_SOURCE:
195 feature->ActionRequest = state;
196 feature->Action = state;
198 case INSTALLSTATE_LOCAL:
199 feature->ActionRequest = INSTALLSTATE_LOCAL;
200 feature->Action = INSTALLSTATE_LOCAL;
203 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
204 feature->Action = INSTALLSTATE_UNKNOWN;
209 feature->ActionRequest = state;
210 feature->Action = state;
214 void msi_component_set_state( MSIPACKAGE *package, MSICOMPONENT *comp, INSTALLSTATE state )
216 if (!package->ProductCode)
218 comp->ActionRequest = state;
219 comp->Action = state;
221 else if (state == INSTALLSTATE_ABSENT)
223 switch (comp->Installed)
225 case INSTALLSTATE_LOCAL:
226 case INSTALLSTATE_SOURCE:
227 case INSTALLSTATE_DEFAULT:
228 comp->ActionRequest = state;
229 comp->Action = state;
232 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
233 comp->Action = INSTALLSTATE_UNKNOWN;
236 else if (state == INSTALLSTATE_SOURCE)
238 if (comp->Installed == INSTALLSTATE_ABSENT ||
239 (comp->Installed == INSTALLSTATE_SOURCE && comp->hasLocalFeature))
241 comp->ActionRequest = state;
242 comp->Action = state;
246 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
247 comp->Action = INSTALLSTATE_UNKNOWN;
252 comp->ActionRequest = state;
253 comp->Action = state;
257 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
259 static const WCHAR Query_t[] =
260 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
261 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
262 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
263 ' ','\'','%','s','\'',0};
266 row = MSI_QueryGetRecord( package->db, Query_t, action );
269 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
270 msiobj_release(&row->hdr);
273 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
277 static const WCHAR template_s[]=
278 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
280 static const WCHAR template_e[]=
281 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
282 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
284 static const WCHAR format[] =
285 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
289 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
291 sprintfW(message,template_s,timet,action);
293 sprintfW(message,template_e,timet,action,rc);
295 row = MSI_CreateRecord(1);
296 MSI_RecordSetStringW(row,1,message);
298 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
299 msiobj_release(&row->hdr);
309 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
311 enum parse_state state = state_quote;
314 int ignore, in_quotes = 0, count = 0, len = 0;
316 for (p = str; *p; p++)
321 case state_whitespace:
325 if (!count) goto done;
331 if (in_quotes) count--;
336 if (!count) in_quotes = 0;
348 if (in_quotes) count--;
352 state = state_whitespace;
353 if (!count) goto done;
357 if (!count) in_quotes = 0;
368 if (in_quotes) count--;
372 state = state_whitespace;
373 if (!count || !len) goto done;
378 if (!count) in_quotes = 0;
387 if (!ignore) *out++ = *p;
391 if (!len) *value = 0;
398 static void remove_quotes( WCHAR *str )
401 int len = strlenW( str );
403 while ((p = strchrW( p, '"' )))
405 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
410 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
420 return ERROR_SUCCESS;
425 while (*ptr == ' ') ptr++;
428 ptr2 = strchrW( ptr, '=' );
429 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
432 if (!len) return ERROR_INVALID_COMMAND_LINE;
434 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
435 memcpy( prop, ptr, len * sizeof(WCHAR) );
437 if (!preserve_case) struprW( prop );
440 while (*ptr2 == ' ') ptr2++;
443 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
444 len = parse_prop( ptr2, val, "es );
447 WARN("unbalanced quotes\n");
450 return ERROR_INVALID_COMMAND_LINE;
452 remove_quotes( val );
453 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
455 r = msi_set_property( package->db, prop, val );
456 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
457 msi_reset_folders( package, TRUE );
465 return ERROR_SUCCESS;
468 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
471 LPWSTR p, *ret = NULL;
477 /* count the number of substrings */
478 for ( pc = str, count = 0; pc; count++ )
480 pc = strchrW( pc, sep );
485 /* allocate space for an array of substring pointers and the substrings */
486 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
487 (lstrlenW(str)+1) * sizeof(WCHAR) );
491 /* copy the string and set the pointers */
492 p = (LPWSTR) &ret[count+1];
494 for( count = 0; (ret[count] = p); count++ )
496 p = strchrW( p, sep );
504 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
506 static const WCHAR szSystemLanguageID[] =
507 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
509 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
510 UINT ret = ERROR_FUNCTION_FAILED;
512 prod_code = msi_dup_property( package->db, szProductCode );
513 patch_product = msi_get_suminfo_product( patch );
515 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
517 if ( strstrW( patch_product, prod_code ) )
522 si = MSI_GetSummaryInformationW( patch, 0 );
525 ERR("no summary information!\n");
529 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
532 ERR("no template property!\n");
533 msiobj_release( &si->hdr );
540 msiobj_release( &si->hdr );
544 langid = msi_dup_property( package->db, szSystemLanguageID );
547 msiobj_release( &si->hdr );
551 p = strchrW( template, ';' );
552 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
554 TRACE("applicable transform\n");
558 /* FIXME: check platform */
560 msiobj_release( &si->hdr );
564 msi_free( patch_product );
565 msi_free( prod_code );
566 msi_free( template );
572 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
573 MSIDATABASE *patch_db, LPCWSTR name )
575 UINT ret = ERROR_FUNCTION_FAILED;
576 IStorage *stg = NULL;
579 TRACE("%p %s\n", package, debugstr_w(name) );
583 ERR("expected a colon in %s\n", debugstr_w(name));
584 return ERROR_FUNCTION_FAILED;
587 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
590 ret = msi_check_transform_applicable( package, stg );
591 if (ret == ERROR_SUCCESS)
592 msi_table_apply_transform( package->db, stg );
594 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
595 IStorage_Release( stg );
598 ERR("failed to open substorage %s\n", debugstr_w(name));
600 return ERROR_SUCCESS;
603 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
605 LPWSTR guid_list, *guids, product_code;
606 UINT i, ret = ERROR_FUNCTION_FAILED;
608 product_code = msi_dup_property( package->db, szProductCode );
611 /* FIXME: the property ProductCode should be written into the DB somewhere */
612 ERR("no product code to check\n");
613 return ERROR_SUCCESS;
616 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
617 guids = msi_split_string( guid_list, ';' );
618 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
620 if (!strcmpW( guids[i], product_code ))
624 msi_free( guid_list );
625 msi_free( product_code );
630 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
633 MSIRECORD *rec = NULL;
638 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
639 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
640 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
641 '`','S','o','u','r','c','e','`',' ','I','S',' ',
642 'N','O','T',' ','N','U','L','L',0};
644 r = MSI_DatabaseOpenViewW(package->db, query, &view);
645 if (r != ERROR_SUCCESS)
648 r = MSI_ViewExecute(view, 0);
649 if (r != ERROR_SUCCESS)
652 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
654 prop = MSI_RecordGetString(rec, 1);
655 patch = msi_dup_property(package->db, szPatch);
656 msi_set_property(package->db, prop, patch);
661 if (rec) msiobj_release(&rec->hdr);
662 msiobj_release(&view->hdr);
667 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
670 UINT r = ERROR_SUCCESS;
673 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
675 return ERROR_OUTOFMEMORY;
677 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
681 return ERROR_OUTOFMEMORY;
687 msi_free( pi->patchcode );
689 return ERROR_PATCH_PACKAGE_INVALID;
692 p = strchrW( p + 1, '}' );
695 msi_free( pi->patchcode );
697 return ERROR_PATCH_PACKAGE_INVALID;
702 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
706 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
708 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
711 msi_free( pi->patchcode );
713 return ERROR_OUTOFMEMORY;
720 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
722 UINT i, r = ERROR_SUCCESS;
725 /* apply substorage transforms */
726 substorage = msi_split_string( patch->transforms, ';' );
727 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
728 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
730 msi_free( substorage );
731 if (r != ERROR_SUCCESS)
734 msi_set_media_source_prop( package );
737 * There might be a CAB file in the patch package,
738 * so append it to the list of storages to search for streams.
740 append_storage_to_db( package->db, patch_db->storage );
742 patch->state = MSIPATCHSTATE_APPLIED;
743 list_add_tail( &package->patches, &patch->entry );
744 return ERROR_SUCCESS;
747 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
749 static const WCHAR dotmsp[] = {'.','m','s','p',0};
750 MSIDATABASE *patch_db = NULL;
751 WCHAR localfile[MAX_PATH];
753 MSIPATCHINFO *patch = NULL;
754 UINT r = ERROR_SUCCESS;
756 TRACE("%p %s\n", package, debugstr_w( file ) );
758 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
759 if ( r != ERROR_SUCCESS )
761 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
765 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
768 msiobj_release( &patch_db->hdr );
769 return ERROR_FUNCTION_FAILED;
772 r = msi_check_patch_applicable( package, si );
773 if (r != ERROR_SUCCESS)
775 TRACE("patch not applicable\n");
780 r = msi_parse_patch_summary( si, &patch );
781 if ( r != ERROR_SUCCESS )
784 r = msi_get_local_package_name( localfile, dotmsp );
785 if ( r != ERROR_SUCCESS )
788 TRACE("copying to local package %s\n", debugstr_w(localfile));
790 if (!CopyFileW( file, localfile, FALSE ))
792 ERR("Unable to copy package (%s -> %s) (error %u)\n",
793 debugstr_w(file), debugstr_w(localfile), GetLastError());
797 patch->localfile = strdupW( localfile );
799 r = msi_apply_patch_db( package, patch_db, patch );
800 if ( r != ERROR_SUCCESS )
801 WARN("patch failed to apply %u\n", r);
804 msiobj_release( &si->hdr );
805 msiobj_release( &patch_db->hdr );
806 if (patch && r != ERROR_SUCCESS)
808 if (patch->localfile)
809 DeleteFileW( patch->localfile );
811 msi_free( patch->patchcode );
812 msi_free( patch->transforms );
813 msi_free( patch->localfile );
819 /* get the PATCH property, and apply all the patches it specifies */
820 static UINT msi_apply_patches( MSIPACKAGE *package )
822 LPWSTR patch_list, *patches;
823 UINT i, r = ERROR_SUCCESS;
825 patch_list = msi_dup_property( package->db, szPatch );
827 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
829 patches = msi_split_string( patch_list, ';' );
830 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
831 r = msi_apply_patch_package( package, patches[i] );
834 msi_free( patch_list );
839 static UINT msi_apply_transforms( MSIPACKAGE *package )
841 static const WCHAR szTransforms[] = {
842 'T','R','A','N','S','F','O','R','M','S',0 };
843 LPWSTR xform_list, *xforms;
844 UINT i, r = ERROR_SUCCESS;
846 xform_list = msi_dup_property( package->db, szTransforms );
847 xforms = msi_split_string( xform_list, ';' );
849 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
851 if (xforms[i][0] == ':')
852 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
857 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
860 WCHAR *p = strrchrW( package->PackagePath, '\\' );
861 DWORD len = p - package->PackagePath + 1;
863 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
866 msi_free( xform_list );
867 return ERROR_OUTOFMEMORY;
869 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
870 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
872 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
873 if (transform != xforms[i]) msi_free( transform );
878 msi_free( xform_list );
883 static BOOL ui_sequence_exists( MSIPACKAGE *package )
888 static const WCHAR ExecSeqQuery [] =
889 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
890 '`','I','n','s','t','a','l','l',
891 'U','I','S','e','q','u','e','n','c','e','`',
892 ' ','W','H','E','R','E',' ',
893 '`','S','e','q','u','e','n','c','e','`',' ',
894 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
895 '`','S','e','q','u','e','n','c','e','`',0};
897 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
898 if (rc == ERROR_SUCCESS)
900 msiobj_release(&view->hdr);
907 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
909 LPWSTR source, check;
911 if (msi_get_property_int( package->db, szInstalled, 0 ))
915 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
916 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
924 db = msi_dup_property( package->db, szOriginalDatabase );
926 return ERROR_OUTOFMEMORY;
928 p = strrchrW( db, '\\' );
931 p = strrchrW( db, '/' );
935 return ERROR_SUCCESS;
940 source = msi_alloc( len * sizeof(WCHAR) );
941 lstrcpynW( source, db, len );
945 check = msi_dup_property( package->db, cszSourceDir );
946 if (!check || replace)
948 UINT r = msi_set_property( package->db, cszSourceDir, source );
949 if (r == ERROR_SUCCESS)
950 msi_reset_folders( package, TRUE );
954 check = msi_dup_property( package->db, cszSOURCEDIR );
955 if (!check || replace)
956 msi_set_property( package->db, cszSOURCEDIR, source );
961 return ERROR_SUCCESS;
964 static BOOL needs_ui_sequence(MSIPACKAGE *package)
966 INT level = msi_get_property_int(package->db, szUILevel, 0);
967 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
970 UINT msi_set_context(MSIPACKAGE *package)
974 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
976 num = msi_get_property_int(package->db, szAllUsers, 0);
977 if (num == 1 || num == 2)
978 package->Context = MSIINSTALLCONTEXT_MACHINE;
980 return ERROR_SUCCESS;
983 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
986 LPCWSTR cond, action;
987 MSIPACKAGE *package = param;
989 action = MSI_RecordGetString(row,1);
992 ERR("Error is retrieving action name\n");
993 return ERROR_FUNCTION_FAILED;
996 /* check conditions */
997 cond = MSI_RecordGetString(row,2);
999 /* this is a hack to skip errors in the condition code */
1000 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1002 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
1003 return ERROR_SUCCESS;
1006 if (needs_ui_sequence(package))
1007 rc = ACTION_PerformUIAction(package, action, -1);
1009 rc = ACTION_PerformAction(package, action, -1);
1011 msi_dialog_check_messages( NULL );
1013 if (package->CurrentInstallState != ERROR_SUCCESS)
1014 rc = package->CurrentInstallState;
1016 if (rc == ERROR_FUNCTION_NOT_CALLED)
1019 if (rc != ERROR_SUCCESS)
1020 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
1025 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
1029 static const WCHAR query[] =
1030 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1032 ' ','W','H','E','R','E',' ',
1033 '`','S','e','q','u','e','n','c','e','`',' ',
1034 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1035 '`','S','e','q','u','e','n','c','e','`',0};
1037 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1039 r = MSI_OpenQuery( package->db, &view, query, szTable );
1040 if (r == ERROR_SUCCESS)
1042 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
1043 msiobj_release(&view->hdr);
1049 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1053 static const WCHAR ExecSeqQuery[] =
1054 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1055 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1056 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1057 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1058 'O','R','D','E','R',' ', 'B','Y',' ',
1059 '`','S','e','q','u','e','n','c','e','`',0 };
1060 static const WCHAR IVQuery[] =
1061 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1062 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1063 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1064 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1065 ' ','\'', 'I','n','s','t','a','l','l',
1066 'V','a','l','i','d','a','t','e','\'', 0};
1069 if (package->script->ExecuteSequenceRun)
1071 TRACE("Execute Sequence already Run\n");
1072 return ERROR_SUCCESS;
1075 package->script->ExecuteSequenceRun = TRUE;
1077 /* get the sequence number */
1080 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
1082 return ERROR_FUNCTION_FAILED;
1083 seq = MSI_RecordGetInteger(row,1);
1084 msiobj_release(&row->hdr);
1087 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1088 if (rc == ERROR_SUCCESS)
1090 TRACE("Running the actions\n");
1092 msi_set_property(package->db, cszSourceDir, NULL);
1094 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1095 msiobj_release(&view->hdr);
1101 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1105 static const WCHAR ExecSeqQuery [] =
1106 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1107 '`','I','n','s','t','a','l','l',
1108 'U','I','S','e','q','u','e','n','c','e','`',
1109 ' ','W','H','E','R','E',' ',
1110 '`','S','e','q','u','e','n','c','e','`',' ',
1111 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1112 '`','S','e','q','u','e','n','c','e','`',0};
1114 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1115 if (rc == ERROR_SUCCESS)
1117 TRACE("Running the actions\n");
1119 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1120 msiobj_release(&view->hdr);
1126 /********************************************************
1127 * ACTION helper functions and functions that perform the actions
1128 *******************************************************/
1129 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1130 UINT* rc, UINT script, BOOL force )
1135 arc = ACTION_CustomAction(package, action, script, force);
1137 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1146 * Actual Action Handlers
1149 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1151 MSIPACKAGE *package = param;
1152 LPCWSTR dir, component;
1158 component = MSI_RecordGetString(row, 2);
1160 return ERROR_SUCCESS;
1162 comp = get_loaded_component(package, component);
1164 return ERROR_SUCCESS;
1168 TRACE("component is disabled\n");
1169 return ERROR_SUCCESS;
1172 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1174 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1175 comp->Action = comp->Installed;
1176 return ERROR_SUCCESS;
1178 comp->Action = INSTALLSTATE_LOCAL;
1180 dir = MSI_RecordGetString(row,1);
1183 ERR("Unable to get folder id\n");
1184 return ERROR_SUCCESS;
1187 uirow = MSI_CreateRecord(1);
1188 MSI_RecordSetStringW(uirow, 1, dir);
1189 ui_actiondata(package, szCreateFolders, uirow);
1190 msiobj_release(&uirow->hdr);
1192 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1195 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1196 return ERROR_SUCCESS;
1199 TRACE("Folder is %s\n",debugstr_w(full_path));
1201 if (folder->State == 0)
1202 create_full_pathW(full_path);
1206 msi_free(full_path);
1207 return ERROR_SUCCESS;
1210 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1212 static const WCHAR query[] =
1213 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1214 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1218 /* create all the empty folders specified in the CreateFolder table */
1219 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1220 if (rc != ERROR_SUCCESS)
1221 return ERROR_SUCCESS;
1223 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1224 msiobj_release(&view->hdr);
1229 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1231 MSIPACKAGE *package = param;
1232 LPCWSTR dir, component;
1238 component = MSI_RecordGetString(row, 2);
1240 return ERROR_SUCCESS;
1242 comp = get_loaded_component(package, component);
1244 return ERROR_SUCCESS;
1248 TRACE("component is disabled\n");
1249 return ERROR_SUCCESS;
1252 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1254 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1255 comp->Action = comp->Installed;
1256 return ERROR_SUCCESS;
1258 comp->Action = INSTALLSTATE_ABSENT;
1260 dir = MSI_RecordGetString( row, 1 );
1263 ERR("Unable to get folder id\n");
1264 return ERROR_SUCCESS;
1267 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1270 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1271 return ERROR_SUCCESS;
1274 TRACE("folder is %s\n", debugstr_w(full_path));
1276 uirow = MSI_CreateRecord( 1 );
1277 MSI_RecordSetStringW( uirow, 1, dir );
1278 ui_actiondata( package, szRemoveFolders, uirow );
1279 msiobj_release( &uirow->hdr );
1281 RemoveDirectoryW( full_path );
1284 msi_free( full_path );
1285 return ERROR_SUCCESS;
1288 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1290 static const WCHAR query[] =
1291 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1292 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1297 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1298 if (rc != ERROR_SUCCESS)
1299 return ERROR_SUCCESS;
1301 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1302 msiobj_release( &view->hdr );
1307 static UINT load_component( MSIRECORD *row, LPVOID param )
1309 MSIPACKAGE *package = param;
1312 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1314 return ERROR_FUNCTION_FAILED;
1316 list_add_tail( &package->components, &comp->entry );
1318 /* fill in the data */
1319 comp->Component = msi_dup_record_field( row, 1 );
1321 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1323 comp->ComponentId = msi_dup_record_field( row, 2 );
1324 comp->Directory = msi_dup_record_field( row, 3 );
1325 comp->Attributes = MSI_RecordGetInteger(row,4);
1326 comp->Condition = msi_dup_record_field( row, 5 );
1327 comp->KeyPath = msi_dup_record_field( row, 6 );
1329 comp->Installed = INSTALLSTATE_UNKNOWN;
1330 comp->Action = INSTALLSTATE_UNKNOWN;
1331 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1333 comp->assembly = load_assembly( package, comp );
1334 return ERROR_SUCCESS;
1337 static UINT load_all_components( MSIPACKAGE *package )
1339 static const WCHAR query[] = {
1340 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1341 '`','C','o','m','p','o','n','e','n','t','`',0 };
1345 if (!list_empty(&package->components))
1346 return ERROR_SUCCESS;
1348 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1349 if (r != ERROR_SUCCESS)
1352 r = MSI_IterateRecords(view, NULL, load_component, package);
1353 msiobj_release(&view->hdr);
1358 MSIPACKAGE *package;
1359 MSIFEATURE *feature;
1362 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1366 cl = msi_alloc( sizeof (*cl) );
1368 return ERROR_NOT_ENOUGH_MEMORY;
1369 cl->component = comp;
1370 list_add_tail( &feature->Components, &cl->entry );
1372 return ERROR_SUCCESS;
1375 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1379 fl = msi_alloc( sizeof(*fl) );
1381 return ERROR_NOT_ENOUGH_MEMORY;
1382 fl->feature = child;
1383 list_add_tail( &parent->Children, &fl->entry );
1385 return ERROR_SUCCESS;
1388 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1390 _ilfs* ilfs = param;
1394 component = MSI_RecordGetString(row,1);
1396 /* check to see if the component is already loaded */
1397 comp = get_loaded_component( ilfs->package, component );
1400 ERR("unknown component %s\n", debugstr_w(component));
1401 return ERROR_FUNCTION_FAILED;
1404 add_feature_component( ilfs->feature, comp );
1405 comp->Enabled = TRUE;
1407 return ERROR_SUCCESS;
1410 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1412 MSIFEATURE *feature;
1417 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1419 if ( !strcmpW( feature->Feature, name ) )
1426 static UINT load_feature(MSIRECORD * row, LPVOID param)
1428 MSIPACKAGE* package = param;
1429 MSIFEATURE* feature;
1430 static const WCHAR Query1[] =
1431 {'S','E','L','E','C','T',' ',
1432 '`','C','o','m','p','o','n','e','n','t','_','`',
1433 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1434 'C','o','m','p','o','n','e','n','t','s','`',' ',
1435 'W','H','E','R','E',' ',
1436 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1441 /* fill in the data */
1443 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1445 return ERROR_NOT_ENOUGH_MEMORY;
1447 list_init( &feature->Children );
1448 list_init( &feature->Components );
1450 feature->Feature = msi_dup_record_field( row, 1 );
1452 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1454 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1455 feature->Title = msi_dup_record_field( row, 3 );
1456 feature->Description = msi_dup_record_field( row, 4 );
1458 if (!MSI_RecordIsNull(row,5))
1459 feature->Display = MSI_RecordGetInteger(row,5);
1461 feature->Level= MSI_RecordGetInteger(row,6);
1462 feature->Directory = msi_dup_record_field( row, 7 );
1463 feature->Attributes = MSI_RecordGetInteger(row,8);
1465 feature->Installed = INSTALLSTATE_UNKNOWN;
1466 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1468 list_add_tail( &package->features, &feature->entry );
1470 /* load feature components */
1472 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1473 if (rc != ERROR_SUCCESS)
1474 return ERROR_SUCCESS;
1476 ilfs.package = package;
1477 ilfs.feature = feature;
1479 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1480 msiobj_release(&view->hdr);
1482 return ERROR_SUCCESS;
1485 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1487 MSIPACKAGE* package = param;
1488 MSIFEATURE *parent, *child;
1490 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1492 return ERROR_FUNCTION_FAILED;
1494 if (!child->Feature_Parent)
1495 return ERROR_SUCCESS;
1497 parent = find_feature_by_name( package, child->Feature_Parent );
1499 return ERROR_FUNCTION_FAILED;
1501 add_feature_child( parent, child );
1502 return ERROR_SUCCESS;
1505 static UINT load_all_features( MSIPACKAGE *package )
1507 static const WCHAR query[] = {
1508 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1509 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1510 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1514 if (!list_empty(&package->features))
1515 return ERROR_SUCCESS;
1517 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1518 if (r != ERROR_SUCCESS)
1521 r = MSI_IterateRecords( view, NULL, load_feature, package );
1522 if (r != ERROR_SUCCESS)
1525 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1526 msiobj_release( &view->hdr );
1531 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1542 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1544 static const WCHAR query[] = {
1545 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1546 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1547 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1548 MSIQUERY *view = NULL;
1549 MSIRECORD *row = NULL;
1552 TRACE("%s\n", debugstr_w(file->File));
1554 r = MSI_OpenQuery(package->db, &view, query, file->File);
1555 if (r != ERROR_SUCCESS)
1558 r = MSI_ViewExecute(view, NULL);
1559 if (r != ERROR_SUCCESS)
1562 r = MSI_ViewFetch(view, &row);
1563 if (r != ERROR_SUCCESS)
1566 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1567 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1568 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1569 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1570 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1573 if (view) msiobj_release(&view->hdr);
1574 if (row) msiobj_release(&row->hdr);
1578 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1581 static const WCHAR query[] = {
1582 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1583 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1584 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1586 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1589 WARN("query failed\n");
1590 return ERROR_FUNCTION_FAILED;
1593 file->disk_id = MSI_RecordGetInteger( row, 1 );
1594 msiobj_release( &row->hdr );
1595 return ERROR_SUCCESS;
1598 static UINT load_file(MSIRECORD *row, LPVOID param)
1600 MSIPACKAGE* package = param;
1604 /* fill in the data */
1606 file = msi_alloc_zero( sizeof (MSIFILE) );
1608 return ERROR_NOT_ENOUGH_MEMORY;
1610 file->File = msi_dup_record_field( row, 1 );
1612 component = MSI_RecordGetString( row, 2 );
1613 file->Component = get_loaded_component( package, component );
1615 if (!file->Component)
1617 WARN("Component not found: %s\n", debugstr_w(component));
1618 msi_free(file->File);
1620 return ERROR_SUCCESS;
1623 file->FileName = msi_dup_record_field( row, 3 );
1624 reduce_to_longfilename( file->FileName );
1626 file->ShortName = msi_dup_record_field( row, 3 );
1627 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1629 file->FileSize = MSI_RecordGetInteger( row, 4 );
1630 file->Version = msi_dup_record_field( row, 5 );
1631 file->Language = msi_dup_record_field( row, 6 );
1632 file->Attributes = MSI_RecordGetInteger( row, 7 );
1633 file->Sequence = MSI_RecordGetInteger( row, 8 );
1635 file->state = msifs_invalid;
1637 /* if the compressed bits are not set in the file attributes,
1638 * then read the information from the package word count property
1640 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1642 file->IsCompressed = FALSE;
1644 else if (file->Attributes &
1645 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1647 file->IsCompressed = TRUE;
1649 else if (file->Attributes & msidbFileAttributesNoncompressed)
1651 file->IsCompressed = FALSE;
1655 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1658 load_file_hash(package, file);
1659 load_file_disk_id(package, file);
1661 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1663 list_add_tail( &package->files, &file->entry );
1665 return ERROR_SUCCESS;
1668 static UINT load_all_files(MSIPACKAGE *package)
1672 static const WCHAR Query[] =
1673 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1674 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1675 '`','S','e','q','u','e','n','c','e','`', 0};
1677 if (!list_empty(&package->files))
1678 return ERROR_SUCCESS;
1680 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1681 if (rc != ERROR_SUCCESS)
1682 return ERROR_SUCCESS;
1684 rc = MSI_IterateRecords(view, NULL, load_file, package);
1685 msiobj_release(&view->hdr);
1687 return ERROR_SUCCESS;
1690 static UINT load_folder( MSIRECORD *row, LPVOID param )
1692 MSIPACKAGE *package = param;
1693 static WCHAR szEmpty[] = { 0 };
1694 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1697 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1699 return ERROR_NOT_ENOUGH_MEMORY;
1701 folder->Directory = msi_dup_record_field( row, 1 );
1703 TRACE("%s\n", debugstr_w(folder->Directory));
1705 p = msi_dup_record_field(row, 3);
1707 /* split src and target dir */
1709 src_short = folder_split_path( p, ':' );
1711 /* split the long and short paths */
1712 tgt_long = folder_split_path( tgt_short, '|' );
1713 src_long = folder_split_path( src_short, '|' );
1715 /* check for no-op dirs */
1716 if (tgt_short && !strcmpW( szDot, tgt_short ))
1717 tgt_short = szEmpty;
1718 if (src_short && !strcmpW( szDot, src_short ))
1719 src_short = szEmpty;
1722 tgt_long = tgt_short;
1725 src_short = tgt_short;
1726 src_long = tgt_long;
1730 src_long = src_short;
1732 /* FIXME: use the target short path too */
1733 folder->TargetDefault = strdupW(tgt_long);
1734 folder->SourceShortPath = strdupW(src_short);
1735 folder->SourceLongPath = strdupW(src_long);
1738 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1739 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1740 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1742 folder->Parent = msi_dup_record_field( row, 2 );
1744 folder->Property = msi_dup_property( package->db, folder->Directory );
1746 list_add_tail( &package->folders, &folder->entry );
1748 TRACE("returning %p\n", folder);
1750 return ERROR_SUCCESS;
1753 static UINT load_all_folders( MSIPACKAGE *package )
1755 static const WCHAR query[] = {
1756 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1757 '`','D','i','r','e','c','t','o','r','y','`',0 };
1761 if (!list_empty(&package->folders))
1762 return ERROR_SUCCESS;
1764 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1765 if (r != ERROR_SUCCESS)
1768 r = MSI_IterateRecords(view, NULL, load_folder, package);
1769 msiobj_release(&view->hdr);
1774 * I am not doing any of the costing functionality yet.
1775 * Mostly looking at doing the Component and Feature loading
1777 * The native MSI does A LOT of modification to tables here. Mostly adding
1778 * a lot of temporary columns to the Feature and Component tables.
1780 * note: Native msi also tracks the short filename. But I am only going to
1781 * track the long ones. Also looking at this directory table
1782 * it appears that the directory table does not get the parents
1783 * resolved base on property only based on their entries in the
1786 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1788 static const WCHAR szCosting[] =
1789 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1791 msi_set_property( package->db, szCosting, szZero );
1792 msi_set_property( package->db, cszRootDrive, c_colon );
1794 load_all_folders( package );
1795 load_all_components( package );
1796 load_all_features( package );
1797 load_all_files( package );
1799 return ERROR_SUCCESS;
1802 static UINT execute_script(MSIPACKAGE *package, UINT script )
1805 UINT rc = ERROR_SUCCESS;
1807 TRACE("Executing Script %i\n",script);
1809 if (!package->script)
1811 ERR("no script!\n");
1812 return ERROR_FUNCTION_FAILED;
1815 for (i = 0; i < package->script->ActionCount[script]; i++)
1818 action = package->script->Actions[script][i];
1819 ui_actionstart(package, action);
1820 TRACE("Executing Action (%s)\n",debugstr_w(action));
1821 rc = ACTION_PerformAction(package, action, script);
1822 if (rc != ERROR_SUCCESS)
1825 msi_free_action_script(package, script);
1829 static UINT ACTION_FileCost(MSIPACKAGE *package)
1831 return ERROR_SUCCESS;
1834 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1837 INSTALLSTATE state = MsiQueryProductStateW( package->ProductCode );
1840 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1842 if (!comp->ComponentId) continue;
1844 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1845 comp->Installed = INSTALLSTATE_ABSENT;
1848 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1849 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1851 if (r != ERROR_SUCCESS)
1852 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1853 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1855 if (r != ERROR_SUCCESS)
1856 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1857 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1859 if (r != ERROR_SUCCESS)
1860 comp->Installed = INSTALLSTATE_ABSENT;
1865 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1867 MSIFEATURE *feature;
1870 state = MsiQueryProductStateW(package->ProductCode);
1872 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1874 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1875 feature->Installed = INSTALLSTATE_ABSENT;
1878 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1884 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1886 return (feature->Level > 0 && feature->Level <= level);
1889 static BOOL process_state_property(MSIPACKAGE* package, int level,
1890 LPCWSTR property, INSTALLSTATE state)
1893 MSIFEATURE *feature;
1895 override = msi_dup_property( package->db, property );
1899 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1901 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1904 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1906 if (!strcmpiW( override, szAll ))
1907 msi_feature_set_state(package, feature, state);
1910 LPWSTR ptr = override;
1911 LPWSTR ptr2 = strchrW(override,',');
1915 int len = ptr2 - ptr;
1917 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1918 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1920 msi_feature_set_state(package, feature, state);
1926 ptr2 = strchrW(ptr,',');
1938 static BOOL process_overrides( MSIPACKAGE *package, int level )
1940 static const WCHAR szAddLocal[] =
1941 {'A','D','D','L','O','C','A','L',0};
1942 static const WCHAR szAddSource[] =
1943 {'A','D','D','S','O','U','R','C','E',0};
1944 static const WCHAR szAdvertise[] =
1945 {'A','D','V','E','R','T','I','S','E',0};
1948 /* all these activation/deactivation things happen in order and things
1949 * later on the list override things earlier on the list.
1951 * 0 INSTALLLEVEL processing
1964 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1965 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1966 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1967 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1968 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1971 msi_set_property( package->db, szPreselected, szOne );
1976 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1979 static const WCHAR szlevel[] =
1980 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1981 MSICOMPONENT* component;
1982 MSIFEATURE *feature;
1984 TRACE("Checking Install Level\n");
1986 level = msi_get_property_int(package->db, szlevel, 1);
1988 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1990 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1992 if (!is_feature_selected( feature, level )) continue;
1994 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1996 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1997 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1998 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1999 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
2001 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
2005 /* disable child features of unselected parent features */
2006 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2010 if (is_feature_selected( feature, level )) continue;
2012 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2013 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
2016 else /* preselected */
2018 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2020 if (!is_feature_selected( feature, level )) continue;
2022 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2024 msi_feature_set_state(package, feature, feature->Installed);
2030 * now we want to enable or disable components based on feature
2032 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2036 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2037 debugstr_w(feature->Feature), feature->Level, feature->Installed,
2038 feature->ActionRequest, feature->Action);
2040 if (!is_feature_selected( feature, level )) continue;
2042 /* features with components that have compressed files are made local */
2043 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2045 if (cl->component->ForceLocalState &&
2046 feature->ActionRequest == INSTALLSTATE_SOURCE)
2048 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
2053 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2055 component = cl->component;
2057 switch (feature->ActionRequest)
2059 case INSTALLSTATE_ABSENT:
2060 component->anyAbsent = 1;
2062 case INSTALLSTATE_ADVERTISED:
2063 component->hasAdvertiseFeature = 1;
2065 case INSTALLSTATE_SOURCE:
2066 component->hasSourceFeature = 1;
2068 case INSTALLSTATE_LOCAL:
2069 component->hasLocalFeature = 1;
2071 case INSTALLSTATE_DEFAULT:
2072 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2073 component->hasAdvertiseFeature = 1;
2074 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2075 component->hasSourceFeature = 1;
2077 component->hasLocalFeature = 1;
2085 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2087 /* check if it's local or source */
2088 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2089 (component->hasLocalFeature || component->hasSourceFeature))
2091 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2092 !component->ForceLocalState)
2093 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2095 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2099 /* if any feature is local, the component must be local too */
2100 if (component->hasLocalFeature)
2102 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2106 if (component->hasSourceFeature)
2108 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2112 if (component->hasAdvertiseFeature)
2114 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2118 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2119 if (component->anyAbsent)
2120 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2123 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2125 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2127 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2128 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2131 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2132 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2135 return ERROR_SUCCESS;
2138 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2140 MSIPACKAGE *package = param;
2145 name = MSI_RecordGetString(row,1);
2147 f = get_loaded_folder(package, name);
2148 if (!f) return ERROR_SUCCESS;
2150 /* reset the ResolvedTarget */
2151 msi_free(f->ResolvedTarget);
2152 f->ResolvedTarget = NULL;
2154 /* This helper function now does ALL the work */
2155 TRACE("Dir %s ...\n",debugstr_w(name));
2156 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2157 TRACE("resolves to %s\n",debugstr_w(path));
2160 return ERROR_SUCCESS;
2163 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2165 MSIPACKAGE *package = param;
2167 MSIFEATURE *feature;
2169 name = MSI_RecordGetString( row, 1 );
2171 feature = get_loaded_feature( package, name );
2173 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2177 Condition = MSI_RecordGetString(row,3);
2179 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2181 int level = MSI_RecordGetInteger(row,2);
2182 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2183 feature->Level = level;
2186 return ERROR_SUCCESS;
2189 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2191 static const WCHAR name[] = {'\\',0};
2192 VS_FIXEDFILEINFO *ptr, *ret;
2194 DWORD versize, handle;
2197 TRACE("%s\n", debugstr_w(filename));
2199 versize = GetFileVersionInfoSizeW( filename, &handle );
2203 version = msi_alloc( versize );
2207 GetFileVersionInfoW( filename, 0, versize, version );
2209 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2211 msi_free( version );
2215 ret = msi_alloc( sz );
2216 memcpy( ret, ptr, sz );
2218 msi_free( version );
2222 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2226 msi_parse_version_string( version, &ms, &ls );
2228 if (fi->dwFileVersionMS > ms) return 1;
2229 else if (fi->dwFileVersionMS < ms) return -1;
2230 else if (fi->dwFileVersionLS > ls) return 1;
2231 else if (fi->dwFileVersionLS < ls) return -1;
2235 static int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2239 msi_parse_version_string( ver1, &ms1, NULL );
2240 msi_parse_version_string( ver2, &ms2, NULL );
2242 if (ms1 > ms2) return 1;
2243 else if (ms1 < ms2) return -1;
2247 static DWORD get_disk_file_size( LPCWSTR filename )
2252 TRACE("%s\n", debugstr_w(filename));
2254 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2255 if (file == INVALID_HANDLE_VALUE)
2256 return INVALID_FILE_SIZE;
2258 size = GetFileSize( file, NULL );
2259 CloseHandle( file );
2263 static BOOL hash_matches( MSIFILE *file )
2266 MSIFILEHASHINFO hash;
2268 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2269 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2270 if (r != ERROR_SUCCESS)
2273 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2276 static WCHAR *get_temp_dir( void )
2279 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2281 GetTempPathW( MAX_PATH, tmp );
2284 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2285 if (CreateDirectoryW( dir, NULL )) break;
2287 return strdupW( dir );
2290 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2292 MSIASSEMBLY *assembly = file->Component->assembly;
2294 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2296 msi_free( file->TargetPath );
2297 if (assembly && !assembly->application)
2299 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2300 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2301 track_tempfile( package, file->TargetPath );
2305 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2306 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2310 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2313 static UINT set_file_install_states( MSIPACKAGE *package )
2315 VS_FIXEDFILEINFO *file_version;
2316 WCHAR *font_version;
2319 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2321 MSICOMPONENT *comp = file->Component;
2324 if (!comp->Enabled) continue;
2326 if (file->IsCompressed)
2327 comp->ForceLocalState = TRUE;
2329 set_target_path( package, file );
2331 if ((comp->assembly && !comp->assembly->installed) ||
2332 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2334 file->state = msifs_missing;
2335 comp->Cost += file->FileSize;
2340 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2342 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2343 HIWORD(file_version->dwFileVersionMS),
2344 LOWORD(file_version->dwFileVersionMS),
2345 HIWORD(file_version->dwFileVersionLS),
2346 LOWORD(file_version->dwFileVersionLS));
2348 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2350 file->state = msifs_overwrite;
2351 comp->Cost += file->FileSize;
2355 TRACE("Destination file version equal or greater, not overwriting\n");
2356 file->state = msifs_present;
2358 msi_free( file_version );
2361 else if ((font_version = font_version_from_file( file->TargetPath )))
2363 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
2365 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2367 file->state = msifs_overwrite;
2368 comp->Cost += file->FileSize;
2372 TRACE("Destination file version equal or greater, not overwriting\n");
2373 file->state = msifs_present;
2375 msi_free( font_version );
2379 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2381 file->state = msifs_overwrite;
2382 comp->Cost += file->FileSize - file_size;
2385 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2387 TRACE("File hashes match, not overwriting\n");
2388 file->state = msifs_present;
2391 file->state = msifs_overwrite;
2392 comp->Cost += file->FileSize - file_size;
2395 return ERROR_SUCCESS;
2399 * A lot is done in this function aside from just the costing.
2400 * The costing needs to be implemented at some point but for now I am going
2401 * to focus on the directory building
2404 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2406 static const WCHAR ExecSeqQuery[] =
2407 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2408 '`','D','i','r','e','c','t','o','r','y','`',0};
2409 static const WCHAR ConditionQuery[] =
2410 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2411 '`','C','o','n','d','i','t','i','o','n','`',0};
2412 static const WCHAR szCosting[] =
2413 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2414 static const WCHAR szlevel[] =
2415 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2416 static const WCHAR szOutOfDiskSpace[] =
2417 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2419 UINT rc = ERROR_SUCCESS;
2423 TRACE("Building Directory properties\n");
2425 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2426 if (rc == ERROR_SUCCESS)
2428 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2430 msiobj_release(&view->hdr);
2433 TRACE("Evaluating component conditions\n");
2434 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2436 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2438 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2439 comp->Enabled = FALSE;
2442 comp->Enabled = TRUE;
2445 /* read components states from the registry */
2446 ACTION_GetComponentInstallStates(package);
2447 ACTION_GetFeatureInstallStates(package);
2449 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2451 TRACE("Evaluating feature conditions\n");
2453 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2454 if (rc == ERROR_SUCCESS)
2456 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2457 msiobj_release( &view->hdr );
2461 TRACE("Calculating file install states\n");
2462 set_file_install_states( package );
2464 msi_set_property( package->db, szCosting, szOne );
2465 /* set default run level if not set */
2466 level = msi_dup_property( package->db, szlevel );
2468 msi_set_property( package->db, szlevel, szOne );
2471 /* FIXME: check volume disk space */
2472 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2474 return MSI_SetFeatureStates(package);
2477 /* OK this value is "interpreted" and then formatted based on the
2478 first few characters */
2479 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2484 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2490 LPWSTR deformated = NULL;
2493 deformat_string(package, &value[2], &deformated);
2495 /* binary value type */
2499 *size = (strlenW(ptr)/2)+1;
2501 *size = strlenW(ptr)/2;
2503 data = msi_alloc(*size);
2509 /* if uneven pad with a zero in front */
2515 data[count] = (BYTE)strtol(byte,NULL,0);
2517 TRACE("Uneven byte count\n");
2525 data[count] = (BYTE)strtol(byte,NULL,0);
2528 msi_free(deformated);
2530 TRACE("Data %i bytes(%i)\n",*size,count);
2537 deformat_string(package, &value[1], &deformated);
2540 *size = sizeof(DWORD);
2541 data = msi_alloc(*size);
2547 if ( (*p < '0') || (*p > '9') )
2553 if (deformated[0] == '-')
2556 TRACE("DWORD %i\n",*(LPDWORD)data);
2558 msi_free(deformated);
2563 static const WCHAR szMulti[] = {'[','~',']',0};
2572 *type=REG_EXPAND_SZ;
2580 if (strstrW(value, szMulti))
2581 *type = REG_MULTI_SZ;
2583 /* remove initial delimiter */
2584 if (!strncmpW(value, szMulti, 3))
2587 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2589 /* add double NULL terminator */
2590 if (*type == REG_MULTI_SZ)
2592 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2593 data = msi_realloc_zero(data, *size);
2599 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2606 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2608 *root_key = HKEY_LOCAL_MACHINE;
2613 *root_key = HKEY_CURRENT_USER;
2618 *root_key = HKEY_CLASSES_ROOT;
2622 *root_key = HKEY_CURRENT_USER;
2626 *root_key = HKEY_LOCAL_MACHINE;
2630 *root_key = HKEY_USERS;
2634 ERR("Unknown root %i\n", root);
2641 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2643 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2644 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2646 if (is_64bit && package->platform == PLATFORM_INTEL &&
2647 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2652 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2653 path_32node = msi_alloc( size );
2657 memcpy( path_32node, path, len * sizeof(WCHAR) );
2658 path_32node[len] = 0;
2659 strcatW( path_32node, szWow6432Node );
2660 strcatW( path_32node, szBackSlash );
2661 strcatW( path_32node, path + len );
2665 return strdupW( path );
2668 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2670 MSIPACKAGE *package = param;
2671 LPSTR value_data = NULL;
2672 HKEY root_key, hkey;
2674 LPWSTR deformated, uikey, keypath;
2675 LPCWSTR szRoot, component, name, key, value;
2679 BOOL check_first = FALSE;
2682 ui_progress(package,2,0,0,0);
2684 component = MSI_RecordGetString(row, 6);
2685 comp = get_loaded_component(package,component);
2687 return ERROR_SUCCESS;
2691 TRACE("component is disabled\n");
2692 return ERROR_SUCCESS;
2695 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2697 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2698 comp->Action = comp->Installed;
2699 return ERROR_SUCCESS;
2701 comp->Action = INSTALLSTATE_LOCAL;
2703 name = MSI_RecordGetString(row, 4);
2704 if( MSI_RecordIsNull(row,5) && name )
2706 /* null values can have special meanings */
2707 if (name[0]=='-' && name[1] == 0)
2708 return ERROR_SUCCESS;
2709 else if ((name[0]=='+' && name[1] == 0) ||
2710 (name[0] == '*' && name[1] == 0))
2715 root = MSI_RecordGetInteger(row,2);
2716 key = MSI_RecordGetString(row, 3);
2718 szRoot = get_root_key( package, root, &root_key );
2720 return ERROR_SUCCESS;
2722 deformat_string(package, key , &deformated);
2723 size = strlenW(deformated) + strlenW(szRoot) + 1;
2724 uikey = msi_alloc(size*sizeof(WCHAR));
2725 strcpyW(uikey,szRoot);
2726 strcatW(uikey,deformated);
2728 keypath = get_keypath( package, root_key, deformated );
2729 msi_free( deformated );
2730 if (RegCreateKeyW( root_key, keypath, &hkey ))
2732 ERR("Could not create key %s\n", debugstr_w(keypath));
2735 return ERROR_SUCCESS;
2738 value = MSI_RecordGetString(row,5);
2740 value_data = parse_value(package, value, &type, &size);
2743 value_data = (LPSTR)strdupW(szEmpty);
2744 size = sizeof(szEmpty);
2748 deformat_string(package, name, &deformated);
2752 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2754 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2759 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2760 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2762 TRACE("value %s of %s checked already exists\n",
2763 debugstr_w(deformated), debugstr_w(uikey));
2767 TRACE("Checked and setting value %s of %s\n",
2768 debugstr_w(deformated), debugstr_w(uikey));
2769 if (deformated || size)
2770 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2775 uirow = MSI_CreateRecord(3);
2776 MSI_RecordSetStringW(uirow,2,deformated);
2777 MSI_RecordSetStringW(uirow,1,uikey);
2778 if (type == REG_SZ || type == REG_EXPAND_SZ)
2779 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2780 ui_actiondata(package,szWriteRegistryValues,uirow);
2781 msiobj_release( &uirow->hdr );
2783 msi_free(value_data);
2784 msi_free(deformated);
2788 return ERROR_SUCCESS;
2791 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2795 static const WCHAR ExecSeqQuery[] =
2796 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2797 '`','R','e','g','i','s','t','r','y','`',0 };
2799 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2800 if (rc != ERROR_SUCCESS)
2801 return ERROR_SUCCESS;
2803 /* increment progress bar each time action data is sent */
2804 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2806 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2808 msiobj_release(&view->hdr);
2812 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2816 DWORD num_subkeys, num_values;
2820 if ((res = RegDeleteTreeW( hkey_root, key )))
2822 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2827 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2829 if ((res = RegDeleteValueW( hkey, value )))
2831 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2833 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2834 NULL, NULL, NULL, NULL );
2835 RegCloseKey( hkey );
2836 if (!res && !num_subkeys && !num_values)
2838 TRACE("Removing empty key %s\n", debugstr_w(key));
2839 RegDeleteKeyW( hkey_root, key );
2843 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2847 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2849 MSIPACKAGE *package = param;
2850 LPCWSTR component, name, key_str, root_key_str;
2851 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2854 BOOL delete_key = FALSE;
2859 ui_progress( package, 2, 0, 0, 0 );
2861 component = MSI_RecordGetString( row, 6 );
2862 comp = get_loaded_component( package, component );
2864 return ERROR_SUCCESS;
2868 TRACE("component is disabled\n");
2869 return ERROR_SUCCESS;
2872 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2874 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2875 comp->Action = comp->Installed;
2876 return ERROR_SUCCESS;
2878 comp->Action = INSTALLSTATE_ABSENT;
2880 name = MSI_RecordGetString( row, 4 );
2881 if (MSI_RecordIsNull( row, 5 ) && name )
2883 if (name[0] == '+' && !name[1])
2884 return ERROR_SUCCESS;
2885 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2892 root = MSI_RecordGetInteger( row, 2 );
2893 key_str = MSI_RecordGetString( row, 3 );
2895 root_key_str = get_root_key( package, root, &hkey_root );
2897 return ERROR_SUCCESS;
2899 deformat_string( package, key_str, &deformated_key );
2900 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2901 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2902 strcpyW( ui_key_str, root_key_str );
2903 strcatW( ui_key_str, deformated_key );
2905 deformat_string( package, name, &deformated_name );
2907 keypath = get_keypath( package, hkey_root, deformated_key );
2908 msi_free( deformated_key );
2909 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2910 msi_free( keypath );
2912 uirow = MSI_CreateRecord( 2 );
2913 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2914 MSI_RecordSetStringW( uirow, 2, deformated_name );
2916 ui_actiondata( package, szRemoveRegistryValues, uirow );
2917 msiobj_release( &uirow->hdr );
2919 msi_free( ui_key_str );
2920 msi_free( deformated_name );
2921 return ERROR_SUCCESS;
2924 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2926 MSIPACKAGE *package = param;
2927 LPCWSTR component, name, key_str, root_key_str;
2928 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2931 BOOL delete_key = FALSE;
2936 ui_progress( package, 2, 0, 0, 0 );
2938 component = MSI_RecordGetString( row, 5 );
2939 comp = get_loaded_component( package, component );
2941 return ERROR_SUCCESS;
2945 TRACE("component is disabled\n");
2946 return ERROR_SUCCESS;
2949 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2951 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2952 comp->Action = comp->Installed;
2953 return ERROR_SUCCESS;
2955 comp->Action = INSTALLSTATE_LOCAL;
2957 if ((name = MSI_RecordGetString( row, 4 )))
2959 if (name[0] == '-' && !name[1])
2966 root = MSI_RecordGetInteger( row, 2 );
2967 key_str = MSI_RecordGetString( row, 3 );
2969 root_key_str = get_root_key( package, root, &hkey_root );
2971 return ERROR_SUCCESS;
2973 deformat_string( package, key_str, &deformated_key );
2974 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2975 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2976 strcpyW( ui_key_str, root_key_str );
2977 strcatW( ui_key_str, deformated_key );
2979 deformat_string( package, name, &deformated_name );
2981 keypath = get_keypath( package, hkey_root, deformated_key );
2982 msi_free( deformated_key );
2983 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2984 msi_free( keypath );
2986 uirow = MSI_CreateRecord( 2 );
2987 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2988 MSI_RecordSetStringW( uirow, 2, deformated_name );
2990 ui_actiondata( package, szRemoveRegistryValues, uirow );
2991 msiobj_release( &uirow->hdr );
2993 msi_free( ui_key_str );
2994 msi_free( deformated_name );
2995 return ERROR_SUCCESS;
2998 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3002 static const WCHAR registry_query[] =
3003 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3004 '`','R','e','g','i','s','t','r','y','`',0 };
3005 static const WCHAR remove_registry_query[] =
3006 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3007 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
3009 /* increment progress bar each time action data is sent */
3010 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
3012 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3013 if (rc == ERROR_SUCCESS)
3015 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3016 msiobj_release( &view->hdr );
3017 if (rc != ERROR_SUCCESS)
3021 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3022 if (rc == ERROR_SUCCESS)
3024 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3025 msiobj_release( &view->hdr );
3026 if (rc != ERROR_SUCCESS)
3030 return ERROR_SUCCESS;
3033 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3035 package->script->CurrentlyScripting = TRUE;
3037 return ERROR_SUCCESS;
3041 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3046 static const WCHAR q1[]=
3047 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3048 '`','R','e','g','i','s','t','r','y','`',0};
3051 MSIFEATURE *feature;
3054 TRACE("InstallValidate\n");
3056 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3057 if (rc == ERROR_SUCCESS)
3059 MSI_IterateRecords( view, &progress, NULL, package );
3060 msiobj_release( &view->hdr );
3061 total += progress * REG_PROGRESS_VALUE;
3064 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3065 total += COMPONENT_PROGRESS_VALUE;
3067 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3068 total += file->FileSize;
3070 ui_progress(package,0,total,0,0);
3072 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3074 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3075 debugstr_w(feature->Feature), feature->Installed,
3076 feature->ActionRequest, feature->Action);
3079 return ERROR_SUCCESS;
3082 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3084 MSIPACKAGE* package = param;
3085 LPCWSTR cond = NULL;
3086 LPCWSTR message = NULL;
3089 static const WCHAR title[]=
3090 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3092 cond = MSI_RecordGetString(row,1);
3094 r = MSI_EvaluateConditionW(package,cond);
3095 if (r == MSICONDITION_FALSE)
3097 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3100 message = MSI_RecordGetString(row,2);
3101 deformat_string(package,message,&deformated);
3102 MessageBoxW(NULL,deformated,title,MB_OK);
3103 msi_free(deformated);
3106 return ERROR_INSTALL_FAILURE;
3109 return ERROR_SUCCESS;
3112 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3115 MSIQUERY * view = NULL;
3116 static const WCHAR ExecSeqQuery[] =
3117 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3118 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3120 TRACE("Checking launch conditions\n");
3122 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3123 if (rc != ERROR_SUCCESS)
3124 return ERROR_SUCCESS;
3126 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3127 msiobj_release(&view->hdr);
3132 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3136 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
3138 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3140 MSIRECORD * row = 0;
3142 LPWSTR deformated,buffer,deformated_name;
3144 static const WCHAR ExecSeqQuery[] =
3145 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3146 '`','R','e','g','i','s','t','r','y','`',' ',
3147 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3148 ' ','=',' ' ,'\'','%','s','\'',0 };
3149 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3150 static const WCHAR fmt2[]=
3151 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3153 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3157 root = MSI_RecordGetInteger(row,2);
3158 key = MSI_RecordGetString(row, 3);
3159 name = MSI_RecordGetString(row, 4);
3160 deformat_string(package, key , &deformated);
3161 deformat_string(package, name, &deformated_name);
3163 len = strlenW(deformated) + 6;
3164 if (deformated_name)
3165 len+=strlenW(deformated_name);
3167 buffer = msi_alloc( len *sizeof(WCHAR));
3169 if (deformated_name)
3170 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3172 sprintfW(buffer,fmt,root,deformated);
3174 msi_free(deformated);
3175 msi_free(deformated_name);
3176 msiobj_release(&row->hdr);
3180 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3182 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3187 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3190 return strdupW( file->TargetPath );
3195 static HKEY openSharedDLLsKey(void)
3198 static const WCHAR path[] =
3199 {'S','o','f','t','w','a','r','e','\\',
3200 'M','i','c','r','o','s','o','f','t','\\',
3201 'W','i','n','d','o','w','s','\\',
3202 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3203 'S','h','a','r','e','d','D','L','L','s',0};
3205 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3209 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3214 DWORD sz = sizeof(count);
3217 hkey = openSharedDLLsKey();
3218 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3219 if (rc != ERROR_SUCCESS)
3225 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3229 hkey = openSharedDLLsKey();
3231 msi_reg_set_val_dword( hkey, path, count );
3233 RegDeleteValueW(hkey,path);
3239 * Return TRUE if the count should be written out and FALSE if not
3241 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3243 MSIFEATURE *feature;
3247 /* only refcount DLLs */
3248 if (comp->KeyPath == NULL ||
3249 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3250 comp->Attributes & msidbComponentAttributesODBCDataSource)
3254 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3255 write = (count > 0);
3257 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3261 /* increment counts */
3262 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3266 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3269 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3271 if ( cl->component == comp )
3276 /* decrement counts */
3277 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3281 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3284 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3286 if ( cl->component == comp )
3291 /* ref count all the files in the component */
3296 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3298 if (file->Component == comp)
3299 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3303 /* add a count for permanent */
3304 if (comp->Attributes & msidbComponentAttributesPermanent)
3307 comp->RefCount = count;
3310 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3313 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3315 WCHAR squished_pc[GUID_SIZE];
3316 WCHAR squished_cc[GUID_SIZE];
3323 squash_guid(package->ProductCode,squished_pc);
3324 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3326 msi_set_sourcedir_props(package, FALSE);
3328 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3332 ui_progress(package,2,0,0,0);
3333 if (!comp->ComponentId)
3336 squash_guid(comp->ComponentId,squished_cc);
3338 msi_free(comp->FullKeypath);
3339 comp->FullKeypath = resolve_keypath( package, comp );
3341 ACTION_RefCountComponent( package, comp );
3343 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3344 debugstr_w(comp->Component),
3345 debugstr_w(squished_cc),
3346 debugstr_w(comp->FullKeypath),
3348 comp->ActionRequest);
3350 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3351 comp->ActionRequest == INSTALLSTATE_SOURCE)
3353 if (!comp->FullKeypath)
3356 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3357 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3360 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3363 if (rc != ERROR_SUCCESS)
3366 if (comp->Attributes & msidbComponentAttributesPermanent)
3368 static const WCHAR szPermKey[] =
3369 { '0','0','0','0','0','0','0','0','0','0','0','0',
3370 '0','0','0','0','0','0','0','0','0','0','0','0',
3371 '0','0','0','0','0','0','0','0',0 };
3373 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3376 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3377 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3383 WCHAR source[MAX_PATH];
3384 WCHAR base[MAX_PATH];
3387 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3388 static const WCHAR query[] = {
3389 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3390 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3391 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3392 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3393 '`','D','i','s','k','I','d','`',0};
3395 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3398 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3399 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3400 ptr2 = strrchrW(source, '\\') + 1;
3401 msiobj_release(&row->hdr);
3403 lstrcpyW(base, package->PackagePath);
3404 ptr = strrchrW(base, '\\');
3407 sourcepath = resolve_file_source(package, file);
3408 ptr = sourcepath + lstrlenW(base);
3409 lstrcpyW(ptr2, ptr);
3410 msi_free(sourcepath);
3412 msi_reg_set_val_str(hkey, squished_pc, source);
3416 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3418 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3419 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3421 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3423 comp->Action = comp->ActionRequest;
3426 uirow = MSI_CreateRecord(3);
3427 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3428 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3429 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3430 ui_actiondata(package,szProcessComponents,uirow);
3431 msiobj_release( &uirow->hdr );
3434 return ERROR_SUCCESS;
3445 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3446 LPWSTR lpszName, LONG_PTR lParam)
3449 typelib_struct *tl_struct = (typelib_struct*) lParam;
3450 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3454 if (!IS_INTRESOURCE(lpszName))
3456 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3460 sz = strlenW(tl_struct->source)+4;
3461 sz *= sizeof(WCHAR);
3463 if ((INT_PTR)lpszName == 1)
3464 tl_struct->path = strdupW(tl_struct->source);
3467 tl_struct->path = msi_alloc(sz);
3468 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3471 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3472 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3475 msi_free(tl_struct->path);
3476 tl_struct->path = NULL;
3481 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3482 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3484 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3488 msi_free(tl_struct->path);
3489 tl_struct->path = NULL;
3491 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3492 ITypeLib_Release(tl_struct->ptLib);
3497 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3499 MSIPACKAGE* package = param;
3503 typelib_struct tl_struct;
3508 component = MSI_RecordGetString(row,3);
3509 comp = get_loaded_component(package,component);
3511 return ERROR_SUCCESS;
3515 TRACE("component is disabled\n");
3516 return ERROR_SUCCESS;
3519 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3521 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3522 comp->Action = comp->Installed;
3523 return ERROR_SUCCESS;
3525 comp->Action = INSTALLSTATE_LOCAL;
3527 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3529 TRACE("component has no key path\n");
3530 return ERROR_SUCCESS;
3532 ui_actiondata( package, szRegisterTypeLibraries, row );
3534 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3538 guid = MSI_RecordGetString(row,1);
3539 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3540 tl_struct.source = strdupW( file->TargetPath );
3541 tl_struct.path = NULL;
3543 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3544 (LONG_PTR)&tl_struct);
3552 helpid = MSI_RecordGetString(row,6);
3555 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3556 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3560 ERR("Failed to register type library %s\n",
3561 debugstr_w(tl_struct.path));
3563 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3565 ITypeLib_Release(tl_struct.ptLib);
3566 msi_free(tl_struct.path);
3569 ERR("Failed to load type library %s\n",
3570 debugstr_w(tl_struct.source));
3572 FreeLibrary(module);
3573 msi_free(tl_struct.source);
3577 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3580 ERR("Failed to load type library: %08x\n", hr);
3581 return ERROR_INSTALL_FAILURE;
3584 ITypeLib_Release(tlib);
3587 return ERROR_SUCCESS;
3590 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3593 * OK this is a bit confusing.. I am given a _Component key and I believe
3594 * that the file that is being registered as a type library is the "key file
3595 * of that component" which I interpret to mean "The file in the KeyPath of
3600 static const WCHAR Query[] =
3601 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3602 '`','T','y','p','e','L','i','b','`',0};
3604 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3605 if (rc != ERROR_SUCCESS)
3606 return ERROR_SUCCESS;
3608 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3609 msiobj_release(&view->hdr);
3613 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3615 MSIPACKAGE *package = param;
3616 LPCWSTR component, guid;
3624 component = MSI_RecordGetString( row, 3 );
3625 comp = get_loaded_component( package, component );
3627 return ERROR_SUCCESS;
3631 TRACE("component is disabled\n");
3632 return ERROR_SUCCESS;
3635 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3637 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3638 comp->Action = comp->Installed;
3639 return ERROR_SUCCESS;
3641 comp->Action = INSTALLSTATE_ABSENT;
3643 ui_actiondata( package, szUnregisterTypeLibraries, row );
3645 guid = MSI_RecordGetString( row, 1 );
3646 CLSIDFromString( (LPCWSTR)guid, &libid );
3647 version = MSI_RecordGetInteger( row, 4 );
3648 language = MSI_RecordGetInteger( row, 2 );
3651 syskind = SYS_WIN64;
3653 syskind = SYS_WIN32;
3656 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3659 WARN("Failed to unregister typelib: %08x\n", hr);
3662 return ERROR_SUCCESS;
3665 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3669 static const WCHAR query[] =
3670 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3671 '`','T','y','p','e','L','i','b','`',0};
3673 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3674 if (rc != ERROR_SUCCESS)
3675 return ERROR_SUCCESS;
3677 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3678 msiobj_release( &view->hdr );
3682 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3684 static const WCHAR szlnk[] = {'.','l','n','k',0};
3685 LPCWSTR directory, extension;
3686 LPWSTR link_folder, link_file, filename;
3688 directory = MSI_RecordGetString( row, 2 );
3689 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3691 /* may be needed because of a bug somewhere else */
3692 create_full_pathW( link_folder );
3694 filename = msi_dup_record_field( row, 3 );
3695 reduce_to_longfilename( filename );
3697 extension = strchrW( filename, '.' );
3698 if (!extension || strcmpiW( extension, szlnk ))
3700 int len = strlenW( filename );
3701 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3702 memcpy( filename + len, szlnk, sizeof(szlnk) );
3704 link_file = build_directory_name( 2, link_folder, filename );
3705 msi_free( link_folder );
3706 msi_free( filename );
3711 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3713 MSIPACKAGE *package = param;
3714 LPWSTR link_file, deformated, path;
3715 LPCWSTR component, target;
3717 IShellLinkW *sl = NULL;
3718 IPersistFile *pf = NULL;
3721 component = MSI_RecordGetString(row, 4);
3722 comp = get_loaded_component(package, component);
3724 return ERROR_SUCCESS;
3728 TRACE("component is disabled\n");
3729 return ERROR_SUCCESS;
3732 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3734 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3735 comp->Action = comp->Installed;
3736 return ERROR_SUCCESS;
3738 comp->Action = INSTALLSTATE_LOCAL;
3740 ui_actiondata(package,szCreateShortcuts,row);
3742 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3743 &IID_IShellLinkW, (LPVOID *) &sl );
3747 ERR("CLSID_ShellLink not available\n");
3751 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3754 ERR("QueryInterface(IID_IPersistFile) failed\n");
3758 target = MSI_RecordGetString(row, 5);
3759 if (strchrW(target, '['))
3761 deformat_string(package, target, &deformated);
3762 IShellLinkW_SetPath(sl,deformated);
3763 msi_free(deformated);
3767 FIXME("poorly handled shortcut format, advertised shortcut\n");
3768 IShellLinkW_SetPath(sl,comp->FullKeypath);
3771 if (!MSI_RecordIsNull(row,6))
3773 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3774 deformat_string(package, arguments, &deformated);
3775 IShellLinkW_SetArguments(sl,deformated);
3776 msi_free(deformated);
3779 if (!MSI_RecordIsNull(row,7))
3781 LPCWSTR description = MSI_RecordGetString(row, 7);
3782 IShellLinkW_SetDescription(sl, description);
3785 if (!MSI_RecordIsNull(row,8))
3786 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3788 if (!MSI_RecordIsNull(row,9))
3791 LPCWSTR icon = MSI_RecordGetString(row, 9);
3793 path = build_icon_path(package, icon);
3794 index = MSI_RecordGetInteger(row,10);
3796 /* no value means 0 */
3797 if (index == MSI_NULL_INTEGER)
3800 IShellLinkW_SetIconLocation(sl, path, index);
3804 if (!MSI_RecordIsNull(row,11))
3805 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3807 if (!MSI_RecordIsNull(row,12))
3809 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3810 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3812 IShellLinkW_SetWorkingDirectory(sl, path);
3816 link_file = get_link_file(package, row);
3818 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3819 IPersistFile_Save(pf, link_file, FALSE);
3821 msi_free(link_file);
3825 IPersistFile_Release( pf );
3827 IShellLinkW_Release( sl );
3829 return ERROR_SUCCESS;
3832 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3837 static const WCHAR Query[] =
3838 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3839 '`','S','h','o','r','t','c','u','t','`',0};
3841 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3842 if (rc != ERROR_SUCCESS)
3843 return ERROR_SUCCESS;
3845 res = CoInitialize( NULL );
3847 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3848 msiobj_release(&view->hdr);
3856 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3858 MSIPACKAGE *package = param;
3863 component = MSI_RecordGetString( row, 4 );
3864 comp = get_loaded_component( package, component );
3866 return ERROR_SUCCESS;
3870 TRACE("component is disabled\n");
3871 return ERROR_SUCCESS;
3874 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3876 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3877 comp->Action = comp->Installed;
3878 return ERROR_SUCCESS;
3880 comp->Action = INSTALLSTATE_ABSENT;
3882 ui_actiondata( package, szRemoveShortcuts, row );
3884 link_file = get_link_file( package, row );
3886 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3887 if (!DeleteFileW( link_file ))
3889 WARN("Failed to remove shortcut file %u\n", GetLastError());
3891 msi_free( link_file );
3893 return ERROR_SUCCESS;
3896 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3900 static const WCHAR query[] =
3901 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3902 '`','S','h','o','r','t','c','u','t','`',0};
3904 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3905 if (rc != ERROR_SUCCESS)
3906 return ERROR_SUCCESS;
3908 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3909 msiobj_release( &view->hdr );
3914 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3916 MSIPACKAGE* package = param;
3924 FileName = MSI_RecordGetString(row,1);
3927 ERR("Unable to get FileName\n");
3928 return ERROR_SUCCESS;
3931 FilePath = build_icon_path(package,FileName);
3933 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3935 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3936 FILE_ATTRIBUTE_NORMAL, NULL);
3938 if (the_file == INVALID_HANDLE_VALUE)
3940 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3942 return ERROR_SUCCESS;
3949 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3950 if (rc != ERROR_SUCCESS)
3952 ERR("Failed to get stream\n");
3953 CloseHandle(the_file);
3954 DeleteFileW(FilePath);
3957 WriteFile(the_file,buffer,sz,&write,NULL);
3958 } while (sz == 1024);
3961 CloseHandle(the_file);
3963 return ERROR_SUCCESS;
3966 static UINT msi_publish_icons(MSIPACKAGE *package)
3971 static const WCHAR query[]= {
3972 'S','E','L','E','C','T',' ','*',' ',
3973 'F','R','O','M',' ','`','I','c','o','n','`',0};
3975 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3976 if (r == ERROR_SUCCESS)
3978 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3979 msiobj_release(&view->hdr);
3982 return ERROR_SUCCESS;
3985 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3991 MSISOURCELISTINFO *info;
3993 r = RegCreateKeyW(hkey, szSourceList, &source);
3994 if (r != ERROR_SUCCESS)
3997 RegCloseKey(source);
3999 buffer = strrchrW(package->PackagePath, '\\') + 1;
4000 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4001 package->Context, MSICODE_PRODUCT,
4002 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4003 if (r != ERROR_SUCCESS)
4006 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4007 package->Context, MSICODE_PRODUCT,
4008 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4009 if (r != ERROR_SUCCESS)
4012 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4013 package->Context, MSICODE_PRODUCT,
4014 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4015 if (r != ERROR_SUCCESS)
4018 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4020 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4021 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4022 info->options, info->value);
4024 MsiSourceListSetInfoW(package->ProductCode, NULL,
4025 info->context, info->options,
4026 info->property, info->value);
4029 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4031 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4032 disk->context, disk->options,
4033 disk->disk_id, disk->volume_label, disk->disk_prompt);
4036 return ERROR_SUCCESS;
4039 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4041 MSIHANDLE hdb, suminfo;
4042 WCHAR guids[MAX_PATH];
4043 WCHAR packcode[SQUISH_GUID_SIZE];
4050 static const WCHAR szProductLanguage[] =
4051 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4052 static const WCHAR szARPProductIcon[] =
4053 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4054 static const WCHAR szProductVersion[] =
4055 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4056 static const WCHAR szAssignment[] =
4057 {'A','s','s','i','g','n','m','e','n','t',0};
4058 static const WCHAR szAdvertiseFlags[] =
4059 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4060 static const WCHAR szClients[] =
4061 {'C','l','i','e','n','t','s',0};
4062 static const WCHAR szColon[] = {':',0};
4064 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4065 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4068 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4069 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4072 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4074 buffer = msi_dup_property(package->db, szARPProductIcon);
4077 LPWSTR path = build_icon_path(package,buffer);
4078 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4083 buffer = msi_dup_property(package->db, szProductVersion);
4086 DWORD verdword = msi_version_str_to_dword(buffer);
4087 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4091 msi_reg_set_val_dword(hkey, szAssignment, 0);
4092 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4093 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4094 msi_reg_set_val_str(hkey, szClients, szColon);
4096 hdb = alloc_msihandle(&package->db->hdr);
4098 return ERROR_NOT_ENOUGH_MEMORY;
4100 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4101 MsiCloseHandle(hdb);
4102 if (r != ERROR_SUCCESS)
4106 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4107 NULL, guids, &size);
4108 if (r != ERROR_SUCCESS)
4111 ptr = strchrW(guids, ';');
4113 squash_guid(guids, packcode);
4114 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4117 MsiCloseHandle(suminfo);
4118 return ERROR_SUCCESS;
4121 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4126 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4128 upgrade = msi_dup_property(package->db, szUpgradeCode);
4130 return ERROR_SUCCESS;
4132 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4134 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4135 if (r != ERROR_SUCCESS)
4140 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4141 if (r != ERROR_SUCCESS)
4145 squash_guid(package->ProductCode, squashed_pc);
4146 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4155 static BOOL msi_check_publish(MSIPACKAGE *package)
4157 MSIFEATURE *feature;
4159 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4161 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4168 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4170 MSIFEATURE *feature;
4172 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4174 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4181 static UINT msi_publish_patches( MSIPACKAGE *package )
4183 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4184 WCHAR patch_squashed[GUID_SIZE];
4185 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4187 MSIPATCHINFO *patch;
4189 WCHAR *p, *all_patches = NULL;
4192 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4193 if (r != ERROR_SUCCESS)
4194 return ERROR_FUNCTION_FAILED;
4196 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4197 if (res != ERROR_SUCCESS)
4199 r = ERROR_FUNCTION_FAILED;
4203 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4204 if (r != ERROR_SUCCESS)
4207 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4209 squash_guid( patch->patchcode, patch_squashed );
4210 len += strlenW( patch_squashed ) + 1;
4213 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4217 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4221 squash_guid( patch->patchcode, p );
4222 p += strlenW( p ) + 1;
4224 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4225 (const BYTE *)patch->transforms,
4226 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4227 if (res != ERROR_SUCCESS)
4230 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4231 if (r != ERROR_SUCCESS)
4234 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4235 (const BYTE *)patch->localfile,
4236 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4237 RegCloseKey( patch_key );
4238 if (res != ERROR_SUCCESS)
4241 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4242 if (res != ERROR_SUCCESS)
4245 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4246 RegCloseKey( patch_key );
4247 if (res != ERROR_SUCCESS)
4251 all_patches[len] = 0;
4252 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4253 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4254 if (res != ERROR_SUCCESS)
4257 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4258 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4259 if (res != ERROR_SUCCESS)
4260 r = ERROR_FUNCTION_FAILED;
4263 RegCloseKey( product_patches_key );
4264 RegCloseKey( patches_key );
4265 RegCloseKey( product_key );
4266 msi_free( all_patches );
4271 * 99% of the work done here is only done for
4272 * advertised installs. However this is where the
4273 * Icon table is processed and written out
4274 * so that is what I am going to do here.
4276 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4279 HKEY hukey = NULL, hudkey = NULL;
4282 if (!list_empty(&package->patches))
4284 rc = msi_publish_patches(package);
4285 if (rc != ERROR_SUCCESS)
4289 /* FIXME: also need to publish if the product is in advertise mode */
4290 if (!msi_check_publish(package))
4291 return ERROR_SUCCESS;
4293 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4295 if (rc != ERROR_SUCCESS)
4298 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4299 NULL, &hudkey, TRUE);
4300 if (rc != ERROR_SUCCESS)
4303 rc = msi_publish_upgrade_code(package);
4304 if (rc != ERROR_SUCCESS)
4307 rc = msi_publish_product_properties(package, hukey);
4308 if (rc != ERROR_SUCCESS)
4311 rc = msi_publish_sourcelist(package, hukey);
4312 if (rc != ERROR_SUCCESS)
4315 rc = msi_publish_icons(package);
4318 uirow = MSI_CreateRecord( 1 );
4319 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4320 ui_actiondata( package, szPublishProduct, uirow );
4321 msiobj_release( &uirow->hdr );
4324 RegCloseKey(hudkey);
4329 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4331 WCHAR *filename, *ptr, *folder, *ret;
4332 const WCHAR *dirprop;
4334 filename = msi_dup_record_field( row, 2 );
4335 if (filename && (ptr = strchrW( filename, '|' )))
4340 dirprop = MSI_RecordGetString( row, 3 );
4343 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4345 folder = msi_dup_property( package->db, dirprop );
4348 folder = msi_dup_property( package->db, szWindowsFolder );
4352 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4353 msi_free( filename );
4357 ret = build_directory_name( 2, folder, ptr );
4359 msi_free( filename );
4364 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4366 MSIPACKAGE *package = param;
4367 LPCWSTR component, section, key, value, identifier;
4368 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4373 component = MSI_RecordGetString(row, 8);
4374 comp = get_loaded_component(package,component);
4376 return ERROR_SUCCESS;
4380 TRACE("component is disabled\n");
4381 return ERROR_SUCCESS;
4384 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4386 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4387 comp->Action = comp->Installed;
4388 return ERROR_SUCCESS;
4390 comp->Action = INSTALLSTATE_LOCAL;
4392 identifier = MSI_RecordGetString(row,1);
4393 section = MSI_RecordGetString(row,4);
4394 key = MSI_RecordGetString(row,5);
4395 value = MSI_RecordGetString(row,6);
4396 action = MSI_RecordGetInteger(row,7);
4398 deformat_string(package,section,&deformated_section);
4399 deformat_string(package,key,&deformated_key);
4400 deformat_string(package,value,&deformated_value);
4402 fullname = get_ini_file_name(package, row);
4406 TRACE("Adding value %s to section %s in %s\n",
4407 debugstr_w(deformated_key), debugstr_w(deformated_section),
4408 debugstr_w(fullname));
4409 WritePrivateProfileStringW(deformated_section, deformated_key,
4410 deformated_value, fullname);
4412 else if (action == 1)
4415 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4416 returned, 10, fullname);
4417 if (returned[0] == 0)
4419 TRACE("Adding value %s to section %s in %s\n",
4420 debugstr_w(deformated_key), debugstr_w(deformated_section),
4421 debugstr_w(fullname));
4423 WritePrivateProfileStringW(deformated_section, deformated_key,
4424 deformated_value, fullname);
4427 else if (action == 3)
4428 FIXME("Append to existing section not yet implemented\n");
4430 uirow = MSI_CreateRecord(4);
4431 MSI_RecordSetStringW(uirow,1,identifier);
4432 MSI_RecordSetStringW(uirow,2,deformated_section);
4433 MSI_RecordSetStringW(uirow,3,deformated_key);
4434 MSI_RecordSetStringW(uirow,4,deformated_value);
4435 ui_actiondata(package,szWriteIniValues,uirow);
4436 msiobj_release( &uirow->hdr );
4439 msi_free(deformated_key);
4440 msi_free(deformated_value);
4441 msi_free(deformated_section);
4442 return ERROR_SUCCESS;
4445 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4449 static const WCHAR ExecSeqQuery[] =
4450 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4451 '`','I','n','i','F','i','l','e','`',0};
4453 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4454 if (rc != ERROR_SUCCESS)
4456 TRACE("no IniFile table\n");
4457 return ERROR_SUCCESS;
4460 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4461 msiobj_release(&view->hdr);
4465 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4467 MSIPACKAGE *package = param;
4468 LPCWSTR component, section, key, value, identifier;
4469 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4474 component = MSI_RecordGetString( row, 8 );
4475 comp = get_loaded_component( package, component );
4477 return ERROR_SUCCESS;
4481 TRACE("component is disabled\n");
4482 return ERROR_SUCCESS;
4485 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4487 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4488 comp->Action = comp->Installed;
4489 return ERROR_SUCCESS;
4491 comp->Action = INSTALLSTATE_ABSENT;
4493 identifier = MSI_RecordGetString( row, 1 );
4494 section = MSI_RecordGetString( row, 4 );
4495 key = MSI_RecordGetString( row, 5 );
4496 value = MSI_RecordGetString( row, 6 );
4497 action = MSI_RecordGetInteger( row, 7 );
4499 deformat_string( package, section, &deformated_section );
4500 deformat_string( package, key, &deformated_key );
4501 deformat_string( package, value, &deformated_value );
4503 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4505 filename = get_ini_file_name( package, row );
4507 TRACE("Removing key %s from section %s in %s\n",
4508 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4510 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4512 WARN("Unable to remove key %u\n", GetLastError());
4514 msi_free( filename );
4517 FIXME("Unsupported action %d\n", action);
4520 uirow = MSI_CreateRecord( 4 );
4521 MSI_RecordSetStringW( uirow, 1, identifier );
4522 MSI_RecordSetStringW( uirow, 2, deformated_section );
4523 MSI_RecordSetStringW( uirow, 3, deformated_key );
4524 MSI_RecordSetStringW( uirow, 4, deformated_value );
4525 ui_actiondata( package, szRemoveIniValues, uirow );
4526 msiobj_release( &uirow->hdr );
4528 msi_free( deformated_key );
4529 msi_free( deformated_value );
4530 msi_free( deformated_section );
4531 return ERROR_SUCCESS;
4534 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4536 MSIPACKAGE *package = param;
4537 LPCWSTR component, section, key, value, identifier;
4538 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4543 component = MSI_RecordGetString( row, 8 );
4544 comp = get_loaded_component( package, component );
4546 return ERROR_SUCCESS;
4550 TRACE("component is disabled\n");
4551 return ERROR_SUCCESS;
4554 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4556 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4557 comp->Action = comp->Installed;
4558 return ERROR_SUCCESS;
4560 comp->Action = INSTALLSTATE_LOCAL;
4562 identifier = MSI_RecordGetString( row, 1 );
4563 section = MSI_RecordGetString( row, 4 );
4564 key = MSI_RecordGetString( row, 5 );
4565 value = MSI_RecordGetString( row, 6 );
4566 action = MSI_RecordGetInteger( row, 7 );
4568 deformat_string( package, section, &deformated_section );
4569 deformat_string( package, key, &deformated_key );
4570 deformat_string( package, value, &deformated_value );
4572 if (action == msidbIniFileActionRemoveLine)
4574 filename = get_ini_file_name( package, row );
4576 TRACE("Removing key %s from section %s in %s\n",
4577 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4579 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4581 WARN("Unable to remove key %u\n", GetLastError());
4583 msi_free( filename );
4586 FIXME("Unsupported action %d\n", action);
4588 uirow = MSI_CreateRecord( 4 );
4589 MSI_RecordSetStringW( uirow, 1, identifier );
4590 MSI_RecordSetStringW( uirow, 2, deformated_section );
4591 MSI_RecordSetStringW( uirow, 3, deformated_key );
4592 MSI_RecordSetStringW( uirow, 4, deformated_value );
4593 ui_actiondata( package, szRemoveIniValues, uirow );
4594 msiobj_release( &uirow->hdr );
4596 msi_free( deformated_key );
4597 msi_free( deformated_value );
4598 msi_free( deformated_section );
4599 return ERROR_SUCCESS;
4602 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4606 static const WCHAR query[] =
4607 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4608 '`','I','n','i','F','i','l','e','`',0};
4609 static const WCHAR remove_query[] =
4610 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4611 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4613 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4614 if (rc == ERROR_SUCCESS)
4616 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4617 msiobj_release( &view->hdr );
4618 if (rc != ERROR_SUCCESS)
4622 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4623 if (rc == ERROR_SUCCESS)
4625 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4626 msiobj_release( &view->hdr );
4627 if (rc != ERROR_SUCCESS)
4631 return ERROR_SUCCESS;
4634 static void register_dll( const WCHAR *dll, BOOL unregister )
4638 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4641 HRESULT (WINAPI *func_ptr)( void );
4642 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4644 func_ptr = (void *)GetProcAddress( hmod, func );
4647 HRESULT hr = func_ptr();
4649 WARN("failed to register dll 0x%08x\n", hr);
4652 WARN("entry point %s not found\n", func);
4653 FreeLibrary( hmod );
4656 WARN("failed to load library %u\n", GetLastError());
4659 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4661 MSIPACKAGE *package = param;
4666 filename = MSI_RecordGetString(row,1);
4667 file = get_loaded_file( package, filename );
4671 ERR("Unable to find file id %s\n",debugstr_w(filename));
4672 return ERROR_SUCCESS;
4675 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4677 register_dll( file->TargetPath, FALSE );
4679 uirow = MSI_CreateRecord( 2 );
4680 MSI_RecordSetStringW( uirow, 1, filename );
4681 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4682 ui_actiondata( package, szSelfRegModules, uirow );
4683 msiobj_release( &uirow->hdr );
4685 return ERROR_SUCCESS;
4688 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4692 static const WCHAR ExecSeqQuery[] =
4693 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4694 '`','S','e','l','f','R','e','g','`',0};
4696 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4697 if (rc != ERROR_SUCCESS)
4699 TRACE("no SelfReg table\n");
4700 return ERROR_SUCCESS;
4703 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4704 msiobj_release(&view->hdr);
4706 return ERROR_SUCCESS;
4709 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4711 MSIPACKAGE *package = param;
4716 filename = MSI_RecordGetString( row, 1 );
4717 file = get_loaded_file( package, filename );
4721 ERR("Unable to find file id %s\n", debugstr_w(filename));
4722 return ERROR_SUCCESS;
4725 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4727 register_dll( file->TargetPath, TRUE );
4729 uirow = MSI_CreateRecord( 2 );
4730 MSI_RecordSetStringW( uirow, 1, filename );
4731 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4732 ui_actiondata( package, szSelfUnregModules, uirow );
4733 msiobj_release( &uirow->hdr );
4735 return ERROR_SUCCESS;
4738 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4742 static const WCHAR query[] =
4743 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4744 '`','S','e','l','f','R','e','g','`',0};
4746 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4747 if (rc != ERROR_SUCCESS)
4749 TRACE("no SelfReg table\n");
4750 return ERROR_SUCCESS;
4753 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4754 msiobj_release( &view->hdr );
4756 return ERROR_SUCCESS;
4759 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4761 MSIFEATURE *feature;
4763 HKEY hkey = NULL, userdata = NULL;
4765 if (!msi_check_publish(package))
4766 return ERROR_SUCCESS;
4768 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4770 if (rc != ERROR_SUCCESS)
4773 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4775 if (rc != ERROR_SUCCESS)
4778 /* here the guids are base 85 encoded */
4779 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4785 BOOL absent = FALSE;
4788 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4789 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4790 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4793 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4797 if (feature->Feature_Parent)
4798 size += strlenW( feature->Feature_Parent )+2;
4800 data = msi_alloc(size * sizeof(WCHAR));
4803 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4805 MSICOMPONENT* component = cl->component;
4809 if (component->ComponentId)
4811 TRACE("From %s\n",debugstr_w(component->ComponentId));
4812 CLSIDFromString(component->ComponentId, &clsid);
4813 encode_base85_guid(&clsid,buf);
4814 TRACE("to %s\n",debugstr_w(buf));
4819 if (feature->Feature_Parent)
4821 static const WCHAR sep[] = {'\2',0};
4823 strcatW(data,feature->Feature_Parent);
4826 msi_reg_set_val_str( userdata, feature->Feature, data );
4830 if (feature->Feature_Parent)
4831 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4834 size += sizeof(WCHAR);
4835 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4836 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4840 size += 2*sizeof(WCHAR);
4841 data = msi_alloc(size);
4844 if (feature->Feature_Parent)
4845 strcpyW( &data[1], feature->Feature_Parent );
4846 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4852 uirow = MSI_CreateRecord( 1 );
4853 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4854 ui_actiondata( package, szPublishFeatures, uirow);
4855 msiobj_release( &uirow->hdr );
4856 /* FIXME: call ui_progress? */
4861 RegCloseKey(userdata);
4865 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4871 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4873 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4875 if (r == ERROR_SUCCESS)
4877 RegDeleteValueW(hkey, feature->Feature);
4881 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4883 if (r == ERROR_SUCCESS)
4885 RegDeleteValueW(hkey, feature->Feature);
4889 uirow = MSI_CreateRecord( 1 );
4890 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4891 ui_actiondata( package, szUnpublishFeatures, uirow );
4892 msiobj_release( &uirow->hdr );
4894 return ERROR_SUCCESS;
4897 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4899 MSIFEATURE *feature;
4901 if (!msi_check_unpublish(package))
4902 return ERROR_SUCCESS;
4904 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4906 msi_unpublish_feature(package, feature);
4909 return ERROR_SUCCESS;
4912 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4916 WCHAR date[9], *val, *buffer;
4917 const WCHAR *prop, *key;
4919 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4920 static const WCHAR szWindowsInstaller[] =
4921 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4922 static const WCHAR modpath_fmt[] =
4923 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4924 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4925 static const WCHAR szModifyPath[] =
4926 {'M','o','d','i','f','y','P','a','t','h',0};
4927 static const WCHAR szUninstallString[] =
4928 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4929 static const WCHAR szEstimatedSize[] =
4930 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4931 static const WCHAR szProductLanguage[] =
4932 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4933 static const WCHAR szProductVersion[] =
4934 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4935 static const WCHAR szDisplayVersion[] =
4936 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4937 static const WCHAR szInstallSource[] =
4938 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4939 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4940 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4941 static const WCHAR szAuthorizedCDFPrefix[] =
4942 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4943 static const WCHAR szARPCONTACT[] =
4944 {'A','R','P','C','O','N','T','A','C','T',0};
4945 static const WCHAR szContact[] =
4946 {'C','o','n','t','a','c','t',0};
4947 static const WCHAR szARPCOMMENTS[] =
4948 {'A','R','P','C','O','M','M','E','N','T','S',0};
4949 static const WCHAR szComments[] =
4950 {'C','o','m','m','e','n','t','s',0};
4951 static const WCHAR szProductName[] =
4952 {'P','r','o','d','u','c','t','N','a','m','e',0};
4953 static const WCHAR szDisplayName[] =
4954 {'D','i','s','p','l','a','y','N','a','m','e',0};
4955 static const WCHAR szARPHELPLINK[] =
4956 {'A','R','P','H','E','L','P','L','I','N','K',0};
4957 static const WCHAR szHelpLink[] =
4958 {'H','e','l','p','L','i','n','k',0};
4959 static const WCHAR szARPHELPTELEPHONE[] =
4960 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4961 static const WCHAR szHelpTelephone[] =
4962 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4963 static const WCHAR szARPINSTALLLOCATION[] =
4964 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4965 static const WCHAR szInstallLocation[] =
4966 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4967 static const WCHAR szManufacturer[] =
4968 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4969 static const WCHAR szPublisher[] =
4970 {'P','u','b','l','i','s','h','e','r',0};
4971 static const WCHAR szARPREADME[] =
4972 {'A','R','P','R','E','A','D','M','E',0};
4973 static const WCHAR szReadme[] =
4974 {'R','e','a','d','M','e',0};
4975 static const WCHAR szARPSIZE[] =
4976 {'A','R','P','S','I','Z','E',0};
4977 static const WCHAR szSize[] =
4978 {'S','i','z','e',0};
4979 static const WCHAR szARPURLINFOABOUT[] =
4980 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4981 static const WCHAR szURLInfoAbout[] =
4982 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4983 static const WCHAR szARPURLUPDATEINFO[] =
4984 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4985 static const WCHAR szURLUpdateInfo[] =
4986 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4988 static const WCHAR *propval[] = {
4989 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4990 szARPCONTACT, szContact,
4991 szARPCOMMENTS, szComments,
4992 szProductName, szDisplayName,
4993 szARPHELPLINK, szHelpLink,
4994 szARPHELPTELEPHONE, szHelpTelephone,
4995 szARPINSTALLLOCATION, szInstallLocation,
4996 cszSourceDir, szInstallSource,
4997 szManufacturer, szPublisher,
4998 szARPREADME, szReadme,
5000 szARPURLINFOABOUT, szURLInfoAbout,
5001 szARPURLUPDATEINFO, szURLUpdateInfo,
5004 const WCHAR **p = propval;
5010 val = msi_dup_property(package->db, prop);
5011 msi_reg_set_val_str(hkey, key, val);
5015 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5017 size = deformat_string(package, modpath_fmt, &buffer);
5018 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5019 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5022 /* FIXME: Write real Estimated Size when we have it */
5023 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5025 GetLocalTime(&systime);
5026 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5027 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5029 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5030 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5032 buffer = msi_dup_property(package->db, szProductVersion);
5033 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5036 DWORD verdword = msi_version_str_to_dword(buffer);
5038 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5039 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5040 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5044 return ERROR_SUCCESS;
5047 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5049 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5051 LPWSTR upgrade_code;
5056 /* FIXME: also need to publish if the product is in advertise mode */
5057 if (!msi_check_publish(package))
5058 return ERROR_SUCCESS;
5060 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5061 if (rc != ERROR_SUCCESS)
5064 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5065 NULL, &props, TRUE);
5066 if (rc != ERROR_SUCCESS)
5069 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5070 msi_free( package->db->localfile );
5071 package->db->localfile = NULL;
5073 rc = msi_publish_install_properties(package, hkey);
5074 if (rc != ERROR_SUCCESS)
5077 rc = msi_publish_install_properties(package, props);
5078 if (rc != ERROR_SUCCESS)
5081 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5084 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5085 squash_guid(package->ProductCode, squashed_pc);
5086 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5087 RegCloseKey(upgrade);
5088 msi_free(upgrade_code);
5092 uirow = MSI_CreateRecord( 1 );
5093 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5094 ui_actiondata( package, szRegisterProduct, uirow );
5095 msiobj_release( &uirow->hdr );
5098 return ERROR_SUCCESS;
5101 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5103 return execute_script(package,INSTALL_SCRIPT);
5106 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5108 WCHAR *upgrade, **features;
5109 BOOL full_uninstall = TRUE;
5110 MSIFEATURE *feature;
5111 MSIPATCHINFO *patch;
5113 static const WCHAR szUpgradeCode[] =
5114 {'U','p','g','r','a','d','e','C','o','d','e',0};
5116 features = msi_split_string(remove, ',');
5119 ERR("REMOVE feature list is empty!\n");
5120 return ERROR_FUNCTION_FAILED;
5123 if (!strcmpW( features[0], szAll ))
5124 full_uninstall = TRUE;
5127 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5129 if (feature->Action != INSTALLSTATE_ABSENT)
5130 full_uninstall = FALSE;
5135 if (!full_uninstall)
5136 return ERROR_SUCCESS;
5138 MSIREG_DeleteProductKey(package->ProductCode);
5139 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5140 MSIREG_DeleteUninstallKey(package);
5142 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5143 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5144 MSIREG_DeleteUserProductKey(package->ProductCode);
5145 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5147 upgrade = msi_dup_property(package->db, szUpgradeCode);
5150 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5151 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5155 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5157 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5160 return ERROR_SUCCESS;
5163 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5168 /* turn off scheduling */
5169 package->script->CurrentlyScripting= FALSE;
5171 /* first do the same as an InstallExecute */
5172 rc = ACTION_InstallExecute(package);
5173 if (rc != ERROR_SUCCESS)
5176 /* then handle Commit Actions */
5177 rc = execute_script(package,COMMIT_SCRIPT);
5178 if (rc != ERROR_SUCCESS)
5181 remove = msi_dup_property(package->db, szRemove);
5183 rc = msi_unpublish_product(package, remove);
5189 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5191 static const WCHAR RunOnce[] = {
5192 'S','o','f','t','w','a','r','e','\\',
5193 'M','i','c','r','o','s','o','f','t','\\',
5194 'W','i','n','d','o','w','s','\\',
5195 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5196 'R','u','n','O','n','c','e',0};
5197 static const WCHAR InstallRunOnce[] = {
5198 'S','o','f','t','w','a','r','e','\\',
5199 'M','i','c','r','o','s','o','f','t','\\',
5200 'W','i','n','d','o','w','s','\\',
5201 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5202 'I','n','s','t','a','l','l','e','r','\\',
5203 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5205 static const WCHAR msiexec_fmt[] = {
5207 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5208 '\"','%','s','\"',0};
5209 static const WCHAR install_fmt[] = {
5210 '/','I',' ','\"','%','s','\"',' ',
5211 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5212 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5213 WCHAR buffer[256], sysdir[MAX_PATH];
5215 WCHAR squished_pc[100];
5217 squash_guid(package->ProductCode,squished_pc);
5219 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5220 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5221 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5224 msi_reg_set_val_str( hkey, squished_pc, buffer );
5227 TRACE("Reboot command %s\n",debugstr_w(buffer));
5229 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5230 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5232 msi_reg_set_val_str( hkey, squished_pc, buffer );
5235 return ERROR_INSTALL_SUSPEND;
5238 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5244 * We are currently doing what should be done here in the top level Install
5245 * however for Administrative and uninstalls this step will be needed
5247 if (!package->PackagePath)
5248 return ERROR_SUCCESS;
5250 msi_set_sourcedir_props(package, TRUE);
5252 attrib = GetFileAttributesW(package->db->path);
5253 if (attrib == INVALID_FILE_ATTRIBUTES)
5259 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5260 package->Context, MSICODE_PRODUCT,
5261 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5262 if (rc == ERROR_MORE_DATA)
5264 prompt = msi_alloc(size * sizeof(WCHAR));
5265 MsiSourceListGetInfoW(package->ProductCode, NULL,
5266 package->Context, MSICODE_PRODUCT,
5267 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5270 prompt = strdupW(package->db->path);
5272 msg = generate_error_string(package,1302,1,prompt);
5273 while(attrib == INVALID_FILE_ATTRIBUTES)
5275 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5278 rc = ERROR_INSTALL_USEREXIT;
5281 attrib = GetFileAttributesW(package->db->path);
5287 return ERROR_SUCCESS;
5292 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5295 LPWSTR buffer, productid = NULL;
5296 UINT i, rc = ERROR_SUCCESS;
5299 static const WCHAR szPropKeys[][80] =
5301 {'P','r','o','d','u','c','t','I','D',0},
5302 {'U','S','E','R','N','A','M','E',0},
5303 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5307 static const WCHAR szRegKeys[][80] =
5309 {'P','r','o','d','u','c','t','I','D',0},
5310 {'R','e','g','O','w','n','e','r',0},
5311 {'R','e','g','C','o','m','p','a','n','y',0},
5315 if (msi_check_unpublish(package))
5317 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5321 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5325 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5327 if (rc != ERROR_SUCCESS)
5330 for( i = 0; szPropKeys[i][0]; i++ )
5332 buffer = msi_dup_property( package->db, szPropKeys[i] );
5333 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5338 uirow = MSI_CreateRecord( 1 );
5339 MSI_RecordSetStringW( uirow, 1, productid );
5340 ui_actiondata( package, szRegisterUser, uirow );
5341 msiobj_release( &uirow->hdr );
5343 msi_free(productid);
5349 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5353 package->script->InWhatSequence |= SEQUENCE_EXEC;
5354 rc = ACTION_ProcessExecSequence(package,FALSE);
5359 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5361 MSIPACKAGE *package = param;
5362 LPCWSTR compgroupid, component, feature, qualifier, text;
5363 LPWSTR advertise = NULL, output = NULL;
5371 feature = MSI_RecordGetString(rec, 5);
5372 feat = get_loaded_feature(package, feature);
5374 return ERROR_SUCCESS;
5376 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5377 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5378 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5380 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5381 feat->Action = feat->Installed;
5382 return ERROR_SUCCESS;
5385 component = MSI_RecordGetString(rec, 3);
5386 comp = get_loaded_component(package, component);
5388 return ERROR_SUCCESS;
5390 compgroupid = MSI_RecordGetString(rec,1);
5391 qualifier = MSI_RecordGetString(rec,2);
5393 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5394 if (rc != ERROR_SUCCESS)
5397 text = MSI_RecordGetString(rec,4);
5398 advertise = create_component_advertise_string(package, comp, feature);
5400 sz = strlenW(advertise);
5403 sz += lstrlenW(text);
5406 sz *= sizeof(WCHAR);
5408 output = msi_alloc_zero(sz);
5409 strcpyW(output,advertise);
5410 msi_free(advertise);
5413 strcatW(output,text);
5415 msi_reg_set_val_multi_str( hkey, qualifier, output );
5422 uirow = MSI_CreateRecord( 2 );
5423 MSI_RecordSetStringW( uirow, 1, compgroupid );
5424 MSI_RecordSetStringW( uirow, 2, qualifier);
5425 ui_actiondata( package, szPublishComponents, uirow);
5426 msiobj_release( &uirow->hdr );
5427 /* FIXME: call ui_progress? */
5433 * At present I am ignorning the advertised components part of this and only
5434 * focusing on the qualified component sets
5436 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5440 static const WCHAR ExecSeqQuery[] =
5441 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5442 '`','P','u','b','l','i','s','h',
5443 'C','o','m','p','o','n','e','n','t','`',0};
5445 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5446 if (rc != ERROR_SUCCESS)
5447 return ERROR_SUCCESS;
5449 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5450 msiobj_release(&view->hdr);
5455 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5457 static const WCHAR szInstallerComponents[] = {
5458 'S','o','f','t','w','a','r','e','\\',
5459 'M','i','c','r','o','s','o','f','t','\\',
5460 'I','n','s','t','a','l','l','e','r','\\',
5461 'C','o','m','p','o','n','e','n','t','s','\\',0};
5463 MSIPACKAGE *package = param;
5464 LPCWSTR compgroupid, component, feature, qualifier;
5468 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5471 feature = MSI_RecordGetString( rec, 5 );
5472 feat = get_loaded_feature( package, feature );
5474 return ERROR_SUCCESS;
5476 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5478 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5479 feat->Action = feat->Installed;
5480 return ERROR_SUCCESS;
5483 component = MSI_RecordGetString( rec, 3 );
5484 comp = get_loaded_component( package, component );
5486 return ERROR_SUCCESS;
5488 compgroupid = MSI_RecordGetString( rec, 1 );
5489 qualifier = MSI_RecordGetString( rec, 2 );
5491 squash_guid( compgroupid, squashed );
5492 strcpyW( keypath, szInstallerComponents );
5493 strcatW( keypath, squashed );
5495 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5496 if (res != ERROR_SUCCESS)
5498 WARN("Unable to delete component key %d\n", res);
5501 uirow = MSI_CreateRecord( 2 );
5502 MSI_RecordSetStringW( uirow, 1, compgroupid );
5503 MSI_RecordSetStringW( uirow, 2, qualifier );
5504 ui_actiondata( package, szUnpublishComponents, uirow );
5505 msiobj_release( &uirow->hdr );
5507 return ERROR_SUCCESS;
5510 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5514 static const WCHAR query[] =
5515 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5516 '`','P','u','b','l','i','s','h',
5517 'C','o','m','p','o','n','e','n','t','`',0};
5519 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5520 if (rc != ERROR_SUCCESS)
5521 return ERROR_SUCCESS;
5523 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5524 msiobj_release( &view->hdr );
5529 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5531 MSIPACKAGE *package = param;
5534 SC_HANDLE hscm, service = NULL;
5536 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5537 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5538 DWORD serv_type, start_type, err_control;
5539 SERVICE_DESCRIPTIONW sd = {NULL};
5541 static const WCHAR query[] =
5542 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5543 '`','C','o','m','p','o','n','e','n','t','`',' ',
5544 'W','H','E','R','E',' ',
5545 '`','C','o','m','p','o','n','e','n','t','`',' ',
5546 '=','\'','%','s','\'',0};
5548 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5551 ERR("Failed to open the SC Manager!\n");
5555 comp = MSI_RecordGetString( rec, 12 );
5556 if (!get_loaded_component( package, comp ))
5559 start_type = MSI_RecordGetInteger(rec, 5);
5560 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5563 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5564 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5565 serv_type = MSI_RecordGetInteger(rec, 4);
5566 err_control = MSI_RecordGetInteger(rec, 6);
5567 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5568 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5569 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5570 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5571 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5572 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5574 /* fetch the service path */
5575 row = MSI_QueryGetRecord(package->db, query, comp);
5578 ERR("Control query failed!\n");
5581 key = MSI_RecordGetString(row, 6);
5583 file = get_loaded_file(package, key);
5584 msiobj_release(&row->hdr);
5587 ERR("Failed to load the service file\n");
5591 if (!args || !args[0]) image_path = file->TargetPath;
5594 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5595 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5596 return ERROR_OUTOFMEMORY;
5598 strcpyW(image_path, file->TargetPath);
5599 strcatW(image_path, szSpace);
5600 strcatW(image_path, args);
5602 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5603 start_type, err_control, image_path, load_order,
5604 NULL, depends, serv_name, pass);
5608 if (GetLastError() != ERROR_SERVICE_EXISTS)
5609 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5611 else if (sd.lpDescription)
5613 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5614 WARN("failed to set service description %u\n", GetLastError());
5617 if (image_path != file->TargetPath) msi_free(image_path);
5619 CloseServiceHandle(service);
5620 CloseServiceHandle(hscm);
5623 msi_free(sd.lpDescription);
5624 msi_free(load_order);
5625 msi_free(serv_name);
5630 return ERROR_SUCCESS;
5633 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5637 static const WCHAR ExecSeqQuery[] =
5638 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5639 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5642 if (rc != ERROR_SUCCESS)
5643 return ERROR_SUCCESS;
5645 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5646 msiobj_release(&view->hdr);
5651 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5652 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5654 LPCWSTR *vector, *temp_vector;
5658 static const WCHAR separator[] = {'[','~',']',0};
5661 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5666 vector = msi_alloc(sizeof(LPWSTR));
5674 vector[*numargs - 1] = p;
5676 if ((q = strstrW(p, separator)))
5680 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5686 vector = temp_vector;
5695 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5697 MSIPACKAGE *package = param;
5700 SC_HANDLE scm = NULL, service = NULL;
5701 LPCWSTR component, *vector = NULL;
5702 LPWSTR name, args, display_name = NULL;
5703 DWORD event, numargs, len;
5704 UINT r = ERROR_FUNCTION_FAILED;
5706 component = MSI_RecordGetString(rec, 6);
5707 comp = get_loaded_component(package, component);
5709 return ERROR_SUCCESS;
5713 TRACE("component is disabled\n");
5714 return ERROR_SUCCESS;
5717 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5719 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5720 comp->Action = comp->Installed;
5721 return ERROR_SUCCESS;
5723 comp->Action = INSTALLSTATE_LOCAL;
5725 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5726 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5727 event = MSI_RecordGetInteger(rec, 3);
5729 if (!(event & msidbServiceControlEventStart))
5735 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5738 ERR("Failed to open the service control manager\n");
5743 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5744 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5746 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5747 GetServiceDisplayNameW( scm, name, display_name, &len );
5750 service = OpenServiceW(scm, name, SERVICE_START);
5753 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5757 vector = msi_service_args_to_vector(args, &numargs);
5759 if (!StartServiceW(service, numargs, vector) &&
5760 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5762 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5769 uirow = MSI_CreateRecord( 2 );
5770 MSI_RecordSetStringW( uirow, 1, display_name );
5771 MSI_RecordSetStringW( uirow, 2, name );
5772 ui_actiondata( package, szStartServices, uirow );
5773 msiobj_release( &uirow->hdr );
5775 CloseServiceHandle(service);
5776 CloseServiceHandle(scm);
5781 msi_free(display_name);
5785 static UINT ACTION_StartServices( MSIPACKAGE *package )
5790 static const WCHAR query[] = {
5791 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5792 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5794 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5795 if (rc != ERROR_SUCCESS)
5796 return ERROR_SUCCESS;
5798 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5799 msiobj_release(&view->hdr);
5804 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5806 DWORD i, needed, count;
5807 ENUM_SERVICE_STATUSW *dependencies;
5811 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5812 0, &needed, &count))
5815 if (GetLastError() != ERROR_MORE_DATA)
5818 dependencies = msi_alloc(needed);
5822 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5823 needed, &needed, &count))
5826 for (i = 0; i < count; i++)
5828 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5829 SERVICE_STOP | SERVICE_QUERY_STATUS);
5833 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5840 msi_free(dependencies);
5844 static UINT stop_service( LPCWSTR name )
5846 SC_HANDLE scm = NULL, service = NULL;
5847 SERVICE_STATUS status;
5848 SERVICE_STATUS_PROCESS ssp;
5851 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5854 WARN("Failed to open the SCM: %d\n", GetLastError());
5858 service = OpenServiceW(scm, name,
5860 SERVICE_QUERY_STATUS |
5861 SERVICE_ENUMERATE_DEPENDENTS);
5864 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5868 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5869 sizeof(SERVICE_STATUS_PROCESS), &needed))
5871 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5875 if (ssp.dwCurrentState == SERVICE_STOPPED)
5878 stop_service_dependents(scm, service);
5880 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5881 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5884 CloseServiceHandle(service);
5885 CloseServiceHandle(scm);
5887 return ERROR_SUCCESS;
5890 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5892 MSIPACKAGE *package = param;
5896 LPWSTR name = NULL, display_name = NULL;
5900 event = MSI_RecordGetInteger( rec, 3 );
5901 if (!(event & msidbServiceControlEventStop))
5902 return ERROR_SUCCESS;
5904 component = MSI_RecordGetString( rec, 6 );
5905 comp = get_loaded_component( package, component );
5907 return ERROR_SUCCESS;
5911 TRACE("component is disabled\n");
5912 return ERROR_SUCCESS;
5915 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5917 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5918 comp->Action = comp->Installed;
5919 return ERROR_SUCCESS;
5921 comp->Action = INSTALLSTATE_ABSENT;
5923 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5926 ERR("Failed to open the service control manager\n");
5931 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5932 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5934 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5935 GetServiceDisplayNameW( scm, name, display_name, &len );
5937 CloseServiceHandle( scm );
5939 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5940 stop_service( name );
5943 uirow = MSI_CreateRecord( 2 );
5944 MSI_RecordSetStringW( uirow, 1, display_name );
5945 MSI_RecordSetStringW( uirow, 2, name );
5946 ui_actiondata( package, szStopServices, uirow );
5947 msiobj_release( &uirow->hdr );
5950 msi_free( display_name );
5951 return ERROR_SUCCESS;
5954 static UINT ACTION_StopServices( MSIPACKAGE *package )
5959 static const WCHAR query[] = {
5960 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5961 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5963 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5964 if (rc != ERROR_SUCCESS)
5965 return ERROR_SUCCESS;
5967 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5968 msiobj_release(&view->hdr);
5973 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5975 MSIPACKAGE *package = param;
5979 LPWSTR name = NULL, display_name = NULL;
5981 SC_HANDLE scm = NULL, service = NULL;
5983 event = MSI_RecordGetInteger( rec, 3 );
5984 if (!(event & msidbServiceControlEventDelete))
5985 return ERROR_SUCCESS;
5987 component = MSI_RecordGetString(rec, 6);
5988 comp = get_loaded_component(package, component);
5990 return ERROR_SUCCESS;
5994 TRACE("component is disabled\n");
5995 return ERROR_SUCCESS;
5998 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6000 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6001 comp->Action = comp->Installed;
6002 return ERROR_SUCCESS;
6004 comp->Action = INSTALLSTATE_ABSENT;
6006 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6007 stop_service( name );
6009 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6012 WARN("Failed to open the SCM: %d\n", GetLastError());
6017 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6018 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6020 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6021 GetServiceDisplayNameW( scm, name, display_name, &len );
6024 service = OpenServiceW( scm, name, DELETE );
6027 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6031 if (!DeleteService( service ))
6032 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6035 uirow = MSI_CreateRecord( 2 );
6036 MSI_RecordSetStringW( uirow, 1, display_name );
6037 MSI_RecordSetStringW( uirow, 2, name );
6038 ui_actiondata( package, szDeleteServices, uirow );
6039 msiobj_release( &uirow->hdr );
6041 CloseServiceHandle( service );
6042 CloseServiceHandle( scm );
6044 msi_free( display_name );
6046 return ERROR_SUCCESS;
6049 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6054 static const WCHAR query[] = {
6055 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6056 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6058 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6059 if (rc != ERROR_SUCCESS)
6060 return ERROR_SUCCESS;
6062 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6063 msiobj_release( &view->hdr );
6068 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6070 MSIPACKAGE *package = param;
6071 LPWSTR driver, driver_path, ptr;
6072 WCHAR outpath[MAX_PATH];
6073 MSIFILE *driver_file = NULL, *setup_file = NULL;
6076 LPCWSTR desc, file_key, component;
6078 UINT r = ERROR_SUCCESS;
6080 static const WCHAR driver_fmt[] = {
6081 'D','r','i','v','e','r','=','%','s',0};
6082 static const WCHAR setup_fmt[] = {
6083 'S','e','t','u','p','=','%','s',0};
6084 static const WCHAR usage_fmt[] = {
6085 'F','i','l','e','U','s','a','g','e','=','1',0};
6087 component = MSI_RecordGetString( rec, 2 );
6088 comp = get_loaded_component( package, component );
6090 return ERROR_SUCCESS;
6094 TRACE("component is disabled\n");
6095 return ERROR_SUCCESS;
6098 desc = MSI_RecordGetString(rec, 3);
6100 file_key = MSI_RecordGetString( rec, 4 );
6101 if (file_key) driver_file = get_loaded_file( package, file_key );
6103 file_key = MSI_RecordGetString( rec, 5 );
6104 if (file_key) setup_file = get_loaded_file( package, file_key );
6108 ERR("ODBC Driver entry not found!\n");
6109 return ERROR_FUNCTION_FAILED;
6112 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6114 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6115 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6117 driver = msi_alloc(len * sizeof(WCHAR));
6119 return ERROR_OUTOFMEMORY;
6122 lstrcpyW(ptr, desc);
6123 ptr += lstrlenW(ptr) + 1;
6125 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6130 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6134 lstrcpyW(ptr, usage_fmt);
6135 ptr += lstrlenW(ptr) + 1;
6138 driver_path = strdupW(driver_file->TargetPath);
6139 ptr = strrchrW(driver_path, '\\');
6140 if (ptr) *ptr = '\0';
6142 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6143 NULL, ODBC_INSTALL_COMPLETE, &usage))
6145 ERR("Failed to install SQL driver!\n");
6146 r = ERROR_FUNCTION_FAILED;
6149 uirow = MSI_CreateRecord( 5 );
6150 MSI_RecordSetStringW( uirow, 1, desc );
6151 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6152 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6153 ui_actiondata( package, szInstallODBC, uirow );
6154 msiobj_release( &uirow->hdr );
6157 msi_free(driver_path);
6162 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6164 MSIPACKAGE *package = param;
6165 LPWSTR translator, translator_path, ptr;
6166 WCHAR outpath[MAX_PATH];
6167 MSIFILE *translator_file = NULL, *setup_file = NULL;
6170 LPCWSTR desc, file_key, component;
6172 UINT r = ERROR_SUCCESS;
6174 static const WCHAR translator_fmt[] = {
6175 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6176 static const WCHAR setup_fmt[] = {
6177 'S','e','t','u','p','=','%','s',0};
6179 component = MSI_RecordGetString( rec, 2 );
6180 comp = get_loaded_component( package, component );
6182 return ERROR_SUCCESS;
6186 TRACE("component is disabled\n");
6187 return ERROR_SUCCESS;
6190 desc = MSI_RecordGetString(rec, 3);
6192 file_key = MSI_RecordGetString( rec, 4 );
6193 if (file_key) translator_file = get_loaded_file( package, file_key );
6195 file_key = MSI_RecordGetString( rec, 5 );
6196 if (file_key) setup_file = get_loaded_file( package, file_key );
6198 if (!translator_file)
6200 ERR("ODBC Translator entry not found!\n");
6201 return ERROR_FUNCTION_FAILED;
6204 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6206 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6208 translator = msi_alloc(len * sizeof(WCHAR));
6210 return ERROR_OUTOFMEMORY;
6213 lstrcpyW(ptr, desc);
6214 ptr += lstrlenW(ptr) + 1;
6216 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6221 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6226 translator_path = strdupW(translator_file->TargetPath);
6227 ptr = strrchrW(translator_path, '\\');
6228 if (ptr) *ptr = '\0';
6230 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6231 NULL, ODBC_INSTALL_COMPLETE, &usage))
6233 ERR("Failed to install SQL translator!\n");
6234 r = ERROR_FUNCTION_FAILED;
6237 uirow = MSI_CreateRecord( 5 );
6238 MSI_RecordSetStringW( uirow, 1, desc );
6239 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6240 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6241 ui_actiondata( package, szInstallODBC, uirow );
6242 msiobj_release( &uirow->hdr );
6244 msi_free(translator);
6245 msi_free(translator_path);
6250 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6252 MSIPACKAGE *package = param;
6255 LPCWSTR desc, driver, component;
6256 WORD request = ODBC_ADD_SYS_DSN;
6259 UINT r = ERROR_SUCCESS;
6262 static const WCHAR attrs_fmt[] = {
6263 'D','S','N','=','%','s',0 };
6265 component = MSI_RecordGetString( rec, 2 );
6266 comp = get_loaded_component( package, component );
6268 return ERROR_SUCCESS;
6272 TRACE("component is disabled\n");
6273 return ERROR_SUCCESS;
6276 desc = MSI_RecordGetString(rec, 3);
6277 driver = MSI_RecordGetString(rec, 4);
6278 registration = MSI_RecordGetInteger(rec, 5);
6280 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6281 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6283 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6284 attrs = msi_alloc(len * sizeof(WCHAR));
6286 return ERROR_OUTOFMEMORY;
6288 len = sprintfW(attrs, attrs_fmt, desc);
6291 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6293 ERR("Failed to install SQL data source!\n");
6294 r = ERROR_FUNCTION_FAILED;
6297 uirow = MSI_CreateRecord( 5 );
6298 MSI_RecordSetStringW( uirow, 1, desc );
6299 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6300 MSI_RecordSetInteger( uirow, 3, request );
6301 ui_actiondata( package, szInstallODBC, uirow );
6302 msiobj_release( &uirow->hdr );
6309 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6314 static const WCHAR driver_query[] = {
6315 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6316 'O','D','B','C','D','r','i','v','e','r',0 };
6318 static const WCHAR translator_query[] = {
6319 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6320 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6322 static const WCHAR source_query[] = {
6323 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6324 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6326 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6327 if (rc != ERROR_SUCCESS)
6328 return ERROR_SUCCESS;
6330 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6331 msiobj_release(&view->hdr);
6333 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6334 if (rc != ERROR_SUCCESS)
6335 return ERROR_SUCCESS;
6337 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6338 msiobj_release(&view->hdr);
6340 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6341 if (rc != ERROR_SUCCESS)
6342 return ERROR_SUCCESS;
6344 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6345 msiobj_release(&view->hdr);
6350 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6352 MSIPACKAGE *package = param;
6356 LPCWSTR desc, component;
6358 component = MSI_RecordGetString( rec, 2 );
6359 comp = get_loaded_component( package, component );
6361 return ERROR_SUCCESS;
6365 TRACE("component is disabled\n");
6366 return ERROR_SUCCESS;
6369 desc = MSI_RecordGetString( rec, 3 );
6370 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6372 WARN("Failed to remove ODBC driver\n");
6376 FIXME("Usage count reached 0\n");
6379 uirow = MSI_CreateRecord( 2 );
6380 MSI_RecordSetStringW( uirow, 1, desc );
6381 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6382 ui_actiondata( package, szRemoveODBC, uirow );
6383 msiobj_release( &uirow->hdr );
6385 return ERROR_SUCCESS;
6388 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6390 MSIPACKAGE *package = param;
6394 LPCWSTR desc, component;
6396 component = MSI_RecordGetString( rec, 2 );
6397 comp = get_loaded_component( package, component );
6399 return ERROR_SUCCESS;
6403 TRACE("component is disabled\n");
6404 return ERROR_SUCCESS;
6407 desc = MSI_RecordGetString( rec, 3 );
6408 if (!SQLRemoveTranslatorW( desc, &usage ))
6410 WARN("Failed to remove ODBC translator\n");
6414 FIXME("Usage count reached 0\n");
6417 uirow = MSI_CreateRecord( 2 );
6418 MSI_RecordSetStringW( uirow, 1, desc );
6419 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6420 ui_actiondata( package, szRemoveODBC, uirow );
6421 msiobj_release( &uirow->hdr );
6423 return ERROR_SUCCESS;
6426 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6428 MSIPACKAGE *package = param;
6432 LPCWSTR desc, driver, component;
6433 WORD request = ODBC_REMOVE_SYS_DSN;
6437 static const WCHAR attrs_fmt[] = {
6438 'D','S','N','=','%','s',0 };
6440 component = MSI_RecordGetString( rec, 2 );
6441 comp = get_loaded_component( package, component );
6443 return ERROR_SUCCESS;
6447 TRACE("component is disabled\n");
6448 return ERROR_SUCCESS;
6451 desc = MSI_RecordGetString( rec, 3 );
6452 driver = MSI_RecordGetString( rec, 4 );
6453 registration = MSI_RecordGetInteger( rec, 5 );
6455 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6456 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6458 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6459 attrs = msi_alloc( len * sizeof(WCHAR) );
6461 return ERROR_OUTOFMEMORY;
6463 FIXME("Use ODBCSourceAttribute table\n");
6465 len = sprintfW( attrs, attrs_fmt, desc );
6468 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6470 WARN("Failed to remove ODBC data source\n");
6474 uirow = MSI_CreateRecord( 3 );
6475 MSI_RecordSetStringW( uirow, 1, desc );
6476 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6477 MSI_RecordSetInteger( uirow, 3, request );
6478 ui_actiondata( package, szRemoveODBC, uirow );
6479 msiobj_release( &uirow->hdr );
6481 return ERROR_SUCCESS;
6484 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6489 static const WCHAR driver_query[] = {
6490 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6491 'O','D','B','C','D','r','i','v','e','r',0 };
6493 static const WCHAR translator_query[] = {
6494 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6495 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6497 static const WCHAR source_query[] = {
6498 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6499 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6501 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6502 if (rc != ERROR_SUCCESS)
6503 return ERROR_SUCCESS;
6505 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6506 msiobj_release( &view->hdr );
6508 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6509 if (rc != ERROR_SUCCESS)
6510 return ERROR_SUCCESS;
6512 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6513 msiobj_release( &view->hdr );
6515 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6516 if (rc != ERROR_SUCCESS)
6517 return ERROR_SUCCESS;
6519 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6520 msiobj_release( &view->hdr );
6525 #define ENV_ACT_SETALWAYS 0x1
6526 #define ENV_ACT_SETABSENT 0x2
6527 #define ENV_ACT_REMOVE 0x4
6528 #define ENV_ACT_REMOVEMATCH 0x8
6530 #define ENV_MOD_MACHINE 0x20000000
6531 #define ENV_MOD_APPEND 0x40000000
6532 #define ENV_MOD_PREFIX 0x80000000
6533 #define ENV_MOD_MASK 0xC0000000
6535 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6537 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6539 LPCWSTR cptr = *name;
6541 static const WCHAR prefix[] = {'[','~',']',0};
6542 static const int prefix_len = 3;
6548 *flags |= ENV_ACT_SETALWAYS;
6549 else if (*cptr == '+')
6550 *flags |= ENV_ACT_SETABSENT;
6551 else if (*cptr == '-')
6552 *flags |= ENV_ACT_REMOVE;
6553 else if (*cptr == '!')
6554 *flags |= ENV_ACT_REMOVEMATCH;
6555 else if (*cptr == '*')
6556 *flags |= ENV_MOD_MACHINE;
6566 ERR("Missing environment variable\n");
6567 return ERROR_FUNCTION_FAILED;
6572 LPCWSTR ptr = *value;
6573 if (!strncmpW(ptr, prefix, prefix_len))
6575 if (ptr[prefix_len] == szSemiColon[0])
6577 *flags |= ENV_MOD_APPEND;
6578 *value += lstrlenW(prefix);
6585 else if (lstrlenW(*value) >= prefix_len)
6587 ptr += lstrlenW(ptr) - prefix_len;
6588 if (!strcmpW( ptr, prefix ))
6590 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6592 *flags |= ENV_MOD_PREFIX;
6593 /* the "[~]" will be removed by deformat_string */;
6603 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6604 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6605 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6606 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6608 ERR("Invalid flags: %08x\n", *flags);
6609 return ERROR_FUNCTION_FAILED;
6613 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6615 return ERROR_SUCCESS;
6618 static UINT open_env_key( DWORD flags, HKEY *key )
6620 static const WCHAR user_env[] =
6621 {'E','n','v','i','r','o','n','m','e','n','t',0};
6622 static const WCHAR machine_env[] =
6623 {'S','y','s','t','e','m','\\',
6624 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6625 'C','o','n','t','r','o','l','\\',
6626 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6627 'E','n','v','i','r','o','n','m','e','n','t',0};
6632 if (flags & ENV_MOD_MACHINE)
6635 root = HKEY_LOCAL_MACHINE;
6640 root = HKEY_CURRENT_USER;
6643 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6644 if (res != ERROR_SUCCESS)
6646 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6647 return ERROR_FUNCTION_FAILED;
6650 return ERROR_SUCCESS;
6653 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6655 MSIPACKAGE *package = param;
6656 LPCWSTR name, value, component;
6657 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6658 DWORD flags, type, size;
6665 component = MSI_RecordGetString(rec, 4);
6666 comp = get_loaded_component(package, component);
6668 return ERROR_SUCCESS;
6672 TRACE("component is disabled\n");
6673 return ERROR_SUCCESS;
6676 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6678 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6679 comp->Action = comp->Installed;
6680 return ERROR_SUCCESS;
6682 comp->Action = INSTALLSTATE_LOCAL;
6684 name = MSI_RecordGetString(rec, 2);
6685 value = MSI_RecordGetString(rec, 3);
6687 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6689 res = env_parse_flags(&name, &value, &flags);
6690 if (res != ERROR_SUCCESS || !value)
6693 if (value && !deformat_string(package, value, &deformatted))
6695 res = ERROR_OUTOFMEMORY;
6699 value = deformatted;
6701 res = open_env_key( flags, &env );
6702 if (res != ERROR_SUCCESS)
6705 if (flags & ENV_MOD_MACHINE)
6706 action |= 0x20000000;
6710 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6711 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6712 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6715 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6719 /* Nothing to do. */
6722 res = ERROR_SUCCESS;
6726 /* If we are appending but the string was empty, strip ; */
6727 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6729 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6730 newval = strdupW(value);
6733 res = ERROR_OUTOFMEMORY;
6741 /* Contrary to MSDN, +-variable to [~];path works */
6742 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6744 res = ERROR_SUCCESS;
6748 data = msi_alloc(size);
6752 return ERROR_OUTOFMEMORY;
6755 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6756 if (res != ERROR_SUCCESS)
6759 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6762 res = RegDeleteValueW(env, name);
6763 if (res != ERROR_SUCCESS)
6764 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6768 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6769 if (flags & ENV_MOD_MASK)
6773 if (flags & ENV_MOD_APPEND) multiplier++;
6774 if (flags & ENV_MOD_PREFIX) multiplier++;
6775 mod_size = lstrlenW(value) * multiplier;
6776 size += mod_size * sizeof(WCHAR);
6779 newval = msi_alloc(size);
6783 res = ERROR_OUTOFMEMORY;
6787 if (flags & ENV_MOD_PREFIX)
6789 lstrcpyW(newval, value);
6790 ptr = newval + lstrlenW(value);
6791 action |= 0x80000000;
6794 lstrcpyW(ptr, data);
6796 if (flags & ENV_MOD_APPEND)
6798 lstrcatW(newval, value);
6799 action |= 0x40000000;
6802 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6803 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6806 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6810 uirow = MSI_CreateRecord( 3 );
6811 MSI_RecordSetStringW( uirow, 1, name );
6812 MSI_RecordSetStringW( uirow, 2, newval );
6813 MSI_RecordSetInteger( uirow, 3, action );
6814 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6815 msiobj_release( &uirow->hdr );
6817 if (env) RegCloseKey(env);
6818 msi_free(deformatted);
6824 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6828 static const WCHAR ExecSeqQuery[] =
6829 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6830 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6831 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6832 if (rc != ERROR_SUCCESS)
6833 return ERROR_SUCCESS;
6835 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6836 msiobj_release(&view->hdr);
6841 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6843 MSIPACKAGE *package = param;
6844 LPCWSTR name, value, component;
6845 LPWSTR deformatted = NULL;
6854 component = MSI_RecordGetString( rec, 4 );
6855 comp = get_loaded_component( package, component );
6857 return ERROR_SUCCESS;
6861 TRACE("component is disabled\n");
6862 return ERROR_SUCCESS;
6865 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6867 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6868 comp->Action = comp->Installed;
6869 return ERROR_SUCCESS;
6871 comp->Action = INSTALLSTATE_ABSENT;
6873 name = MSI_RecordGetString( rec, 2 );
6874 value = MSI_RecordGetString( rec, 3 );
6876 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6878 r = env_parse_flags( &name, &value, &flags );
6879 if (r != ERROR_SUCCESS)
6882 if (!(flags & ENV_ACT_REMOVE))
6884 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6885 return ERROR_SUCCESS;
6888 if (value && !deformat_string( package, value, &deformatted ))
6889 return ERROR_OUTOFMEMORY;
6891 value = deformatted;
6893 r = open_env_key( flags, &env );
6894 if (r != ERROR_SUCCESS)
6900 if (flags & ENV_MOD_MACHINE)
6901 action |= 0x20000000;
6903 TRACE("Removing %s\n", debugstr_w(name));
6905 res = RegDeleteValueW( env, name );
6906 if (res != ERROR_SUCCESS)
6908 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6913 uirow = MSI_CreateRecord( 3 );
6914 MSI_RecordSetStringW( uirow, 1, name );
6915 MSI_RecordSetStringW( uirow, 2, value );
6916 MSI_RecordSetInteger( uirow, 3, action );
6917 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6918 msiobj_release( &uirow->hdr );
6920 if (env) RegCloseKey( env );
6921 msi_free( deformatted );
6925 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6929 static const WCHAR query[] =
6930 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6931 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6933 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6934 if (rc != ERROR_SUCCESS)
6935 return ERROR_SUCCESS;
6937 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6938 msiobj_release( &view->hdr );
6943 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6945 LPWSTR key, template, id;
6946 UINT r = ERROR_SUCCESS;
6948 id = msi_dup_property( package->db, szProductID );
6952 return ERROR_SUCCESS;
6954 template = msi_dup_property( package->db, szPIDTemplate );
6955 key = msi_dup_property( package->db, szPIDKEY );
6957 if (key && template)
6959 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6960 r = msi_set_property( package->db, szProductID, key );
6962 msi_free( template );
6967 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6970 package->need_reboot = 1;
6971 return ERROR_SUCCESS;
6974 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6976 static const WCHAR szAvailableFreeReg[] =
6977 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6979 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6981 TRACE("%p %d kilobytes\n", package, space);
6983 uirow = MSI_CreateRecord( 1 );
6984 MSI_RecordSetInteger( uirow, 1, space );
6985 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6986 msiobj_release( &uirow->hdr );
6988 return ERROR_SUCCESS;
6991 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6993 FIXME("%p\n", package);
6994 return ERROR_SUCCESS;
6997 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6999 FIXME("%p\n", package);
7000 return ERROR_SUCCESS;
7003 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7008 static const WCHAR driver_query[] = {
7009 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7010 'O','D','B','C','D','r','i','v','e','r',0 };
7012 static const WCHAR translator_query[] = {
7013 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7014 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7016 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7017 if (r == ERROR_SUCCESS)
7020 r = MSI_IterateRecords( view, &count, NULL, package );
7021 msiobj_release( &view->hdr );
7022 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7025 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7026 if (r == ERROR_SUCCESS)
7029 r = MSI_IterateRecords( view, &count, NULL, package );
7030 msiobj_release( &view->hdr );
7031 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7034 return ERROR_SUCCESS;
7037 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7039 MSIPACKAGE *package = param;
7040 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7043 if ((value = msi_dup_property( package->db, property )))
7045 FIXME("remove %s\n", debugstr_w(value));
7048 return ERROR_SUCCESS;
7051 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7056 static const WCHAR query[] =
7057 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7058 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7060 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7061 if (r == ERROR_SUCCESS)
7063 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7064 msiobj_release( &view->hdr );
7066 return ERROR_SUCCESS;
7069 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7071 MSIPACKAGE *package = param;
7072 int attributes = MSI_RecordGetInteger( rec, 5 );
7074 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7076 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7077 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7078 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7079 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7083 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7085 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7086 if (r != ERROR_SUCCESS)
7087 return ERROR_SUCCESS;
7091 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7092 if (r != ERROR_SUCCESS)
7093 return ERROR_SUCCESS;
7095 RegCloseKey( hkey );
7097 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7098 debugstr_w(upgrade_code), debugstr_w(version_min),
7099 debugstr_w(version_max), debugstr_w(language));
7101 return ERROR_SUCCESS;
7104 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7109 static const WCHAR query[] =
7110 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7112 if (msi_get_property_int( package->db, szInstalled, 0 ))
7114 TRACE("product is installed, skipping action\n");
7115 return ERROR_SUCCESS;
7117 if (msi_get_property_int( package->db, szPreselected, 0 ))
7119 TRACE("Preselected property is set, not migrating feature states\n");
7120 return ERROR_SUCCESS;
7123 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7124 if (r == ERROR_SUCCESS)
7126 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7127 msiobj_release( &view->hdr );
7129 return ERROR_SUCCESS;
7132 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7133 LPCSTR action, LPCWSTR table )
7135 static const WCHAR query[] = {
7136 'S','E','L','E','C','T',' ','*',' ',
7137 'F','R','O','M',' ','`','%','s','`',0 };
7138 MSIQUERY *view = NULL;
7142 r = MSI_OpenQuery( package->db, &view, query, table );
7143 if (r == ERROR_SUCCESS)
7145 r = MSI_IterateRecords(view, &count, NULL, package);
7146 msiobj_release(&view->hdr);
7150 FIXME("%s -> %u ignored %s table values\n",
7151 action, count, debugstr_w(table));
7153 return ERROR_SUCCESS;
7156 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7158 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7159 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7162 static UINT ACTION_BindImage( MSIPACKAGE *package )
7164 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7165 return msi_unimplemented_action_stub( package, "BindImage", table );
7168 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7170 static const WCHAR table[] = {
7171 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7172 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7175 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7177 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7178 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7181 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7183 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7184 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7187 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7189 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7190 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7193 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7195 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7196 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7199 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7203 const WCHAR *action;
7204 UINT (*handler)(MSIPACKAGE *);
7208 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7209 { szAppSearch, ACTION_AppSearch },
7210 { szBindImage, ACTION_BindImage },
7211 { szCCPSearch, ACTION_CCPSearch },
7212 { szCostFinalize, ACTION_CostFinalize },
7213 { szCostInitialize, ACTION_CostInitialize },
7214 { szCreateFolders, ACTION_CreateFolders },
7215 { szCreateShortcuts, ACTION_CreateShortcuts },
7216 { szDeleteServices, ACTION_DeleteServices },
7217 { szDisableRollback, ACTION_DisableRollback },
7218 { szDuplicateFiles, ACTION_DuplicateFiles },
7219 { szExecuteAction, ACTION_ExecuteAction },
7220 { szFileCost, ACTION_FileCost },
7221 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7222 { szForceReboot, ACTION_ForceReboot },
7223 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7224 { szInstallExecute, ACTION_InstallExecute },
7225 { szInstallExecuteAgain, ACTION_InstallExecute },
7226 { szInstallFiles, ACTION_InstallFiles},
7227 { szInstallFinalize, ACTION_InstallFinalize },
7228 { szInstallInitialize, ACTION_InstallInitialize },
7229 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7230 { szInstallValidate, ACTION_InstallValidate },
7231 { szIsolateComponents, ACTION_IsolateComponents },
7232 { szLaunchConditions, ACTION_LaunchConditions },
7233 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7234 { szMoveFiles, ACTION_MoveFiles },
7235 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7236 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7237 { szInstallODBC, ACTION_InstallODBC },
7238 { szInstallServices, ACTION_InstallServices },
7239 { szPatchFiles, ACTION_PatchFiles },
7240 { szProcessComponents, ACTION_ProcessComponents },
7241 { szPublishComponents, ACTION_PublishComponents },
7242 { szPublishFeatures, ACTION_PublishFeatures },
7243 { szPublishProduct, ACTION_PublishProduct },
7244 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7245 { szRegisterComPlus, ACTION_RegisterComPlus},
7246 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7247 { szRegisterFonts, ACTION_RegisterFonts },
7248 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7249 { szRegisterProduct, ACTION_RegisterProduct },
7250 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7251 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7252 { szRegisterUser, ACTION_RegisterUser },
7253 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7254 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7255 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7256 { szRemoveFiles, ACTION_RemoveFiles },
7257 { szRemoveFolders, ACTION_RemoveFolders },
7258 { szRemoveIniValues, ACTION_RemoveIniValues },
7259 { szRemoveODBC, ACTION_RemoveODBC },
7260 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7261 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7262 { szResolveSource, ACTION_ResolveSource },
7263 { szRMCCPSearch, ACTION_RMCCPSearch },
7264 { szScheduleReboot, ACTION_ScheduleReboot },
7265 { szSelfRegModules, ACTION_SelfRegModules },
7266 { szSelfUnregModules, ACTION_SelfUnregModules },
7267 { szSetODBCFolders, ACTION_SetODBCFolders },
7268 { szStartServices, ACTION_StartServices },
7269 { szStopServices, ACTION_StopServices },
7270 { szUnpublishComponents, ACTION_UnpublishComponents },
7271 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7272 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7273 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7274 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7275 { szUnregisterFonts, ACTION_UnregisterFonts },
7276 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7277 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7278 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7279 { szValidateProductID, ACTION_ValidateProductID },
7280 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7281 { szWriteIniValues, ACTION_WriteIniValues },
7282 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7286 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7292 while (StandardActions[i].action != NULL)
7294 if (!strcmpW( StandardActions[i].action, action ))
7296 ui_actionstart( package, action );
7297 if (StandardActions[i].handler)
7299 ui_actioninfo( package, action, TRUE, 0 );
7300 *rc = StandardActions[i].handler( package );
7301 ui_actioninfo( package, action, FALSE, *rc );
7305 FIXME("unhandled standard action %s\n", debugstr_w(action));
7306 *rc = ERROR_SUCCESS;
7316 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7318 UINT rc = ERROR_SUCCESS;
7321 TRACE("Performing action (%s)\n", debugstr_w(action));
7323 handled = ACTION_HandleStandardAction(package, action, &rc);
7326 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7330 WARN("unhandled msi action %s\n", debugstr_w(action));
7331 rc = ERROR_FUNCTION_NOT_CALLED;
7337 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7339 UINT rc = ERROR_SUCCESS;
7340 BOOL handled = FALSE;
7342 TRACE("Performing action (%s)\n", debugstr_w(action));
7344 handled = ACTION_HandleStandardAction(package, action, &rc);
7347 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7349 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7354 WARN("unhandled msi action %s\n", debugstr_w(action));
7355 rc = ERROR_FUNCTION_NOT_CALLED;
7361 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7363 UINT rc = ERROR_SUCCESS;
7366 static const WCHAR ExecSeqQuery[] =
7367 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7368 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7369 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7370 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7371 static const WCHAR UISeqQuery[] =
7372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7373 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7374 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7375 ' ', '=',' ','%','i',0};
7377 if (needs_ui_sequence(package))
7378 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7380 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7384 LPCWSTR action, cond;
7386 TRACE("Running the actions\n");
7388 /* check conditions */
7389 cond = MSI_RecordGetString(row, 2);
7391 /* this is a hack to skip errors in the condition code */
7392 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7394 msiobj_release(&row->hdr);
7395 return ERROR_SUCCESS;
7398 action = MSI_RecordGetString(row, 1);
7401 ERR("failed to fetch action\n");
7402 msiobj_release(&row->hdr);
7403 return ERROR_FUNCTION_FAILED;
7406 if (needs_ui_sequence(package))
7407 rc = ACTION_PerformUIAction(package, action, -1);
7409 rc = ACTION_PerformAction(package, action, -1);
7411 msiobj_release(&row->hdr);
7417 /****************************************************
7418 * TOP level entry points
7419 *****************************************************/
7421 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7422 LPCWSTR szCommandLine )
7427 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7428 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7430 msi_set_property( package->db, szAction, szInstall );
7432 package->script->InWhatSequence = SEQUENCE_INSTALL;
7439 dir = strdupW(szPackagePath);
7440 p = strrchrW(dir, '\\');
7444 file = szPackagePath + (p - dir);
7449 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7450 GetCurrentDirectoryW(MAX_PATH, dir);
7451 lstrcatW(dir, szBackSlash);
7452 file = szPackagePath;
7455 msi_free( package->PackagePath );
7456 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7457 if (!package->PackagePath)
7460 return ERROR_OUTOFMEMORY;
7463 lstrcpyW(package->PackagePath, dir);
7464 lstrcatW(package->PackagePath, file);
7467 msi_set_sourcedir_props(package, FALSE);
7470 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7471 if (rc != ERROR_SUCCESS)
7474 msi_apply_transforms( package );
7475 msi_apply_patches( package );
7477 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7479 TRACE("setting reinstall property\n");
7480 msi_set_property( package->db, szReinstall, szAll );
7483 /* properties may have been added by a transform */
7484 msi_clone_properties( package );
7486 msi_parse_command_line( package, szCommandLine, FALSE );
7487 msi_adjust_privilege_properties( package );
7488 msi_set_context( package );
7490 if (needs_ui_sequence( package))
7492 package->script->InWhatSequence |= SEQUENCE_UI;
7493 rc = ACTION_ProcessUISequence(package);
7494 ui_exists = ui_sequence_exists(package);
7495 if (rc == ERROR_SUCCESS || !ui_exists)
7497 package->script->InWhatSequence |= SEQUENCE_EXEC;
7498 rc = ACTION_ProcessExecSequence(package, ui_exists);
7502 rc = ACTION_ProcessExecSequence(package, FALSE);
7504 package->script->CurrentlyScripting = FALSE;
7506 /* process the ending type action */
7507 if (rc == ERROR_SUCCESS)
7508 ACTION_PerformActionSequence(package, -1);
7509 else if (rc == ERROR_INSTALL_USEREXIT)
7510 ACTION_PerformActionSequence(package, -2);
7511 else if (rc == ERROR_INSTALL_SUSPEND)
7512 ACTION_PerformActionSequence(package, -4);
7514 ACTION_PerformActionSequence(package, -3);
7516 /* finish up running custom actions */
7517 ACTION_FinishCustomActions(package);
7519 if (rc == ERROR_SUCCESS && package->need_reboot)
7520 return ERROR_SUCCESS_REBOOT_REQUIRED;