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;
469 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
472 LPWSTR p, *ret = NULL;
478 /* count the number of substrings */
479 for ( pc = str, count = 0; pc; count++ )
481 pc = strchrW( pc, sep );
486 /* allocate space for an array of substring pointers and the substrings */
487 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
488 (lstrlenW(str)+1) * sizeof(WCHAR) );
492 /* copy the string and set the pointers */
493 p = (LPWSTR) &ret[count+1];
495 for( count = 0; (ret[count] = p); count++ )
497 p = strchrW( p, sep );
505 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
507 static const WCHAR szSystemLanguageID[] =
508 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
510 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
511 UINT ret = ERROR_FUNCTION_FAILED;
513 prod_code = msi_dup_property( package->db, szProductCode );
514 patch_product = msi_get_suminfo_product( patch );
516 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
518 if ( strstrW( patch_product, prod_code ) )
523 si = MSI_GetSummaryInformationW( patch, 0 );
526 ERR("no summary information!\n");
530 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
533 ERR("no template property!\n");
534 msiobj_release( &si->hdr );
541 msiobj_release( &si->hdr );
545 langid = msi_dup_property( package->db, szSystemLanguageID );
548 msiobj_release( &si->hdr );
552 p = strchrW( template, ';' );
553 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
555 TRACE("applicable transform\n");
559 /* FIXME: check platform */
561 msiobj_release( &si->hdr );
565 msi_free( patch_product );
566 msi_free( prod_code );
567 msi_free( template );
573 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
574 MSIDATABASE *patch_db, LPCWSTR name )
576 UINT ret = ERROR_FUNCTION_FAILED;
577 IStorage *stg = NULL;
580 TRACE("%p %s\n", package, debugstr_w(name) );
584 ERR("expected a colon in %s\n", debugstr_w(name));
585 return ERROR_FUNCTION_FAILED;
588 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
591 ret = msi_check_transform_applicable( package, stg );
592 if (ret == ERROR_SUCCESS)
593 msi_table_apply_transform( package->db, stg );
595 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
596 IStorage_Release( stg );
599 ERR("failed to open substorage %s\n", debugstr_w(name));
601 return ERROR_SUCCESS;
604 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
606 LPWSTR guid_list, *guids, product_code;
607 UINT i, ret = ERROR_FUNCTION_FAILED;
609 product_code = msi_dup_property( package->db, szProductCode );
612 /* FIXME: the property ProductCode should be written into the DB somewhere */
613 ERR("no product code to check\n");
614 return ERROR_SUCCESS;
617 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
618 guids = msi_split_string( guid_list, ';' );
619 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
621 if (!strcmpW( guids[i], product_code ))
625 msi_free( guid_list );
626 msi_free( product_code );
631 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
634 MSIRECORD *rec = NULL;
639 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
640 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
641 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
642 '`','S','o','u','r','c','e','`',' ','I','S',' ',
643 'N','O','T',' ','N','U','L','L',0};
645 r = MSI_DatabaseOpenViewW(package->db, query, &view);
646 if (r != ERROR_SUCCESS)
649 r = MSI_ViewExecute(view, 0);
650 if (r != ERROR_SUCCESS)
653 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
655 prop = MSI_RecordGetString(rec, 1);
656 patch = msi_dup_property(package->db, szPatch);
657 msi_set_property(package->db, prop, patch);
662 if (rec) msiobj_release(&rec->hdr);
663 msiobj_release(&view->hdr);
668 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
671 UINT r = ERROR_SUCCESS;
674 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
676 return ERROR_OUTOFMEMORY;
678 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
682 return ERROR_OUTOFMEMORY;
688 msi_free( pi->patchcode );
690 return ERROR_PATCH_PACKAGE_INVALID;
693 p = strchrW( p + 1, '}' );
696 msi_free( pi->patchcode );
698 return ERROR_PATCH_PACKAGE_INVALID;
703 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
707 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
709 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
712 msi_free( pi->patchcode );
714 return ERROR_OUTOFMEMORY;
721 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
723 UINT i, r = ERROR_SUCCESS;
726 /* apply substorage transforms */
727 substorage = msi_split_string( patch->transforms, ';' );
728 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
729 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
731 msi_free( substorage );
732 if (r != ERROR_SUCCESS)
735 msi_set_media_source_prop( package );
738 * There might be a CAB file in the patch package,
739 * so append it to the list of storages to search for streams.
741 append_storage_to_db( package->db, patch_db->storage );
743 patch->state = MSIPATCHSTATE_APPLIED;
744 list_add_tail( &package->patches, &patch->entry );
745 return ERROR_SUCCESS;
748 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
750 static const WCHAR dotmsp[] = {'.','m','s','p',0};
751 MSIDATABASE *patch_db = NULL;
752 WCHAR localfile[MAX_PATH];
754 MSIPATCHINFO *patch = NULL;
755 UINT r = ERROR_SUCCESS;
757 TRACE("%p %s\n", package, debugstr_w( file ) );
759 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
760 if ( r != ERROR_SUCCESS )
762 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
766 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
769 msiobj_release( &patch_db->hdr );
770 return ERROR_FUNCTION_FAILED;
773 r = msi_check_patch_applicable( package, si );
774 if (r != ERROR_SUCCESS)
776 TRACE("patch not applicable\n");
781 r = msi_parse_patch_summary( si, &patch );
782 if ( r != ERROR_SUCCESS )
785 r = msi_get_local_package_name( localfile, dotmsp );
786 if ( r != ERROR_SUCCESS )
789 TRACE("copying to local package %s\n", debugstr_w(localfile));
791 if (!CopyFileW( file, localfile, FALSE ))
793 ERR("Unable to copy package (%s -> %s) (error %u)\n",
794 debugstr_w(file), debugstr_w(localfile), GetLastError());
798 patch->localfile = strdupW( localfile );
800 r = msi_apply_patch_db( package, patch_db, patch );
801 if ( r != ERROR_SUCCESS )
802 WARN("patch failed to apply %u\n", r);
805 msiobj_release( &si->hdr );
806 msiobj_release( &patch_db->hdr );
807 if (patch && r != ERROR_SUCCESS)
809 if (patch->localfile)
810 DeleteFileW( patch->localfile );
812 msi_free( patch->patchcode );
813 msi_free( patch->transforms );
814 msi_free( patch->localfile );
820 /* get the PATCH property, and apply all the patches it specifies */
821 static UINT msi_apply_patches( MSIPACKAGE *package )
823 LPWSTR patch_list, *patches;
824 UINT i, r = ERROR_SUCCESS;
826 patch_list = msi_dup_property( package->db, szPatch );
828 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
830 patches = msi_split_string( patch_list, ';' );
831 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
832 r = msi_apply_patch_package( package, patches[i] );
835 msi_free( patch_list );
840 static UINT msi_apply_transforms( MSIPACKAGE *package )
842 static const WCHAR szTransforms[] = {
843 'T','R','A','N','S','F','O','R','M','S',0 };
844 LPWSTR xform_list, *xforms;
845 UINT i, r = ERROR_SUCCESS;
847 xform_list = msi_dup_property( package->db, szTransforms );
848 xforms = msi_split_string( xform_list, ';' );
850 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
852 if (xforms[i][0] == ':')
853 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
858 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
861 WCHAR *p = strrchrW( package->PackagePath, '\\' );
862 DWORD len = p - package->PackagePath + 1;
864 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
867 msi_free( xform_list );
868 return ERROR_OUTOFMEMORY;
870 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
871 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
873 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
874 if (transform != xforms[i]) msi_free( transform );
879 msi_free( xform_list );
884 static BOOL ui_sequence_exists( MSIPACKAGE *package )
889 static const WCHAR ExecSeqQuery [] =
890 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
891 '`','I','n','s','t','a','l','l',
892 'U','I','S','e','q','u','e','n','c','e','`',
893 ' ','W','H','E','R','E',' ',
894 '`','S','e','q','u','e','n','c','e','`',' ',
895 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
896 '`','S','e','q','u','e','n','c','e','`',0};
898 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
899 if (rc == ERROR_SUCCESS)
901 msiobj_release(&view->hdr);
908 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
910 LPWSTR source, check;
912 if (msi_get_property_int( package->db, szInstalled, 0 ))
916 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
917 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
925 db = msi_dup_property( package->db, szOriginalDatabase );
927 return ERROR_OUTOFMEMORY;
929 p = strrchrW( db, '\\' );
932 p = strrchrW( db, '/' );
936 return ERROR_SUCCESS;
941 source = msi_alloc( len * sizeof(WCHAR) );
942 lstrcpynW( source, db, len );
946 check = msi_dup_property( package->db, cszSourceDir );
947 if (!check || replace)
949 UINT r = msi_set_property( package->db, cszSourceDir, source );
950 if (r == ERROR_SUCCESS)
951 msi_reset_folders( package, TRUE );
955 check = msi_dup_property( package->db, cszSOURCEDIR );
956 if (!check || replace)
957 msi_set_property( package->db, cszSOURCEDIR, source );
962 return ERROR_SUCCESS;
965 static BOOL needs_ui_sequence(MSIPACKAGE *package)
967 INT level = msi_get_property_int(package->db, szUILevel, 0);
968 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
971 UINT msi_set_context(MSIPACKAGE *package)
975 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
977 num = msi_get_property_int(package->db, szAllUsers, 0);
978 if (num == 1 || num == 2)
979 package->Context = MSIINSTALLCONTEXT_MACHINE;
981 return ERROR_SUCCESS;
984 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
987 LPCWSTR cond, action;
988 MSIPACKAGE *package = param;
990 action = MSI_RecordGetString(row,1);
993 ERR("Error is retrieving action name\n");
994 return ERROR_FUNCTION_FAILED;
997 /* check conditions */
998 cond = MSI_RecordGetString(row,2);
1000 /* this is a hack to skip errors in the condition code */
1001 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1003 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
1004 return ERROR_SUCCESS;
1007 if (needs_ui_sequence(package))
1008 rc = ACTION_PerformUIAction(package, action, -1);
1010 rc = ACTION_PerformAction(package, action, -1);
1012 msi_dialog_check_messages( NULL );
1014 if (package->CurrentInstallState != ERROR_SUCCESS)
1015 rc = package->CurrentInstallState;
1017 if (rc == ERROR_FUNCTION_NOT_CALLED)
1020 if (rc != ERROR_SUCCESS)
1021 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
1026 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
1030 static const WCHAR query[] =
1031 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1033 ' ','W','H','E','R','E',' ',
1034 '`','S','e','q','u','e','n','c','e','`',' ',
1035 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1036 '`','S','e','q','u','e','n','c','e','`',0};
1038 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1040 r = MSI_OpenQuery( package->db, &view, query, szTable );
1041 if (r == ERROR_SUCCESS)
1043 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
1044 msiobj_release(&view->hdr);
1050 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1054 static const WCHAR ExecSeqQuery[] =
1055 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1056 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1057 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1058 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1059 'O','R','D','E','R',' ', 'B','Y',' ',
1060 '`','S','e','q','u','e','n','c','e','`',0 };
1061 static const WCHAR IVQuery[] =
1062 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1063 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1064 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1065 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1066 ' ','\'', 'I','n','s','t','a','l','l',
1067 'V','a','l','i','d','a','t','e','\'', 0};
1070 if (package->script->ExecuteSequenceRun)
1072 TRACE("Execute Sequence already Run\n");
1073 return ERROR_SUCCESS;
1076 package->script->ExecuteSequenceRun = TRUE;
1078 /* get the sequence number */
1081 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
1083 return ERROR_FUNCTION_FAILED;
1084 seq = MSI_RecordGetInteger(row,1);
1085 msiobj_release(&row->hdr);
1088 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1089 if (rc == ERROR_SUCCESS)
1091 TRACE("Running the actions\n");
1093 msi_set_property(package->db, cszSourceDir, NULL);
1095 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1096 msiobj_release(&view->hdr);
1102 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1106 static const WCHAR ExecSeqQuery [] =
1107 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1108 '`','I','n','s','t','a','l','l',
1109 'U','I','S','e','q','u','e','n','c','e','`',
1110 ' ','W','H','E','R','E',' ',
1111 '`','S','e','q','u','e','n','c','e','`',' ',
1112 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1113 '`','S','e','q','u','e','n','c','e','`',0};
1115 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1116 if (rc == ERROR_SUCCESS)
1118 TRACE("Running the actions\n");
1120 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1121 msiobj_release(&view->hdr);
1127 /********************************************************
1128 * ACTION helper functions and functions that perform the actions
1129 *******************************************************/
1130 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1131 UINT* rc, UINT script, BOOL force )
1136 arc = ACTION_CustomAction(package, action, script, force);
1138 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1147 * Actual Action Handlers
1150 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1152 MSIPACKAGE *package = param;
1153 LPCWSTR dir, component;
1159 component = MSI_RecordGetString(row, 2);
1161 return ERROR_SUCCESS;
1163 comp = get_loaded_component(package, component);
1165 return ERROR_SUCCESS;
1169 TRACE("component is disabled\n");
1170 return ERROR_SUCCESS;
1173 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1175 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1176 comp->Action = comp->Installed;
1177 return ERROR_SUCCESS;
1179 comp->Action = INSTALLSTATE_LOCAL;
1181 dir = MSI_RecordGetString(row,1);
1184 ERR("Unable to get folder id\n");
1185 return ERROR_SUCCESS;
1188 uirow = MSI_CreateRecord(1);
1189 MSI_RecordSetStringW(uirow, 1, dir);
1190 ui_actiondata(package, szCreateFolders, uirow);
1191 msiobj_release(&uirow->hdr);
1193 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1196 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1197 return ERROR_SUCCESS;
1200 TRACE("Folder is %s\n",debugstr_w(full_path));
1202 if (folder->State == 0)
1203 create_full_pathW(full_path);
1207 msi_free(full_path);
1208 return ERROR_SUCCESS;
1211 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1213 static const WCHAR query[] =
1214 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1215 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1219 /* create all the empty folders specified in the CreateFolder table */
1220 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1221 if (rc != ERROR_SUCCESS)
1222 return ERROR_SUCCESS;
1224 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1225 msiobj_release(&view->hdr);
1230 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1232 MSIPACKAGE *package = param;
1233 LPCWSTR dir, component;
1239 component = MSI_RecordGetString(row, 2);
1241 return ERROR_SUCCESS;
1243 comp = get_loaded_component(package, component);
1245 return ERROR_SUCCESS;
1249 TRACE("component is disabled\n");
1250 return ERROR_SUCCESS;
1253 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1255 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1256 comp->Action = comp->Installed;
1257 return ERROR_SUCCESS;
1259 comp->Action = INSTALLSTATE_ABSENT;
1261 dir = MSI_RecordGetString( row, 1 );
1264 ERR("Unable to get folder id\n");
1265 return ERROR_SUCCESS;
1268 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1271 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1272 return ERROR_SUCCESS;
1275 TRACE("folder is %s\n", debugstr_w(full_path));
1277 uirow = MSI_CreateRecord( 1 );
1278 MSI_RecordSetStringW( uirow, 1, dir );
1279 ui_actiondata( package, szRemoveFolders, uirow );
1280 msiobj_release( &uirow->hdr );
1282 RemoveDirectoryW( full_path );
1285 msi_free( full_path );
1286 return ERROR_SUCCESS;
1289 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1291 static const WCHAR query[] =
1292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1293 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1298 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1299 if (rc != ERROR_SUCCESS)
1300 return ERROR_SUCCESS;
1302 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1303 msiobj_release( &view->hdr );
1308 static UINT load_component( MSIRECORD *row, LPVOID param )
1310 MSIPACKAGE *package = param;
1313 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1315 return ERROR_FUNCTION_FAILED;
1317 list_add_tail( &package->components, &comp->entry );
1319 /* fill in the data */
1320 comp->Component = msi_dup_record_field( row, 1 );
1322 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1324 comp->ComponentId = msi_dup_record_field( row, 2 );
1325 comp->Directory = msi_dup_record_field( row, 3 );
1326 comp->Attributes = MSI_RecordGetInteger(row,4);
1327 comp->Condition = msi_dup_record_field( row, 5 );
1328 comp->KeyPath = msi_dup_record_field( row, 6 );
1330 comp->Installed = INSTALLSTATE_UNKNOWN;
1331 comp->Action = INSTALLSTATE_UNKNOWN;
1332 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1334 comp->assembly = load_assembly( package, comp );
1335 return ERROR_SUCCESS;
1338 static UINT load_all_components( MSIPACKAGE *package )
1340 static const WCHAR query[] = {
1341 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1342 '`','C','o','m','p','o','n','e','n','t','`',0 };
1346 if (!list_empty(&package->components))
1347 return ERROR_SUCCESS;
1349 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1350 if (r != ERROR_SUCCESS)
1353 r = MSI_IterateRecords(view, NULL, load_component, package);
1354 msiobj_release(&view->hdr);
1359 MSIPACKAGE *package;
1360 MSIFEATURE *feature;
1363 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1367 cl = msi_alloc( sizeof (*cl) );
1369 return ERROR_NOT_ENOUGH_MEMORY;
1370 cl->component = comp;
1371 list_add_tail( &feature->Components, &cl->entry );
1373 return ERROR_SUCCESS;
1376 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1380 fl = msi_alloc( sizeof(*fl) );
1382 return ERROR_NOT_ENOUGH_MEMORY;
1383 fl->feature = child;
1384 list_add_tail( &parent->Children, &fl->entry );
1386 return ERROR_SUCCESS;
1389 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1391 _ilfs* ilfs = param;
1395 component = MSI_RecordGetString(row,1);
1397 /* check to see if the component is already loaded */
1398 comp = get_loaded_component( ilfs->package, component );
1401 ERR("unknown component %s\n", debugstr_w(component));
1402 return ERROR_FUNCTION_FAILED;
1405 add_feature_component( ilfs->feature, comp );
1406 comp->Enabled = TRUE;
1408 return ERROR_SUCCESS;
1411 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1413 MSIFEATURE *feature;
1418 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1420 if ( !strcmpW( feature->Feature, name ) )
1427 static UINT load_feature(MSIRECORD * row, LPVOID param)
1429 MSIPACKAGE* package = param;
1430 MSIFEATURE* feature;
1431 static const WCHAR Query1[] =
1432 {'S','E','L','E','C','T',' ',
1433 '`','C','o','m','p','o','n','e','n','t','_','`',
1434 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1435 'C','o','m','p','o','n','e','n','t','s','`',' ',
1436 'W','H','E','R','E',' ',
1437 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1442 /* fill in the data */
1444 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1446 return ERROR_NOT_ENOUGH_MEMORY;
1448 list_init( &feature->Children );
1449 list_init( &feature->Components );
1451 feature->Feature = msi_dup_record_field( row, 1 );
1453 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1455 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1456 feature->Title = msi_dup_record_field( row, 3 );
1457 feature->Description = msi_dup_record_field( row, 4 );
1459 if (!MSI_RecordIsNull(row,5))
1460 feature->Display = MSI_RecordGetInteger(row,5);
1462 feature->Level= MSI_RecordGetInteger(row,6);
1463 feature->Directory = msi_dup_record_field( row, 7 );
1464 feature->Attributes = MSI_RecordGetInteger(row,8);
1466 feature->Installed = INSTALLSTATE_UNKNOWN;
1467 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1469 list_add_tail( &package->features, &feature->entry );
1471 /* load feature components */
1473 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1474 if (rc != ERROR_SUCCESS)
1475 return ERROR_SUCCESS;
1477 ilfs.package = package;
1478 ilfs.feature = feature;
1480 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1481 msiobj_release(&view->hdr);
1483 return ERROR_SUCCESS;
1486 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1488 MSIPACKAGE* package = param;
1489 MSIFEATURE *parent, *child;
1491 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1493 return ERROR_FUNCTION_FAILED;
1495 if (!child->Feature_Parent)
1496 return ERROR_SUCCESS;
1498 parent = find_feature_by_name( package, child->Feature_Parent );
1500 return ERROR_FUNCTION_FAILED;
1502 add_feature_child( parent, child );
1503 return ERROR_SUCCESS;
1506 static UINT load_all_features( MSIPACKAGE *package )
1508 static const WCHAR query[] = {
1509 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1510 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1511 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1515 if (!list_empty(&package->features))
1516 return ERROR_SUCCESS;
1518 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1519 if (r != ERROR_SUCCESS)
1522 r = MSI_IterateRecords( view, NULL, load_feature, package );
1523 if (r != ERROR_SUCCESS)
1526 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1527 msiobj_release( &view->hdr );
1532 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1543 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1545 static const WCHAR query[] = {
1546 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1547 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1548 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1549 MSIQUERY *view = NULL;
1550 MSIRECORD *row = NULL;
1553 TRACE("%s\n", debugstr_w(file->File));
1555 r = MSI_OpenQuery(package->db, &view, query, file->File);
1556 if (r != ERROR_SUCCESS)
1559 r = MSI_ViewExecute(view, NULL);
1560 if (r != ERROR_SUCCESS)
1563 r = MSI_ViewFetch(view, &row);
1564 if (r != ERROR_SUCCESS)
1567 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1568 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1569 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1570 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1571 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1574 if (view) msiobj_release(&view->hdr);
1575 if (row) msiobj_release(&row->hdr);
1579 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1582 static const WCHAR query[] = {
1583 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1584 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1585 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1587 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1590 WARN("query failed\n");
1591 return ERROR_FUNCTION_FAILED;
1594 file->disk_id = MSI_RecordGetInteger( row, 1 );
1595 msiobj_release( &row->hdr );
1596 return ERROR_SUCCESS;
1599 static UINT load_file(MSIRECORD *row, LPVOID param)
1601 MSIPACKAGE* package = param;
1605 /* fill in the data */
1607 file = msi_alloc_zero( sizeof (MSIFILE) );
1609 return ERROR_NOT_ENOUGH_MEMORY;
1611 file->File = msi_dup_record_field( row, 1 );
1613 component = MSI_RecordGetString( row, 2 );
1614 file->Component = get_loaded_component( package, component );
1616 if (!file->Component)
1618 WARN("Component not found: %s\n", debugstr_w(component));
1619 msi_free(file->File);
1621 return ERROR_SUCCESS;
1624 file->FileName = msi_dup_record_field( row, 3 );
1625 reduce_to_longfilename( file->FileName );
1627 file->ShortName = msi_dup_record_field( row, 3 );
1628 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1630 file->FileSize = MSI_RecordGetInteger( row, 4 );
1631 file->Version = msi_dup_record_field( row, 5 );
1632 file->Language = msi_dup_record_field( row, 6 );
1633 file->Attributes = MSI_RecordGetInteger( row, 7 );
1634 file->Sequence = MSI_RecordGetInteger( row, 8 );
1636 file->state = msifs_invalid;
1638 /* if the compressed bits are not set in the file attributes,
1639 * then read the information from the package word count property
1641 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1643 file->IsCompressed = FALSE;
1645 else if (file->Attributes &
1646 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1648 file->IsCompressed = TRUE;
1650 else if (file->Attributes & msidbFileAttributesNoncompressed)
1652 file->IsCompressed = FALSE;
1656 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1659 load_file_hash(package, file);
1660 load_file_disk_id(package, file);
1662 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1664 list_add_tail( &package->files, &file->entry );
1666 return ERROR_SUCCESS;
1669 static UINT load_all_files(MSIPACKAGE *package)
1673 static const WCHAR Query[] =
1674 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1675 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1676 '`','S','e','q','u','e','n','c','e','`', 0};
1678 if (!list_empty(&package->files))
1679 return ERROR_SUCCESS;
1681 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1682 if (rc != ERROR_SUCCESS)
1683 return ERROR_SUCCESS;
1685 rc = MSI_IterateRecords(view, NULL, load_file, package);
1686 msiobj_release(&view->hdr);
1688 return ERROR_SUCCESS;
1691 static UINT load_folder( MSIRECORD *row, LPVOID param )
1693 MSIPACKAGE *package = param;
1694 static WCHAR szEmpty[] = { 0 };
1695 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1698 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1700 return ERROR_NOT_ENOUGH_MEMORY;
1702 folder->Directory = msi_dup_record_field( row, 1 );
1704 TRACE("%s\n", debugstr_w(folder->Directory));
1706 p = msi_dup_record_field(row, 3);
1708 /* split src and target dir */
1710 src_short = folder_split_path( p, ':' );
1712 /* split the long and short paths */
1713 tgt_long = folder_split_path( tgt_short, '|' );
1714 src_long = folder_split_path( src_short, '|' );
1716 /* check for no-op dirs */
1717 if (tgt_short && !strcmpW( szDot, tgt_short ))
1718 tgt_short = szEmpty;
1719 if (src_short && !strcmpW( szDot, src_short ))
1720 src_short = szEmpty;
1723 tgt_long = tgt_short;
1726 src_short = tgt_short;
1727 src_long = tgt_long;
1731 src_long = src_short;
1733 /* FIXME: use the target short path too */
1734 folder->TargetDefault = strdupW(tgt_long);
1735 folder->SourceShortPath = strdupW(src_short);
1736 folder->SourceLongPath = strdupW(src_long);
1739 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1740 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1741 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1743 folder->Parent = msi_dup_record_field( row, 2 );
1745 folder->Property = msi_dup_property( package->db, folder->Directory );
1747 list_add_tail( &package->folders, &folder->entry );
1749 TRACE("returning %p\n", folder);
1751 return ERROR_SUCCESS;
1754 static UINT load_all_folders( MSIPACKAGE *package )
1756 static const WCHAR query[] = {
1757 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1758 '`','D','i','r','e','c','t','o','r','y','`',0 };
1762 if (!list_empty(&package->folders))
1763 return ERROR_SUCCESS;
1765 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1766 if (r != ERROR_SUCCESS)
1769 r = MSI_IterateRecords(view, NULL, load_folder, package);
1770 msiobj_release(&view->hdr);
1775 * I am not doing any of the costing functionality yet.
1776 * Mostly looking at doing the Component and Feature loading
1778 * The native MSI does A LOT of modification to tables here. Mostly adding
1779 * a lot of temporary columns to the Feature and Component tables.
1781 * note: Native msi also tracks the short filename. But I am only going to
1782 * track the long ones. Also looking at this directory table
1783 * it appears that the directory table does not get the parents
1784 * resolved base on property only based on their entries in the
1787 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1789 static const WCHAR szCosting[] =
1790 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1792 msi_set_property( package->db, szCosting, szZero );
1793 msi_set_property( package->db, cszRootDrive, c_colon );
1795 load_all_folders( package );
1796 load_all_components( package );
1797 load_all_features( package );
1798 load_all_files( package );
1800 return ERROR_SUCCESS;
1803 static UINT execute_script(MSIPACKAGE *package, UINT script )
1806 UINT rc = ERROR_SUCCESS;
1808 TRACE("Executing Script %i\n",script);
1810 if (!package->script)
1812 ERR("no script!\n");
1813 return ERROR_FUNCTION_FAILED;
1816 for (i = 0; i < package->script->ActionCount[script]; i++)
1819 action = package->script->Actions[script][i];
1820 ui_actionstart(package, action);
1821 TRACE("Executing Action (%s)\n",debugstr_w(action));
1822 rc = ACTION_PerformAction(package, action, script);
1823 if (rc != ERROR_SUCCESS)
1826 msi_free_action_script(package, script);
1830 static UINT ACTION_FileCost(MSIPACKAGE *package)
1832 return ERROR_SUCCESS;
1835 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1841 state = MsiQueryProductStateW(package->ProductCode);
1843 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1845 if (!comp->Enabled || !comp->ComponentId)
1848 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1849 comp->Installed = INSTALLSTATE_ABSENT;
1852 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1853 package->Context, comp->ComponentId,
1855 if (r != ERROR_SUCCESS)
1856 comp->Installed = INSTALLSTATE_ABSENT;
1861 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1863 MSIFEATURE *feature;
1866 state = MsiQueryProductStateW(package->ProductCode);
1868 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1870 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1871 feature->Installed = INSTALLSTATE_ABSENT;
1874 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1880 static BOOL process_state_property(MSIPACKAGE* package, int level,
1881 LPCWSTR property, INSTALLSTATE state)
1884 MSIFEATURE *feature;
1886 override = msi_dup_property( package->db, property );
1890 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1892 if (strcmpW( property, szRemove ) &&
1893 (feature->Level <= 0 || feature->Level > level))
1896 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1898 if (!strcmpiW( override, szAll ))
1899 msi_feature_set_state(package, feature, state);
1902 LPWSTR ptr = override;
1903 LPWSTR ptr2 = strchrW(override,',');
1907 int len = ptr2 - ptr;
1909 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1910 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1912 msi_feature_set_state(package, feature, state);
1918 ptr2 = strchrW(ptr,',');
1930 static BOOL process_overrides( MSIPACKAGE *package, int level )
1932 static const WCHAR szAddLocal[] =
1933 {'A','D','D','L','O','C','A','L',0};
1934 static const WCHAR szAddSource[] =
1935 {'A','D','D','S','O','U','R','C','E',0};
1936 static const WCHAR szAdvertise[] =
1937 {'A','D','V','E','R','T','I','S','E',0};
1940 /* all these activation/deactivation things happen in order and things
1941 * later on the list override things earlier on the list.
1943 * 0 INSTALLLEVEL processing
1956 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1957 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1958 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1959 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1960 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1963 msi_set_property( package->db, szPreselected, szOne );
1968 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1971 static const WCHAR szlevel[] =
1972 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1973 MSICOMPONENT* component;
1974 MSIFEATURE *feature;
1976 TRACE("Checking Install Level\n");
1978 level = msi_get_property_int(package->db, szlevel, 1);
1980 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1982 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1984 BOOL feature_state = ((feature->Level > 0) &&
1985 (feature->Level <= level));
1987 if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1989 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1990 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1991 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1992 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1994 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1998 /* disable child features of unselected parent features */
1999 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2003 if (feature->Level > 0 && feature->Level <= level)
2006 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2007 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
2012 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2014 BOOL selected = feature->Level > 0 && feature->Level <= level;
2016 if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2018 msi_feature_set_state(package, feature, feature->Installed);
2024 * now we want to enable or disable components based on feature
2026 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2030 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2031 debugstr_w(feature->Feature), feature->Level, feature->Installed,
2032 feature->ActionRequest, feature->Action);
2034 if (!feature->Level)
2037 /* features with components that have compressed files are made local */
2038 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2040 if (!cl->component->Enabled) continue;
2042 if (cl->component->ForceLocalState &&
2043 feature->ActionRequest == INSTALLSTATE_SOURCE)
2045 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
2050 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2052 component = cl->component;
2054 if (!component->Enabled) continue;
2056 switch (feature->ActionRequest)
2058 case INSTALLSTATE_ABSENT:
2059 component->anyAbsent = 1;
2061 case INSTALLSTATE_ADVERTISED:
2062 component->hasAdvertiseFeature = 1;
2064 case INSTALLSTATE_SOURCE:
2065 component->hasSourceFeature = 1;
2067 case INSTALLSTATE_LOCAL:
2068 component->hasLocalFeature = 1;
2070 case INSTALLSTATE_DEFAULT:
2071 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2072 component->hasAdvertiseFeature = 1;
2073 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2074 component->hasSourceFeature = 1;
2076 component->hasLocalFeature = 1;
2084 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2086 if (!component->Enabled) continue;
2088 /* check if it's local or source */
2089 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2090 (component->hasLocalFeature || component->hasSourceFeature))
2092 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2093 !component->ForceLocalState)
2094 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2096 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2100 /* if any feature is local, the component must be local too */
2101 if (component->hasLocalFeature)
2103 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2107 if (component->hasSourceFeature)
2109 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2113 if (component->hasAdvertiseFeature)
2115 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2119 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2120 if (component->anyAbsent)
2121 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2124 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2126 if (!component->Enabled) continue;
2128 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2130 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2131 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2134 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2135 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2138 return ERROR_SUCCESS;
2141 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2143 MSIPACKAGE *package = param;
2148 name = MSI_RecordGetString(row,1);
2150 f = get_loaded_folder(package, name);
2151 if (!f) return ERROR_SUCCESS;
2153 /* reset the ResolvedTarget */
2154 msi_free(f->ResolvedTarget);
2155 f->ResolvedTarget = NULL;
2157 /* This helper function now does ALL the work */
2158 TRACE("Dir %s ...\n",debugstr_w(name));
2159 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2160 TRACE("resolves to %s\n",debugstr_w(path));
2163 return ERROR_SUCCESS;
2166 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2168 MSIPACKAGE *package = param;
2170 MSIFEATURE *feature;
2172 name = MSI_RecordGetString( row, 1 );
2174 feature = get_loaded_feature( package, name );
2176 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2180 Condition = MSI_RecordGetString(row,3);
2182 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2184 int level = MSI_RecordGetInteger(row,2);
2185 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2186 feature->Level = level;
2189 return ERROR_SUCCESS;
2192 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2194 static const WCHAR name[] = {'\\',0};
2195 VS_FIXEDFILEINFO *ptr, *ret;
2197 DWORD versize, handle;
2200 TRACE("%s\n", debugstr_w(filename));
2202 versize = GetFileVersionInfoSizeW( filename, &handle );
2206 version = msi_alloc( versize );
2210 GetFileVersionInfoW( filename, 0, versize, version );
2212 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2214 msi_free( version );
2218 ret = msi_alloc( sz );
2219 memcpy( ret, ptr, sz );
2221 msi_free( version );
2225 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2229 msi_parse_version_string( version, &ms, &ls );
2231 if (fi->dwFileVersionMS > ms) return 1;
2232 else if (fi->dwFileVersionMS < ms) return -1;
2233 else if (fi->dwFileVersionLS > ls) return 1;
2234 else if (fi->dwFileVersionLS < ls) return -1;
2238 static DWORD get_disk_file_size( LPCWSTR filename )
2243 TRACE("%s\n", debugstr_w(filename));
2245 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2246 if (file == INVALID_HANDLE_VALUE)
2247 return INVALID_FILE_SIZE;
2249 size = GetFileSize( file, NULL );
2250 CloseHandle( file );
2254 static BOOL hash_matches( MSIFILE *file )
2257 MSIFILEHASHINFO hash;
2259 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2260 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2261 if (r != ERROR_SUCCESS)
2264 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2267 static WCHAR *get_temp_dir( void )
2270 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2272 GetTempPathW( MAX_PATH, tmp );
2275 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2276 if (CreateDirectoryW( dir, NULL )) break;
2278 return strdupW( dir );
2281 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2283 MSIASSEMBLY *assembly = file->Component->assembly;
2285 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2287 msi_free( file->TargetPath );
2288 if (assembly && !assembly->application)
2290 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2291 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2292 track_tempfile( package, file->TargetPath );
2296 WCHAR *dir = resolve_folder( package, file->Component->Directory, FALSE, FALSE, TRUE, NULL );
2297 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2301 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2304 static UINT set_file_install_states( MSIPACKAGE *package )
2306 VS_FIXEDFILEINFO *file_version;
2309 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2311 MSICOMPONENT *comp = file->Component;
2314 if (!comp->Enabled) continue;
2316 if (file->IsCompressed)
2317 comp->ForceLocalState = TRUE;
2319 set_target_path( package, file );
2321 if ((comp->assembly && !comp->assembly->installed) ||
2322 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2324 file->state = msifs_missing;
2325 comp->Cost += file->FileSize;
2328 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2330 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2331 HIWORD(file_version->dwFileVersionMS),
2332 LOWORD(file_version->dwFileVersionMS),
2333 HIWORD(file_version->dwFileVersionLS),
2334 LOWORD(file_version->dwFileVersionLS));
2336 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2338 file->state = msifs_overwrite;
2339 comp->Cost += file->FileSize;
2343 TRACE("Destination file version equal or greater, not overwriting\n");
2344 file->state = msifs_present;
2346 msi_free( file_version );
2349 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2351 file->state = msifs_overwrite;
2352 comp->Cost += file->FileSize - file_size;
2355 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2357 TRACE("File hashes match, not overwriting\n");
2358 file->state = msifs_present;
2361 file->state = msifs_overwrite;
2362 comp->Cost += file->FileSize - file_size;
2365 return ERROR_SUCCESS;
2369 * A lot is done in this function aside from just the costing.
2370 * The costing needs to be implemented at some point but for now I am going
2371 * to focus on the directory building
2374 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2376 static const WCHAR ExecSeqQuery[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','D','i','r','e','c','t','o','r','y','`',0};
2379 static const WCHAR ConditionQuery[] =
2380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2381 '`','C','o','n','d','i','t','i','o','n','`',0};
2382 static const WCHAR szCosting[] =
2383 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2384 static const WCHAR szlevel[] =
2385 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2386 static const WCHAR szOutOfDiskSpace[] =
2387 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2389 UINT rc = ERROR_SUCCESS;
2393 TRACE("Building Directory properties\n");
2395 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2396 if (rc == ERROR_SUCCESS)
2398 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2400 msiobj_release(&view->hdr);
2403 TRACE("Evaluating component conditions\n");
2404 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2406 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2408 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2409 comp->Enabled = FALSE;
2412 comp->Enabled = TRUE;
2415 /* read components states from the registry */
2416 ACTION_GetComponentInstallStates(package);
2417 ACTION_GetFeatureInstallStates(package);
2419 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2421 TRACE("Evaluating feature conditions\n");
2423 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2424 if (rc == ERROR_SUCCESS)
2426 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2427 msiobj_release( &view->hdr );
2431 TRACE("Calculating file install states\n");
2432 set_file_install_states( package );
2434 msi_set_property( package->db, szCosting, szOne );
2435 /* set default run level if not set */
2436 level = msi_dup_property( package->db, szlevel );
2438 msi_set_property( package->db, szlevel, szOne );
2441 /* FIXME: check volume disk space */
2442 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2444 return MSI_SetFeatureStates(package);
2447 /* OK this value is "interpreted" and then formatted based on the
2448 first few characters */
2449 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2454 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2460 LPWSTR deformated = NULL;
2463 deformat_string(package, &value[2], &deformated);
2465 /* binary value type */
2469 *size = (strlenW(ptr)/2)+1;
2471 *size = strlenW(ptr)/2;
2473 data = msi_alloc(*size);
2479 /* if uneven pad with a zero in front */
2485 data[count] = (BYTE)strtol(byte,NULL,0);
2487 TRACE("Uneven byte count\n");
2495 data[count] = (BYTE)strtol(byte,NULL,0);
2498 msi_free(deformated);
2500 TRACE("Data %i bytes(%i)\n",*size,count);
2507 deformat_string(package, &value[1], &deformated);
2510 *size = sizeof(DWORD);
2511 data = msi_alloc(*size);
2517 if ( (*p < '0') || (*p > '9') )
2523 if (deformated[0] == '-')
2526 TRACE("DWORD %i\n",*(LPDWORD)data);
2528 msi_free(deformated);
2533 static const WCHAR szMulti[] = {'[','~',']',0};
2542 *type=REG_EXPAND_SZ;
2550 if (strstrW(value, szMulti))
2551 *type = REG_MULTI_SZ;
2553 /* remove initial delimiter */
2554 if (!strncmpW(value, szMulti, 3))
2557 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2559 /* add double NULL terminator */
2560 if (*type == REG_MULTI_SZ)
2562 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2563 data = msi_realloc_zero(data, *size);
2569 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2576 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2578 *root_key = HKEY_LOCAL_MACHINE;
2583 *root_key = HKEY_CURRENT_USER;
2588 *root_key = HKEY_CLASSES_ROOT;
2592 *root_key = HKEY_CURRENT_USER;
2596 *root_key = HKEY_LOCAL_MACHINE;
2600 *root_key = HKEY_USERS;
2604 ERR("Unknown root %i\n", root);
2611 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2613 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2614 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2616 if (is_64bit && package->platform == PLATFORM_INTEL &&
2617 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2622 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2623 path_32node = msi_alloc( size );
2627 memcpy( path_32node, path, len * sizeof(WCHAR) );
2628 path_32node[len] = 0;
2629 strcatW( path_32node, szWow6432Node );
2630 strcatW( path_32node, szBackSlash );
2631 strcatW( path_32node, path + len );
2635 return strdupW( path );
2638 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2640 MSIPACKAGE *package = param;
2641 LPSTR value_data = NULL;
2642 HKEY root_key, hkey;
2644 LPWSTR deformated, uikey, keypath;
2645 LPCWSTR szRoot, component, name, key, value;
2649 BOOL check_first = FALSE;
2652 ui_progress(package,2,0,0,0);
2654 component = MSI_RecordGetString(row, 6);
2655 comp = get_loaded_component(package,component);
2657 return ERROR_SUCCESS;
2661 TRACE("component is disabled\n");
2662 return ERROR_SUCCESS;
2665 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2667 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2668 comp->Action = comp->Installed;
2669 return ERROR_SUCCESS;
2671 comp->Action = INSTALLSTATE_LOCAL;
2673 name = MSI_RecordGetString(row, 4);
2674 if( MSI_RecordIsNull(row,5) && name )
2676 /* null values can have special meanings */
2677 if (name[0]=='-' && name[1] == 0)
2678 return ERROR_SUCCESS;
2679 else if ((name[0]=='+' && name[1] == 0) ||
2680 (name[0] == '*' && name[1] == 0))
2685 root = MSI_RecordGetInteger(row,2);
2686 key = MSI_RecordGetString(row, 3);
2688 szRoot = get_root_key( package, root, &root_key );
2690 return ERROR_SUCCESS;
2692 deformat_string(package, key , &deformated);
2693 size = strlenW(deformated) + strlenW(szRoot) + 1;
2694 uikey = msi_alloc(size*sizeof(WCHAR));
2695 strcpyW(uikey,szRoot);
2696 strcatW(uikey,deformated);
2698 keypath = get_keypath( package, root_key, deformated );
2699 msi_free( deformated );
2700 if (RegCreateKeyW( root_key, keypath, &hkey ))
2702 ERR("Could not create key %s\n", debugstr_w(keypath));
2704 return ERROR_SUCCESS;
2707 value = MSI_RecordGetString(row,5);
2709 value_data = parse_value(package, value, &type, &size);
2712 value_data = (LPSTR)strdupW(szEmpty);
2713 size = sizeof(szEmpty);
2717 deformat_string(package, name, &deformated);
2721 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2723 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2728 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2729 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2731 TRACE("value %s of %s checked already exists\n",
2732 debugstr_w(deformated), debugstr_w(uikey));
2736 TRACE("Checked and setting value %s of %s\n",
2737 debugstr_w(deformated), debugstr_w(uikey));
2738 if (deformated || size)
2739 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2744 uirow = MSI_CreateRecord(3);
2745 MSI_RecordSetStringW(uirow,2,deformated);
2746 MSI_RecordSetStringW(uirow,1,uikey);
2747 if (type == REG_SZ || type == REG_EXPAND_SZ)
2748 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2749 ui_actiondata(package,szWriteRegistryValues,uirow);
2750 msiobj_release( &uirow->hdr );
2752 msi_free(value_data);
2753 msi_free(deformated);
2756 return ERROR_SUCCESS;
2759 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2763 static const WCHAR ExecSeqQuery[] =
2764 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2765 '`','R','e','g','i','s','t','r','y','`',0 };
2767 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2768 if (rc != ERROR_SUCCESS)
2769 return ERROR_SUCCESS;
2771 /* increment progress bar each time action data is sent */
2772 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2774 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2776 msiobj_release(&view->hdr);
2780 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2784 DWORD num_subkeys, num_values;
2788 if ((res = RegDeleteTreeW( hkey_root, key )))
2790 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2795 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2797 if ((res = RegDeleteValueW( hkey, value )))
2799 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2801 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2802 NULL, NULL, NULL, NULL );
2803 RegCloseKey( hkey );
2804 if (!res && !num_subkeys && !num_values)
2806 TRACE("Removing empty key %s\n", debugstr_w(key));
2807 RegDeleteKeyW( hkey_root, key );
2811 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2815 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2817 MSIPACKAGE *package = param;
2818 LPCWSTR component, name, key_str, root_key_str;
2819 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2822 BOOL delete_key = FALSE;
2827 ui_progress( package, 2, 0, 0, 0 );
2829 component = MSI_RecordGetString( row, 6 );
2830 comp = get_loaded_component( package, component );
2832 return ERROR_SUCCESS;
2836 TRACE("component is disabled\n");
2837 return ERROR_SUCCESS;
2840 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2842 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2843 comp->Action = comp->Installed;
2844 return ERROR_SUCCESS;
2846 comp->Action = INSTALLSTATE_ABSENT;
2848 name = MSI_RecordGetString( row, 4 );
2849 if (MSI_RecordIsNull( row, 5 ) && name )
2851 if (name[0] == '+' && !name[1])
2852 return ERROR_SUCCESS;
2853 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2860 root = MSI_RecordGetInteger( row, 2 );
2861 key_str = MSI_RecordGetString( row, 3 );
2863 root_key_str = get_root_key( package, root, &hkey_root );
2865 return ERROR_SUCCESS;
2867 deformat_string( package, key_str, &deformated_key );
2868 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2869 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2870 strcpyW( ui_key_str, root_key_str );
2871 strcatW( ui_key_str, deformated_key );
2873 deformat_string( package, name, &deformated_name );
2875 keypath = get_keypath( package, hkey_root, deformated_key );
2876 msi_free( deformated_key );
2877 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2878 msi_free( keypath );
2880 uirow = MSI_CreateRecord( 2 );
2881 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2882 MSI_RecordSetStringW( uirow, 2, deformated_name );
2884 ui_actiondata( package, szRemoveRegistryValues, uirow );
2885 msiobj_release( &uirow->hdr );
2887 msi_free( ui_key_str );
2888 msi_free( deformated_name );
2889 return ERROR_SUCCESS;
2892 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2894 MSIPACKAGE *package = param;
2895 LPCWSTR component, name, key_str, root_key_str;
2896 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2899 BOOL delete_key = FALSE;
2904 ui_progress( package, 2, 0, 0, 0 );
2906 component = MSI_RecordGetString( row, 5 );
2907 comp = get_loaded_component( package, component );
2909 return ERROR_SUCCESS;
2913 TRACE("component is disabled\n");
2914 return ERROR_SUCCESS;
2917 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2919 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2920 comp->Action = comp->Installed;
2921 return ERROR_SUCCESS;
2923 comp->Action = INSTALLSTATE_LOCAL;
2925 if ((name = MSI_RecordGetString( row, 4 )))
2927 if (name[0] == '-' && !name[1])
2934 root = MSI_RecordGetInteger( row, 2 );
2935 key_str = MSI_RecordGetString( row, 3 );
2937 root_key_str = get_root_key( package, root, &hkey_root );
2939 return ERROR_SUCCESS;
2941 deformat_string( package, key_str, &deformated_key );
2942 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2943 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2944 strcpyW( ui_key_str, root_key_str );
2945 strcatW( ui_key_str, deformated_key );
2947 deformat_string( package, name, &deformated_name );
2949 keypath = get_keypath( package, hkey_root, deformated_key );
2950 msi_free( deformated_key );
2951 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2952 msi_free( keypath );
2954 uirow = MSI_CreateRecord( 2 );
2955 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2956 MSI_RecordSetStringW( uirow, 2, deformated_name );
2958 ui_actiondata( package, szRemoveRegistryValues, uirow );
2959 msiobj_release( &uirow->hdr );
2961 msi_free( ui_key_str );
2962 msi_free( deformated_name );
2963 return ERROR_SUCCESS;
2966 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2970 static const WCHAR registry_query[] =
2971 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2972 '`','R','e','g','i','s','t','r','y','`',0 };
2973 static const WCHAR remove_registry_query[] =
2974 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2975 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2977 /* increment progress bar each time action data is sent */
2978 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2980 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2981 if (rc == ERROR_SUCCESS)
2983 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2984 msiobj_release( &view->hdr );
2985 if (rc != ERROR_SUCCESS)
2989 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2990 if (rc == ERROR_SUCCESS)
2992 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2993 msiobj_release( &view->hdr );
2994 if (rc != ERROR_SUCCESS)
2998 return ERROR_SUCCESS;
3001 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3003 package->script->CurrentlyScripting = TRUE;
3005 return ERROR_SUCCESS;
3009 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3014 static const WCHAR q1[]=
3015 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3016 '`','R','e','g','i','s','t','r','y','`',0};
3019 MSIFEATURE *feature;
3022 TRACE("InstallValidate\n");
3024 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3025 if (rc == ERROR_SUCCESS)
3027 MSI_IterateRecords( view, &progress, NULL, package );
3028 msiobj_release( &view->hdr );
3029 total += progress * REG_PROGRESS_VALUE;
3032 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3033 total += COMPONENT_PROGRESS_VALUE;
3035 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3036 total += file->FileSize;
3038 ui_progress(package,0,total,0,0);
3040 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3042 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3043 debugstr_w(feature->Feature), feature->Installed,
3044 feature->ActionRequest, feature->Action);
3047 return ERROR_SUCCESS;
3050 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3052 MSIPACKAGE* package = param;
3053 LPCWSTR cond = NULL;
3054 LPCWSTR message = NULL;
3057 static const WCHAR title[]=
3058 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3060 cond = MSI_RecordGetString(row,1);
3062 r = MSI_EvaluateConditionW(package,cond);
3063 if (r == MSICONDITION_FALSE)
3065 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3068 message = MSI_RecordGetString(row,2);
3069 deformat_string(package,message,&deformated);
3070 MessageBoxW(NULL,deformated,title,MB_OK);
3071 msi_free(deformated);
3074 return ERROR_INSTALL_FAILURE;
3077 return ERROR_SUCCESS;
3080 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3083 MSIQUERY * view = NULL;
3084 static const WCHAR ExecSeqQuery[] =
3085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3086 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3088 TRACE("Checking launch conditions\n");
3090 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3091 if (rc != ERROR_SUCCESS)
3092 return ERROR_SUCCESS;
3094 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3095 msiobj_release(&view->hdr);
3100 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3104 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
3106 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3108 MSIRECORD * row = 0;
3110 LPWSTR deformated,buffer,deformated_name;
3112 static const WCHAR ExecSeqQuery[] =
3113 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3114 '`','R','e','g','i','s','t','r','y','`',' ',
3115 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3116 ' ','=',' ' ,'\'','%','s','\'',0 };
3117 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3118 static const WCHAR fmt2[]=
3119 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3121 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3125 root = MSI_RecordGetInteger(row,2);
3126 key = MSI_RecordGetString(row, 3);
3127 name = MSI_RecordGetString(row, 4);
3128 deformat_string(package, key , &deformated);
3129 deformat_string(package, name, &deformated_name);
3131 len = strlenW(deformated) + 6;
3132 if (deformated_name)
3133 len+=strlenW(deformated_name);
3135 buffer = msi_alloc( len *sizeof(WCHAR));
3137 if (deformated_name)
3138 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3140 sprintfW(buffer,fmt,root,deformated);
3142 msi_free(deformated);
3143 msi_free(deformated_name);
3144 msiobj_release(&row->hdr);
3148 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3150 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3155 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3158 return strdupW( file->TargetPath );
3163 static HKEY openSharedDLLsKey(void)
3166 static const WCHAR path[] =
3167 {'S','o','f','t','w','a','r','e','\\',
3168 'M','i','c','r','o','s','o','f','t','\\',
3169 'W','i','n','d','o','w','s','\\',
3170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3171 'S','h','a','r','e','d','D','L','L','s',0};
3173 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3177 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3182 DWORD sz = sizeof(count);
3185 hkey = openSharedDLLsKey();
3186 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3187 if (rc != ERROR_SUCCESS)
3193 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3197 hkey = openSharedDLLsKey();
3199 msi_reg_set_val_dword( hkey, path, count );
3201 RegDeleteValueW(hkey,path);
3207 * Return TRUE if the count should be written out and FALSE if not
3209 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3211 MSIFEATURE *feature;
3215 /* only refcount DLLs */
3216 if (comp->KeyPath == NULL ||
3217 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3218 comp->Attributes & msidbComponentAttributesODBCDataSource)
3222 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3223 write = (count > 0);
3225 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3229 /* increment counts */
3230 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3234 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3237 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3239 if ( cl->component == comp )
3244 /* decrement counts */
3245 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3249 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3252 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3254 if ( cl->component == comp )
3259 /* ref count all the files in the component */
3264 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3266 if (file->Component == comp)
3267 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3271 /* add a count for permanent */
3272 if (comp->Attributes & msidbComponentAttributesPermanent)
3275 comp->RefCount = count;
3278 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3281 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3283 WCHAR squished_pc[GUID_SIZE];
3284 WCHAR squished_cc[GUID_SIZE];
3291 squash_guid(package->ProductCode,squished_pc);
3292 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3294 msi_set_sourcedir_props(package, FALSE);
3296 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3300 ui_progress(package,2,0,0,0);
3301 if (!comp->ComponentId)
3304 squash_guid(comp->ComponentId,squished_cc);
3306 msi_free(comp->FullKeypath);
3307 comp->FullKeypath = resolve_keypath( package, comp );
3309 ACTION_RefCountComponent( package, comp );
3311 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3312 debugstr_w(comp->Component),
3313 debugstr_w(squished_cc),
3314 debugstr_w(comp->FullKeypath),
3316 comp->ActionRequest);
3318 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3319 comp->ActionRequest == INSTALLSTATE_SOURCE)
3321 if (!comp->FullKeypath)
3324 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3325 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3328 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3331 if (rc != ERROR_SUCCESS)
3334 if (comp->Attributes & msidbComponentAttributesPermanent)
3336 static const WCHAR szPermKey[] =
3337 { '0','0','0','0','0','0','0','0','0','0','0','0',
3338 '0','0','0','0','0','0','0','0','0','0','0','0',
3339 '0','0','0','0','0','0','0','0',0 };
3341 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3344 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3345 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3351 WCHAR source[MAX_PATH];
3352 WCHAR base[MAX_PATH];
3355 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3356 static const WCHAR query[] = {
3357 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3358 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3359 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3360 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3361 '`','D','i','s','k','I','d','`',0};
3363 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3366 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3367 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3368 ptr2 = strrchrW(source, '\\') + 1;
3369 msiobj_release(&row->hdr);
3371 lstrcpyW(base, package->PackagePath);
3372 ptr = strrchrW(base, '\\');
3375 sourcepath = resolve_file_source(package, file);
3376 ptr = sourcepath + lstrlenW(base);
3377 lstrcpyW(ptr2, ptr);
3378 msi_free(sourcepath);
3380 msi_reg_set_val_str(hkey, squished_pc, source);
3384 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3386 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3387 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3389 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3391 comp->Action = comp->ActionRequest;
3394 uirow = MSI_CreateRecord(3);
3395 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3396 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3397 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3398 ui_actiondata(package,szProcessComponents,uirow);
3399 msiobj_release( &uirow->hdr );
3402 return ERROR_SUCCESS;
3413 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3414 LPWSTR lpszName, LONG_PTR lParam)
3417 typelib_struct *tl_struct = (typelib_struct*) lParam;
3418 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3422 if (!IS_INTRESOURCE(lpszName))
3424 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3428 sz = strlenW(tl_struct->source)+4;
3429 sz *= sizeof(WCHAR);
3431 if ((INT_PTR)lpszName == 1)
3432 tl_struct->path = strdupW(tl_struct->source);
3435 tl_struct->path = msi_alloc(sz);
3436 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3439 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3440 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3443 msi_free(tl_struct->path);
3444 tl_struct->path = NULL;
3449 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3450 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3452 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3456 msi_free(tl_struct->path);
3457 tl_struct->path = NULL;
3459 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3460 ITypeLib_Release(tl_struct->ptLib);
3465 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3467 MSIPACKAGE* package = param;
3471 typelib_struct tl_struct;
3476 component = MSI_RecordGetString(row,3);
3477 comp = get_loaded_component(package,component);
3479 return ERROR_SUCCESS;
3483 TRACE("component is disabled\n");
3484 return ERROR_SUCCESS;
3487 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3489 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3490 comp->Action = comp->Installed;
3491 return ERROR_SUCCESS;
3493 comp->Action = INSTALLSTATE_LOCAL;
3495 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3497 TRACE("component has no key path\n");
3498 return ERROR_SUCCESS;
3500 ui_actiondata( package, szRegisterTypeLibraries, row );
3502 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3506 guid = MSI_RecordGetString(row,1);
3507 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3508 tl_struct.source = strdupW( file->TargetPath );
3509 tl_struct.path = NULL;
3511 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3512 (LONG_PTR)&tl_struct);
3520 helpid = MSI_RecordGetString(row,6);
3523 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3524 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3528 ERR("Failed to register type library %s\n",
3529 debugstr_w(tl_struct.path));
3531 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3533 ITypeLib_Release(tl_struct.ptLib);
3534 msi_free(tl_struct.path);
3537 ERR("Failed to load type library %s\n",
3538 debugstr_w(tl_struct.source));
3540 FreeLibrary(module);
3541 msi_free(tl_struct.source);
3545 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3548 ERR("Failed to load type library: %08x\n", hr);
3549 return ERROR_INSTALL_FAILURE;
3552 ITypeLib_Release(tlib);
3555 return ERROR_SUCCESS;
3558 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3561 * OK this is a bit confusing.. I am given a _Component key and I believe
3562 * that the file that is being registered as a type library is the "key file
3563 * of that component" which I interpret to mean "The file in the KeyPath of
3568 static const WCHAR Query[] =
3569 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3570 '`','T','y','p','e','L','i','b','`',0};
3572 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3573 if (rc != ERROR_SUCCESS)
3574 return ERROR_SUCCESS;
3576 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3577 msiobj_release(&view->hdr);
3581 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3583 MSIPACKAGE *package = param;
3584 LPCWSTR component, guid;
3592 component = MSI_RecordGetString( row, 3 );
3593 comp = get_loaded_component( package, component );
3595 return ERROR_SUCCESS;
3599 TRACE("component is disabled\n");
3600 return ERROR_SUCCESS;
3603 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3605 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3606 comp->Action = comp->Installed;
3607 return ERROR_SUCCESS;
3609 comp->Action = INSTALLSTATE_ABSENT;
3611 ui_actiondata( package, szUnregisterTypeLibraries, row );
3613 guid = MSI_RecordGetString( row, 1 );
3614 CLSIDFromString( (LPCWSTR)guid, &libid );
3615 version = MSI_RecordGetInteger( row, 4 );
3616 language = MSI_RecordGetInteger( row, 2 );
3619 syskind = SYS_WIN64;
3621 syskind = SYS_WIN32;
3624 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3627 WARN("Failed to unregister typelib: %08x\n", hr);
3630 return ERROR_SUCCESS;
3633 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3637 static const WCHAR query[] =
3638 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3639 '`','T','y','p','e','L','i','b','`',0};
3641 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3642 if (rc != ERROR_SUCCESS)
3643 return ERROR_SUCCESS;
3645 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3646 msiobj_release( &view->hdr );
3650 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3652 static const WCHAR szlnk[] = {'.','l','n','k',0};
3653 LPCWSTR directory, extension;
3654 LPWSTR link_folder, link_file, filename;
3656 directory = MSI_RecordGetString( row, 2 );
3657 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3659 /* may be needed because of a bug somewhere else */
3660 create_full_pathW( link_folder );
3662 filename = msi_dup_record_field( row, 3 );
3663 reduce_to_longfilename( filename );
3665 extension = strchrW( filename, '.' );
3666 if (!extension || strcmpiW( extension, szlnk ))
3668 int len = strlenW( filename );
3669 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3670 memcpy( filename + len, szlnk, sizeof(szlnk) );
3672 link_file = build_directory_name( 2, link_folder, filename );
3673 msi_free( link_folder );
3674 msi_free( filename );
3679 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3681 MSIPACKAGE *package = param;
3682 LPWSTR link_file, deformated, path;
3683 LPCWSTR component, target;
3685 IShellLinkW *sl = NULL;
3686 IPersistFile *pf = NULL;
3689 component = MSI_RecordGetString(row, 4);
3690 comp = get_loaded_component(package, component);
3692 return ERROR_SUCCESS;
3696 TRACE("component is disabled\n");
3697 return ERROR_SUCCESS;
3700 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3702 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3703 comp->Action = comp->Installed;
3704 return ERROR_SUCCESS;
3706 comp->Action = INSTALLSTATE_LOCAL;
3708 ui_actiondata(package,szCreateShortcuts,row);
3710 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3711 &IID_IShellLinkW, (LPVOID *) &sl );
3715 ERR("CLSID_ShellLink not available\n");
3719 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3722 ERR("QueryInterface(IID_IPersistFile) failed\n");
3726 target = MSI_RecordGetString(row, 5);
3727 if (strchrW(target, '['))
3729 deformat_string(package, target, &deformated);
3730 IShellLinkW_SetPath(sl,deformated);
3731 msi_free(deformated);
3735 FIXME("poorly handled shortcut format, advertised shortcut\n");
3736 IShellLinkW_SetPath(sl,comp->FullKeypath);
3739 if (!MSI_RecordIsNull(row,6))
3741 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3742 deformat_string(package, arguments, &deformated);
3743 IShellLinkW_SetArguments(sl,deformated);
3744 msi_free(deformated);
3747 if (!MSI_RecordIsNull(row,7))
3749 LPCWSTR description = MSI_RecordGetString(row, 7);
3750 IShellLinkW_SetDescription(sl, description);
3753 if (!MSI_RecordIsNull(row,8))
3754 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3756 if (!MSI_RecordIsNull(row,9))
3759 LPCWSTR icon = MSI_RecordGetString(row, 9);
3761 path = build_icon_path(package, icon);
3762 index = MSI_RecordGetInteger(row,10);
3764 /* no value means 0 */
3765 if (index == MSI_NULL_INTEGER)
3768 IShellLinkW_SetIconLocation(sl, path, index);
3772 if (!MSI_RecordIsNull(row,11))
3773 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3775 if (!MSI_RecordIsNull(row,12))
3777 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3778 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3780 IShellLinkW_SetWorkingDirectory(sl, path);
3784 link_file = get_link_file(package, row);
3786 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3787 IPersistFile_Save(pf, link_file, FALSE);
3789 msi_free(link_file);
3793 IPersistFile_Release( pf );
3795 IShellLinkW_Release( sl );
3797 return ERROR_SUCCESS;
3800 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3805 static const WCHAR Query[] =
3806 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3807 '`','S','h','o','r','t','c','u','t','`',0};
3809 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3810 if (rc != ERROR_SUCCESS)
3811 return ERROR_SUCCESS;
3813 res = CoInitialize( NULL );
3815 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3816 msiobj_release(&view->hdr);
3824 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3826 MSIPACKAGE *package = param;
3831 component = MSI_RecordGetString( row, 4 );
3832 comp = get_loaded_component( package, component );
3834 return ERROR_SUCCESS;
3838 TRACE("component is disabled\n");
3839 return ERROR_SUCCESS;
3842 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3844 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3845 comp->Action = comp->Installed;
3846 return ERROR_SUCCESS;
3848 comp->Action = INSTALLSTATE_ABSENT;
3850 ui_actiondata( package, szRemoveShortcuts, row );
3852 link_file = get_link_file( package, row );
3854 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3855 if (!DeleteFileW( link_file ))
3857 WARN("Failed to remove shortcut file %u\n", GetLastError());
3859 msi_free( link_file );
3861 return ERROR_SUCCESS;
3864 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3868 static const WCHAR query[] =
3869 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3870 '`','S','h','o','r','t','c','u','t','`',0};
3872 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3873 if (rc != ERROR_SUCCESS)
3874 return ERROR_SUCCESS;
3876 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3877 msiobj_release( &view->hdr );
3882 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3884 MSIPACKAGE* package = param;
3892 FileName = MSI_RecordGetString(row,1);
3895 ERR("Unable to get FileName\n");
3896 return ERROR_SUCCESS;
3899 FilePath = build_icon_path(package,FileName);
3901 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3903 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3904 FILE_ATTRIBUTE_NORMAL, NULL);
3906 if (the_file == INVALID_HANDLE_VALUE)
3908 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3910 return ERROR_SUCCESS;
3917 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3918 if (rc != ERROR_SUCCESS)
3920 ERR("Failed to get stream\n");
3921 CloseHandle(the_file);
3922 DeleteFileW(FilePath);
3925 WriteFile(the_file,buffer,sz,&write,NULL);
3926 } while (sz == 1024);
3929 CloseHandle(the_file);
3931 return ERROR_SUCCESS;
3934 static UINT msi_publish_icons(MSIPACKAGE *package)
3939 static const WCHAR query[]= {
3940 'S','E','L','E','C','T',' ','*',' ',
3941 'F','R','O','M',' ','`','I','c','o','n','`',0};
3943 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3944 if (r == ERROR_SUCCESS)
3946 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3947 msiobj_release(&view->hdr);
3950 return ERROR_SUCCESS;
3953 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3959 MSISOURCELISTINFO *info;
3961 r = RegCreateKeyW(hkey, szSourceList, &source);
3962 if (r != ERROR_SUCCESS)
3965 RegCloseKey(source);
3967 buffer = strrchrW(package->PackagePath, '\\') + 1;
3968 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3969 package->Context, MSICODE_PRODUCT,
3970 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3971 if (r != ERROR_SUCCESS)
3974 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3975 package->Context, MSICODE_PRODUCT,
3976 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3977 if (r != ERROR_SUCCESS)
3980 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3981 package->Context, MSICODE_PRODUCT,
3982 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3983 if (r != ERROR_SUCCESS)
3986 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3988 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3989 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3990 info->options, info->value);
3992 MsiSourceListSetInfoW(package->ProductCode, NULL,
3993 info->context, info->options,
3994 info->property, info->value);
3997 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3999 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4000 disk->context, disk->options,
4001 disk->disk_id, disk->volume_label, disk->disk_prompt);
4004 return ERROR_SUCCESS;
4007 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4009 MSIHANDLE hdb, suminfo;
4010 WCHAR guids[MAX_PATH];
4011 WCHAR packcode[SQUISH_GUID_SIZE];
4018 static const WCHAR szProductLanguage[] =
4019 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4020 static const WCHAR szARPProductIcon[] =
4021 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4022 static const WCHAR szProductVersion[] =
4023 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4024 static const WCHAR szAssignment[] =
4025 {'A','s','s','i','g','n','m','e','n','t',0};
4026 static const WCHAR szAdvertiseFlags[] =
4027 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4028 static const WCHAR szClients[] =
4029 {'C','l','i','e','n','t','s',0};
4030 static const WCHAR szColon[] = {':',0};
4032 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4033 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4036 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4037 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4040 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4042 buffer = msi_dup_property(package->db, szARPProductIcon);
4045 LPWSTR path = build_icon_path(package,buffer);
4046 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4051 buffer = msi_dup_property(package->db, szProductVersion);
4054 DWORD verdword = msi_version_str_to_dword(buffer);
4055 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4059 msi_reg_set_val_dword(hkey, szAssignment, 0);
4060 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4061 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4062 msi_reg_set_val_str(hkey, szClients, szColon);
4064 hdb = alloc_msihandle(&package->db->hdr);
4066 return ERROR_NOT_ENOUGH_MEMORY;
4068 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4069 MsiCloseHandle(hdb);
4070 if (r != ERROR_SUCCESS)
4074 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4075 NULL, guids, &size);
4076 if (r != ERROR_SUCCESS)
4079 ptr = strchrW(guids, ';');
4081 squash_guid(guids, packcode);
4082 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4085 MsiCloseHandle(suminfo);
4086 return ERROR_SUCCESS;
4089 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4094 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4096 upgrade = msi_dup_property(package->db, szUpgradeCode);
4098 return ERROR_SUCCESS;
4100 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4102 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4103 if (r != ERROR_SUCCESS)
4108 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4109 if (r != ERROR_SUCCESS)
4113 squash_guid(package->ProductCode, squashed_pc);
4114 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4123 static BOOL msi_check_publish(MSIPACKAGE *package)
4125 MSIFEATURE *feature;
4127 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4129 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4136 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4138 MSIFEATURE *feature;
4140 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4142 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4149 static UINT msi_publish_patches( MSIPACKAGE *package )
4151 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4152 WCHAR patch_squashed[GUID_SIZE];
4153 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4155 MSIPATCHINFO *patch;
4157 WCHAR *p, *all_patches = NULL;
4160 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4161 if (r != ERROR_SUCCESS)
4162 return ERROR_FUNCTION_FAILED;
4164 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4165 if (res != ERROR_SUCCESS)
4167 r = ERROR_FUNCTION_FAILED;
4171 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4172 if (r != ERROR_SUCCESS)
4175 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4177 squash_guid( patch->patchcode, patch_squashed );
4178 len += strlenW( patch_squashed ) + 1;
4181 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4185 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4189 squash_guid( patch->patchcode, p );
4190 p += strlenW( p ) + 1;
4192 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4193 (const BYTE *)patch->transforms,
4194 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4195 if (res != ERROR_SUCCESS)
4198 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4199 if (r != ERROR_SUCCESS)
4202 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4203 (const BYTE *)patch->localfile,
4204 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4205 RegCloseKey( patch_key );
4206 if (res != ERROR_SUCCESS)
4209 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4210 if (res != ERROR_SUCCESS)
4213 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4214 RegCloseKey( patch_key );
4215 if (res != ERROR_SUCCESS)
4219 all_patches[len] = 0;
4220 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4221 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4222 if (res != ERROR_SUCCESS)
4225 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4226 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4227 if (res != ERROR_SUCCESS)
4228 r = ERROR_FUNCTION_FAILED;
4231 RegCloseKey( product_patches_key );
4232 RegCloseKey( patches_key );
4233 RegCloseKey( product_key );
4234 msi_free( all_patches );
4239 * 99% of the work done here is only done for
4240 * advertised installs. However this is where the
4241 * Icon table is processed and written out
4242 * so that is what I am going to do here.
4244 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4247 HKEY hukey = NULL, hudkey = NULL;
4250 if (!list_empty(&package->patches))
4252 rc = msi_publish_patches(package);
4253 if (rc != ERROR_SUCCESS)
4257 /* FIXME: also need to publish if the product is in advertise mode */
4258 if (!msi_check_publish(package))
4259 return ERROR_SUCCESS;
4261 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4263 if (rc != ERROR_SUCCESS)
4266 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4267 NULL, &hudkey, TRUE);
4268 if (rc != ERROR_SUCCESS)
4271 rc = msi_publish_upgrade_code(package);
4272 if (rc != ERROR_SUCCESS)
4275 rc = msi_publish_product_properties(package, hukey);
4276 if (rc != ERROR_SUCCESS)
4279 rc = msi_publish_sourcelist(package, hukey);
4280 if (rc != ERROR_SUCCESS)
4283 rc = msi_publish_icons(package);
4286 uirow = MSI_CreateRecord( 1 );
4287 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4288 ui_actiondata( package, szPublishProduct, uirow );
4289 msiobj_release( &uirow->hdr );
4292 RegCloseKey(hudkey);
4297 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4299 WCHAR *filename, *ptr, *folder, *ret;
4300 const WCHAR *dirprop;
4302 filename = msi_dup_record_field( row, 2 );
4303 if (filename && (ptr = strchrW( filename, '|' )))
4308 dirprop = MSI_RecordGetString( row, 3 );
4311 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4313 folder = msi_dup_property( package->db, dirprop );
4316 folder = msi_dup_property( package->db, szWindowsFolder );
4320 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4321 msi_free( filename );
4325 ret = build_directory_name( 2, folder, ptr );
4327 msi_free( filename );
4332 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4334 MSIPACKAGE *package = param;
4335 LPCWSTR component, section, key, value, identifier;
4336 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4341 component = MSI_RecordGetString(row, 8);
4342 comp = get_loaded_component(package,component);
4344 return ERROR_SUCCESS;
4348 TRACE("component is disabled\n");
4349 return ERROR_SUCCESS;
4352 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4354 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4355 comp->Action = comp->Installed;
4356 return ERROR_SUCCESS;
4358 comp->Action = INSTALLSTATE_LOCAL;
4360 identifier = MSI_RecordGetString(row,1);
4361 section = MSI_RecordGetString(row,4);
4362 key = MSI_RecordGetString(row,5);
4363 value = MSI_RecordGetString(row,6);
4364 action = MSI_RecordGetInteger(row,7);
4366 deformat_string(package,section,&deformated_section);
4367 deformat_string(package,key,&deformated_key);
4368 deformat_string(package,value,&deformated_value);
4370 fullname = get_ini_file_name(package, row);
4374 TRACE("Adding value %s to section %s in %s\n",
4375 debugstr_w(deformated_key), debugstr_w(deformated_section),
4376 debugstr_w(fullname));
4377 WritePrivateProfileStringW(deformated_section, deformated_key,
4378 deformated_value, fullname);
4380 else if (action == 1)
4383 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4384 returned, 10, fullname);
4385 if (returned[0] == 0)
4387 TRACE("Adding value %s to section %s in %s\n",
4388 debugstr_w(deformated_key), debugstr_w(deformated_section),
4389 debugstr_w(fullname));
4391 WritePrivateProfileStringW(deformated_section, deformated_key,
4392 deformated_value, fullname);
4395 else if (action == 3)
4396 FIXME("Append to existing section not yet implemented\n");
4398 uirow = MSI_CreateRecord(4);
4399 MSI_RecordSetStringW(uirow,1,identifier);
4400 MSI_RecordSetStringW(uirow,2,deformated_section);
4401 MSI_RecordSetStringW(uirow,3,deformated_key);
4402 MSI_RecordSetStringW(uirow,4,deformated_value);
4403 ui_actiondata(package,szWriteIniValues,uirow);
4404 msiobj_release( &uirow->hdr );
4407 msi_free(deformated_key);
4408 msi_free(deformated_value);
4409 msi_free(deformated_section);
4410 return ERROR_SUCCESS;
4413 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4417 static const WCHAR ExecSeqQuery[] =
4418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4419 '`','I','n','i','F','i','l','e','`',0};
4421 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4422 if (rc != ERROR_SUCCESS)
4424 TRACE("no IniFile table\n");
4425 return ERROR_SUCCESS;
4428 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4429 msiobj_release(&view->hdr);
4433 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4435 MSIPACKAGE *package = param;
4436 LPCWSTR component, section, key, value, identifier;
4437 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4442 component = MSI_RecordGetString( row, 8 );
4443 comp = get_loaded_component( package, component );
4445 return ERROR_SUCCESS;
4449 TRACE("component is disabled\n");
4450 return ERROR_SUCCESS;
4453 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4455 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4456 comp->Action = comp->Installed;
4457 return ERROR_SUCCESS;
4459 comp->Action = INSTALLSTATE_ABSENT;
4461 identifier = MSI_RecordGetString( row, 1 );
4462 section = MSI_RecordGetString( row, 4 );
4463 key = MSI_RecordGetString( row, 5 );
4464 value = MSI_RecordGetString( row, 6 );
4465 action = MSI_RecordGetInteger( row, 7 );
4467 deformat_string( package, section, &deformated_section );
4468 deformat_string( package, key, &deformated_key );
4469 deformat_string( package, value, &deformated_value );
4471 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4473 filename = get_ini_file_name( package, row );
4475 TRACE("Removing key %s from section %s in %s\n",
4476 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4478 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4480 WARN("Unable to remove key %u\n", GetLastError());
4482 msi_free( filename );
4485 FIXME("Unsupported action %d\n", action);
4488 uirow = MSI_CreateRecord( 4 );
4489 MSI_RecordSetStringW( uirow, 1, identifier );
4490 MSI_RecordSetStringW( uirow, 2, deformated_section );
4491 MSI_RecordSetStringW( uirow, 3, deformated_key );
4492 MSI_RecordSetStringW( uirow, 4, deformated_value );
4493 ui_actiondata( package, szRemoveIniValues, uirow );
4494 msiobj_release( &uirow->hdr );
4496 msi_free( deformated_key );
4497 msi_free( deformated_value );
4498 msi_free( deformated_section );
4499 return ERROR_SUCCESS;
4502 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4504 MSIPACKAGE *package = param;
4505 LPCWSTR component, section, key, value, identifier;
4506 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4511 component = MSI_RecordGetString( row, 8 );
4512 comp = get_loaded_component( package, component );
4514 return ERROR_SUCCESS;
4518 TRACE("component is disabled\n");
4519 return ERROR_SUCCESS;
4522 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4524 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4525 comp->Action = comp->Installed;
4526 return ERROR_SUCCESS;
4528 comp->Action = INSTALLSTATE_LOCAL;
4530 identifier = MSI_RecordGetString( row, 1 );
4531 section = MSI_RecordGetString( row, 4 );
4532 key = MSI_RecordGetString( row, 5 );
4533 value = MSI_RecordGetString( row, 6 );
4534 action = MSI_RecordGetInteger( row, 7 );
4536 deformat_string( package, section, &deformated_section );
4537 deformat_string( package, key, &deformated_key );
4538 deformat_string( package, value, &deformated_value );
4540 if (action == msidbIniFileActionRemoveLine)
4542 filename = get_ini_file_name( package, row );
4544 TRACE("Removing key %s from section %s in %s\n",
4545 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4547 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4549 WARN("Unable to remove key %u\n", GetLastError());
4551 msi_free( filename );
4554 FIXME("Unsupported action %d\n", action);
4556 uirow = MSI_CreateRecord( 4 );
4557 MSI_RecordSetStringW( uirow, 1, identifier );
4558 MSI_RecordSetStringW( uirow, 2, deformated_section );
4559 MSI_RecordSetStringW( uirow, 3, deformated_key );
4560 MSI_RecordSetStringW( uirow, 4, deformated_value );
4561 ui_actiondata( package, szRemoveIniValues, uirow );
4562 msiobj_release( &uirow->hdr );
4564 msi_free( deformated_key );
4565 msi_free( deformated_value );
4566 msi_free( deformated_section );
4567 return ERROR_SUCCESS;
4570 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4574 static const WCHAR query[] =
4575 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4576 '`','I','n','i','F','i','l','e','`',0};
4577 static const WCHAR remove_query[] =
4578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4579 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4581 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4582 if (rc == ERROR_SUCCESS)
4584 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4585 msiobj_release( &view->hdr );
4586 if (rc != ERROR_SUCCESS)
4590 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4591 if (rc == ERROR_SUCCESS)
4593 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4594 msiobj_release( &view->hdr );
4595 if (rc != ERROR_SUCCESS)
4599 return ERROR_SUCCESS;
4602 static void register_dll( const WCHAR *dll, BOOL unregister )
4606 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4609 HRESULT (WINAPI *func_ptr)( void );
4610 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4612 func_ptr = (void *)GetProcAddress( hmod, func );
4615 HRESULT hr = func_ptr();
4617 WARN("failed to register dll 0x%08x\n", hr);
4620 WARN("entry point %s not found\n", func);
4621 FreeLibrary( hmod );
4624 WARN("failed to load library %u\n", GetLastError());
4627 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4629 MSIPACKAGE *package = param;
4634 filename = MSI_RecordGetString(row,1);
4635 file = get_loaded_file( package, filename );
4639 ERR("Unable to find file id %s\n",debugstr_w(filename));
4640 return ERROR_SUCCESS;
4643 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4645 register_dll( file->TargetPath, FALSE );
4647 uirow = MSI_CreateRecord( 2 );
4648 MSI_RecordSetStringW( uirow, 1, filename );
4649 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4650 ui_actiondata( package, szSelfRegModules, uirow );
4651 msiobj_release( &uirow->hdr );
4653 return ERROR_SUCCESS;
4656 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4660 static const WCHAR ExecSeqQuery[] =
4661 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4662 '`','S','e','l','f','R','e','g','`',0};
4664 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4665 if (rc != ERROR_SUCCESS)
4667 TRACE("no SelfReg table\n");
4668 return ERROR_SUCCESS;
4671 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4672 msiobj_release(&view->hdr);
4674 return ERROR_SUCCESS;
4677 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4679 MSIPACKAGE *package = param;
4684 filename = MSI_RecordGetString( row, 1 );
4685 file = get_loaded_file( package, filename );
4689 ERR("Unable to find file id %s\n", debugstr_w(filename));
4690 return ERROR_SUCCESS;
4693 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4695 register_dll( file->TargetPath, TRUE );
4697 uirow = MSI_CreateRecord( 2 );
4698 MSI_RecordSetStringW( uirow, 1, filename );
4699 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4700 ui_actiondata( package, szSelfUnregModules, uirow );
4701 msiobj_release( &uirow->hdr );
4703 return ERROR_SUCCESS;
4706 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4710 static const WCHAR query[] =
4711 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4712 '`','S','e','l','f','R','e','g','`',0};
4714 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4715 if (rc != ERROR_SUCCESS)
4717 TRACE("no SelfReg table\n");
4718 return ERROR_SUCCESS;
4721 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4722 msiobj_release( &view->hdr );
4724 return ERROR_SUCCESS;
4727 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4729 MSIFEATURE *feature;
4731 HKEY hkey = NULL, userdata = NULL;
4733 if (!msi_check_publish(package))
4734 return ERROR_SUCCESS;
4736 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4738 if (rc != ERROR_SUCCESS)
4741 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4743 if (rc != ERROR_SUCCESS)
4746 /* here the guids are base 85 encoded */
4747 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4753 BOOL absent = FALSE;
4756 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4757 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4758 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4761 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4765 if (feature->Feature_Parent)
4766 size += strlenW( feature->Feature_Parent )+2;
4768 data = msi_alloc(size * sizeof(WCHAR));
4771 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4773 MSICOMPONENT* component = cl->component;
4777 if (component->ComponentId)
4779 TRACE("From %s\n",debugstr_w(component->ComponentId));
4780 CLSIDFromString(component->ComponentId, &clsid);
4781 encode_base85_guid(&clsid,buf);
4782 TRACE("to %s\n",debugstr_w(buf));
4787 if (feature->Feature_Parent)
4789 static const WCHAR sep[] = {'\2',0};
4791 strcatW(data,feature->Feature_Parent);
4794 msi_reg_set_val_str( userdata, feature->Feature, data );
4798 if (feature->Feature_Parent)
4799 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4802 size += sizeof(WCHAR);
4803 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4804 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4808 size += 2*sizeof(WCHAR);
4809 data = msi_alloc(size);
4812 if (feature->Feature_Parent)
4813 strcpyW( &data[1], feature->Feature_Parent );
4814 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4820 uirow = MSI_CreateRecord( 1 );
4821 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4822 ui_actiondata( package, szPublishFeatures, uirow);
4823 msiobj_release( &uirow->hdr );
4824 /* FIXME: call ui_progress? */
4829 RegCloseKey(userdata);
4833 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4839 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4841 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4843 if (r == ERROR_SUCCESS)
4845 RegDeleteValueW(hkey, feature->Feature);
4849 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4851 if (r == ERROR_SUCCESS)
4853 RegDeleteValueW(hkey, feature->Feature);
4857 uirow = MSI_CreateRecord( 1 );
4858 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4859 ui_actiondata( package, szUnpublishFeatures, uirow );
4860 msiobj_release( &uirow->hdr );
4862 return ERROR_SUCCESS;
4865 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4867 MSIFEATURE *feature;
4869 if (!msi_check_unpublish(package))
4870 return ERROR_SUCCESS;
4872 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4874 msi_unpublish_feature(package, feature);
4877 return ERROR_SUCCESS;
4880 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4884 WCHAR date[9], *val, *buffer;
4885 const WCHAR *prop, *key;
4887 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4888 static const WCHAR szWindowsInstaller[] =
4889 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4890 static const WCHAR modpath_fmt[] =
4891 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4892 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4893 static const WCHAR szModifyPath[] =
4894 {'M','o','d','i','f','y','P','a','t','h',0};
4895 static const WCHAR szUninstallString[] =
4896 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4897 static const WCHAR szEstimatedSize[] =
4898 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4899 static const WCHAR szProductLanguage[] =
4900 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4901 static const WCHAR szProductVersion[] =
4902 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4903 static const WCHAR szDisplayVersion[] =
4904 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4905 static const WCHAR szInstallSource[] =
4906 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4907 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4908 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4909 static const WCHAR szAuthorizedCDFPrefix[] =
4910 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4911 static const WCHAR szARPCONTACT[] =
4912 {'A','R','P','C','O','N','T','A','C','T',0};
4913 static const WCHAR szContact[] =
4914 {'C','o','n','t','a','c','t',0};
4915 static const WCHAR szARPCOMMENTS[] =
4916 {'A','R','P','C','O','M','M','E','N','T','S',0};
4917 static const WCHAR szComments[] =
4918 {'C','o','m','m','e','n','t','s',0};
4919 static const WCHAR szProductName[] =
4920 {'P','r','o','d','u','c','t','N','a','m','e',0};
4921 static const WCHAR szDisplayName[] =
4922 {'D','i','s','p','l','a','y','N','a','m','e',0};
4923 static const WCHAR szARPHELPLINK[] =
4924 {'A','R','P','H','E','L','P','L','I','N','K',0};
4925 static const WCHAR szHelpLink[] =
4926 {'H','e','l','p','L','i','n','k',0};
4927 static const WCHAR szARPHELPTELEPHONE[] =
4928 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4929 static const WCHAR szHelpTelephone[] =
4930 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4931 static const WCHAR szARPINSTALLLOCATION[] =
4932 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4933 static const WCHAR szInstallLocation[] =
4934 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4935 static const WCHAR szManufacturer[] =
4936 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4937 static const WCHAR szPublisher[] =
4938 {'P','u','b','l','i','s','h','e','r',0};
4939 static const WCHAR szARPREADME[] =
4940 {'A','R','P','R','E','A','D','M','E',0};
4941 static const WCHAR szReadme[] =
4942 {'R','e','a','d','M','e',0};
4943 static const WCHAR szARPSIZE[] =
4944 {'A','R','P','S','I','Z','E',0};
4945 static const WCHAR szSize[] =
4946 {'S','i','z','e',0};
4947 static const WCHAR szARPURLINFOABOUT[] =
4948 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4949 static const WCHAR szURLInfoAbout[] =
4950 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4951 static const WCHAR szARPURLUPDATEINFO[] =
4952 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4953 static const WCHAR szURLUpdateInfo[] =
4954 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4956 static const WCHAR *propval[] = {
4957 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4958 szARPCONTACT, szContact,
4959 szARPCOMMENTS, szComments,
4960 szProductName, szDisplayName,
4961 szARPHELPLINK, szHelpLink,
4962 szARPHELPTELEPHONE, szHelpTelephone,
4963 szARPINSTALLLOCATION, szInstallLocation,
4964 cszSourceDir, szInstallSource,
4965 szManufacturer, szPublisher,
4966 szARPREADME, szReadme,
4968 szARPURLINFOABOUT, szURLInfoAbout,
4969 szARPURLUPDATEINFO, szURLUpdateInfo,
4972 const WCHAR **p = propval;
4978 val = msi_dup_property(package->db, prop);
4979 msi_reg_set_val_str(hkey, key, val);
4983 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4985 size = deformat_string(package, modpath_fmt, &buffer);
4986 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4987 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4990 /* FIXME: Write real Estimated Size when we have it */
4991 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4993 GetLocalTime(&systime);
4994 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4995 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4997 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4998 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5000 buffer = msi_dup_property(package->db, szProductVersion);
5001 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5004 DWORD verdword = msi_version_str_to_dword(buffer);
5006 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5007 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5008 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5012 return ERROR_SUCCESS;
5015 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5017 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5019 LPWSTR upgrade_code;
5024 /* FIXME: also need to publish if the product is in advertise mode */
5025 if (!msi_check_publish(package))
5026 return ERROR_SUCCESS;
5028 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5029 if (rc != ERROR_SUCCESS)
5032 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5033 NULL, &props, TRUE);
5034 if (rc != ERROR_SUCCESS)
5037 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5038 msi_free( package->db->localfile );
5039 package->db->localfile = NULL;
5041 rc = msi_publish_install_properties(package, hkey);
5042 if (rc != ERROR_SUCCESS)
5045 rc = msi_publish_install_properties(package, props);
5046 if (rc != ERROR_SUCCESS)
5049 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5052 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5053 squash_guid(package->ProductCode, squashed_pc);
5054 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5055 RegCloseKey(upgrade);
5056 msi_free(upgrade_code);
5060 uirow = MSI_CreateRecord( 1 );
5061 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5062 ui_actiondata( package, szRegisterProduct, uirow );
5063 msiobj_release( &uirow->hdr );
5066 return ERROR_SUCCESS;
5069 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5071 return execute_script(package,INSTALL_SCRIPT);
5074 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5076 WCHAR *upgrade, **features;
5077 BOOL full_uninstall = TRUE;
5078 MSIFEATURE *feature;
5079 MSIPATCHINFO *patch;
5081 static const WCHAR szUpgradeCode[] =
5082 {'U','p','g','r','a','d','e','C','o','d','e',0};
5084 features = msi_split_string(remove, ',');
5087 ERR("REMOVE feature list is empty!\n");
5088 return ERROR_FUNCTION_FAILED;
5091 if (!strcmpW( features[0], szAll ))
5092 full_uninstall = TRUE;
5095 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5097 if (feature->Action != INSTALLSTATE_ABSENT)
5098 full_uninstall = FALSE;
5103 if (!full_uninstall)
5104 return ERROR_SUCCESS;
5106 MSIREG_DeleteProductKey(package->ProductCode);
5107 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5108 MSIREG_DeleteUninstallKey(package);
5110 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
5112 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5113 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5117 MSIREG_DeleteUserProductKey(package->ProductCode);
5118 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5121 upgrade = msi_dup_property(package->db, szUpgradeCode);
5124 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5128 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5130 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5133 return ERROR_SUCCESS;
5136 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5141 /* turn off scheduling */
5142 package->script->CurrentlyScripting= FALSE;
5144 /* first do the same as an InstallExecute */
5145 rc = ACTION_InstallExecute(package);
5146 if (rc != ERROR_SUCCESS)
5149 /* then handle Commit Actions */
5150 rc = execute_script(package,COMMIT_SCRIPT);
5151 if (rc != ERROR_SUCCESS)
5154 remove = msi_dup_property(package->db, szRemove);
5156 rc = msi_unpublish_product(package, remove);
5162 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5164 static const WCHAR RunOnce[] = {
5165 'S','o','f','t','w','a','r','e','\\',
5166 'M','i','c','r','o','s','o','f','t','\\',
5167 'W','i','n','d','o','w','s','\\',
5168 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5169 'R','u','n','O','n','c','e',0};
5170 static const WCHAR InstallRunOnce[] = {
5171 'S','o','f','t','w','a','r','e','\\',
5172 'M','i','c','r','o','s','o','f','t','\\',
5173 'W','i','n','d','o','w','s','\\',
5174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5175 'I','n','s','t','a','l','l','e','r','\\',
5176 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5178 static const WCHAR msiexec_fmt[] = {
5180 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5181 '\"','%','s','\"',0};
5182 static const WCHAR install_fmt[] = {
5183 '/','I',' ','\"','%','s','\"',' ',
5184 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5185 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5186 WCHAR buffer[256], sysdir[MAX_PATH];
5188 WCHAR squished_pc[100];
5190 squash_guid(package->ProductCode,squished_pc);
5192 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5193 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5194 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5197 msi_reg_set_val_str( hkey, squished_pc, buffer );
5200 TRACE("Reboot command %s\n",debugstr_w(buffer));
5202 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5203 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5205 msi_reg_set_val_str( hkey, squished_pc, buffer );
5208 return ERROR_INSTALL_SUSPEND;
5211 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5217 * We are currently doing what should be done here in the top level Install
5218 * however for Administrative and uninstalls this step will be needed
5220 if (!package->PackagePath)
5221 return ERROR_SUCCESS;
5223 msi_set_sourcedir_props(package, TRUE);
5225 attrib = GetFileAttributesW(package->db->path);
5226 if (attrib == INVALID_FILE_ATTRIBUTES)
5232 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5233 package->Context, MSICODE_PRODUCT,
5234 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5235 if (rc == ERROR_MORE_DATA)
5237 prompt = msi_alloc(size * sizeof(WCHAR));
5238 MsiSourceListGetInfoW(package->ProductCode, NULL,
5239 package->Context, MSICODE_PRODUCT,
5240 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5243 prompt = strdupW(package->db->path);
5245 msg = generate_error_string(package,1302,1,prompt);
5246 while(attrib == INVALID_FILE_ATTRIBUTES)
5248 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5251 rc = ERROR_INSTALL_USEREXIT;
5254 attrib = GetFileAttributesW(package->db->path);
5260 return ERROR_SUCCESS;
5265 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5268 LPWSTR buffer, productid = NULL;
5269 UINT i, rc = ERROR_SUCCESS;
5272 static const WCHAR szPropKeys[][80] =
5274 {'P','r','o','d','u','c','t','I','D',0},
5275 {'U','S','E','R','N','A','M','E',0},
5276 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5280 static const WCHAR szRegKeys[][80] =
5282 {'P','r','o','d','u','c','t','I','D',0},
5283 {'R','e','g','O','w','n','e','r',0},
5284 {'R','e','g','C','o','m','p','a','n','y',0},
5288 if (msi_check_unpublish(package))
5290 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5294 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5298 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5300 if (rc != ERROR_SUCCESS)
5303 for( i = 0; szPropKeys[i][0]; i++ )
5305 buffer = msi_dup_property( package->db, szPropKeys[i] );
5306 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5311 uirow = MSI_CreateRecord( 1 );
5312 MSI_RecordSetStringW( uirow, 1, productid );
5313 ui_actiondata( package, szRegisterUser, uirow );
5314 msiobj_release( &uirow->hdr );
5316 msi_free(productid);
5322 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5326 package->script->InWhatSequence |= SEQUENCE_EXEC;
5327 rc = ACTION_ProcessExecSequence(package,FALSE);
5332 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5334 MSIPACKAGE *package = param;
5335 LPCWSTR compgroupid, component, feature, qualifier, text;
5336 LPWSTR advertise = NULL, output = NULL;
5344 feature = MSI_RecordGetString(rec, 5);
5345 feat = get_loaded_feature(package, feature);
5347 return ERROR_SUCCESS;
5349 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5350 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5351 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5353 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5354 feat->Action = feat->Installed;
5355 return ERROR_SUCCESS;
5358 component = MSI_RecordGetString(rec, 3);
5359 comp = get_loaded_component(package, component);
5361 return ERROR_SUCCESS;
5363 compgroupid = MSI_RecordGetString(rec,1);
5364 qualifier = MSI_RecordGetString(rec,2);
5366 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5367 if (rc != ERROR_SUCCESS)
5370 text = MSI_RecordGetString(rec,4);
5371 advertise = create_component_advertise_string(package, comp, feature);
5373 sz = strlenW(advertise);
5376 sz += lstrlenW(text);
5379 sz *= sizeof(WCHAR);
5381 output = msi_alloc_zero(sz);
5382 strcpyW(output,advertise);
5383 msi_free(advertise);
5386 strcatW(output,text);
5388 msi_reg_set_val_multi_str( hkey, qualifier, output );
5395 uirow = MSI_CreateRecord( 2 );
5396 MSI_RecordSetStringW( uirow, 1, compgroupid );
5397 MSI_RecordSetStringW( uirow, 2, qualifier);
5398 ui_actiondata( package, szPublishComponents, uirow);
5399 msiobj_release( &uirow->hdr );
5400 /* FIXME: call ui_progress? */
5406 * At present I am ignorning the advertised components part of this and only
5407 * focusing on the qualified component sets
5409 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5413 static const WCHAR ExecSeqQuery[] =
5414 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5415 '`','P','u','b','l','i','s','h',
5416 'C','o','m','p','o','n','e','n','t','`',0};
5418 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5419 if (rc != ERROR_SUCCESS)
5420 return ERROR_SUCCESS;
5422 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5423 msiobj_release(&view->hdr);
5428 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5430 static const WCHAR szInstallerComponents[] = {
5431 'S','o','f','t','w','a','r','e','\\',
5432 'M','i','c','r','o','s','o','f','t','\\',
5433 'I','n','s','t','a','l','l','e','r','\\',
5434 'C','o','m','p','o','n','e','n','t','s','\\',0};
5436 MSIPACKAGE *package = param;
5437 LPCWSTR compgroupid, component, feature, qualifier;
5441 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5444 feature = MSI_RecordGetString( rec, 5 );
5445 feat = get_loaded_feature( package, feature );
5447 return ERROR_SUCCESS;
5449 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5451 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5452 feat->Action = feat->Installed;
5453 return ERROR_SUCCESS;
5456 component = MSI_RecordGetString( rec, 3 );
5457 comp = get_loaded_component( package, component );
5459 return ERROR_SUCCESS;
5461 compgroupid = MSI_RecordGetString( rec, 1 );
5462 qualifier = MSI_RecordGetString( rec, 2 );
5464 squash_guid( compgroupid, squashed );
5465 strcpyW( keypath, szInstallerComponents );
5466 strcatW( keypath, squashed );
5468 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5469 if (res != ERROR_SUCCESS)
5471 WARN("Unable to delete component key %d\n", res);
5474 uirow = MSI_CreateRecord( 2 );
5475 MSI_RecordSetStringW( uirow, 1, compgroupid );
5476 MSI_RecordSetStringW( uirow, 2, qualifier );
5477 ui_actiondata( package, szUnpublishComponents, uirow );
5478 msiobj_release( &uirow->hdr );
5480 return ERROR_SUCCESS;
5483 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5487 static const WCHAR query[] =
5488 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5489 '`','P','u','b','l','i','s','h',
5490 'C','o','m','p','o','n','e','n','t','`',0};
5492 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5493 if (rc != ERROR_SUCCESS)
5494 return ERROR_SUCCESS;
5496 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5497 msiobj_release( &view->hdr );
5502 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5504 MSIPACKAGE *package = param;
5507 SC_HANDLE hscm, service = NULL;
5509 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5510 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5511 DWORD serv_type, start_type, err_control;
5512 SERVICE_DESCRIPTIONW sd = {NULL};
5514 static const WCHAR query[] =
5515 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5516 '`','C','o','m','p','o','n','e','n','t','`',' ',
5517 'W','H','E','R','E',' ',
5518 '`','C','o','m','p','o','n','e','n','t','`',' ',
5519 '=','\'','%','s','\'',0};
5521 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5524 ERR("Failed to open the SC Manager!\n");
5528 start_type = MSI_RecordGetInteger(rec, 5);
5529 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5532 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5533 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5534 serv_type = MSI_RecordGetInteger(rec, 4);
5535 err_control = MSI_RecordGetInteger(rec, 6);
5536 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5537 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5538 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5539 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5540 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5541 comp = MSI_RecordGetString(rec, 12);
5542 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5544 /* fetch the service path */
5545 row = MSI_QueryGetRecord(package->db, query, comp);
5548 ERR("Control query failed!\n");
5551 key = MSI_RecordGetString(row, 6);
5553 file = get_loaded_file(package, key);
5554 msiobj_release(&row->hdr);
5557 ERR("Failed to load the service file\n");
5561 if (!args || !args[0]) image_path = file->TargetPath;
5564 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5565 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5566 return ERROR_OUTOFMEMORY;
5568 strcpyW(image_path, file->TargetPath);
5569 strcatW(image_path, szSpace);
5570 strcatW(image_path, args);
5572 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5573 start_type, err_control, image_path, load_order,
5574 NULL, depends, serv_name, pass);
5578 if (GetLastError() != ERROR_SERVICE_EXISTS)
5579 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5581 else if (sd.lpDescription)
5583 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5584 WARN("failed to set service description %u\n", GetLastError());
5587 if (image_path != file->TargetPath) msi_free(image_path);
5589 CloseServiceHandle(service);
5590 CloseServiceHandle(hscm);
5593 msi_free(sd.lpDescription);
5594 msi_free(load_order);
5595 msi_free(serv_name);
5600 return ERROR_SUCCESS;
5603 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5607 static const WCHAR ExecSeqQuery[] =
5608 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5609 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5611 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5612 if (rc != ERROR_SUCCESS)
5613 return ERROR_SUCCESS;
5615 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5616 msiobj_release(&view->hdr);
5621 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5622 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5624 LPCWSTR *vector, *temp_vector;
5628 static const WCHAR separator[] = {'[','~',']',0};
5631 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5636 vector = msi_alloc(sizeof(LPWSTR));
5644 vector[*numargs - 1] = p;
5646 if ((q = strstrW(p, separator)))
5650 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5656 vector = temp_vector;
5665 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5667 MSIPACKAGE *package = param;
5670 SC_HANDLE scm = NULL, service = NULL;
5671 LPCWSTR component, *vector = NULL;
5672 LPWSTR name, args, display_name = NULL;
5673 DWORD event, numargs, len;
5674 UINT r = ERROR_FUNCTION_FAILED;
5676 component = MSI_RecordGetString(rec, 6);
5677 comp = get_loaded_component(package, component);
5679 return ERROR_SUCCESS;
5683 TRACE("component is disabled\n");
5684 return ERROR_SUCCESS;
5687 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5689 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5690 comp->Action = comp->Installed;
5691 return ERROR_SUCCESS;
5693 comp->Action = INSTALLSTATE_LOCAL;
5695 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5696 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5697 event = MSI_RecordGetInteger(rec, 3);
5699 if (!(event & msidbServiceControlEventStart))
5705 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5708 ERR("Failed to open the service control manager\n");
5713 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5714 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5716 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5717 GetServiceDisplayNameW( scm, name, display_name, &len );
5720 service = OpenServiceW(scm, name, SERVICE_START);
5723 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5727 vector = msi_service_args_to_vector(args, &numargs);
5729 if (!StartServiceW(service, numargs, vector) &&
5730 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5732 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5739 uirow = MSI_CreateRecord( 2 );
5740 MSI_RecordSetStringW( uirow, 1, display_name );
5741 MSI_RecordSetStringW( uirow, 2, name );
5742 ui_actiondata( package, szStartServices, uirow );
5743 msiobj_release( &uirow->hdr );
5745 CloseServiceHandle(service);
5746 CloseServiceHandle(scm);
5751 msi_free(display_name);
5755 static UINT ACTION_StartServices( MSIPACKAGE *package )
5760 static const WCHAR query[] = {
5761 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5762 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5764 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5765 if (rc != ERROR_SUCCESS)
5766 return ERROR_SUCCESS;
5768 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5769 msiobj_release(&view->hdr);
5774 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5776 DWORD i, needed, count;
5777 ENUM_SERVICE_STATUSW *dependencies;
5781 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5782 0, &needed, &count))
5785 if (GetLastError() != ERROR_MORE_DATA)
5788 dependencies = msi_alloc(needed);
5792 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5793 needed, &needed, &count))
5796 for (i = 0; i < count; i++)
5798 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5799 SERVICE_STOP | SERVICE_QUERY_STATUS);
5803 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5810 msi_free(dependencies);
5814 static UINT stop_service( LPCWSTR name )
5816 SC_HANDLE scm = NULL, service = NULL;
5817 SERVICE_STATUS status;
5818 SERVICE_STATUS_PROCESS ssp;
5821 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5824 WARN("Failed to open the SCM: %d\n", GetLastError());
5828 service = OpenServiceW(scm, name,
5830 SERVICE_QUERY_STATUS |
5831 SERVICE_ENUMERATE_DEPENDENTS);
5834 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5838 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5839 sizeof(SERVICE_STATUS_PROCESS), &needed))
5841 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5845 if (ssp.dwCurrentState == SERVICE_STOPPED)
5848 stop_service_dependents(scm, service);
5850 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5851 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5854 CloseServiceHandle(service);
5855 CloseServiceHandle(scm);
5857 return ERROR_SUCCESS;
5860 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5862 MSIPACKAGE *package = param;
5866 LPWSTR name = NULL, display_name = NULL;
5870 event = MSI_RecordGetInteger( rec, 3 );
5871 if (!(event & msidbServiceControlEventStop))
5872 return ERROR_SUCCESS;
5874 component = MSI_RecordGetString( rec, 6 );
5875 comp = get_loaded_component( package, component );
5877 return ERROR_SUCCESS;
5881 TRACE("component is disabled\n");
5882 return ERROR_SUCCESS;
5885 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5887 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5888 comp->Action = comp->Installed;
5889 return ERROR_SUCCESS;
5891 comp->Action = INSTALLSTATE_ABSENT;
5893 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5896 ERR("Failed to open the service control manager\n");
5901 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5902 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5904 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5905 GetServiceDisplayNameW( scm, name, display_name, &len );
5907 CloseServiceHandle( scm );
5909 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5910 stop_service( name );
5913 uirow = MSI_CreateRecord( 2 );
5914 MSI_RecordSetStringW( uirow, 1, display_name );
5915 MSI_RecordSetStringW( uirow, 2, name );
5916 ui_actiondata( package, szStopServices, uirow );
5917 msiobj_release( &uirow->hdr );
5920 msi_free( display_name );
5921 return ERROR_SUCCESS;
5924 static UINT ACTION_StopServices( MSIPACKAGE *package )
5929 static const WCHAR query[] = {
5930 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5931 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5933 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5934 if (rc != ERROR_SUCCESS)
5935 return ERROR_SUCCESS;
5937 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5938 msiobj_release(&view->hdr);
5943 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5945 MSIPACKAGE *package = param;
5949 LPWSTR name = NULL, display_name = NULL;
5951 SC_HANDLE scm = NULL, service = NULL;
5953 event = MSI_RecordGetInteger( rec, 3 );
5954 if (!(event & msidbServiceControlEventDelete))
5955 return ERROR_SUCCESS;
5957 component = MSI_RecordGetString(rec, 6);
5958 comp = get_loaded_component(package, component);
5960 return ERROR_SUCCESS;
5964 TRACE("component is disabled\n");
5965 return ERROR_SUCCESS;
5968 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5970 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5971 comp->Action = comp->Installed;
5972 return ERROR_SUCCESS;
5974 comp->Action = INSTALLSTATE_ABSENT;
5976 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5977 stop_service( name );
5979 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5982 WARN("Failed to open the SCM: %d\n", GetLastError());
5987 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5988 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5990 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5991 GetServiceDisplayNameW( scm, name, display_name, &len );
5994 service = OpenServiceW( scm, name, DELETE );
5997 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6001 if (!DeleteService( service ))
6002 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6005 uirow = MSI_CreateRecord( 2 );
6006 MSI_RecordSetStringW( uirow, 1, display_name );
6007 MSI_RecordSetStringW( uirow, 2, name );
6008 ui_actiondata( package, szDeleteServices, uirow );
6009 msiobj_release( &uirow->hdr );
6011 CloseServiceHandle( service );
6012 CloseServiceHandle( scm );
6014 msi_free( display_name );
6016 return ERROR_SUCCESS;
6019 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6024 static const WCHAR query[] = {
6025 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6026 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6028 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6029 if (rc != ERROR_SUCCESS)
6030 return ERROR_SUCCESS;
6032 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6033 msiobj_release( &view->hdr );
6038 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6040 MSIPACKAGE *package = param;
6041 LPWSTR driver, driver_path, ptr;
6042 WCHAR outpath[MAX_PATH];
6043 MSIFILE *driver_file = NULL, *setup_file = NULL;
6046 LPCWSTR desc, file_key, component;
6048 UINT r = ERROR_SUCCESS;
6050 static const WCHAR driver_fmt[] = {
6051 'D','r','i','v','e','r','=','%','s',0};
6052 static const WCHAR setup_fmt[] = {
6053 'S','e','t','u','p','=','%','s',0};
6054 static const WCHAR usage_fmt[] = {
6055 'F','i','l','e','U','s','a','g','e','=','1',0};
6057 component = MSI_RecordGetString( rec, 2 );
6058 comp = get_loaded_component( package, component );
6060 return ERROR_SUCCESS;
6064 TRACE("component is disabled\n");
6065 return ERROR_SUCCESS;
6068 desc = MSI_RecordGetString(rec, 3);
6070 file_key = MSI_RecordGetString( rec, 4 );
6071 if (file_key) driver_file = get_loaded_file( package, file_key );
6073 file_key = MSI_RecordGetString( rec, 5 );
6074 if (file_key) setup_file = get_loaded_file( package, file_key );
6078 ERR("ODBC Driver entry not found!\n");
6079 return ERROR_FUNCTION_FAILED;
6082 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6084 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6085 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6087 driver = msi_alloc(len * sizeof(WCHAR));
6089 return ERROR_OUTOFMEMORY;
6092 lstrcpyW(ptr, desc);
6093 ptr += lstrlenW(ptr) + 1;
6095 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6100 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6104 lstrcpyW(ptr, usage_fmt);
6105 ptr += lstrlenW(ptr) + 1;
6108 driver_path = strdupW(driver_file->TargetPath);
6109 ptr = strrchrW(driver_path, '\\');
6110 if (ptr) *ptr = '\0';
6112 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6113 NULL, ODBC_INSTALL_COMPLETE, &usage))
6115 ERR("Failed to install SQL driver!\n");
6116 r = ERROR_FUNCTION_FAILED;
6119 uirow = MSI_CreateRecord( 5 );
6120 MSI_RecordSetStringW( uirow, 1, desc );
6121 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6122 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6123 ui_actiondata( package, szInstallODBC, uirow );
6124 msiobj_release( &uirow->hdr );
6127 msi_free(driver_path);
6132 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6134 MSIPACKAGE *package = param;
6135 LPWSTR translator, translator_path, ptr;
6136 WCHAR outpath[MAX_PATH];
6137 MSIFILE *translator_file = NULL, *setup_file = NULL;
6140 LPCWSTR desc, file_key, component;
6142 UINT r = ERROR_SUCCESS;
6144 static const WCHAR translator_fmt[] = {
6145 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6146 static const WCHAR setup_fmt[] = {
6147 'S','e','t','u','p','=','%','s',0};
6149 component = MSI_RecordGetString( rec, 2 );
6150 comp = get_loaded_component( package, component );
6152 return ERROR_SUCCESS;
6156 TRACE("component is disabled\n");
6157 return ERROR_SUCCESS;
6160 desc = MSI_RecordGetString(rec, 3);
6162 file_key = MSI_RecordGetString( rec, 4 );
6163 if (file_key) translator_file = get_loaded_file( package, file_key );
6165 file_key = MSI_RecordGetString( rec, 5 );
6166 if (file_key) setup_file = get_loaded_file( package, file_key );
6168 if (!translator_file)
6170 ERR("ODBC Translator entry not found!\n");
6171 return ERROR_FUNCTION_FAILED;
6174 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6176 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6178 translator = msi_alloc(len * sizeof(WCHAR));
6180 return ERROR_OUTOFMEMORY;
6183 lstrcpyW(ptr, desc);
6184 ptr += lstrlenW(ptr) + 1;
6186 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6191 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6196 translator_path = strdupW(translator_file->TargetPath);
6197 ptr = strrchrW(translator_path, '\\');
6198 if (ptr) *ptr = '\0';
6200 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6201 NULL, ODBC_INSTALL_COMPLETE, &usage))
6203 ERR("Failed to install SQL translator!\n");
6204 r = ERROR_FUNCTION_FAILED;
6207 uirow = MSI_CreateRecord( 5 );
6208 MSI_RecordSetStringW( uirow, 1, desc );
6209 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6210 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6211 ui_actiondata( package, szInstallODBC, uirow );
6212 msiobj_release( &uirow->hdr );
6214 msi_free(translator);
6215 msi_free(translator_path);
6220 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6222 MSIPACKAGE *package = param;
6225 LPCWSTR desc, driver, component;
6226 WORD request = ODBC_ADD_SYS_DSN;
6229 UINT r = ERROR_SUCCESS;
6232 static const WCHAR attrs_fmt[] = {
6233 'D','S','N','=','%','s',0 };
6235 component = MSI_RecordGetString( rec, 2 );
6236 comp = get_loaded_component( package, component );
6238 return ERROR_SUCCESS;
6242 TRACE("component is disabled\n");
6243 return ERROR_SUCCESS;
6246 desc = MSI_RecordGetString(rec, 3);
6247 driver = MSI_RecordGetString(rec, 4);
6248 registration = MSI_RecordGetInteger(rec, 5);
6250 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6251 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6253 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6254 attrs = msi_alloc(len * sizeof(WCHAR));
6256 return ERROR_OUTOFMEMORY;
6258 len = sprintfW(attrs, attrs_fmt, desc);
6261 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6263 ERR("Failed to install SQL data source!\n");
6264 r = ERROR_FUNCTION_FAILED;
6267 uirow = MSI_CreateRecord( 5 );
6268 MSI_RecordSetStringW( uirow, 1, desc );
6269 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6270 MSI_RecordSetInteger( uirow, 3, request );
6271 ui_actiondata( package, szInstallODBC, uirow );
6272 msiobj_release( &uirow->hdr );
6279 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6284 static const WCHAR driver_query[] = {
6285 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6286 'O','D','B','C','D','r','i','v','e','r',0 };
6288 static const WCHAR translator_query[] = {
6289 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6290 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6292 static const WCHAR source_query[] = {
6293 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6294 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6296 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6297 if (rc != ERROR_SUCCESS)
6298 return ERROR_SUCCESS;
6300 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6301 msiobj_release(&view->hdr);
6303 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6304 if (rc != ERROR_SUCCESS)
6305 return ERROR_SUCCESS;
6307 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6308 msiobj_release(&view->hdr);
6310 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6311 if (rc != ERROR_SUCCESS)
6312 return ERROR_SUCCESS;
6314 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6315 msiobj_release(&view->hdr);
6320 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6322 MSIPACKAGE *package = param;
6326 LPCWSTR desc, component;
6328 component = MSI_RecordGetString( rec, 2 );
6329 comp = get_loaded_component( package, component );
6331 return ERROR_SUCCESS;
6335 TRACE("component is disabled\n");
6336 return ERROR_SUCCESS;
6339 desc = MSI_RecordGetString( rec, 3 );
6340 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6342 WARN("Failed to remove ODBC driver\n");
6346 FIXME("Usage count reached 0\n");
6349 uirow = MSI_CreateRecord( 2 );
6350 MSI_RecordSetStringW( uirow, 1, desc );
6351 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6352 ui_actiondata( package, szRemoveODBC, uirow );
6353 msiobj_release( &uirow->hdr );
6355 return ERROR_SUCCESS;
6358 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6360 MSIPACKAGE *package = param;
6364 LPCWSTR desc, component;
6366 component = MSI_RecordGetString( rec, 2 );
6367 comp = get_loaded_component( package, component );
6369 return ERROR_SUCCESS;
6373 TRACE("component is disabled\n");
6374 return ERROR_SUCCESS;
6377 desc = MSI_RecordGetString( rec, 3 );
6378 if (!SQLRemoveTranslatorW( desc, &usage ))
6380 WARN("Failed to remove ODBC translator\n");
6384 FIXME("Usage count reached 0\n");
6387 uirow = MSI_CreateRecord( 2 );
6388 MSI_RecordSetStringW( uirow, 1, desc );
6389 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6390 ui_actiondata( package, szRemoveODBC, uirow );
6391 msiobj_release( &uirow->hdr );
6393 return ERROR_SUCCESS;
6396 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6398 MSIPACKAGE *package = param;
6402 LPCWSTR desc, driver, component;
6403 WORD request = ODBC_REMOVE_SYS_DSN;
6407 static const WCHAR attrs_fmt[] = {
6408 'D','S','N','=','%','s',0 };
6410 component = MSI_RecordGetString( rec, 2 );
6411 comp = get_loaded_component( package, component );
6413 return ERROR_SUCCESS;
6417 TRACE("component is disabled\n");
6418 return ERROR_SUCCESS;
6421 desc = MSI_RecordGetString( rec, 3 );
6422 driver = MSI_RecordGetString( rec, 4 );
6423 registration = MSI_RecordGetInteger( rec, 5 );
6425 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6426 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6428 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6429 attrs = msi_alloc( len * sizeof(WCHAR) );
6431 return ERROR_OUTOFMEMORY;
6433 FIXME("Use ODBCSourceAttribute table\n");
6435 len = sprintfW( attrs, attrs_fmt, desc );
6438 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6440 WARN("Failed to remove ODBC data source\n");
6444 uirow = MSI_CreateRecord( 3 );
6445 MSI_RecordSetStringW( uirow, 1, desc );
6446 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6447 MSI_RecordSetInteger( uirow, 3, request );
6448 ui_actiondata( package, szRemoveODBC, uirow );
6449 msiobj_release( &uirow->hdr );
6451 return ERROR_SUCCESS;
6454 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6459 static const WCHAR driver_query[] = {
6460 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6461 'O','D','B','C','D','r','i','v','e','r',0 };
6463 static const WCHAR translator_query[] = {
6464 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6465 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6467 static const WCHAR source_query[] = {
6468 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6469 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6471 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6472 if (rc != ERROR_SUCCESS)
6473 return ERROR_SUCCESS;
6475 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6476 msiobj_release( &view->hdr );
6478 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6479 if (rc != ERROR_SUCCESS)
6480 return ERROR_SUCCESS;
6482 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6483 msiobj_release( &view->hdr );
6485 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6486 if (rc != ERROR_SUCCESS)
6487 return ERROR_SUCCESS;
6489 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6490 msiobj_release( &view->hdr );
6495 #define ENV_ACT_SETALWAYS 0x1
6496 #define ENV_ACT_SETABSENT 0x2
6497 #define ENV_ACT_REMOVE 0x4
6498 #define ENV_ACT_REMOVEMATCH 0x8
6500 #define ENV_MOD_MACHINE 0x20000000
6501 #define ENV_MOD_APPEND 0x40000000
6502 #define ENV_MOD_PREFIX 0x80000000
6503 #define ENV_MOD_MASK 0xC0000000
6505 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6507 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6509 LPCWSTR cptr = *name;
6511 static const WCHAR prefix[] = {'[','~',']',0};
6512 static const int prefix_len = 3;
6518 *flags |= ENV_ACT_SETALWAYS;
6519 else if (*cptr == '+')
6520 *flags |= ENV_ACT_SETABSENT;
6521 else if (*cptr == '-')
6522 *flags |= ENV_ACT_REMOVE;
6523 else if (*cptr == '!')
6524 *flags |= ENV_ACT_REMOVEMATCH;
6525 else if (*cptr == '*')
6526 *flags |= ENV_MOD_MACHINE;
6536 ERR("Missing environment variable\n");
6537 return ERROR_FUNCTION_FAILED;
6542 LPCWSTR ptr = *value;
6543 if (!strncmpW(ptr, prefix, prefix_len))
6545 if (ptr[prefix_len] == szSemiColon[0])
6547 *flags |= ENV_MOD_APPEND;
6548 *value += lstrlenW(prefix);
6555 else if (lstrlenW(*value) >= prefix_len)
6557 ptr += lstrlenW(ptr) - prefix_len;
6558 if (!strcmpW( ptr, prefix ))
6560 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6562 *flags |= ENV_MOD_PREFIX;
6563 /* the "[~]" will be removed by deformat_string */;
6573 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6574 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6575 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6576 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6578 ERR("Invalid flags: %08x\n", *flags);
6579 return ERROR_FUNCTION_FAILED;
6583 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6585 return ERROR_SUCCESS;
6588 static UINT open_env_key( DWORD flags, HKEY *key )
6590 static const WCHAR user_env[] =
6591 {'E','n','v','i','r','o','n','m','e','n','t',0};
6592 static const WCHAR machine_env[] =
6593 {'S','y','s','t','e','m','\\',
6594 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6595 'C','o','n','t','r','o','l','\\',
6596 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6597 'E','n','v','i','r','o','n','m','e','n','t',0};
6602 if (flags & ENV_MOD_MACHINE)
6605 root = HKEY_LOCAL_MACHINE;
6610 root = HKEY_CURRENT_USER;
6613 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6614 if (res != ERROR_SUCCESS)
6616 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6617 return ERROR_FUNCTION_FAILED;
6620 return ERROR_SUCCESS;
6623 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6625 MSIPACKAGE *package = param;
6626 LPCWSTR name, value, component;
6627 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6628 DWORD flags, type, size;
6635 component = MSI_RecordGetString(rec, 4);
6636 comp = get_loaded_component(package, component);
6638 return ERROR_SUCCESS;
6642 TRACE("component is disabled\n");
6643 return ERROR_SUCCESS;
6646 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6648 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6649 comp->Action = comp->Installed;
6650 return ERROR_SUCCESS;
6652 comp->Action = INSTALLSTATE_LOCAL;
6654 name = MSI_RecordGetString(rec, 2);
6655 value = MSI_RecordGetString(rec, 3);
6657 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6659 res = env_parse_flags(&name, &value, &flags);
6660 if (res != ERROR_SUCCESS || !value)
6663 if (value && !deformat_string(package, value, &deformatted))
6665 res = ERROR_OUTOFMEMORY;
6669 value = deformatted;
6671 res = open_env_key( flags, &env );
6672 if (res != ERROR_SUCCESS)
6675 if (flags & ENV_MOD_MACHINE)
6676 action |= 0x20000000;
6680 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6681 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6682 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6685 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6689 /* Nothing to do. */
6692 res = ERROR_SUCCESS;
6696 /* If we are appending but the string was empty, strip ; */
6697 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6699 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6700 newval = strdupW(value);
6703 res = ERROR_OUTOFMEMORY;
6711 /* Contrary to MSDN, +-variable to [~];path works */
6712 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6714 res = ERROR_SUCCESS;
6718 data = msi_alloc(size);
6722 return ERROR_OUTOFMEMORY;
6725 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6726 if (res != ERROR_SUCCESS)
6729 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6732 res = RegDeleteValueW(env, name);
6733 if (res != ERROR_SUCCESS)
6734 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6738 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6739 if (flags & ENV_MOD_MASK)
6743 if (flags & ENV_MOD_APPEND) multiplier++;
6744 if (flags & ENV_MOD_PREFIX) multiplier++;
6745 mod_size = lstrlenW(value) * multiplier;
6746 size += mod_size * sizeof(WCHAR);
6749 newval = msi_alloc(size);
6753 res = ERROR_OUTOFMEMORY;
6757 if (flags & ENV_MOD_PREFIX)
6759 lstrcpyW(newval, value);
6760 ptr = newval + lstrlenW(value);
6761 action |= 0x80000000;
6764 lstrcpyW(ptr, data);
6766 if (flags & ENV_MOD_APPEND)
6768 lstrcatW(newval, value);
6769 action |= 0x40000000;
6772 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6773 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6776 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6780 uirow = MSI_CreateRecord( 3 );
6781 MSI_RecordSetStringW( uirow, 1, name );
6782 MSI_RecordSetStringW( uirow, 2, newval );
6783 MSI_RecordSetInteger( uirow, 3, action );
6784 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6785 msiobj_release( &uirow->hdr );
6787 if (env) RegCloseKey(env);
6788 msi_free(deformatted);
6794 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6798 static const WCHAR ExecSeqQuery[] =
6799 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6800 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6801 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6802 if (rc != ERROR_SUCCESS)
6803 return ERROR_SUCCESS;
6805 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6806 msiobj_release(&view->hdr);
6811 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6813 MSIPACKAGE *package = param;
6814 LPCWSTR name, value, component;
6815 LPWSTR deformatted = NULL;
6824 component = MSI_RecordGetString( rec, 4 );
6825 comp = get_loaded_component( package, component );
6827 return ERROR_SUCCESS;
6831 TRACE("component is disabled\n");
6832 return ERROR_SUCCESS;
6835 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6837 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6838 comp->Action = comp->Installed;
6839 return ERROR_SUCCESS;
6841 comp->Action = INSTALLSTATE_ABSENT;
6843 name = MSI_RecordGetString( rec, 2 );
6844 value = MSI_RecordGetString( rec, 3 );
6846 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6848 r = env_parse_flags( &name, &value, &flags );
6849 if (r != ERROR_SUCCESS)
6852 if (!(flags & ENV_ACT_REMOVE))
6854 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6855 return ERROR_SUCCESS;
6858 if (value && !deformat_string( package, value, &deformatted ))
6859 return ERROR_OUTOFMEMORY;
6861 value = deformatted;
6863 r = open_env_key( flags, &env );
6864 if (r != ERROR_SUCCESS)
6870 if (flags & ENV_MOD_MACHINE)
6871 action |= 0x20000000;
6873 TRACE("Removing %s\n", debugstr_w(name));
6875 res = RegDeleteValueW( env, name );
6876 if (res != ERROR_SUCCESS)
6878 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6883 uirow = MSI_CreateRecord( 3 );
6884 MSI_RecordSetStringW( uirow, 1, name );
6885 MSI_RecordSetStringW( uirow, 2, value );
6886 MSI_RecordSetInteger( uirow, 3, action );
6887 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6888 msiobj_release( &uirow->hdr );
6890 if (env) RegCloseKey( env );
6891 msi_free( deformatted );
6895 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6899 static const WCHAR query[] =
6900 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6901 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6903 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6904 if (rc != ERROR_SUCCESS)
6905 return ERROR_SUCCESS;
6907 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6908 msiobj_release( &view->hdr );
6913 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6915 LPWSTR key, template, id;
6916 UINT r = ERROR_SUCCESS;
6918 id = msi_dup_property( package->db, szProductID );
6922 return ERROR_SUCCESS;
6924 template = msi_dup_property( package->db, szPIDTemplate );
6925 key = msi_dup_property( package->db, szPIDKEY );
6927 if (key && template)
6929 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6930 r = msi_set_property( package->db, szProductID, key );
6932 msi_free( template );
6937 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6940 package->need_reboot = 1;
6941 return ERROR_SUCCESS;
6944 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6946 static const WCHAR szAvailableFreeReg[] =
6947 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6949 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6951 TRACE("%p %d kilobytes\n", package, space);
6953 uirow = MSI_CreateRecord( 1 );
6954 MSI_RecordSetInteger( uirow, 1, space );
6955 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6956 msiobj_release( &uirow->hdr );
6958 return ERROR_SUCCESS;
6961 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6963 FIXME("%p\n", package);
6964 return ERROR_SUCCESS;
6967 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6969 FIXME("%p\n", package);
6970 return ERROR_SUCCESS;
6973 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6978 static const WCHAR driver_query[] = {
6979 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6980 'O','D','B','C','D','r','i','v','e','r',0 };
6982 static const WCHAR translator_query[] = {
6983 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6984 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6986 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6987 if (r == ERROR_SUCCESS)
6990 r = MSI_IterateRecords( view, &count, NULL, package );
6991 msiobj_release( &view->hdr );
6992 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6995 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6996 if (r == ERROR_SUCCESS)
6999 r = MSI_IterateRecords( view, &count, NULL, package );
7000 msiobj_release( &view->hdr );
7001 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7004 return ERROR_SUCCESS;
7007 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7009 MSIPACKAGE *package = param;
7010 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7013 if ((value = msi_dup_property( package->db, property )))
7015 FIXME("remove %s\n", debugstr_w(value));
7018 return ERROR_SUCCESS;
7021 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7026 static const WCHAR query[] =
7027 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7028 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7030 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7031 if (r == ERROR_SUCCESS)
7033 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7034 msiobj_release( &view->hdr );
7036 return ERROR_SUCCESS;
7039 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7041 MSIPACKAGE *package = param;
7042 int attributes = MSI_RecordGetInteger( rec, 5 );
7044 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7046 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7047 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7048 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7049 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7053 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7055 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7056 if (r != ERROR_SUCCESS)
7057 return ERROR_SUCCESS;
7061 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7062 if (r != ERROR_SUCCESS)
7063 return ERROR_SUCCESS;
7065 RegCloseKey( hkey );
7067 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7068 debugstr_w(upgrade_code), debugstr_w(version_min),
7069 debugstr_w(version_max), debugstr_w(language));
7071 return ERROR_SUCCESS;
7074 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7079 static const WCHAR query[] =
7080 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7082 if (msi_get_property_int( package->db, szInstalled, 0 ))
7084 TRACE("product is installed, skipping action\n");
7085 return ERROR_SUCCESS;
7087 if (msi_get_property_int( package->db, szPreselected, 0 ))
7089 TRACE("Preselected property is set, not migrating feature states\n");
7090 return ERROR_SUCCESS;
7093 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7094 if (r == ERROR_SUCCESS)
7096 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7097 msiobj_release( &view->hdr );
7099 return ERROR_SUCCESS;
7102 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7103 LPCSTR action, LPCWSTR table )
7105 static const WCHAR query[] = {
7106 'S','E','L','E','C','T',' ','*',' ',
7107 'F','R','O','M',' ','`','%','s','`',0 };
7108 MSIQUERY *view = NULL;
7112 r = MSI_OpenQuery( package->db, &view, query, table );
7113 if (r == ERROR_SUCCESS)
7115 r = MSI_IterateRecords(view, &count, NULL, package);
7116 msiobj_release(&view->hdr);
7120 FIXME("%s -> %u ignored %s table values\n",
7121 action, count, debugstr_w(table));
7123 return ERROR_SUCCESS;
7126 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7128 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7129 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7132 static UINT ACTION_BindImage( MSIPACKAGE *package )
7134 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7135 return msi_unimplemented_action_stub( package, "BindImage", table );
7138 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7140 static const WCHAR table[] = {
7141 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7142 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7145 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7147 static const WCHAR table[] = {
7148 'M','s','i','A','s','s','e','m','b','l','y',0 };
7149 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7152 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7154 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7155 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7158 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7160 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7161 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7164 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7166 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7167 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7170 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7172 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7173 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7176 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7180 const WCHAR *action;
7181 UINT (*handler)(MSIPACKAGE *);
7185 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7186 { szAppSearch, ACTION_AppSearch },
7187 { szBindImage, ACTION_BindImage },
7188 { szCCPSearch, ACTION_CCPSearch },
7189 { szCostFinalize, ACTION_CostFinalize },
7190 { szCostInitialize, ACTION_CostInitialize },
7191 { szCreateFolders, ACTION_CreateFolders },
7192 { szCreateShortcuts, ACTION_CreateShortcuts },
7193 { szDeleteServices, ACTION_DeleteServices },
7194 { szDisableRollback, ACTION_DisableRollback },
7195 { szDuplicateFiles, ACTION_DuplicateFiles },
7196 { szExecuteAction, ACTION_ExecuteAction },
7197 { szFileCost, ACTION_FileCost },
7198 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7199 { szForceReboot, ACTION_ForceReboot },
7200 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7201 { szInstallExecute, ACTION_InstallExecute },
7202 { szInstallExecuteAgain, ACTION_InstallExecute },
7203 { szInstallFiles, ACTION_InstallFiles},
7204 { szInstallFinalize, ACTION_InstallFinalize },
7205 { szInstallInitialize, ACTION_InstallInitialize },
7206 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7207 { szInstallValidate, ACTION_InstallValidate },
7208 { szIsolateComponents, ACTION_IsolateComponents },
7209 { szLaunchConditions, ACTION_LaunchConditions },
7210 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7211 { szMoveFiles, ACTION_MoveFiles },
7212 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7213 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7214 { szInstallODBC, ACTION_InstallODBC },
7215 { szInstallServices, ACTION_InstallServices },
7216 { szPatchFiles, ACTION_PatchFiles },
7217 { szProcessComponents, ACTION_ProcessComponents },
7218 { szPublishComponents, ACTION_PublishComponents },
7219 { szPublishFeatures, ACTION_PublishFeatures },
7220 { szPublishProduct, ACTION_PublishProduct },
7221 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7222 { szRegisterComPlus, ACTION_RegisterComPlus},
7223 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7224 { szRegisterFonts, ACTION_RegisterFonts },
7225 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7226 { szRegisterProduct, ACTION_RegisterProduct },
7227 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7228 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7229 { szRegisterUser, ACTION_RegisterUser },
7230 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7231 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7232 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7233 { szRemoveFiles, ACTION_RemoveFiles },
7234 { szRemoveFolders, ACTION_RemoveFolders },
7235 { szRemoveIniValues, ACTION_RemoveIniValues },
7236 { szRemoveODBC, ACTION_RemoveODBC },
7237 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7238 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7239 { szResolveSource, ACTION_ResolveSource },
7240 { szRMCCPSearch, ACTION_RMCCPSearch },
7241 { szScheduleReboot, ACTION_ScheduleReboot },
7242 { szSelfRegModules, ACTION_SelfRegModules },
7243 { szSelfUnregModules, ACTION_SelfUnregModules },
7244 { szSetODBCFolders, ACTION_SetODBCFolders },
7245 { szStartServices, ACTION_StartServices },
7246 { szStopServices, ACTION_StopServices },
7247 { szUnpublishComponents, ACTION_UnpublishComponents },
7248 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7249 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7250 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7251 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7252 { szUnregisterFonts, ACTION_UnregisterFonts },
7253 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7254 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7255 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7256 { szValidateProductID, ACTION_ValidateProductID },
7257 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7258 { szWriteIniValues, ACTION_WriteIniValues },
7259 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7263 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7269 while (StandardActions[i].action != NULL)
7271 if (!strcmpW( StandardActions[i].action, action ))
7273 ui_actionstart( package, action );
7274 if (StandardActions[i].handler)
7276 ui_actioninfo( package, action, TRUE, 0 );
7277 *rc = StandardActions[i].handler( package );
7278 ui_actioninfo( package, action, FALSE, *rc );
7282 FIXME("unhandled standard action %s\n", debugstr_w(action));
7283 *rc = ERROR_SUCCESS;
7293 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7295 UINT rc = ERROR_SUCCESS;
7298 TRACE("Performing action (%s)\n", debugstr_w(action));
7300 handled = ACTION_HandleStandardAction(package, action, &rc);
7303 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7307 WARN("unhandled msi action %s\n", debugstr_w(action));
7308 rc = ERROR_FUNCTION_NOT_CALLED;
7314 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7316 UINT rc = ERROR_SUCCESS;
7317 BOOL handled = FALSE;
7319 TRACE("Performing action (%s)\n", debugstr_w(action));
7321 handled = ACTION_HandleStandardAction(package, action, &rc);
7324 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7326 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7331 WARN("unhandled msi action %s\n", debugstr_w(action));
7332 rc = ERROR_FUNCTION_NOT_CALLED;
7338 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7340 UINT rc = ERROR_SUCCESS;
7343 static const WCHAR ExecSeqQuery[] =
7344 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7345 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7346 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7347 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7348 static const WCHAR UISeqQuery[] =
7349 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7350 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7351 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7352 ' ', '=',' ','%','i',0};
7354 if (needs_ui_sequence(package))
7355 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7357 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7361 LPCWSTR action, cond;
7363 TRACE("Running the actions\n");
7365 /* check conditions */
7366 cond = MSI_RecordGetString(row, 2);
7368 /* this is a hack to skip errors in the condition code */
7369 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7371 msiobj_release(&row->hdr);
7372 return ERROR_SUCCESS;
7375 action = MSI_RecordGetString(row, 1);
7378 ERR("failed to fetch action\n");
7379 msiobj_release(&row->hdr);
7380 return ERROR_FUNCTION_FAILED;
7383 if (needs_ui_sequence(package))
7384 rc = ACTION_PerformUIAction(package, action, -1);
7386 rc = ACTION_PerformAction(package, action, -1);
7388 msiobj_release(&row->hdr);
7394 /****************************************************
7395 * TOP level entry points
7396 *****************************************************/
7398 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7399 LPCWSTR szCommandLine )
7404 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7405 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7407 msi_set_property( package->db, szAction, szInstall );
7409 package->script->InWhatSequence = SEQUENCE_INSTALL;
7416 dir = strdupW(szPackagePath);
7417 p = strrchrW(dir, '\\');
7421 file = szPackagePath + (p - dir);
7426 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7427 GetCurrentDirectoryW(MAX_PATH, dir);
7428 lstrcatW(dir, szBackSlash);
7429 file = szPackagePath;
7432 msi_free( package->PackagePath );
7433 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7434 if (!package->PackagePath)
7437 return ERROR_OUTOFMEMORY;
7440 lstrcpyW(package->PackagePath, dir);
7441 lstrcatW(package->PackagePath, file);
7444 msi_set_sourcedir_props(package, FALSE);
7447 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7448 if (rc != ERROR_SUCCESS)
7451 msi_apply_transforms( package );
7452 msi_apply_patches( package );
7454 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7456 TRACE("setting reinstall property\n");
7457 msi_set_property( package->db, szReinstall, szAll );
7460 /* properties may have been added by a transform */
7461 msi_clone_properties( package );
7463 msi_parse_command_line( package, szCommandLine, FALSE );
7464 msi_adjust_privilege_properties( package );
7465 msi_set_context( package );
7467 if (needs_ui_sequence( package))
7469 package->script->InWhatSequence |= SEQUENCE_UI;
7470 rc = ACTION_ProcessUISequence(package);
7471 ui_exists = ui_sequence_exists(package);
7472 if (rc == ERROR_SUCCESS || !ui_exists)
7474 package->script->InWhatSequence |= SEQUENCE_EXEC;
7475 rc = ACTION_ProcessExecSequence(package, ui_exists);
7479 rc = ACTION_ProcessExecSequence(package, FALSE);
7481 package->script->CurrentlyScripting = FALSE;
7483 /* process the ending type action */
7484 if (rc == ERROR_SUCCESS)
7485 ACTION_PerformActionSequence(package, -1);
7486 else if (rc == ERROR_INSTALL_USEREXIT)
7487 ACTION_PerformActionSequence(package, -2);
7488 else if (rc == ERROR_INSTALL_SUSPEND)
7489 ACTION_PerformActionSequence(package, -4);
7491 ACTION_PerformActionSequence(package, -3);
7493 /* finish up running custom actions */
7494 ACTION_FinishCustomActions(package);
7496 if (rc == ERROR_SUCCESS && package->need_reboot)
7497 return ERROR_SUCCESS_REBOOT_REQUIRED;