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"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings[] =
130 {'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};
131 static const WCHAR szRemoveExistingProducts[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterTypeLibraries[] =
162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
163 static const WCHAR szValidateProductID[] =
164 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
165 static const WCHAR szWriteEnvironmentStrings[] =
166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
168 /********************************************************
170 ********************************************************/
172 void msi_feature_set_state( MSIPACKAGE *package, MSIFEATURE *feature, INSTALLSTATE state )
174 if (!package->ProductCode)
176 feature->ActionRequest = state;
177 feature->Action = state;
179 else if (state == INSTALLSTATE_ABSENT)
181 switch (feature->Installed)
183 case INSTALLSTATE_ABSENT:
184 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
185 feature->Action = INSTALLSTATE_UNKNOWN;
188 feature->ActionRequest = state;
189 feature->Action = state;
192 else if (state == INSTALLSTATE_SOURCE)
194 switch (feature->Installed)
196 case INSTALLSTATE_ABSENT:
197 case INSTALLSTATE_SOURCE:
198 feature->ActionRequest = state;
199 feature->Action = state;
201 case INSTALLSTATE_LOCAL:
202 feature->ActionRequest = INSTALLSTATE_LOCAL;
203 feature->Action = INSTALLSTATE_LOCAL;
206 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
207 feature->Action = INSTALLSTATE_UNKNOWN;
212 feature->ActionRequest = state;
213 feature->Action = state;
215 if (feature->Attributes & msidbFeatureAttributesUIDisallowAbsent)
217 feature->Action = INSTALLSTATE_UNKNOWN;
221 void msi_component_set_state( MSIPACKAGE *package, MSICOMPONENT *comp, INSTALLSTATE state )
223 if (!package->ProductCode)
225 comp->ActionRequest = state;
226 comp->Action = state;
228 else if (state == INSTALLSTATE_ABSENT)
230 switch (comp->Installed)
232 case INSTALLSTATE_LOCAL:
233 case INSTALLSTATE_SOURCE:
234 case INSTALLSTATE_DEFAULT:
235 comp->ActionRequest = state;
236 comp->Action = state;
239 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
240 comp->Action = INSTALLSTATE_UNKNOWN;
243 else if (state == INSTALLSTATE_SOURCE)
245 if (comp->Installed == INSTALLSTATE_ABSENT ||
246 (comp->Installed == INSTALLSTATE_SOURCE && comp->hasLocalFeature))
248 comp->ActionRequest = state;
249 comp->Action = state;
253 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
254 comp->Action = INSTALLSTATE_UNKNOWN;
259 comp->ActionRequest = state;
260 comp->Action = state;
264 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
266 static const WCHAR Query_t[] =
267 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
268 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
269 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
270 ' ','\'','%','s','\'',0};
273 row = MSI_QueryGetRecord( package->db, Query_t, action );
276 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
277 msiobj_release(&row->hdr);
280 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
284 static const WCHAR template_s[]=
285 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
287 static const WCHAR template_e[]=
288 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
289 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
291 static const WCHAR format[] =
292 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
296 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
298 sprintfW(message,template_s,timet,action);
300 sprintfW(message,template_e,timet,action,rc);
302 row = MSI_CreateRecord(1);
303 MSI_RecordSetStringW(row,1,message);
305 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
306 msiobj_release(&row->hdr);
309 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
315 LPWSTR prop = NULL, val = NULL;
318 return ERROR_SUCCESS;
330 TRACE("Looking at %s\n",debugstr_w(ptr));
332 ptr2 = strchrW(ptr,'=');
335 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
342 prop = msi_alloc((len+1)*sizeof(WCHAR));
343 memcpy(prop,ptr,len*sizeof(WCHAR));
353 while (*ptr && (quote || (!quote && *ptr!=' ')))
366 val = msi_alloc((len+1)*sizeof(WCHAR));
367 memcpy(val,ptr2,len*sizeof(WCHAR));
370 if (lstrlenW(prop) > 0)
372 UINT r = msi_set_property( package->db, prop, val );
374 TRACE("Found commandline property (%s) = (%s)\n",
375 debugstr_w(prop), debugstr_w(val));
377 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
378 msi_reset_folders( package, TRUE );
384 return ERROR_SUCCESS;
388 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
391 LPWSTR p, *ret = NULL;
397 /* count the number of substrings */
398 for ( pc = str, count = 0; pc; count++ )
400 pc = strchrW( pc, sep );
405 /* allocate space for an array of substring pointers and the substrings */
406 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
407 (lstrlenW(str)+1) * sizeof(WCHAR) );
411 /* copy the string and set the pointers */
412 p = (LPWSTR) &ret[count+1];
414 for( count = 0; (ret[count] = p); count++ )
416 p = strchrW( p, sep );
424 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
426 static const WCHAR szSystemLanguageID[] =
427 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
429 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
430 UINT ret = ERROR_FUNCTION_FAILED;
432 prod_code = msi_dup_property( package->db, szProductCode );
433 patch_product = msi_get_suminfo_product( patch );
435 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
437 if ( strstrW( patch_product, prod_code ) )
442 si = MSI_GetSummaryInformationW( patch, 0 );
445 ERR("no summary information!\n");
449 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
452 ERR("no template property!\n");
453 msiobj_release( &si->hdr );
460 msiobj_release( &si->hdr );
464 langid = msi_dup_property( package->db, szSystemLanguageID );
467 msiobj_release( &si->hdr );
471 p = strchrW( template, ';' );
472 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
474 TRACE("applicable transform\n");
478 /* FIXME: check platform */
480 msiobj_release( &si->hdr );
484 msi_free( patch_product );
485 msi_free( prod_code );
486 msi_free( template );
492 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
493 MSIDATABASE *patch_db, LPCWSTR name )
495 UINT ret = ERROR_FUNCTION_FAILED;
496 IStorage *stg = NULL;
499 TRACE("%p %s\n", package, debugstr_w(name) );
503 ERR("expected a colon in %s\n", debugstr_w(name));
504 return ERROR_FUNCTION_FAILED;
507 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
510 ret = msi_check_transform_applicable( package, stg );
511 if (ret == ERROR_SUCCESS)
512 msi_table_apply_transform( package->db, stg );
514 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
515 IStorage_Release( stg );
518 ERR("failed to open substorage %s\n", debugstr_w(name));
520 return ERROR_SUCCESS;
523 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
525 LPWSTR guid_list, *guids, product_code;
526 UINT i, ret = ERROR_FUNCTION_FAILED;
528 product_code = msi_dup_property( package->db, szProductCode );
531 /* FIXME: the property ProductCode should be written into the DB somewhere */
532 ERR("no product code to check\n");
533 return ERROR_SUCCESS;
536 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
537 guids = msi_split_string( guid_list, ';' );
538 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
540 if (!strcmpW( guids[i], product_code ))
544 msi_free( guid_list );
545 msi_free( product_code );
550 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
553 MSIRECORD *rec = NULL;
558 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
559 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
560 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
561 '`','S','o','u','r','c','e','`',' ','I','S',' ',
562 'N','O','T',' ','N','U','L','L',0};
564 r = MSI_DatabaseOpenViewW(package->db, query, &view);
565 if (r != ERROR_SUCCESS)
568 r = MSI_ViewExecute(view, 0);
569 if (r != ERROR_SUCCESS)
572 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
574 prop = MSI_RecordGetString(rec, 1);
575 patch = msi_dup_property(package->db, szPatch);
576 msi_set_property(package->db, prop, patch);
581 if (rec) msiobj_release(&rec->hdr);
582 msiobj_release(&view->hdr);
587 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
590 UINT r = ERROR_SUCCESS;
593 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
595 return ERROR_OUTOFMEMORY;
597 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
601 return ERROR_OUTOFMEMORY;
607 msi_free( pi->patchcode );
609 return ERROR_PATCH_PACKAGE_INVALID;
612 p = strchrW( p + 1, '}' );
615 msi_free( pi->patchcode );
617 return ERROR_PATCH_PACKAGE_INVALID;
622 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
626 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
628 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
631 msi_free( pi->patchcode );
633 return ERROR_OUTOFMEMORY;
640 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
642 UINT i, r = ERROR_SUCCESS;
645 /* apply substorage transforms */
646 substorage = msi_split_string( patch->transforms, ';' );
647 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
648 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
650 msi_free( substorage );
651 if (r != ERROR_SUCCESS)
654 msi_set_media_source_prop( package );
657 * There might be a CAB file in the patch package,
658 * so append it to the list of storages to search for streams.
660 append_storage_to_db( package->db, patch_db->storage );
662 patch->state = MSIPATCHSTATE_APPLIED;
663 list_add_tail( &package->patches, &patch->entry );
664 return ERROR_SUCCESS;
667 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
669 static const WCHAR dotmsp[] = {'.','m','s','p',0};
670 MSIDATABASE *patch_db = NULL;
671 WCHAR localfile[MAX_PATH];
673 MSIPATCHINFO *patch = NULL;
674 UINT r = ERROR_SUCCESS;
676 TRACE("%p %s\n", package, debugstr_w( file ) );
678 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
679 if ( r != ERROR_SUCCESS )
681 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
685 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
688 msiobj_release( &patch_db->hdr );
689 return ERROR_FUNCTION_FAILED;
692 r = msi_check_patch_applicable( package, si );
693 if (r != ERROR_SUCCESS)
695 TRACE("patch not applicable\n");
700 r = msi_parse_patch_summary( si, &patch );
701 if ( r != ERROR_SUCCESS )
704 r = msi_get_local_package_name( localfile, dotmsp );
705 if ( r != ERROR_SUCCESS )
708 TRACE("copying to local package %s\n", debugstr_w(localfile));
710 if (!CopyFileW( file, localfile, FALSE ))
712 ERR("Unable to copy package (%s -> %s) (error %u)\n",
713 debugstr_w(file), debugstr_w(localfile), GetLastError());
717 patch->localfile = strdupW( localfile );
719 r = msi_apply_patch_db( package, patch_db, patch );
720 if ( r != ERROR_SUCCESS )
721 WARN("patch failed to apply %u\n", r);
724 msiobj_release( &si->hdr );
725 msiobj_release( &patch_db->hdr );
726 if (patch && r != ERROR_SUCCESS)
728 if (patch->localfile)
729 DeleteFileW( patch->localfile );
731 msi_free( patch->patchcode );
732 msi_free( patch->transforms );
733 msi_free( patch->localfile );
739 /* get the PATCH property, and apply all the patches it specifies */
740 static UINT msi_apply_patches( MSIPACKAGE *package )
742 LPWSTR patch_list, *patches;
743 UINT i, r = ERROR_SUCCESS;
745 patch_list = msi_dup_property( package->db, szPatch );
747 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
749 patches = msi_split_string( patch_list, ';' );
750 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
751 r = msi_apply_patch_package( package, patches[i] );
754 msi_free( patch_list );
759 static UINT msi_apply_transforms( MSIPACKAGE *package )
761 static const WCHAR szTransforms[] = {
762 'T','R','A','N','S','F','O','R','M','S',0 };
763 LPWSTR xform_list, *xforms;
764 UINT i, r = ERROR_SUCCESS;
766 xform_list = msi_dup_property( package->db, szTransforms );
767 xforms = msi_split_string( xform_list, ';' );
769 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
771 if (xforms[i][0] == ':')
772 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
774 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
778 msi_free( xform_list );
783 static BOOL ui_sequence_exists( MSIPACKAGE *package )
788 static const WCHAR ExecSeqQuery [] =
789 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
790 '`','I','n','s','t','a','l','l',
791 'U','I','S','e','q','u','e','n','c','e','`',
792 ' ','W','H','E','R','E',' ',
793 '`','S','e','q','u','e','n','c','e','`',' ',
794 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
795 '`','S','e','q','u','e','n','c','e','`',0};
797 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
798 if (rc == ERROR_SUCCESS)
800 msiobj_release(&view->hdr);
807 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
809 LPWSTR source, check;
811 if (msi_get_property_int( package->db, szInstalled, 0 ))
815 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
816 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
824 db = msi_dup_property( package->db, szOriginalDatabase );
826 return ERROR_OUTOFMEMORY;
828 p = strrchrW( db, '\\' );
831 p = strrchrW( db, '/' );
835 return ERROR_SUCCESS;
840 source = msi_alloc( len * sizeof(WCHAR) );
841 lstrcpynW( source, db, len );
845 check = msi_dup_property( package->db, cszSourceDir );
846 if (!check || replace)
848 UINT r = msi_set_property( package->db, cszSourceDir, source );
849 if (r == ERROR_SUCCESS)
850 msi_reset_folders( package, TRUE );
854 check = msi_dup_property( package->db, cszSOURCEDIR );
855 if (!check || replace)
856 msi_set_property( package->db, cszSOURCEDIR, source );
861 return ERROR_SUCCESS;
864 static BOOL needs_ui_sequence(MSIPACKAGE *package)
866 INT level = msi_get_property_int(package->db, szUILevel, 0);
867 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
870 UINT msi_set_context(MSIPACKAGE *package)
874 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
876 num = msi_get_property_int(package->db, szAllUsers, 0);
877 if (num == 1 || num == 2)
878 package->Context = MSIINSTALLCONTEXT_MACHINE;
880 return ERROR_SUCCESS;
883 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
886 LPCWSTR cond, action;
887 MSIPACKAGE *package = param;
889 action = MSI_RecordGetString(row,1);
892 ERR("Error is retrieving action name\n");
893 return ERROR_FUNCTION_FAILED;
896 /* check conditions */
897 cond = MSI_RecordGetString(row,2);
899 /* this is a hack to skip errors in the condition code */
900 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
902 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
903 return ERROR_SUCCESS;
906 if (needs_ui_sequence(package))
907 rc = ACTION_PerformUIAction(package, action, -1);
909 rc = ACTION_PerformAction(package, action, -1);
911 msi_dialog_check_messages( NULL );
913 if (package->CurrentInstallState != ERROR_SUCCESS)
914 rc = package->CurrentInstallState;
916 if (rc == ERROR_FUNCTION_NOT_CALLED)
919 if (rc != ERROR_SUCCESS)
920 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
925 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
929 static const WCHAR query[] =
930 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
932 ' ','W','H','E','R','E',' ',
933 '`','S','e','q','u','e','n','c','e','`',' ',
934 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
935 '`','S','e','q','u','e','n','c','e','`',0};
937 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
939 r = MSI_OpenQuery( package->db, &view, query, szTable );
940 if (r == ERROR_SUCCESS)
942 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
943 msiobj_release(&view->hdr);
949 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
953 static const WCHAR ExecSeqQuery[] =
954 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
955 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
956 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
957 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
958 'O','R','D','E','R',' ', 'B','Y',' ',
959 '`','S','e','q','u','e','n','c','e','`',0 };
960 static const WCHAR IVQuery[] =
961 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
962 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
963 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
964 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
965 ' ','\'', 'I','n','s','t','a','l','l',
966 'V','a','l','i','d','a','t','e','\'', 0};
969 if (package->script->ExecuteSequenceRun)
971 TRACE("Execute Sequence already Run\n");
972 return ERROR_SUCCESS;
975 package->script->ExecuteSequenceRun = TRUE;
977 /* get the sequence number */
980 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
982 return ERROR_FUNCTION_FAILED;
983 seq = MSI_RecordGetInteger(row,1);
984 msiobj_release(&row->hdr);
987 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
988 if (rc == ERROR_SUCCESS)
990 TRACE("Running the actions\n");
992 msi_set_property(package->db, cszSourceDir, NULL);
994 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
995 msiobj_release(&view->hdr);
1001 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1005 static const WCHAR ExecSeqQuery [] =
1006 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1007 '`','I','n','s','t','a','l','l',
1008 'U','I','S','e','q','u','e','n','c','e','`',
1009 ' ','W','H','E','R','E',' ',
1010 '`','S','e','q','u','e','n','c','e','`',' ',
1011 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1012 '`','S','e','q','u','e','n','c','e','`',0};
1014 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1015 if (rc == ERROR_SUCCESS)
1017 TRACE("Running the actions\n");
1019 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1020 msiobj_release(&view->hdr);
1026 /********************************************************
1027 * ACTION helper functions and functions that perform the actions
1028 *******************************************************/
1029 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1030 UINT* rc, UINT script, BOOL force )
1035 arc = ACTION_CustomAction(package, action, script, force);
1037 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1046 * Actual Action Handlers
1049 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1051 MSIPACKAGE *package = param;
1052 LPCWSTR dir, component;
1058 component = MSI_RecordGetString(row, 2);
1060 return ERROR_SUCCESS;
1062 comp = get_loaded_component(package, component);
1064 return ERROR_SUCCESS;
1068 TRACE("component is disabled\n");
1069 return ERROR_SUCCESS;
1072 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1074 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1075 comp->Action = comp->Installed;
1076 return ERROR_SUCCESS;
1078 comp->Action = INSTALLSTATE_LOCAL;
1080 dir = MSI_RecordGetString(row,1);
1083 ERR("Unable to get folder id\n");
1084 return ERROR_SUCCESS;
1087 uirow = MSI_CreateRecord(1);
1088 MSI_RecordSetStringW(uirow, 1, dir);
1089 ui_actiondata(package, szCreateFolders, uirow);
1090 msiobj_release(&uirow->hdr);
1092 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1095 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1096 return ERROR_SUCCESS;
1099 TRACE("Folder is %s\n",debugstr_w(full_path));
1101 if (folder->State == 0)
1102 create_full_pathW(full_path);
1106 msi_free(full_path);
1107 return ERROR_SUCCESS;
1110 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1112 static const WCHAR ExecSeqQuery[] =
1113 {'S','E','L','E','C','T',' ',
1114 '`','D','i','r','e','c','t','o','r','y','_','`',
1115 ' ','F','R','O','M',' ',
1116 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1120 /* create all the empty folders specified in the CreateFolder table */
1121 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1126 msiobj_release(&view->hdr);
1131 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1133 MSIPACKAGE *package = param;
1134 LPCWSTR dir, component;
1140 component = MSI_RecordGetString(row, 2);
1142 return ERROR_SUCCESS;
1144 comp = get_loaded_component(package, component);
1146 return ERROR_SUCCESS;
1150 TRACE("component is disabled\n");
1151 return ERROR_SUCCESS;
1154 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1156 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1157 comp->Action = comp->Installed;
1158 return ERROR_SUCCESS;
1160 comp->Action = INSTALLSTATE_ABSENT;
1162 dir = MSI_RecordGetString( row, 1 );
1165 ERR("Unable to get folder id\n");
1166 return ERROR_SUCCESS;
1169 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1172 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1173 return ERROR_SUCCESS;
1176 TRACE("folder is %s\n", debugstr_w(full_path));
1178 uirow = MSI_CreateRecord( 1 );
1179 MSI_RecordSetStringW( uirow, 1, dir );
1180 ui_actiondata( package, szRemoveFolders, uirow );
1181 msiobj_release( &uirow->hdr );
1183 RemoveDirectoryW( full_path );
1186 msi_free( full_path );
1187 return ERROR_SUCCESS;
1190 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1192 static const WCHAR query[] =
1193 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1194 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1199 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1200 if (rc != ERROR_SUCCESS)
1201 return ERROR_SUCCESS;
1203 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1204 msiobj_release( &view->hdr );
1209 static UINT load_component( MSIRECORD *row, LPVOID param )
1211 MSIPACKAGE *package = param;
1214 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1216 return ERROR_FUNCTION_FAILED;
1218 list_add_tail( &package->components, &comp->entry );
1220 /* fill in the data */
1221 comp->Component = msi_dup_record_field( row, 1 );
1223 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1225 comp->ComponentId = msi_dup_record_field( row, 2 );
1226 comp->Directory = msi_dup_record_field( row, 3 );
1227 comp->Attributes = MSI_RecordGetInteger(row,4);
1228 comp->Condition = msi_dup_record_field( row, 5 );
1229 comp->KeyPath = msi_dup_record_field( row, 6 );
1231 comp->Installed = INSTALLSTATE_UNKNOWN;
1232 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1234 return ERROR_SUCCESS;
1237 static UINT load_all_components( MSIPACKAGE *package )
1239 static const WCHAR query[] = {
1240 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1241 '`','C','o','m','p','o','n','e','n','t','`',0 };
1245 if (!list_empty(&package->components))
1246 return ERROR_SUCCESS;
1248 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1249 if (r != ERROR_SUCCESS)
1252 r = MSI_IterateRecords(view, NULL, load_component, package);
1253 msiobj_release(&view->hdr);
1258 MSIPACKAGE *package;
1259 MSIFEATURE *feature;
1262 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1266 cl = msi_alloc( sizeof (*cl) );
1268 return ERROR_NOT_ENOUGH_MEMORY;
1269 cl->component = comp;
1270 list_add_tail( &feature->Components, &cl->entry );
1272 return ERROR_SUCCESS;
1275 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1279 fl = msi_alloc( sizeof(*fl) );
1281 return ERROR_NOT_ENOUGH_MEMORY;
1282 fl->feature = child;
1283 list_add_tail( &parent->Children, &fl->entry );
1285 return ERROR_SUCCESS;
1288 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1290 _ilfs* ilfs = param;
1294 component = MSI_RecordGetString(row,1);
1296 /* check to see if the component is already loaded */
1297 comp = get_loaded_component( ilfs->package, component );
1300 ERR("unknown component %s\n", debugstr_w(component));
1301 return ERROR_FUNCTION_FAILED;
1304 add_feature_component( ilfs->feature, comp );
1305 comp->Enabled = TRUE;
1307 return ERROR_SUCCESS;
1310 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1312 MSIFEATURE *feature;
1317 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1319 if ( !strcmpW( feature->Feature, name ) )
1326 static UINT load_feature(MSIRECORD * row, LPVOID param)
1328 MSIPACKAGE* package = param;
1329 MSIFEATURE* feature;
1330 static const WCHAR Query1[] =
1331 {'S','E','L','E','C','T',' ',
1332 '`','C','o','m','p','o','n','e','n','t','_','`',
1333 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1334 'C','o','m','p','o','n','e','n','t','s','`',' ',
1335 'W','H','E','R','E',' ',
1336 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1341 /* fill in the data */
1343 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1345 return ERROR_NOT_ENOUGH_MEMORY;
1347 list_init( &feature->Children );
1348 list_init( &feature->Components );
1350 feature->Feature = msi_dup_record_field( row, 1 );
1352 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1354 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1355 feature->Title = msi_dup_record_field( row, 3 );
1356 feature->Description = msi_dup_record_field( row, 4 );
1358 if (!MSI_RecordIsNull(row,5))
1359 feature->Display = MSI_RecordGetInteger(row,5);
1361 feature->Level= MSI_RecordGetInteger(row,6);
1362 feature->Directory = msi_dup_record_field( row, 7 );
1363 feature->Attributes = MSI_RecordGetInteger(row,8);
1365 feature->Installed = INSTALLSTATE_UNKNOWN;
1366 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1368 list_add_tail( &package->features, &feature->entry );
1370 /* load feature components */
1372 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1373 if (rc != ERROR_SUCCESS)
1374 return ERROR_SUCCESS;
1376 ilfs.package = package;
1377 ilfs.feature = feature;
1379 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1380 msiobj_release(&view->hdr);
1382 return ERROR_SUCCESS;
1385 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1387 MSIPACKAGE* package = param;
1388 MSIFEATURE *parent, *child;
1390 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1392 return ERROR_FUNCTION_FAILED;
1394 if (!child->Feature_Parent)
1395 return ERROR_SUCCESS;
1397 parent = find_feature_by_name( package, child->Feature_Parent );
1399 return ERROR_FUNCTION_FAILED;
1401 add_feature_child( parent, child );
1402 return ERROR_SUCCESS;
1405 static UINT load_all_features( MSIPACKAGE *package )
1407 static const WCHAR query[] = {
1408 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1409 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1410 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1414 if (!list_empty(&package->features))
1415 return ERROR_SUCCESS;
1417 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1418 if (r != ERROR_SUCCESS)
1421 r = MSI_IterateRecords( view, NULL, load_feature, package );
1422 if (r != ERROR_SUCCESS)
1425 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1426 msiobj_release( &view->hdr );
1431 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1442 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1444 static const WCHAR query[] = {
1445 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1446 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1447 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1448 MSIQUERY *view = NULL;
1449 MSIRECORD *row = NULL;
1452 TRACE("%s\n", debugstr_w(file->File));
1454 r = MSI_OpenQuery(package->db, &view, query, file->File);
1455 if (r != ERROR_SUCCESS)
1458 r = MSI_ViewExecute(view, NULL);
1459 if (r != ERROR_SUCCESS)
1462 r = MSI_ViewFetch(view, &row);
1463 if (r != ERROR_SUCCESS)
1466 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1467 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1468 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1469 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1470 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1473 if (view) msiobj_release(&view->hdr);
1474 if (row) msiobj_release(&row->hdr);
1478 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1481 static const WCHAR query[] = {
1482 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1483 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1484 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1486 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1489 WARN("query failed\n");
1490 return ERROR_FUNCTION_FAILED;
1493 file->disk_id = MSI_RecordGetInteger( row, 1 );
1494 msiobj_release( &row->hdr );
1495 return ERROR_SUCCESS;
1498 static UINT load_file(MSIRECORD *row, LPVOID param)
1500 MSIPACKAGE* package = param;
1504 /* fill in the data */
1506 file = msi_alloc_zero( sizeof (MSIFILE) );
1508 return ERROR_NOT_ENOUGH_MEMORY;
1510 file->File = msi_dup_record_field( row, 1 );
1512 component = MSI_RecordGetString( row, 2 );
1513 file->Component = get_loaded_component( package, component );
1515 if (!file->Component)
1517 WARN("Component not found: %s\n", debugstr_w(component));
1518 msi_free(file->File);
1520 return ERROR_SUCCESS;
1523 file->FileName = msi_dup_record_field( row, 3 );
1524 reduce_to_longfilename( file->FileName );
1526 file->ShortName = msi_dup_record_field( row, 3 );
1527 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1529 file->FileSize = MSI_RecordGetInteger( row, 4 );
1530 file->Version = msi_dup_record_field( row, 5 );
1531 file->Language = msi_dup_record_field( row, 6 );
1532 file->Attributes = MSI_RecordGetInteger( row, 7 );
1533 file->Sequence = MSI_RecordGetInteger( row, 8 );
1535 file->state = msifs_invalid;
1537 /* if the compressed bits are not set in the file attributes,
1538 * then read the information from the package word count property
1540 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1542 file->IsCompressed = FALSE;
1544 else if (file->Attributes &
1545 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1547 file->IsCompressed = TRUE;
1549 else if (file->Attributes & msidbFileAttributesNoncompressed)
1551 file->IsCompressed = FALSE;
1555 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1558 load_file_hash(package, file);
1559 load_file_disk_id(package, file);
1561 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1563 list_add_tail( &package->files, &file->entry );
1565 return ERROR_SUCCESS;
1568 static UINT load_all_files(MSIPACKAGE *package)
1572 static const WCHAR Query[] =
1573 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1574 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1575 '`','S','e','q','u','e','n','c','e','`', 0};
1577 if (!list_empty(&package->files))
1578 return ERROR_SUCCESS;
1580 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1581 if (rc != ERROR_SUCCESS)
1582 return ERROR_SUCCESS;
1584 rc = MSI_IterateRecords(view, NULL, load_file, package);
1585 msiobj_release(&view->hdr);
1587 return ERROR_SUCCESS;
1590 static UINT load_folder( MSIRECORD *row, LPVOID param )
1592 MSIPACKAGE *package = param;
1593 static WCHAR szEmpty[] = { 0 };
1594 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1597 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1599 return ERROR_NOT_ENOUGH_MEMORY;
1601 folder->Directory = msi_dup_record_field( row, 1 );
1603 TRACE("%s\n", debugstr_w(folder->Directory));
1605 p = msi_dup_record_field(row, 3);
1607 /* split src and target dir */
1609 src_short = folder_split_path( p, ':' );
1611 /* split the long and short paths */
1612 tgt_long = folder_split_path( tgt_short, '|' );
1613 src_long = folder_split_path( src_short, '|' );
1615 /* check for no-op dirs */
1616 if (tgt_short && !strcmpW( szDot, tgt_short ))
1617 tgt_short = szEmpty;
1618 if (src_short && !strcmpW( szDot, src_short ))
1619 src_short = szEmpty;
1622 tgt_long = tgt_short;
1625 src_short = tgt_short;
1626 src_long = tgt_long;
1630 src_long = src_short;
1632 /* FIXME: use the target short path too */
1633 folder->TargetDefault = strdupW(tgt_long);
1634 folder->SourceShortPath = strdupW(src_short);
1635 folder->SourceLongPath = strdupW(src_long);
1638 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1639 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1640 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1642 folder->Parent = msi_dup_record_field( row, 2 );
1644 folder->Property = msi_dup_property( package->db, folder->Directory );
1646 list_add_tail( &package->folders, &folder->entry );
1648 TRACE("returning %p\n", folder);
1650 return ERROR_SUCCESS;
1653 static UINT load_all_folders( MSIPACKAGE *package )
1655 static const WCHAR query[] = {
1656 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1657 '`','D','i','r','e','c','t','o','r','y','`',0 };
1661 if (!list_empty(&package->folders))
1662 return ERROR_SUCCESS;
1664 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1665 if (r != ERROR_SUCCESS)
1668 r = MSI_IterateRecords(view, NULL, load_folder, package);
1669 msiobj_release(&view->hdr);
1674 * I am not doing any of the costing functionality yet.
1675 * Mostly looking at doing the Component and Feature loading
1677 * The native MSI does A LOT of modification to tables here. Mostly adding
1678 * a lot of temporary columns to the Feature and Component tables.
1680 * note: Native msi also tracks the short filename. But I am only going to
1681 * track the long ones. Also looking at this directory table
1682 * it appears that the directory table does not get the parents
1683 * resolved base on property only based on their entries in the
1686 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1688 static const WCHAR szCosting[] =
1689 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1691 msi_set_property( package->db, szCosting, szZero );
1692 msi_set_property( package->db, cszRootDrive, c_colon );
1694 load_all_folders( package );
1695 load_all_components( package );
1696 load_all_features( package );
1697 load_all_files( package );
1699 return ERROR_SUCCESS;
1702 static UINT execute_script(MSIPACKAGE *package, UINT script )
1705 UINT rc = ERROR_SUCCESS;
1707 TRACE("Executing Script %i\n",script);
1709 if (!package->script)
1711 ERR("no script!\n");
1712 return ERROR_FUNCTION_FAILED;
1715 for (i = 0; i < package->script->ActionCount[script]; i++)
1718 action = package->script->Actions[script][i];
1719 ui_actionstart(package, action);
1720 TRACE("Executing Action (%s)\n",debugstr_w(action));
1721 rc = ACTION_PerformAction(package, action, script);
1722 if (rc != ERROR_SUCCESS)
1725 msi_free_action_script(package, script);
1729 static UINT ACTION_FileCost(MSIPACKAGE *package)
1731 return ERROR_SUCCESS;
1734 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1740 state = MsiQueryProductStateW(package->ProductCode);
1742 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1744 if (!comp->ComponentId)
1747 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1748 comp->Installed = INSTALLSTATE_ABSENT;
1751 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1752 package->Context, comp->ComponentId,
1754 if (r != ERROR_SUCCESS)
1755 comp->Installed = INSTALLSTATE_ABSENT;
1760 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1762 MSIFEATURE *feature;
1765 state = MsiQueryProductStateW(package->ProductCode);
1767 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1769 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1770 feature->Installed = INSTALLSTATE_ABSENT;
1773 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1779 static BOOL process_state_property(MSIPACKAGE* package, int level,
1780 LPCWSTR property, INSTALLSTATE state)
1783 MSIFEATURE *feature;
1785 override = msi_dup_property( package->db, property );
1789 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1791 if (strcmpW( property, szRemove ) &&
1792 (feature->Level <= 0 || feature->Level > level))
1795 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1797 if (!strcmpiW( override, szAll ))
1798 msi_feature_set_state(package, feature, state);
1801 LPWSTR ptr = override;
1802 LPWSTR ptr2 = strchrW(override,',');
1806 int len = ptr2 - ptr;
1808 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1809 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1811 msi_feature_set_state(package, feature, state);
1817 ptr2 = strchrW(ptr,',');
1829 static BOOL process_overrides( MSIPACKAGE *package, int level )
1831 static const WCHAR szAddLocal[] =
1832 {'A','D','D','L','O','C','A','L',0};
1833 static const WCHAR szAddSource[] =
1834 {'A','D','D','S','O','U','R','C','E',0};
1835 static const WCHAR szAdvertise[] =
1836 {'A','D','V','E','R','T','I','S','E',0};
1839 /* all these activation/deactivation things happen in order and things
1840 * later on the list override things earlier on the list.
1842 * 0 INSTALLLEVEL processing
1855 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1856 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1857 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1858 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1859 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1862 msi_set_property( package->db, szPreselected, szOne );
1867 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1870 static const WCHAR szlevel[] =
1871 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1872 MSICOMPONENT* component;
1873 MSIFEATURE *feature;
1875 TRACE("Checking Install Level\n");
1877 level = msi_get_property_int(package->db, szlevel, 1);
1879 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1881 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1883 BOOL feature_state = ((feature->Level > 0) &&
1884 (feature->Level <= level));
1886 if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1888 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1889 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1890 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1891 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1893 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1897 /* disable child features of unselected parent features */
1898 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1902 if (feature->Level > 0 && feature->Level <= level)
1905 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1906 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1911 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1913 BOOL selected = feature->Level > 0 && feature->Level <= level;
1915 if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1917 msi_feature_set_state(package, feature, feature->Installed);
1923 * now we want to enable or disable components based on feature
1925 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1929 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1930 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1931 feature->ActionRequest, feature->Action);
1933 if (!feature->Level)
1936 /* features with components that have compressed files are made local */
1937 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1939 if (cl->component->ForceLocalState &&
1940 feature->ActionRequest == INSTALLSTATE_SOURCE)
1942 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1947 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1949 component = cl->component;
1951 switch (feature->ActionRequest)
1953 case INSTALLSTATE_ABSENT:
1954 component->anyAbsent = 1;
1956 case INSTALLSTATE_ADVERTISED:
1957 component->hasAdvertiseFeature = 1;
1959 case INSTALLSTATE_SOURCE:
1960 component->hasSourceFeature = 1;
1962 case INSTALLSTATE_LOCAL:
1963 component->hasLocalFeature = 1;
1965 case INSTALLSTATE_DEFAULT:
1966 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1967 component->hasAdvertiseFeature = 1;
1968 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1969 component->hasSourceFeature = 1;
1971 component->hasLocalFeature = 1;
1979 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1981 /* check if it's local or source */
1982 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1983 (component->hasLocalFeature || component->hasSourceFeature))
1985 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1986 !component->ForceLocalState)
1987 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1989 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1993 /* if any feature is local, the component must be local too */
1994 if (component->hasLocalFeature)
1996 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2000 if (component->hasSourceFeature)
2002 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2006 if (component->hasAdvertiseFeature)
2008 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2012 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2013 if (component->anyAbsent)
2014 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2017 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2019 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2021 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2022 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2025 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2026 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2029 return ERROR_SUCCESS;
2032 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2034 MSIPACKAGE *package = param;
2039 name = MSI_RecordGetString(row,1);
2041 f = get_loaded_folder(package, name);
2042 if (!f) return ERROR_SUCCESS;
2044 /* reset the ResolvedTarget */
2045 msi_free(f->ResolvedTarget);
2046 f->ResolvedTarget = NULL;
2048 /* This helper function now does ALL the work */
2049 TRACE("Dir %s ...\n",debugstr_w(name));
2050 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2051 TRACE("resolves to %s\n",debugstr_w(path));
2054 return ERROR_SUCCESS;
2057 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2059 MSIPACKAGE *package = param;
2061 MSIFEATURE *feature;
2063 name = MSI_RecordGetString( row, 1 );
2065 feature = get_loaded_feature( package, name );
2067 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2071 Condition = MSI_RecordGetString(row,3);
2073 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2075 int level = MSI_RecordGetInteger(row,2);
2076 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2077 feature->Level = level;
2080 return ERROR_SUCCESS;
2083 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2085 static const WCHAR name[] = {'\\',0};
2086 VS_FIXEDFILEINFO *ptr, *ret;
2088 DWORD versize, handle;
2091 TRACE("%s\n", debugstr_w(filename));
2093 versize = GetFileVersionInfoSizeW( filename, &handle );
2097 version = msi_alloc( versize );
2101 GetFileVersionInfoW( filename, 0, versize, version );
2103 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2105 msi_free( version );
2109 ret = msi_alloc( sz );
2110 memcpy( ret, ptr, sz );
2112 msi_free( version );
2116 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2120 msi_parse_version_string( version, &ms, &ls );
2122 if (fi->dwFileVersionMS > ms) return 1;
2123 else if (fi->dwFileVersionMS < ms) return -1;
2124 else if (fi->dwFileVersionLS > ls) return 1;
2125 else if (fi->dwFileVersionLS < ls) return -1;
2129 static DWORD get_disk_file_size( LPCWSTR filename )
2134 TRACE("%s\n", debugstr_w(filename));
2136 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2137 if (file == INVALID_HANDLE_VALUE)
2138 return INVALID_FILE_SIZE;
2140 size = GetFileSize( file, NULL );
2141 CloseHandle( file );
2145 static BOOL hash_matches( MSIFILE *file )
2148 MSIFILEHASHINFO hash;
2150 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2151 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2152 if (r != ERROR_SUCCESS)
2155 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2158 static UINT set_file_install_states( MSIPACKAGE *package )
2160 VS_FIXEDFILEINFO *file_version;
2163 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2165 MSICOMPONENT* comp = file->Component;
2172 if (file->IsCompressed)
2173 comp->ForceLocalState = TRUE;
2175 /* calculate target */
2176 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2177 msi_free(file->TargetPath);
2179 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2181 file->TargetPath = build_directory_name(2, p, file->FileName);
2184 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2186 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2188 file->state = msifs_missing;
2189 comp->Cost += file->FileSize;
2192 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2194 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2195 HIWORD(file_version->dwFileVersionMS),
2196 LOWORD(file_version->dwFileVersionMS),
2197 HIWORD(file_version->dwFileVersionLS),
2198 LOWORD(file_version->dwFileVersionLS));
2200 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2202 file->state = msifs_overwrite;
2203 comp->Cost += file->FileSize;
2207 TRACE("Destination file version equal or greater, not overwriting\n");
2208 file->state = msifs_present;
2210 msi_free( file_version );
2213 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2215 file->state = msifs_overwrite;
2216 comp->Cost += file->FileSize - file_size;
2219 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2221 TRACE("File hashes match, not overwriting\n");
2222 file->state = msifs_present;
2225 file->state = msifs_overwrite;
2226 comp->Cost += file->FileSize - file_size;
2229 return ERROR_SUCCESS;
2233 * A lot is done in this function aside from just the costing.
2234 * The costing needs to be implemented at some point but for now I am going
2235 * to focus on the directory building
2238 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2240 static const WCHAR ExecSeqQuery[] =
2241 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2242 '`','D','i','r','e','c','t','o','r','y','`',0};
2243 static const WCHAR ConditionQuery[] =
2244 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2245 '`','C','o','n','d','i','t','i','o','n','`',0};
2246 static const WCHAR szCosting[] =
2247 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2248 static const WCHAR szlevel[] =
2249 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2250 static const WCHAR szOutOfDiskSpace[] =
2251 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2253 UINT rc = ERROR_SUCCESS;
2257 TRACE("Building Directory properties\n");
2259 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2260 if (rc == ERROR_SUCCESS)
2262 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2264 msiobj_release(&view->hdr);
2267 /* read components states from the registry */
2268 ACTION_GetComponentInstallStates(package);
2269 ACTION_GetFeatureInstallStates(package);
2271 TRACE("Calculating file install states\n");
2272 set_file_install_states( package );
2274 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2276 TRACE("Evaluating feature conditions\n");
2278 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2279 if (rc == ERROR_SUCCESS)
2281 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2282 msiobj_release( &view->hdr );
2285 TRACE("Evaluating component conditions\n");
2287 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2289 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2291 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2292 comp->Enabled = FALSE;
2295 comp->Enabled = TRUE;
2298 msi_set_property( package->db, szCosting, szOne );
2299 /* set default run level if not set */
2300 level = msi_dup_property( package->db, szlevel );
2302 msi_set_property( package->db, szlevel, szOne );
2305 /* FIXME: check volume disk space */
2306 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2308 return MSI_SetFeatureStates(package);
2311 /* OK this value is "interpreted" and then formatted based on the
2312 first few characters */
2313 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2318 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2324 LPWSTR deformated = NULL;
2327 deformat_string(package, &value[2], &deformated);
2329 /* binary value type */
2333 *size = (strlenW(ptr)/2)+1;
2335 *size = strlenW(ptr)/2;
2337 data = msi_alloc(*size);
2343 /* if uneven pad with a zero in front */
2349 data[count] = (BYTE)strtol(byte,NULL,0);
2351 TRACE("Uneven byte count\n");
2359 data[count] = (BYTE)strtol(byte,NULL,0);
2362 msi_free(deformated);
2364 TRACE("Data %i bytes(%i)\n",*size,count);
2371 deformat_string(package, &value[1], &deformated);
2374 *size = sizeof(DWORD);
2375 data = msi_alloc(*size);
2381 if ( (*p < '0') || (*p > '9') )
2387 if (deformated[0] == '-')
2390 TRACE("DWORD %i\n",*(LPDWORD)data);
2392 msi_free(deformated);
2397 static const WCHAR szMulti[] = {'[','~',']',0};
2406 *type=REG_EXPAND_SZ;
2414 if (strstrW(value, szMulti))
2415 *type = REG_MULTI_SZ;
2417 /* remove initial delimiter */
2418 if (!strncmpW(value, szMulti, 3))
2421 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2423 /* add double NULL terminator */
2424 if (*type == REG_MULTI_SZ)
2426 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2427 data = msi_realloc_zero(data, *size);
2433 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2440 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2442 *root_key = HKEY_LOCAL_MACHINE;
2447 *root_key = HKEY_CURRENT_USER;
2452 *root_key = HKEY_CLASSES_ROOT;
2456 *root_key = HKEY_CURRENT_USER;
2460 *root_key = HKEY_LOCAL_MACHINE;
2464 *root_key = HKEY_USERS;
2468 ERR("Unknown root %i\n", root);
2475 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2477 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2478 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2480 if (is_64bit && package->platform == PLATFORM_INTEL &&
2481 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2486 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2487 path_32node = msi_alloc( size );
2491 memcpy( path_32node, path, len * sizeof(WCHAR) );
2492 path_32node[len] = 0;
2493 strcatW( path_32node, szWow6432Node );
2494 strcatW( path_32node, szBackSlash );
2495 strcatW( path_32node, path + len );
2499 return strdupW( path );
2502 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2504 MSIPACKAGE *package = param;
2505 LPSTR value_data = NULL;
2506 HKEY root_key, hkey;
2508 LPWSTR deformated, uikey, keypath;
2509 LPCWSTR szRoot, component, name, key, value;
2513 BOOL check_first = FALSE;
2516 ui_progress(package,2,0,0,0);
2518 component = MSI_RecordGetString(row, 6);
2519 comp = get_loaded_component(package,component);
2521 return ERROR_SUCCESS;
2525 TRACE("component is disabled\n");
2526 return ERROR_SUCCESS;
2529 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2531 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2532 comp->Action = comp->Installed;
2533 return ERROR_SUCCESS;
2535 comp->Action = INSTALLSTATE_LOCAL;
2537 name = MSI_RecordGetString(row, 4);
2538 if( MSI_RecordIsNull(row,5) && name )
2540 /* null values can have special meanings */
2541 if (name[0]=='-' && name[1] == 0)
2542 return ERROR_SUCCESS;
2543 else if ((name[0]=='+' && name[1] == 0) ||
2544 (name[0] == '*' && name[1] == 0))
2549 root = MSI_RecordGetInteger(row,2);
2550 key = MSI_RecordGetString(row, 3);
2552 szRoot = get_root_key( package, root, &root_key );
2554 return ERROR_SUCCESS;
2556 deformat_string(package, key , &deformated);
2557 size = strlenW(deformated) + strlenW(szRoot) + 1;
2558 uikey = msi_alloc(size*sizeof(WCHAR));
2559 strcpyW(uikey,szRoot);
2560 strcatW(uikey,deformated);
2562 keypath = get_keypath( package, root_key, deformated );
2563 msi_free( deformated );
2564 if (RegCreateKeyW( root_key, keypath, &hkey ))
2566 ERR("Could not create key %s\n", debugstr_w(keypath));
2568 return ERROR_SUCCESS;
2571 value = MSI_RecordGetString(row,5);
2573 value_data = parse_value(package, value, &type, &size);
2576 value_data = (LPSTR)strdupW(szEmpty);
2577 size = sizeof(szEmpty);
2581 deformat_string(package, name, &deformated);
2585 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2587 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2592 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2593 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2595 TRACE("value %s of %s checked already exists\n",
2596 debugstr_w(deformated), debugstr_w(uikey));
2600 TRACE("Checked and setting value %s of %s\n",
2601 debugstr_w(deformated), debugstr_w(uikey));
2602 if (deformated || size)
2603 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2608 uirow = MSI_CreateRecord(3);
2609 MSI_RecordSetStringW(uirow,2,deformated);
2610 MSI_RecordSetStringW(uirow,1,uikey);
2611 if (type == REG_SZ || type == REG_EXPAND_SZ)
2612 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2613 ui_actiondata(package,szWriteRegistryValues,uirow);
2614 msiobj_release( &uirow->hdr );
2616 msi_free(value_data);
2617 msi_free(deformated);
2620 return ERROR_SUCCESS;
2623 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2627 static const WCHAR ExecSeqQuery[] =
2628 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2629 '`','R','e','g','i','s','t','r','y','`',0 };
2631 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2632 if (rc != ERROR_SUCCESS)
2633 return ERROR_SUCCESS;
2635 /* increment progress bar each time action data is sent */
2636 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2638 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2640 msiobj_release(&view->hdr);
2644 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2648 DWORD num_subkeys, num_values;
2652 if ((res = RegDeleteTreeW( hkey_root, key )))
2654 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2659 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2661 if ((res = RegDeleteValueW( hkey, value )))
2663 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2665 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2666 NULL, NULL, NULL, NULL );
2667 RegCloseKey( hkey );
2669 if (!res && !num_subkeys && !num_values)
2671 TRACE("Removing empty key %s\n", debugstr_w(key));
2672 RegDeleteKeyW( hkey_root, key );
2676 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2680 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2682 MSIPACKAGE *package = param;
2683 LPCWSTR component, name, key_str, root_key_str;
2684 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2687 BOOL delete_key = FALSE;
2692 ui_progress( package, 2, 0, 0, 0 );
2694 component = MSI_RecordGetString( row, 6 );
2695 comp = get_loaded_component( package, component );
2697 return ERROR_SUCCESS;
2701 TRACE("component is disabled\n");
2702 return ERROR_SUCCESS;
2705 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2707 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2708 comp->Action = comp->Installed;
2709 return ERROR_SUCCESS;
2711 comp->Action = INSTALLSTATE_ABSENT;
2713 name = MSI_RecordGetString( row, 4 );
2714 if (MSI_RecordIsNull( row, 5 ) && name )
2716 if (name[0] == '+' && !name[1])
2717 return ERROR_SUCCESS;
2718 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2725 root = MSI_RecordGetInteger( row, 2 );
2726 key_str = MSI_RecordGetString( row, 3 );
2728 root_key_str = get_root_key( package, root, &hkey_root );
2730 return ERROR_SUCCESS;
2732 deformat_string( package, key_str, &deformated_key );
2733 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2734 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2735 strcpyW( ui_key_str, root_key_str );
2736 strcatW( ui_key_str, deformated_key );
2738 deformat_string( package, name, &deformated_name );
2740 keypath = get_keypath( package, hkey_root, deformated_key );
2741 msi_free( deformated_key );
2742 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2743 msi_free( keypath );
2745 uirow = MSI_CreateRecord( 2 );
2746 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2747 MSI_RecordSetStringW( uirow, 2, deformated_name );
2749 ui_actiondata( package, szRemoveRegistryValues, uirow );
2750 msiobj_release( &uirow->hdr );
2752 msi_free( ui_key_str );
2753 msi_free( deformated_name );
2754 return ERROR_SUCCESS;
2757 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2759 MSIPACKAGE *package = param;
2760 LPCWSTR component, name, key_str, root_key_str;
2761 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2764 BOOL delete_key = FALSE;
2769 ui_progress( package, 2, 0, 0, 0 );
2771 component = MSI_RecordGetString( row, 5 );
2772 comp = get_loaded_component( package, component );
2774 return ERROR_SUCCESS;
2778 TRACE("component is disabled\n");
2779 return ERROR_SUCCESS;
2782 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2784 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2785 comp->Action = comp->Installed;
2786 return ERROR_SUCCESS;
2788 comp->Action = INSTALLSTATE_LOCAL;
2790 if ((name = MSI_RecordGetString( row, 4 )))
2792 if (name[0] == '-' && !name[1])
2799 root = MSI_RecordGetInteger( row, 2 );
2800 key_str = MSI_RecordGetString( row, 3 );
2802 root_key_str = get_root_key( package, root, &hkey_root );
2804 return ERROR_SUCCESS;
2806 deformat_string( package, key_str, &deformated_key );
2807 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2808 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2809 strcpyW( ui_key_str, root_key_str );
2810 strcatW( ui_key_str, deformated_key );
2812 deformat_string( package, name, &deformated_name );
2814 keypath = get_keypath( package, hkey_root, deformated_key );
2815 msi_free( deformated_key );
2816 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2817 msi_free( keypath );
2819 uirow = MSI_CreateRecord( 2 );
2820 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2821 MSI_RecordSetStringW( uirow, 2, deformated_name );
2823 ui_actiondata( package, szRemoveRegistryValues, uirow );
2824 msiobj_release( &uirow->hdr );
2826 msi_free( ui_key_str );
2827 msi_free( deformated_name );
2828 return ERROR_SUCCESS;
2831 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2835 static const WCHAR registry_query[] =
2836 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2837 '`','R','e','g','i','s','t','r','y','`',0 };
2838 static const WCHAR remove_registry_query[] =
2839 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2840 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2842 /* increment progress bar each time action data is sent */
2843 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2845 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2846 if (rc == ERROR_SUCCESS)
2848 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2849 msiobj_release( &view->hdr );
2850 if (rc != ERROR_SUCCESS)
2854 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2855 if (rc == ERROR_SUCCESS)
2857 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2858 msiobj_release( &view->hdr );
2859 if (rc != ERROR_SUCCESS)
2863 return ERROR_SUCCESS;
2866 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2868 package->script->CurrentlyScripting = TRUE;
2870 return ERROR_SUCCESS;
2874 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2879 static const WCHAR q1[]=
2880 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2881 '`','R','e','g','i','s','t','r','y','`',0};
2884 MSIFEATURE *feature;
2887 TRACE("InstallValidate\n");
2889 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2890 if (rc == ERROR_SUCCESS)
2892 MSI_IterateRecords( view, &progress, NULL, package );
2893 msiobj_release( &view->hdr );
2894 total += progress * REG_PROGRESS_VALUE;
2897 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2898 total += COMPONENT_PROGRESS_VALUE;
2900 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2901 total += file->FileSize;
2903 ui_progress(package,0,total,0,0);
2905 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2907 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2908 debugstr_w(feature->Feature), feature->Installed,
2909 feature->ActionRequest, feature->Action);
2912 return ERROR_SUCCESS;
2915 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2917 MSIPACKAGE* package = param;
2918 LPCWSTR cond = NULL;
2919 LPCWSTR message = NULL;
2922 static const WCHAR title[]=
2923 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2925 cond = MSI_RecordGetString(row,1);
2927 r = MSI_EvaluateConditionW(package,cond);
2928 if (r == MSICONDITION_FALSE)
2930 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2933 message = MSI_RecordGetString(row,2);
2934 deformat_string(package,message,&deformated);
2935 MessageBoxW(NULL,deformated,title,MB_OK);
2936 msi_free(deformated);
2939 return ERROR_INSTALL_FAILURE;
2942 return ERROR_SUCCESS;
2945 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2948 MSIQUERY * view = NULL;
2949 static const WCHAR ExecSeqQuery[] =
2950 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2951 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2953 TRACE("Checking launch conditions\n");
2955 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2956 if (rc != ERROR_SUCCESS)
2957 return ERROR_SUCCESS;
2959 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2960 msiobj_release(&view->hdr);
2965 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2969 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2971 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2973 MSIRECORD * row = 0;
2975 LPWSTR deformated,buffer,deformated_name;
2977 static const WCHAR ExecSeqQuery[] =
2978 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2979 '`','R','e','g','i','s','t','r','y','`',' ',
2980 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2981 ' ','=',' ' ,'\'','%','s','\'',0 };
2982 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2983 static const WCHAR fmt2[]=
2984 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2986 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2990 root = MSI_RecordGetInteger(row,2);
2991 key = MSI_RecordGetString(row, 3);
2992 name = MSI_RecordGetString(row, 4);
2993 deformat_string(package, key , &deformated);
2994 deformat_string(package, name, &deformated_name);
2996 len = strlenW(deformated) + 6;
2997 if (deformated_name)
2998 len+=strlenW(deformated_name);
3000 buffer = msi_alloc( len *sizeof(WCHAR));
3002 if (deformated_name)
3003 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3005 sprintfW(buffer,fmt,root,deformated);
3007 msi_free(deformated);
3008 msi_free(deformated_name);
3009 msiobj_release(&row->hdr);
3013 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3015 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3020 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3023 return strdupW( file->TargetPath );
3028 static HKEY openSharedDLLsKey(void)
3031 static const WCHAR path[] =
3032 {'S','o','f','t','w','a','r','e','\\',
3033 'M','i','c','r','o','s','o','f','t','\\',
3034 'W','i','n','d','o','w','s','\\',
3035 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3036 'S','h','a','r','e','d','D','L','L','s',0};
3038 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3042 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3047 DWORD sz = sizeof(count);
3050 hkey = openSharedDLLsKey();
3051 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3052 if (rc != ERROR_SUCCESS)
3058 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3062 hkey = openSharedDLLsKey();
3064 msi_reg_set_val_dword( hkey, path, count );
3066 RegDeleteValueW(hkey,path);
3072 * Return TRUE if the count should be written out and FALSE if not
3074 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3076 MSIFEATURE *feature;
3080 /* only refcount DLLs */
3081 if (comp->KeyPath == NULL ||
3082 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3083 comp->Attributes & msidbComponentAttributesODBCDataSource)
3087 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3088 write = (count > 0);
3090 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3094 /* increment counts */
3095 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3099 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3102 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3104 if ( cl->component == comp )
3109 /* decrement counts */
3110 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3114 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3117 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3119 if ( cl->component == comp )
3124 /* ref count all the files in the component */
3129 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3131 if (file->Component == comp)
3132 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3136 /* add a count for permanent */
3137 if (comp->Attributes & msidbComponentAttributesPermanent)
3140 comp->RefCount = count;
3143 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3146 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3148 WCHAR squished_pc[GUID_SIZE];
3149 WCHAR squished_cc[GUID_SIZE];
3156 squash_guid(package->ProductCode,squished_pc);
3157 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3159 msi_set_sourcedir_props(package, FALSE);
3161 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3165 ui_progress(package,2,0,0,0);
3166 if (!comp->ComponentId)
3169 squash_guid(comp->ComponentId,squished_cc);
3171 msi_free(comp->FullKeypath);
3172 comp->FullKeypath = resolve_keypath( package, comp );
3174 ACTION_RefCountComponent( package, comp );
3176 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3177 debugstr_w(comp->Component),
3178 debugstr_w(squished_cc),
3179 debugstr_w(comp->FullKeypath),
3181 comp->ActionRequest);
3183 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3184 comp->ActionRequest == INSTALLSTATE_SOURCE)
3186 if (!comp->FullKeypath)
3189 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3190 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3193 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3196 if (rc != ERROR_SUCCESS)
3199 if (comp->Attributes & msidbComponentAttributesPermanent)
3201 static const WCHAR szPermKey[] =
3202 { '0','0','0','0','0','0','0','0','0','0','0','0',
3203 '0','0','0','0','0','0','0','0','0','0','0','0',
3204 '0','0','0','0','0','0','0','0',0 };
3206 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3209 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3210 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3216 WCHAR source[MAX_PATH];
3217 WCHAR base[MAX_PATH];
3220 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3221 static const WCHAR query[] = {
3222 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3223 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3224 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3225 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3226 '`','D','i','s','k','I','d','`',0};
3228 file = get_loaded_file(package, comp->KeyPath);
3232 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3233 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3234 ptr2 = strrchrW(source, '\\') + 1;
3235 msiobj_release(&row->hdr);
3237 lstrcpyW(base, package->PackagePath);
3238 ptr = strrchrW(base, '\\');
3241 sourcepath = resolve_file_source(package, file);
3242 ptr = sourcepath + lstrlenW(base);
3243 lstrcpyW(ptr2, ptr);
3244 msi_free(sourcepath);
3246 msi_reg_set_val_str(hkey, squished_pc, source);
3250 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3252 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3253 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3255 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3257 comp->Action = comp->ActionRequest;
3260 uirow = MSI_CreateRecord(3);
3261 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3262 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3263 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3264 ui_actiondata(package,szProcessComponents,uirow);
3265 msiobj_release( &uirow->hdr );
3268 return ERROR_SUCCESS;
3279 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3280 LPWSTR lpszName, LONG_PTR lParam)
3283 typelib_struct *tl_struct = (typelib_struct*) lParam;
3284 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3288 if (!IS_INTRESOURCE(lpszName))
3290 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3294 sz = strlenW(tl_struct->source)+4;
3295 sz *= sizeof(WCHAR);
3297 if ((INT_PTR)lpszName == 1)
3298 tl_struct->path = strdupW(tl_struct->source);
3301 tl_struct->path = msi_alloc(sz);
3302 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3305 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3306 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3309 msi_free(tl_struct->path);
3310 tl_struct->path = NULL;
3315 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3316 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3318 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3322 msi_free(tl_struct->path);
3323 tl_struct->path = NULL;
3325 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3326 ITypeLib_Release(tl_struct->ptLib);
3331 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3333 MSIPACKAGE* package = param;
3337 typelib_struct tl_struct;
3342 component = MSI_RecordGetString(row,3);
3343 comp = get_loaded_component(package,component);
3345 return ERROR_SUCCESS;
3349 TRACE("component is disabled\n");
3350 return ERROR_SUCCESS;
3353 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3355 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3356 comp->Action = comp->Installed;
3357 return ERROR_SUCCESS;
3359 comp->Action = INSTALLSTATE_LOCAL;
3361 file = get_loaded_file( package, comp->KeyPath );
3363 return ERROR_SUCCESS;
3365 ui_actiondata( package, szRegisterTypeLibraries, row );
3367 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3371 guid = MSI_RecordGetString(row,1);
3372 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3373 tl_struct.source = strdupW( file->TargetPath );
3374 tl_struct.path = NULL;
3376 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3377 (LONG_PTR)&tl_struct);
3385 helpid = MSI_RecordGetString(row,6);
3388 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3389 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3393 ERR("Failed to register type library %s\n",
3394 debugstr_w(tl_struct.path));
3396 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3398 ITypeLib_Release(tl_struct.ptLib);
3399 msi_free(tl_struct.path);
3402 ERR("Failed to load type library %s\n",
3403 debugstr_w(tl_struct.source));
3405 FreeLibrary(module);
3406 msi_free(tl_struct.source);
3410 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3413 ERR("Failed to load type library: %08x\n", hr);
3414 return ERROR_INSTALL_FAILURE;
3417 ITypeLib_Release(tlib);
3420 return ERROR_SUCCESS;
3423 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3426 * OK this is a bit confusing.. I am given a _Component key and I believe
3427 * that the file that is being registered as a type library is the "key file
3428 * of that component" which I interpret to mean "The file in the KeyPath of
3433 static const WCHAR Query[] =
3434 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3435 '`','T','y','p','e','L','i','b','`',0};
3437 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3438 if (rc != ERROR_SUCCESS)
3439 return ERROR_SUCCESS;
3441 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3442 msiobj_release(&view->hdr);
3446 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3448 MSIPACKAGE *package = param;
3449 LPCWSTR component, guid;
3457 component = MSI_RecordGetString( row, 3 );
3458 comp = get_loaded_component( package, component );
3460 return ERROR_SUCCESS;
3464 TRACE("component is disabled\n");
3465 return ERROR_SUCCESS;
3468 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3470 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3471 comp->Action = comp->Installed;
3472 return ERROR_SUCCESS;
3474 comp->Action = INSTALLSTATE_ABSENT;
3476 ui_actiondata( package, szUnregisterTypeLibraries, row );
3478 guid = MSI_RecordGetString( row, 1 );
3479 CLSIDFromString( (LPCWSTR)guid, &libid );
3480 version = MSI_RecordGetInteger( row, 4 );
3481 language = MSI_RecordGetInteger( row, 2 );
3484 syskind = SYS_WIN64;
3486 syskind = SYS_WIN32;
3489 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3492 WARN("Failed to unregister typelib: %08x\n", hr);
3495 return ERROR_SUCCESS;
3498 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3502 static const WCHAR query[] =
3503 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3504 '`','T','y','p','e','L','i','b','`',0};
3506 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3507 if (rc != ERROR_SUCCESS)
3508 return ERROR_SUCCESS;
3510 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3511 msiobj_release( &view->hdr );
3515 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3517 static const WCHAR szlnk[] = {'.','l','n','k',0};
3518 LPCWSTR directory, extension;
3519 LPWSTR link_folder, link_file, filename;
3521 directory = MSI_RecordGetString( row, 2 );
3522 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3524 /* may be needed because of a bug somewhere else */
3525 create_full_pathW( link_folder );
3527 filename = msi_dup_record_field( row, 3 );
3528 reduce_to_longfilename( filename );
3530 extension = strchrW( filename, '.' );
3531 if (!extension || strcmpiW( extension, szlnk ))
3533 int len = strlenW( filename );
3534 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3535 memcpy( filename + len, szlnk, sizeof(szlnk) );
3537 link_file = build_directory_name( 2, link_folder, filename );
3538 msi_free( link_folder );
3539 msi_free( filename );
3544 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3546 MSIPACKAGE *package = param;
3547 LPWSTR link_file, deformated, path;
3548 LPCWSTR component, target;
3550 IShellLinkW *sl = NULL;
3551 IPersistFile *pf = NULL;
3554 component = MSI_RecordGetString(row, 4);
3555 comp = get_loaded_component(package, component);
3557 return ERROR_SUCCESS;
3561 TRACE("component is disabled\n");
3562 return ERROR_SUCCESS;
3565 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3567 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3568 comp->Action = comp->Installed;
3569 return ERROR_SUCCESS;
3571 comp->Action = INSTALLSTATE_LOCAL;
3573 ui_actiondata(package,szCreateShortcuts,row);
3575 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3576 &IID_IShellLinkW, (LPVOID *) &sl );
3580 ERR("CLSID_ShellLink not available\n");
3584 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3587 ERR("QueryInterface(IID_IPersistFile) failed\n");
3591 target = MSI_RecordGetString(row, 5);
3592 if (strchrW(target, '['))
3594 deformat_string(package, target, &deformated);
3595 IShellLinkW_SetPath(sl,deformated);
3596 msi_free(deformated);
3600 FIXME("poorly handled shortcut format, advertised shortcut\n");
3601 IShellLinkW_SetPath(sl,comp->FullKeypath);
3604 if (!MSI_RecordIsNull(row,6))
3606 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3607 deformat_string(package, arguments, &deformated);
3608 IShellLinkW_SetArguments(sl,deformated);
3609 msi_free(deformated);
3612 if (!MSI_RecordIsNull(row,7))
3614 LPCWSTR description = MSI_RecordGetString(row, 7);
3615 IShellLinkW_SetDescription(sl, description);
3618 if (!MSI_RecordIsNull(row,8))
3619 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3621 if (!MSI_RecordIsNull(row,9))
3624 LPCWSTR icon = MSI_RecordGetString(row, 9);
3626 path = build_icon_path(package, icon);
3627 index = MSI_RecordGetInteger(row,10);
3629 /* no value means 0 */
3630 if (index == MSI_NULL_INTEGER)
3633 IShellLinkW_SetIconLocation(sl, path, index);
3637 if (!MSI_RecordIsNull(row,11))
3638 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3640 if (!MSI_RecordIsNull(row,12))
3642 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3643 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3645 IShellLinkW_SetWorkingDirectory(sl, path);
3649 link_file = get_link_file(package, row);
3651 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3652 IPersistFile_Save(pf, link_file, FALSE);
3654 msi_free(link_file);
3658 IPersistFile_Release( pf );
3660 IShellLinkW_Release( sl );
3662 return ERROR_SUCCESS;
3665 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3670 static const WCHAR Query[] =
3671 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3672 '`','S','h','o','r','t','c','u','t','`',0};
3674 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3675 if (rc != ERROR_SUCCESS)
3676 return ERROR_SUCCESS;
3678 res = CoInitialize( NULL );
3680 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3681 msiobj_release(&view->hdr);
3689 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3691 MSIPACKAGE *package = param;
3696 component = MSI_RecordGetString( row, 4 );
3697 comp = get_loaded_component( package, component );
3699 return ERROR_SUCCESS;
3703 TRACE("component is disabled\n");
3704 return ERROR_SUCCESS;
3707 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3709 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3710 comp->Action = comp->Installed;
3711 return ERROR_SUCCESS;
3713 comp->Action = INSTALLSTATE_ABSENT;
3715 ui_actiondata( package, szRemoveShortcuts, row );
3717 link_file = get_link_file( package, row );
3719 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3720 if (!DeleteFileW( link_file ))
3722 WARN("Failed to remove shortcut file %u\n", GetLastError());
3724 msi_free( link_file );
3726 return ERROR_SUCCESS;
3729 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3733 static const WCHAR query[] =
3734 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3735 '`','S','h','o','r','t','c','u','t','`',0};
3737 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3738 if (rc != ERROR_SUCCESS)
3739 return ERROR_SUCCESS;
3741 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3742 msiobj_release( &view->hdr );
3747 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3749 MSIPACKAGE* package = param;
3757 FileName = MSI_RecordGetString(row,1);
3760 ERR("Unable to get FileName\n");
3761 return ERROR_SUCCESS;
3764 FilePath = build_icon_path(package,FileName);
3766 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3768 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3769 FILE_ATTRIBUTE_NORMAL, NULL);
3771 if (the_file == INVALID_HANDLE_VALUE)
3773 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3775 return ERROR_SUCCESS;
3782 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3783 if (rc != ERROR_SUCCESS)
3785 ERR("Failed to get stream\n");
3786 CloseHandle(the_file);
3787 DeleteFileW(FilePath);
3790 WriteFile(the_file,buffer,sz,&write,NULL);
3791 } while (sz == 1024);
3794 CloseHandle(the_file);
3796 return ERROR_SUCCESS;
3799 static UINT msi_publish_icons(MSIPACKAGE *package)
3804 static const WCHAR query[]= {
3805 'S','E','L','E','C','T',' ','*',' ',
3806 'F','R','O','M',' ','`','I','c','o','n','`',0};
3808 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3809 if (r == ERROR_SUCCESS)
3811 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3812 msiobj_release(&view->hdr);
3815 return ERROR_SUCCESS;
3818 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3824 MSISOURCELISTINFO *info;
3826 r = RegCreateKeyW(hkey, szSourceList, &source);
3827 if (r != ERROR_SUCCESS)
3830 RegCloseKey(source);
3832 buffer = strrchrW(package->PackagePath, '\\') + 1;
3833 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3834 package->Context, MSICODE_PRODUCT,
3835 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3836 if (r != ERROR_SUCCESS)
3839 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3840 package->Context, MSICODE_PRODUCT,
3841 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3842 if (r != ERROR_SUCCESS)
3845 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3846 package->Context, MSICODE_PRODUCT,
3847 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3848 if (r != ERROR_SUCCESS)
3851 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3853 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3854 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3855 info->options, info->value);
3857 MsiSourceListSetInfoW(package->ProductCode, NULL,
3858 info->context, info->options,
3859 info->property, info->value);
3862 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3864 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3865 disk->context, disk->options,
3866 disk->disk_id, disk->volume_label, disk->disk_prompt);
3869 return ERROR_SUCCESS;
3872 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3874 MSIHANDLE hdb, suminfo;
3875 WCHAR guids[MAX_PATH];
3876 WCHAR packcode[SQUISH_GUID_SIZE];
3883 static const WCHAR szProductLanguage[] =
3884 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3885 static const WCHAR szARPProductIcon[] =
3886 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3887 static const WCHAR szProductVersion[] =
3888 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3889 static const WCHAR szAssignment[] =
3890 {'A','s','s','i','g','n','m','e','n','t',0};
3891 static const WCHAR szAdvertiseFlags[] =
3892 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3893 static const WCHAR szClients[] =
3894 {'C','l','i','e','n','t','s',0};
3895 static const WCHAR szColon[] = {':',0};
3897 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3898 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3901 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3902 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3905 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3907 buffer = msi_dup_property(package->db, szARPProductIcon);
3910 LPWSTR path = build_icon_path(package,buffer);
3911 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3916 buffer = msi_dup_property(package->db, szProductVersion);
3919 DWORD verdword = msi_version_str_to_dword(buffer);
3920 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3924 msi_reg_set_val_dword(hkey, szAssignment, 0);
3925 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3926 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3927 msi_reg_set_val_str(hkey, szClients, szColon);
3929 hdb = alloc_msihandle(&package->db->hdr);
3931 return ERROR_NOT_ENOUGH_MEMORY;
3933 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3934 MsiCloseHandle(hdb);
3935 if (r != ERROR_SUCCESS)
3939 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3940 NULL, guids, &size);
3941 if (r != ERROR_SUCCESS)
3944 ptr = strchrW(guids, ';');
3946 squash_guid(guids, packcode);
3947 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3950 MsiCloseHandle(suminfo);
3951 return ERROR_SUCCESS;
3954 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3959 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3961 upgrade = msi_dup_property(package->db, szUpgradeCode);
3963 return ERROR_SUCCESS;
3965 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3967 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3968 if (r != ERROR_SUCCESS)
3973 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3974 if (r != ERROR_SUCCESS)
3978 squash_guid(package->ProductCode, squashed_pc);
3979 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3988 static BOOL msi_check_publish(MSIPACKAGE *package)
3990 MSIFEATURE *feature;
3992 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3994 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4001 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4003 MSIFEATURE *feature;
4005 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4007 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4014 static UINT msi_publish_patches( MSIPACKAGE *package )
4016 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4017 WCHAR patch_squashed[GUID_SIZE];
4018 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4020 MSIPATCHINFO *patch;
4022 WCHAR *p, *all_patches = NULL;
4025 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4026 if (r != ERROR_SUCCESS)
4027 return ERROR_FUNCTION_FAILED;
4029 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4030 if (res != ERROR_SUCCESS)
4032 r = ERROR_FUNCTION_FAILED;
4036 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4037 if (r != ERROR_SUCCESS)
4040 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4042 squash_guid( patch->patchcode, patch_squashed );
4043 len += strlenW( patch_squashed ) + 1;
4046 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4050 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4054 squash_guid( patch->patchcode, p );
4055 p += strlenW( p ) + 1;
4057 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4058 (const BYTE *)patch->transforms,
4059 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4060 if (res != ERROR_SUCCESS)
4063 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4064 if (r != ERROR_SUCCESS)
4067 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4068 (const BYTE *)patch->localfile,
4069 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4070 RegCloseKey( patch_key );
4071 if (res != ERROR_SUCCESS)
4074 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4075 if (res != ERROR_SUCCESS)
4078 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4079 RegCloseKey( patch_key );
4080 if (res != ERROR_SUCCESS)
4084 all_patches[len] = 0;
4085 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4086 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4087 if (res != ERROR_SUCCESS)
4090 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4091 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4092 if (res != ERROR_SUCCESS)
4093 r = ERROR_FUNCTION_FAILED;
4096 RegCloseKey( product_patches_key );
4097 RegCloseKey( patches_key );
4098 RegCloseKey( product_key );
4099 msi_free( all_patches );
4104 * 99% of the work done here is only done for
4105 * advertised installs. However this is where the
4106 * Icon table is processed and written out
4107 * so that is what I am going to do here.
4109 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4112 HKEY hukey = NULL, hudkey = NULL;
4115 if (!list_empty(&package->patches))
4117 rc = msi_publish_patches(package);
4118 if (rc != ERROR_SUCCESS)
4122 /* FIXME: also need to publish if the product is in advertise mode */
4123 if (!msi_check_publish(package))
4124 return ERROR_SUCCESS;
4126 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4128 if (rc != ERROR_SUCCESS)
4131 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4132 NULL, &hudkey, TRUE);
4133 if (rc != ERROR_SUCCESS)
4136 rc = msi_publish_upgrade_code(package);
4137 if (rc != ERROR_SUCCESS)
4140 rc = msi_publish_product_properties(package, hukey);
4141 if (rc != ERROR_SUCCESS)
4144 rc = msi_publish_sourcelist(package, hukey);
4145 if (rc != ERROR_SUCCESS)
4148 rc = msi_publish_icons(package);
4151 uirow = MSI_CreateRecord( 1 );
4152 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4153 ui_actiondata( package, szPublishProduct, uirow );
4154 msiobj_release( &uirow->hdr );
4157 RegCloseKey(hudkey);
4162 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4164 WCHAR *filename, *ptr, *folder, *ret;
4165 const WCHAR *dirprop;
4167 filename = msi_dup_record_field( row, 2 );
4168 if (filename && (ptr = strchrW( filename, '|' )))
4173 dirprop = MSI_RecordGetString( row, 3 );
4176 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4178 folder = msi_dup_property( package->db, dirprop );
4181 folder = msi_dup_property( package->db, szWindowsFolder );
4185 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4186 msi_free( filename );
4190 ret = build_directory_name( 2, folder, ptr );
4192 msi_free( filename );
4197 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4199 MSIPACKAGE *package = param;
4200 LPCWSTR component, section, key, value, identifier;
4201 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4206 component = MSI_RecordGetString(row, 8);
4207 comp = get_loaded_component(package,component);
4209 return ERROR_SUCCESS;
4213 TRACE("component is disabled\n");
4214 return ERROR_SUCCESS;
4217 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4219 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4220 comp->Action = comp->Installed;
4221 return ERROR_SUCCESS;
4223 comp->Action = INSTALLSTATE_LOCAL;
4225 identifier = MSI_RecordGetString(row,1);
4226 section = MSI_RecordGetString(row,4);
4227 key = MSI_RecordGetString(row,5);
4228 value = MSI_RecordGetString(row,6);
4229 action = MSI_RecordGetInteger(row,7);
4231 deformat_string(package,section,&deformated_section);
4232 deformat_string(package,key,&deformated_key);
4233 deformat_string(package,value,&deformated_value);
4235 fullname = get_ini_file_name(package, row);
4239 TRACE("Adding value %s to section %s in %s\n",
4240 debugstr_w(deformated_key), debugstr_w(deformated_section),
4241 debugstr_w(fullname));
4242 WritePrivateProfileStringW(deformated_section, deformated_key,
4243 deformated_value, fullname);
4245 else if (action == 1)
4248 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4249 returned, 10, fullname);
4250 if (returned[0] == 0)
4252 TRACE("Adding value %s to section %s in %s\n",
4253 debugstr_w(deformated_key), debugstr_w(deformated_section),
4254 debugstr_w(fullname));
4256 WritePrivateProfileStringW(deformated_section, deformated_key,
4257 deformated_value, fullname);
4260 else if (action == 3)
4261 FIXME("Append to existing section not yet implemented\n");
4263 uirow = MSI_CreateRecord(4);
4264 MSI_RecordSetStringW(uirow,1,identifier);
4265 MSI_RecordSetStringW(uirow,2,deformated_section);
4266 MSI_RecordSetStringW(uirow,3,deformated_key);
4267 MSI_RecordSetStringW(uirow,4,deformated_value);
4268 ui_actiondata(package,szWriteIniValues,uirow);
4269 msiobj_release( &uirow->hdr );
4272 msi_free(deformated_key);
4273 msi_free(deformated_value);
4274 msi_free(deformated_section);
4275 return ERROR_SUCCESS;
4278 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4282 static const WCHAR ExecSeqQuery[] =
4283 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4284 '`','I','n','i','F','i','l','e','`',0};
4286 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4287 if (rc != ERROR_SUCCESS)
4289 TRACE("no IniFile table\n");
4290 return ERROR_SUCCESS;
4293 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4294 msiobj_release(&view->hdr);
4298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4300 MSIPACKAGE *package = param;
4301 LPCWSTR component, section, key, value, identifier;
4302 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4307 component = MSI_RecordGetString( row, 8 );
4308 comp = get_loaded_component( package, component );
4310 return ERROR_SUCCESS;
4314 TRACE("component is disabled\n");
4315 return ERROR_SUCCESS;
4318 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4320 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4321 comp->Action = comp->Installed;
4322 return ERROR_SUCCESS;
4324 comp->Action = INSTALLSTATE_ABSENT;
4326 identifier = MSI_RecordGetString( row, 1 );
4327 section = MSI_RecordGetString( row, 4 );
4328 key = MSI_RecordGetString( row, 5 );
4329 value = MSI_RecordGetString( row, 6 );
4330 action = MSI_RecordGetInteger( row, 7 );
4332 deformat_string( package, section, &deformated_section );
4333 deformat_string( package, key, &deformated_key );
4334 deformat_string( package, value, &deformated_value );
4336 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4338 filename = get_ini_file_name( package, row );
4340 TRACE("Removing key %s from section %s in %s\n",
4341 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4343 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4345 WARN("Unable to remove key %u\n", GetLastError());
4347 msi_free( filename );
4350 FIXME("Unsupported action %d\n", action);
4353 uirow = MSI_CreateRecord( 4 );
4354 MSI_RecordSetStringW( uirow, 1, identifier );
4355 MSI_RecordSetStringW( uirow, 2, deformated_section );
4356 MSI_RecordSetStringW( uirow, 3, deformated_key );
4357 MSI_RecordSetStringW( uirow, 4, deformated_value );
4358 ui_actiondata( package, szRemoveIniValues, uirow );
4359 msiobj_release( &uirow->hdr );
4361 msi_free( deformated_key );
4362 msi_free( deformated_value );
4363 msi_free( deformated_section );
4364 return ERROR_SUCCESS;
4367 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4369 MSIPACKAGE *package = param;
4370 LPCWSTR component, section, key, value, identifier;
4371 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4376 component = MSI_RecordGetString( row, 8 );
4377 comp = get_loaded_component( package, component );
4379 return ERROR_SUCCESS;
4383 TRACE("component is disabled\n");
4384 return ERROR_SUCCESS;
4387 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4389 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4390 comp->Action = comp->Installed;
4391 return ERROR_SUCCESS;
4393 comp->Action = INSTALLSTATE_LOCAL;
4395 identifier = MSI_RecordGetString( row, 1 );
4396 section = MSI_RecordGetString( row, 4 );
4397 key = MSI_RecordGetString( row, 5 );
4398 value = MSI_RecordGetString( row, 6 );
4399 action = MSI_RecordGetInteger( row, 7 );
4401 deformat_string( package, section, &deformated_section );
4402 deformat_string( package, key, &deformated_key );
4403 deformat_string( package, value, &deformated_value );
4405 if (action == msidbIniFileActionRemoveLine)
4407 filename = get_ini_file_name( package, row );
4409 TRACE("Removing key %s from section %s in %s\n",
4410 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4412 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4414 WARN("Unable to remove key %u\n", GetLastError());
4416 msi_free( filename );
4419 FIXME("Unsupported action %d\n", action);
4421 uirow = MSI_CreateRecord( 4 );
4422 MSI_RecordSetStringW( uirow, 1, identifier );
4423 MSI_RecordSetStringW( uirow, 2, deformated_section );
4424 MSI_RecordSetStringW( uirow, 3, deformated_key );
4425 MSI_RecordSetStringW( uirow, 4, deformated_value );
4426 ui_actiondata( package, szRemoveIniValues, uirow );
4427 msiobj_release( &uirow->hdr );
4429 msi_free( deformated_key );
4430 msi_free( deformated_value );
4431 msi_free( deformated_section );
4432 return ERROR_SUCCESS;
4435 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4439 static const WCHAR query[] =
4440 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4441 '`','I','n','i','F','i','l','e','`',0};
4442 static const WCHAR remove_query[] =
4443 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4444 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4446 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4447 if (rc == ERROR_SUCCESS)
4449 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4450 msiobj_release( &view->hdr );
4451 if (rc != ERROR_SUCCESS)
4455 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4456 if (rc == ERROR_SUCCESS)
4458 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4459 msiobj_release( &view->hdr );
4460 if (rc != ERROR_SUCCESS)
4464 return ERROR_SUCCESS;
4467 static void register_dll( const WCHAR *dll, BOOL unregister )
4471 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4474 HRESULT (WINAPI *func_ptr)( void );
4475 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4477 func_ptr = (void *)GetProcAddress( hmod, func );
4480 HRESULT hr = func_ptr();
4482 WARN("failed to register dll 0x%08x\n", hr);
4485 WARN("entry point %s not found\n", func);
4486 FreeLibrary( hmod );
4489 WARN("failed to load library %u\n", GetLastError());
4492 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4494 MSIPACKAGE *package = param;
4499 filename = MSI_RecordGetString(row,1);
4500 file = get_loaded_file( package, filename );
4504 ERR("Unable to find file id %s\n",debugstr_w(filename));
4505 return ERROR_SUCCESS;
4508 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4510 register_dll( file->TargetPath, FALSE );
4512 uirow = MSI_CreateRecord( 2 );
4513 MSI_RecordSetStringW( uirow, 1, filename );
4514 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4515 ui_actiondata( package, szSelfRegModules, uirow );
4516 msiobj_release( &uirow->hdr );
4518 return ERROR_SUCCESS;
4521 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4525 static const WCHAR ExecSeqQuery[] =
4526 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4527 '`','S','e','l','f','R','e','g','`',0};
4529 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4530 if (rc != ERROR_SUCCESS)
4532 TRACE("no SelfReg table\n");
4533 return ERROR_SUCCESS;
4536 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4537 msiobj_release(&view->hdr);
4539 return ERROR_SUCCESS;
4542 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4544 MSIPACKAGE *package = param;
4549 filename = MSI_RecordGetString( row, 1 );
4550 file = get_loaded_file( package, filename );
4554 ERR("Unable to find file id %s\n", debugstr_w(filename));
4555 return ERROR_SUCCESS;
4558 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4560 register_dll( file->TargetPath, TRUE );
4562 uirow = MSI_CreateRecord( 2 );
4563 MSI_RecordSetStringW( uirow, 1, filename );
4564 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4565 ui_actiondata( package, szSelfUnregModules, uirow );
4566 msiobj_release( &uirow->hdr );
4568 return ERROR_SUCCESS;
4571 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4575 static const WCHAR query[] =
4576 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4577 '`','S','e','l','f','R','e','g','`',0};
4579 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4580 if (rc != ERROR_SUCCESS)
4582 TRACE("no SelfReg table\n");
4583 return ERROR_SUCCESS;
4586 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4587 msiobj_release( &view->hdr );
4589 return ERROR_SUCCESS;
4592 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4594 MSIFEATURE *feature;
4596 HKEY hkey = NULL, userdata = NULL;
4598 if (!msi_check_publish(package))
4599 return ERROR_SUCCESS;
4601 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4603 if (rc != ERROR_SUCCESS)
4606 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4608 if (rc != ERROR_SUCCESS)
4611 /* here the guids are base 85 encoded */
4612 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4618 BOOL absent = FALSE;
4621 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4622 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4623 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4626 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4630 if (feature->Feature_Parent)
4631 size += strlenW( feature->Feature_Parent )+2;
4633 data = msi_alloc(size * sizeof(WCHAR));
4636 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4638 MSICOMPONENT* component = cl->component;
4642 if (component->ComponentId)
4644 TRACE("From %s\n",debugstr_w(component->ComponentId));
4645 CLSIDFromString(component->ComponentId, &clsid);
4646 encode_base85_guid(&clsid,buf);
4647 TRACE("to %s\n",debugstr_w(buf));
4652 if (feature->Feature_Parent)
4654 static const WCHAR sep[] = {'\2',0};
4656 strcatW(data,feature->Feature_Parent);
4659 msi_reg_set_val_str( userdata, feature->Feature, data );
4663 if (feature->Feature_Parent)
4664 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4667 size += sizeof(WCHAR);
4668 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4669 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4673 size += 2*sizeof(WCHAR);
4674 data = msi_alloc(size);
4677 if (feature->Feature_Parent)
4678 strcpyW( &data[1], feature->Feature_Parent );
4679 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4685 uirow = MSI_CreateRecord( 1 );
4686 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4687 ui_actiondata( package, szPublishFeatures, uirow);
4688 msiobj_release( &uirow->hdr );
4689 /* FIXME: call ui_progress? */
4694 RegCloseKey(userdata);
4698 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4704 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4706 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4708 if (r == ERROR_SUCCESS)
4710 RegDeleteValueW(hkey, feature->Feature);
4714 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4716 if (r == ERROR_SUCCESS)
4718 RegDeleteValueW(hkey, feature->Feature);
4722 uirow = MSI_CreateRecord( 1 );
4723 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4724 ui_actiondata( package, szUnpublishFeatures, uirow );
4725 msiobj_release( &uirow->hdr );
4727 return ERROR_SUCCESS;
4730 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4732 MSIFEATURE *feature;
4734 if (!msi_check_unpublish(package))
4735 return ERROR_SUCCESS;
4737 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4739 msi_unpublish_feature(package, feature);
4742 return ERROR_SUCCESS;
4745 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4749 WCHAR date[9], *val, *buffer;
4750 const WCHAR *prop, *key;
4752 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4753 static const WCHAR szWindowsInstaller[] =
4754 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4755 static const WCHAR modpath_fmt[] =
4756 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4757 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4758 static const WCHAR szModifyPath[] =
4759 {'M','o','d','i','f','y','P','a','t','h',0};
4760 static const WCHAR szUninstallString[] =
4761 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4762 static const WCHAR szEstimatedSize[] =
4763 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4764 static const WCHAR szProductLanguage[] =
4765 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4766 static const WCHAR szProductVersion[] =
4767 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4768 static const WCHAR szDisplayVersion[] =
4769 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4770 static const WCHAR szInstallSource[] =
4771 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4772 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4773 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4774 static const WCHAR szAuthorizedCDFPrefix[] =
4775 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4776 static const WCHAR szARPCONTACT[] =
4777 {'A','R','P','C','O','N','T','A','C','T',0};
4778 static const WCHAR szContact[] =
4779 {'C','o','n','t','a','c','t',0};
4780 static const WCHAR szARPCOMMENTS[] =
4781 {'A','R','P','C','O','M','M','E','N','T','S',0};
4782 static const WCHAR szComments[] =
4783 {'C','o','m','m','e','n','t','s',0};
4784 static const WCHAR szProductName[] =
4785 {'P','r','o','d','u','c','t','N','a','m','e',0};
4786 static const WCHAR szDisplayName[] =
4787 {'D','i','s','p','l','a','y','N','a','m','e',0};
4788 static const WCHAR szARPHELPLINK[] =
4789 {'A','R','P','H','E','L','P','L','I','N','K',0};
4790 static const WCHAR szHelpLink[] =
4791 {'H','e','l','p','L','i','n','k',0};
4792 static const WCHAR szARPHELPTELEPHONE[] =
4793 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4794 static const WCHAR szHelpTelephone[] =
4795 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4796 static const WCHAR szARPINSTALLLOCATION[] =
4797 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4798 static const WCHAR szInstallLocation[] =
4799 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4800 static const WCHAR szManufacturer[] =
4801 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4802 static const WCHAR szPublisher[] =
4803 {'P','u','b','l','i','s','h','e','r',0};
4804 static const WCHAR szARPREADME[] =
4805 {'A','R','P','R','E','A','D','M','E',0};
4806 static const WCHAR szReadme[] =
4807 {'R','e','a','d','M','e',0};
4808 static const WCHAR szARPSIZE[] =
4809 {'A','R','P','S','I','Z','E',0};
4810 static const WCHAR szSize[] =
4811 {'S','i','z','e',0};
4812 static const WCHAR szARPURLINFOABOUT[] =
4813 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4814 static const WCHAR szURLInfoAbout[] =
4815 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4816 static const WCHAR szARPURLUPDATEINFO[] =
4817 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4818 static const WCHAR szURLUpdateInfo[] =
4819 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4821 static const WCHAR *propval[] = {
4822 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4823 szARPCONTACT, szContact,
4824 szARPCOMMENTS, szComments,
4825 szProductName, szDisplayName,
4826 szARPHELPLINK, szHelpLink,
4827 szARPHELPTELEPHONE, szHelpTelephone,
4828 szARPINSTALLLOCATION, szInstallLocation,
4829 cszSourceDir, szInstallSource,
4830 szManufacturer, szPublisher,
4831 szARPREADME, szReadme,
4833 szARPURLINFOABOUT, szURLInfoAbout,
4834 szARPURLUPDATEINFO, szURLUpdateInfo,
4837 const WCHAR **p = propval;
4843 val = msi_dup_property(package->db, prop);
4844 msi_reg_set_val_str(hkey, key, val);
4848 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4850 size = deformat_string(package, modpath_fmt, &buffer);
4851 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4852 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4855 /* FIXME: Write real Estimated Size when we have it */
4856 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4858 GetLocalTime(&systime);
4859 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4860 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4862 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4863 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4865 buffer = msi_dup_property(package->db, szProductVersion);
4866 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4869 DWORD verdword = msi_version_str_to_dword(buffer);
4871 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4872 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4873 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4877 return ERROR_SUCCESS;
4880 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4882 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4884 LPWSTR upgrade_code;
4889 /* FIXME: also need to publish if the product is in advertise mode */
4890 if (!msi_check_publish(package))
4891 return ERROR_SUCCESS;
4893 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4894 if (rc != ERROR_SUCCESS)
4897 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4898 NULL, &props, TRUE);
4899 if (rc != ERROR_SUCCESS)
4902 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4903 msi_free( package->db->localfile );
4904 package->db->localfile = NULL;
4906 rc = msi_publish_install_properties(package, hkey);
4907 if (rc != ERROR_SUCCESS)
4910 rc = msi_publish_install_properties(package, props);
4911 if (rc != ERROR_SUCCESS)
4914 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4917 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4918 squash_guid(package->ProductCode, squashed_pc);
4919 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4920 RegCloseKey(upgrade);
4921 msi_free(upgrade_code);
4925 uirow = MSI_CreateRecord( 1 );
4926 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4927 ui_actiondata( package, szRegisterProduct, uirow );
4928 msiobj_release( &uirow->hdr );
4931 return ERROR_SUCCESS;
4934 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4936 return execute_script(package,INSTALL_SCRIPT);
4939 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4941 WCHAR *upgrade, **features;
4942 BOOL full_uninstall = TRUE;
4943 MSIFEATURE *feature;
4944 MSIPATCHINFO *patch;
4946 static const WCHAR szUpgradeCode[] =
4947 {'U','p','g','r','a','d','e','C','o','d','e',0};
4949 features = msi_split_string(remove, ',');
4952 ERR("REMOVE feature list is empty!\n");
4953 return ERROR_FUNCTION_FAILED;
4956 if (!strcmpW( features[0], szAll ))
4957 full_uninstall = TRUE;
4960 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4962 if (feature->Action != INSTALLSTATE_ABSENT)
4963 full_uninstall = FALSE;
4968 if (!full_uninstall)
4969 return ERROR_SUCCESS;
4971 MSIREG_DeleteProductKey(package->ProductCode);
4972 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4973 MSIREG_DeleteUninstallKey(package);
4975 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4977 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4978 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4982 MSIREG_DeleteUserProductKey(package->ProductCode);
4983 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4986 upgrade = msi_dup_property(package->db, szUpgradeCode);
4989 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4993 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4995 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4998 return ERROR_SUCCESS;
5001 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5006 /* turn off scheduling */
5007 package->script->CurrentlyScripting= FALSE;
5009 /* first do the same as an InstallExecute */
5010 rc = ACTION_InstallExecute(package);
5011 if (rc != ERROR_SUCCESS)
5014 /* then handle Commit Actions */
5015 rc = execute_script(package,COMMIT_SCRIPT);
5016 if (rc != ERROR_SUCCESS)
5019 remove = msi_dup_property(package->db, szRemove);
5021 rc = msi_unpublish_product(package, remove);
5027 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5029 static const WCHAR RunOnce[] = {
5030 'S','o','f','t','w','a','r','e','\\',
5031 'M','i','c','r','o','s','o','f','t','\\',
5032 'W','i','n','d','o','w','s','\\',
5033 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5034 'R','u','n','O','n','c','e',0};
5035 static const WCHAR InstallRunOnce[] = {
5036 'S','o','f','t','w','a','r','e','\\',
5037 'M','i','c','r','o','s','o','f','t','\\',
5038 'W','i','n','d','o','w','s','\\',
5039 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5040 'I','n','s','t','a','l','l','e','r','\\',
5041 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5043 static const WCHAR msiexec_fmt[] = {
5045 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5046 '\"','%','s','\"',0};
5047 static const WCHAR install_fmt[] = {
5048 '/','I',' ','\"','%','s','\"',' ',
5049 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5050 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5051 WCHAR buffer[256], sysdir[MAX_PATH];
5053 WCHAR squished_pc[100];
5055 squash_guid(package->ProductCode,squished_pc);
5057 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5058 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5059 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5062 msi_reg_set_val_str( hkey, squished_pc, buffer );
5065 TRACE("Reboot command %s\n",debugstr_w(buffer));
5067 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5068 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5070 msi_reg_set_val_str( hkey, squished_pc, buffer );
5073 return ERROR_INSTALL_SUSPEND;
5076 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5082 * We are currently doing what should be done here in the top level Install
5083 * however for Administrative and uninstalls this step will be needed
5085 if (!package->PackagePath)
5086 return ERROR_SUCCESS;
5088 msi_set_sourcedir_props(package, TRUE);
5090 attrib = GetFileAttributesW(package->db->path);
5091 if (attrib == INVALID_FILE_ATTRIBUTES)
5097 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5098 package->Context, MSICODE_PRODUCT,
5099 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5100 if (rc == ERROR_MORE_DATA)
5102 prompt = msi_alloc(size * sizeof(WCHAR));
5103 MsiSourceListGetInfoW(package->ProductCode, NULL,
5104 package->Context, MSICODE_PRODUCT,
5105 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5108 prompt = strdupW(package->db->path);
5110 msg = generate_error_string(package,1302,1,prompt);
5111 while(attrib == INVALID_FILE_ATTRIBUTES)
5113 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5116 rc = ERROR_INSTALL_USEREXIT;
5119 attrib = GetFileAttributesW(package->db->path);
5125 return ERROR_SUCCESS;
5130 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5133 LPWSTR buffer, productid = NULL;
5134 UINT i, rc = ERROR_SUCCESS;
5137 static const WCHAR szPropKeys[][80] =
5139 {'P','r','o','d','u','c','t','I','D',0},
5140 {'U','S','E','R','N','A','M','E',0},
5141 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5145 static const WCHAR szRegKeys[][80] =
5147 {'P','r','o','d','u','c','t','I','D',0},
5148 {'R','e','g','O','w','n','e','r',0},
5149 {'R','e','g','C','o','m','p','a','n','y',0},
5153 if (msi_check_unpublish(package))
5155 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5159 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5163 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5165 if (rc != ERROR_SUCCESS)
5168 for( i = 0; szPropKeys[i][0]; i++ )
5170 buffer = msi_dup_property( package->db, szPropKeys[i] );
5171 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5176 uirow = MSI_CreateRecord( 1 );
5177 MSI_RecordSetStringW( uirow, 1, productid );
5178 ui_actiondata( package, szRegisterUser, uirow );
5179 msiobj_release( &uirow->hdr );
5181 msi_free(productid);
5187 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5191 package->script->InWhatSequence |= SEQUENCE_EXEC;
5192 rc = ACTION_ProcessExecSequence(package,FALSE);
5197 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5199 MSIPACKAGE *package = param;
5200 LPCWSTR compgroupid, component, feature, qualifier, text;
5201 LPWSTR advertise = NULL, output = NULL;
5209 feature = MSI_RecordGetString(rec, 5);
5210 feat = get_loaded_feature(package, feature);
5212 return ERROR_SUCCESS;
5214 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5215 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5216 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5218 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5219 feat->Action = feat->Installed;
5220 return ERROR_SUCCESS;
5223 component = MSI_RecordGetString(rec, 3);
5224 comp = get_loaded_component(package, component);
5226 return ERROR_SUCCESS;
5228 compgroupid = MSI_RecordGetString(rec,1);
5229 qualifier = MSI_RecordGetString(rec,2);
5231 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5232 if (rc != ERROR_SUCCESS)
5235 text = MSI_RecordGetString(rec,4);
5236 advertise = create_component_advertise_string(package, comp, feature);
5238 sz = strlenW(advertise);
5241 sz += lstrlenW(text);
5244 sz *= sizeof(WCHAR);
5246 output = msi_alloc_zero(sz);
5247 strcpyW(output,advertise);
5248 msi_free(advertise);
5251 strcatW(output,text);
5253 msi_reg_set_val_multi_str( hkey, qualifier, output );
5260 uirow = MSI_CreateRecord( 2 );
5261 MSI_RecordSetStringW( uirow, 1, compgroupid );
5262 MSI_RecordSetStringW( uirow, 2, qualifier);
5263 ui_actiondata( package, szPublishComponents, uirow);
5264 msiobj_release( &uirow->hdr );
5265 /* FIXME: call ui_progress? */
5271 * At present I am ignorning the advertised components part of this and only
5272 * focusing on the qualified component sets
5274 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5278 static const WCHAR ExecSeqQuery[] =
5279 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5280 '`','P','u','b','l','i','s','h',
5281 'C','o','m','p','o','n','e','n','t','`',0};
5283 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5284 if (rc != ERROR_SUCCESS)
5285 return ERROR_SUCCESS;
5287 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5288 msiobj_release(&view->hdr);
5293 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5295 static const WCHAR szInstallerComponents[] = {
5296 'S','o','f','t','w','a','r','e','\\',
5297 'M','i','c','r','o','s','o','f','t','\\',
5298 'I','n','s','t','a','l','l','e','r','\\',
5299 'C','o','m','p','o','n','e','n','t','s','\\',0};
5301 MSIPACKAGE *package = param;
5302 LPCWSTR compgroupid, component, feature, qualifier;
5306 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5309 feature = MSI_RecordGetString( rec, 5 );
5310 feat = get_loaded_feature( package, feature );
5312 return ERROR_SUCCESS;
5314 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5316 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5317 feat->Action = feat->Installed;
5318 return ERROR_SUCCESS;
5321 component = MSI_RecordGetString( rec, 3 );
5322 comp = get_loaded_component( package, component );
5324 return ERROR_SUCCESS;
5326 compgroupid = MSI_RecordGetString( rec, 1 );
5327 qualifier = MSI_RecordGetString( rec, 2 );
5329 squash_guid( compgroupid, squashed );
5330 strcpyW( keypath, szInstallerComponents );
5331 strcatW( keypath, squashed );
5333 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5334 if (res != ERROR_SUCCESS)
5336 WARN("Unable to delete component key %d\n", res);
5339 uirow = MSI_CreateRecord( 2 );
5340 MSI_RecordSetStringW( uirow, 1, compgroupid );
5341 MSI_RecordSetStringW( uirow, 2, qualifier );
5342 ui_actiondata( package, szUnpublishComponents, uirow );
5343 msiobj_release( &uirow->hdr );
5345 return ERROR_SUCCESS;
5348 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5352 static const WCHAR query[] =
5353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5354 '`','P','u','b','l','i','s','h',
5355 'C','o','m','p','o','n','e','n','t','`',0};
5357 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5358 if (rc != ERROR_SUCCESS)
5359 return ERROR_SUCCESS;
5361 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5362 msiobj_release( &view->hdr );
5367 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5369 MSIPACKAGE *package = param;
5372 SC_HANDLE hscm, service = NULL;
5374 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5375 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5376 DWORD serv_type, start_type, err_control;
5377 SERVICE_DESCRIPTIONW sd = {NULL};
5379 static const WCHAR query[] =
5380 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5381 '`','C','o','m','p','o','n','e','n','t','`',' ',
5382 'W','H','E','R','E',' ',
5383 '`','C','o','m','p','o','n','e','n','t','`',' ',
5384 '=','\'','%','s','\'',0};
5386 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5389 ERR("Failed to open the SC Manager!\n");
5393 start_type = MSI_RecordGetInteger(rec, 5);
5394 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5397 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5398 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5399 serv_type = MSI_RecordGetInteger(rec, 4);
5400 err_control = MSI_RecordGetInteger(rec, 6);
5401 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5402 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5403 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5404 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5405 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5406 comp = MSI_RecordGetString(rec, 12);
5407 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5409 /* fetch the service path */
5410 row = MSI_QueryGetRecord(package->db, query, comp);
5413 ERR("Control query failed!\n");
5416 key = MSI_RecordGetString(row, 6);
5418 file = get_loaded_file(package, key);
5419 msiobj_release(&row->hdr);
5422 ERR("Failed to load the service file\n");
5426 if (!args || !args[0]) image_path = file->TargetPath;
5429 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5430 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5431 return ERROR_OUTOFMEMORY;
5433 strcpyW(image_path, file->TargetPath);
5434 strcatW(image_path, szSpace);
5435 strcatW(image_path, args);
5437 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5438 start_type, err_control, image_path, load_order,
5439 NULL, depends, serv_name, pass);
5443 if (GetLastError() != ERROR_SERVICE_EXISTS)
5444 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5446 else if (sd.lpDescription)
5448 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5449 WARN("failed to set service description %u\n", GetLastError());
5452 if (image_path != file->TargetPath) msi_free(image_path);
5454 CloseServiceHandle(service);
5455 CloseServiceHandle(hscm);
5458 msi_free(sd.lpDescription);
5459 msi_free(load_order);
5460 msi_free(serv_name);
5465 return ERROR_SUCCESS;
5468 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5472 static const WCHAR ExecSeqQuery[] =
5473 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5474 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5476 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5477 if (rc != ERROR_SUCCESS)
5478 return ERROR_SUCCESS;
5480 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5481 msiobj_release(&view->hdr);
5486 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5487 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5489 LPCWSTR *vector, *temp_vector;
5493 static const WCHAR separator[] = {'[','~',']',0};
5496 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5501 vector = msi_alloc(sizeof(LPWSTR));
5509 vector[*numargs - 1] = p;
5511 if ((q = strstrW(p, separator)))
5515 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5521 vector = temp_vector;
5530 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5532 MSIPACKAGE *package = param;
5535 SC_HANDLE scm = NULL, service = NULL;
5536 LPCWSTR component, *vector = NULL;
5537 LPWSTR name, args, display_name = NULL;
5538 DWORD event, numargs, len;
5539 UINT r = ERROR_FUNCTION_FAILED;
5541 component = MSI_RecordGetString(rec, 6);
5542 comp = get_loaded_component(package, component);
5544 return ERROR_SUCCESS;
5548 TRACE("component is disabled\n");
5549 return ERROR_SUCCESS;
5552 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5554 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5555 comp->Action = comp->Installed;
5556 return ERROR_SUCCESS;
5558 comp->Action = INSTALLSTATE_LOCAL;
5560 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5561 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5562 event = MSI_RecordGetInteger(rec, 3);
5564 if (!(event & msidbServiceControlEventStart))
5570 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5573 ERR("Failed to open the service control manager\n");
5578 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5579 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5581 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5582 GetServiceDisplayNameW( scm, name, display_name, &len );
5585 service = OpenServiceW(scm, name, SERVICE_START);
5588 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5592 vector = msi_service_args_to_vector(args, &numargs);
5594 if (!StartServiceW(service, numargs, vector) &&
5595 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5597 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5604 uirow = MSI_CreateRecord( 2 );
5605 MSI_RecordSetStringW( uirow, 1, display_name );
5606 MSI_RecordSetStringW( uirow, 2, name );
5607 ui_actiondata( package, szStartServices, uirow );
5608 msiobj_release( &uirow->hdr );
5610 CloseServiceHandle(service);
5611 CloseServiceHandle(scm);
5616 msi_free(display_name);
5620 static UINT ACTION_StartServices( MSIPACKAGE *package )
5625 static const WCHAR query[] = {
5626 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5627 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5629 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5630 if (rc != ERROR_SUCCESS)
5631 return ERROR_SUCCESS;
5633 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5634 msiobj_release(&view->hdr);
5639 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5641 DWORD i, needed, count;
5642 ENUM_SERVICE_STATUSW *dependencies;
5646 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5647 0, &needed, &count))
5650 if (GetLastError() != ERROR_MORE_DATA)
5653 dependencies = msi_alloc(needed);
5657 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5658 needed, &needed, &count))
5661 for (i = 0; i < count; i++)
5663 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5664 SERVICE_STOP | SERVICE_QUERY_STATUS);
5668 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5675 msi_free(dependencies);
5679 static UINT stop_service( LPCWSTR name )
5681 SC_HANDLE scm = NULL, service = NULL;
5682 SERVICE_STATUS status;
5683 SERVICE_STATUS_PROCESS ssp;
5686 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5689 WARN("Failed to open the SCM: %d\n", GetLastError());
5693 service = OpenServiceW(scm, name,
5695 SERVICE_QUERY_STATUS |
5696 SERVICE_ENUMERATE_DEPENDENTS);
5699 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5703 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5704 sizeof(SERVICE_STATUS_PROCESS), &needed))
5706 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5710 if (ssp.dwCurrentState == SERVICE_STOPPED)
5713 stop_service_dependents(scm, service);
5715 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5716 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5719 CloseServiceHandle(service);
5720 CloseServiceHandle(scm);
5722 return ERROR_SUCCESS;
5725 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5727 MSIPACKAGE *package = param;
5731 LPWSTR name = NULL, display_name = NULL;
5735 event = MSI_RecordGetInteger( rec, 3 );
5736 if (!(event & msidbServiceControlEventStop))
5737 return ERROR_SUCCESS;
5739 component = MSI_RecordGetString( rec, 6 );
5740 comp = get_loaded_component( package, component );
5742 return ERROR_SUCCESS;
5746 TRACE("component is disabled\n");
5747 return ERROR_SUCCESS;
5750 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5752 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5753 comp->Action = comp->Installed;
5754 return ERROR_SUCCESS;
5756 comp->Action = INSTALLSTATE_ABSENT;
5758 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5761 ERR("Failed to open the service control manager\n");
5766 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5767 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5769 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5770 GetServiceDisplayNameW( scm, name, display_name, &len );
5772 CloseServiceHandle( scm );
5774 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5775 stop_service( name );
5778 uirow = MSI_CreateRecord( 2 );
5779 MSI_RecordSetStringW( uirow, 1, display_name );
5780 MSI_RecordSetStringW( uirow, 2, name );
5781 ui_actiondata( package, szStopServices, uirow );
5782 msiobj_release( &uirow->hdr );
5785 msi_free( display_name );
5786 return ERROR_SUCCESS;
5789 static UINT ACTION_StopServices( MSIPACKAGE *package )
5794 static const WCHAR query[] = {
5795 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5796 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5798 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5799 if (rc != ERROR_SUCCESS)
5800 return ERROR_SUCCESS;
5802 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5803 msiobj_release(&view->hdr);
5808 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5810 MSIPACKAGE *package = param;
5814 LPWSTR name = NULL, display_name = NULL;
5816 SC_HANDLE scm = NULL, service = NULL;
5818 event = MSI_RecordGetInteger( rec, 3 );
5819 if (!(event & msidbServiceControlEventDelete))
5820 return ERROR_SUCCESS;
5822 component = MSI_RecordGetString(rec, 6);
5823 comp = get_loaded_component(package, component);
5825 return ERROR_SUCCESS;
5829 TRACE("component is disabled\n");
5830 return ERROR_SUCCESS;
5833 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5835 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5836 comp->Action = comp->Installed;
5837 return ERROR_SUCCESS;
5839 comp->Action = INSTALLSTATE_ABSENT;
5841 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5842 stop_service( name );
5844 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5847 WARN("Failed to open the SCM: %d\n", GetLastError());
5852 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5853 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5855 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5856 GetServiceDisplayNameW( scm, name, display_name, &len );
5859 service = OpenServiceW( scm, name, DELETE );
5862 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5866 if (!DeleteService( service ))
5867 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5870 uirow = MSI_CreateRecord( 2 );
5871 MSI_RecordSetStringW( uirow, 1, display_name );
5872 MSI_RecordSetStringW( uirow, 2, name );
5873 ui_actiondata( package, szDeleteServices, uirow );
5874 msiobj_release( &uirow->hdr );
5876 CloseServiceHandle( service );
5877 CloseServiceHandle( scm );
5879 msi_free( display_name );
5881 return ERROR_SUCCESS;
5884 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5889 static const WCHAR query[] = {
5890 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5891 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5893 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5894 if (rc != ERROR_SUCCESS)
5895 return ERROR_SUCCESS;
5897 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5898 msiobj_release( &view->hdr );
5903 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5907 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5909 if (!strcmpW( file->File, filename ))
5916 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5918 MSIPACKAGE *package = param;
5919 LPWSTR driver, driver_path, ptr;
5920 WCHAR outpath[MAX_PATH];
5921 MSIFILE *driver_file = NULL, *setup_file = NULL;
5923 LPCWSTR desc, file_key;
5925 UINT r = ERROR_SUCCESS;
5927 static const WCHAR driver_fmt[] = {
5928 'D','r','i','v','e','r','=','%','s',0};
5929 static const WCHAR setup_fmt[] = {
5930 'S','e','t','u','p','=','%','s',0};
5931 static const WCHAR usage_fmt[] = {
5932 'F','i','l','e','U','s','a','g','e','=','1',0};
5934 desc = MSI_RecordGetString(rec, 3);
5936 file_key = MSI_RecordGetString( rec, 4 );
5937 if (file_key) driver_file = msi_find_file( package, file_key );
5939 file_key = MSI_RecordGetString( rec, 5 );
5940 if (file_key) setup_file = msi_find_file( package, file_key );
5944 ERR("ODBC Driver entry not found!\n");
5945 return ERROR_FUNCTION_FAILED;
5948 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5950 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5951 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5953 driver = msi_alloc(len * sizeof(WCHAR));
5955 return ERROR_OUTOFMEMORY;
5958 lstrcpyW(ptr, desc);
5959 ptr += lstrlenW(ptr) + 1;
5961 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5966 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5970 lstrcpyW(ptr, usage_fmt);
5971 ptr += lstrlenW(ptr) + 1;
5974 driver_path = strdupW(driver_file->TargetPath);
5975 ptr = strrchrW(driver_path, '\\');
5976 if (ptr) *ptr = '\0';
5978 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5979 NULL, ODBC_INSTALL_COMPLETE, &usage))
5981 ERR("Failed to install SQL driver!\n");
5982 r = ERROR_FUNCTION_FAILED;
5985 uirow = MSI_CreateRecord( 5 );
5986 MSI_RecordSetStringW( uirow, 1, desc );
5987 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5988 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5989 ui_actiondata( package, szInstallODBC, uirow );
5990 msiobj_release( &uirow->hdr );
5993 msi_free(driver_path);
5998 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6000 MSIPACKAGE *package = param;
6001 LPWSTR translator, translator_path, ptr;
6002 WCHAR outpath[MAX_PATH];
6003 MSIFILE *translator_file = NULL, *setup_file = NULL;
6005 LPCWSTR desc, file_key;
6007 UINT r = ERROR_SUCCESS;
6009 static const WCHAR translator_fmt[] = {
6010 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6011 static const WCHAR setup_fmt[] = {
6012 'S','e','t','u','p','=','%','s',0};
6014 desc = MSI_RecordGetString(rec, 3);
6016 file_key = MSI_RecordGetString( rec, 4 );
6017 if (file_key) translator_file = msi_find_file( package, file_key );
6019 file_key = MSI_RecordGetString( rec, 5 );
6020 if (file_key) setup_file = msi_find_file( package, file_key );
6022 if (!translator_file)
6024 ERR("ODBC Translator entry not found!\n");
6025 return ERROR_FUNCTION_FAILED;
6028 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6030 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6032 translator = msi_alloc(len * sizeof(WCHAR));
6034 return ERROR_OUTOFMEMORY;
6037 lstrcpyW(ptr, desc);
6038 ptr += lstrlenW(ptr) + 1;
6040 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6045 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6050 translator_path = strdupW(translator_file->TargetPath);
6051 ptr = strrchrW(translator_path, '\\');
6052 if (ptr) *ptr = '\0';
6054 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6055 NULL, ODBC_INSTALL_COMPLETE, &usage))
6057 ERR("Failed to install SQL translator!\n");
6058 r = ERROR_FUNCTION_FAILED;
6061 uirow = MSI_CreateRecord( 5 );
6062 MSI_RecordSetStringW( uirow, 1, desc );
6063 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6064 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6065 ui_actiondata( package, szInstallODBC, uirow );
6066 msiobj_release( &uirow->hdr );
6068 msi_free(translator);
6069 msi_free(translator_path);
6074 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6076 MSIPACKAGE *package = param;
6078 LPCWSTR desc, driver;
6079 WORD request = ODBC_ADD_SYS_DSN;
6082 UINT r = ERROR_SUCCESS;
6085 static const WCHAR attrs_fmt[] = {
6086 'D','S','N','=','%','s',0 };
6088 desc = MSI_RecordGetString(rec, 3);
6089 driver = MSI_RecordGetString(rec, 4);
6090 registration = MSI_RecordGetInteger(rec, 5);
6092 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6093 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6095 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6096 attrs = msi_alloc(len * sizeof(WCHAR));
6098 return ERROR_OUTOFMEMORY;
6100 len = sprintfW(attrs, attrs_fmt, desc);
6103 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6105 ERR("Failed to install SQL data source!\n");
6106 r = ERROR_FUNCTION_FAILED;
6109 uirow = MSI_CreateRecord( 5 );
6110 MSI_RecordSetStringW( uirow, 1, desc );
6111 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6112 MSI_RecordSetInteger( uirow, 3, request );
6113 ui_actiondata( package, szInstallODBC, uirow );
6114 msiobj_release( &uirow->hdr );
6121 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6126 static const WCHAR driver_query[] = {
6127 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6128 'O','D','B','C','D','r','i','v','e','r',0 };
6130 static const WCHAR translator_query[] = {
6131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6132 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6134 static const WCHAR source_query[] = {
6135 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6136 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6138 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6139 if (rc != ERROR_SUCCESS)
6140 return ERROR_SUCCESS;
6142 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6143 msiobj_release(&view->hdr);
6145 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6146 if (rc != ERROR_SUCCESS)
6147 return ERROR_SUCCESS;
6149 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6150 msiobj_release(&view->hdr);
6152 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6153 if (rc != ERROR_SUCCESS)
6154 return ERROR_SUCCESS;
6156 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6157 msiobj_release(&view->hdr);
6162 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6164 MSIPACKAGE *package = param;
6169 desc = MSI_RecordGetString( rec, 3 );
6170 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6172 WARN("Failed to remove ODBC driver\n");
6176 FIXME("Usage count reached 0\n");
6179 uirow = MSI_CreateRecord( 2 );
6180 MSI_RecordSetStringW( uirow, 1, desc );
6181 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6182 ui_actiondata( package, szRemoveODBC, uirow );
6183 msiobj_release( &uirow->hdr );
6185 return ERROR_SUCCESS;
6188 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6190 MSIPACKAGE *package = param;
6195 desc = MSI_RecordGetString( rec, 3 );
6196 if (!SQLRemoveTranslatorW( desc, &usage ))
6198 WARN("Failed to remove ODBC translator\n");
6202 FIXME("Usage count reached 0\n");
6205 uirow = MSI_CreateRecord( 2 );
6206 MSI_RecordSetStringW( uirow, 1, desc );
6207 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6208 ui_actiondata( package, szRemoveODBC, uirow );
6209 msiobj_release( &uirow->hdr );
6211 return ERROR_SUCCESS;
6214 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6216 MSIPACKAGE *package = param;
6219 LPCWSTR desc, driver;
6220 WORD request = ODBC_REMOVE_SYS_DSN;
6224 static const WCHAR attrs_fmt[] = {
6225 'D','S','N','=','%','s',0 };
6227 desc = MSI_RecordGetString( rec, 3 );
6228 driver = MSI_RecordGetString( rec, 4 );
6229 registration = MSI_RecordGetInteger( rec, 5 );
6231 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6232 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6234 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6235 attrs = msi_alloc( len * sizeof(WCHAR) );
6237 return ERROR_OUTOFMEMORY;
6239 FIXME("Use ODBCSourceAttribute table\n");
6241 len = sprintfW( attrs, attrs_fmt, desc );
6244 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6246 WARN("Failed to remove ODBC data source\n");
6250 uirow = MSI_CreateRecord( 3 );
6251 MSI_RecordSetStringW( uirow, 1, desc );
6252 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6253 MSI_RecordSetInteger( uirow, 3, request );
6254 ui_actiondata( package, szRemoveODBC, uirow );
6255 msiobj_release( &uirow->hdr );
6257 return ERROR_SUCCESS;
6260 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6265 static const WCHAR driver_query[] = {
6266 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6267 'O','D','B','C','D','r','i','v','e','r',0 };
6269 static const WCHAR translator_query[] = {
6270 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6271 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6273 static const WCHAR source_query[] = {
6274 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6275 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6277 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6278 if (rc != ERROR_SUCCESS)
6279 return ERROR_SUCCESS;
6281 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6282 msiobj_release( &view->hdr );
6284 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6285 if (rc != ERROR_SUCCESS)
6286 return ERROR_SUCCESS;
6288 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6289 msiobj_release( &view->hdr );
6291 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6292 if (rc != ERROR_SUCCESS)
6293 return ERROR_SUCCESS;
6295 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6296 msiobj_release( &view->hdr );
6301 #define ENV_ACT_SETALWAYS 0x1
6302 #define ENV_ACT_SETABSENT 0x2
6303 #define ENV_ACT_REMOVE 0x4
6304 #define ENV_ACT_REMOVEMATCH 0x8
6306 #define ENV_MOD_MACHINE 0x20000000
6307 #define ENV_MOD_APPEND 0x40000000
6308 #define ENV_MOD_PREFIX 0x80000000
6309 #define ENV_MOD_MASK 0xC0000000
6311 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6313 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6315 LPCWSTR cptr = *name;
6317 static const WCHAR prefix[] = {'[','~',']',0};
6318 static const int prefix_len = 3;
6324 *flags |= ENV_ACT_SETALWAYS;
6325 else if (*cptr == '+')
6326 *flags |= ENV_ACT_SETABSENT;
6327 else if (*cptr == '-')
6328 *flags |= ENV_ACT_REMOVE;
6329 else if (*cptr == '!')
6330 *flags |= ENV_ACT_REMOVEMATCH;
6331 else if (*cptr == '*')
6332 *flags |= ENV_MOD_MACHINE;
6342 ERR("Missing environment variable\n");
6343 return ERROR_FUNCTION_FAILED;
6348 LPCWSTR ptr = *value;
6349 if (!strncmpW(ptr, prefix, prefix_len))
6351 if (ptr[prefix_len] == szSemiColon[0])
6353 *flags |= ENV_MOD_APPEND;
6354 *value += lstrlenW(prefix);
6361 else if (lstrlenW(*value) >= prefix_len)
6363 ptr += lstrlenW(ptr) - prefix_len;
6364 if (!strcmpW( ptr, prefix ))
6366 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6368 *flags |= ENV_MOD_PREFIX;
6369 /* the "[~]" will be removed by deformat_string */;
6379 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6380 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6381 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6382 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6384 ERR("Invalid flags: %08x\n", *flags);
6385 return ERROR_FUNCTION_FAILED;
6389 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6391 return ERROR_SUCCESS;
6394 static UINT open_env_key( DWORD flags, HKEY *key )
6396 static const WCHAR user_env[] =
6397 {'E','n','v','i','r','o','n','m','e','n','t',0};
6398 static const WCHAR machine_env[] =
6399 {'S','y','s','t','e','m','\\',
6400 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6401 'C','o','n','t','r','o','l','\\',
6402 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6403 'E','n','v','i','r','o','n','m','e','n','t',0};
6408 if (flags & ENV_MOD_MACHINE)
6411 root = HKEY_LOCAL_MACHINE;
6416 root = HKEY_CURRENT_USER;
6419 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6420 if (res != ERROR_SUCCESS)
6422 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6423 return ERROR_FUNCTION_FAILED;
6426 return ERROR_SUCCESS;
6429 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6431 MSIPACKAGE *package = param;
6432 LPCWSTR name, value, component;
6433 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6434 DWORD flags, type, size;
6441 component = MSI_RecordGetString(rec, 4);
6442 comp = get_loaded_component(package, component);
6444 return ERROR_SUCCESS;
6448 TRACE("component is disabled\n");
6449 return ERROR_SUCCESS;
6452 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6454 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6455 comp->Action = comp->Installed;
6456 return ERROR_SUCCESS;
6458 comp->Action = INSTALLSTATE_LOCAL;
6460 name = MSI_RecordGetString(rec, 2);
6461 value = MSI_RecordGetString(rec, 3);
6463 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6465 res = env_parse_flags(&name, &value, &flags);
6466 if (res != ERROR_SUCCESS || !value)
6469 if (value && !deformat_string(package, value, &deformatted))
6471 res = ERROR_OUTOFMEMORY;
6475 value = deformatted;
6477 res = open_env_key( flags, &env );
6478 if (res != ERROR_SUCCESS)
6481 if (flags & ENV_MOD_MACHINE)
6482 action |= 0x20000000;
6486 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6487 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6488 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6491 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6495 /* Nothing to do. */
6498 res = ERROR_SUCCESS;
6502 /* If we are appending but the string was empty, strip ; */
6503 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6505 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6506 newval = strdupW(value);
6509 res = ERROR_OUTOFMEMORY;
6517 /* Contrary to MSDN, +-variable to [~];path works */
6518 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6520 res = ERROR_SUCCESS;
6524 data = msi_alloc(size);
6528 return ERROR_OUTOFMEMORY;
6531 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6532 if (res != ERROR_SUCCESS)
6535 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6538 res = RegDeleteValueW(env, name);
6539 if (res != ERROR_SUCCESS)
6540 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6544 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6545 if (flags & ENV_MOD_MASK)
6549 if (flags & ENV_MOD_APPEND) multiplier++;
6550 if (flags & ENV_MOD_PREFIX) multiplier++;
6551 mod_size = lstrlenW(value) * multiplier;
6552 size += mod_size * sizeof(WCHAR);
6555 newval = msi_alloc(size);
6559 res = ERROR_OUTOFMEMORY;
6563 if (flags & ENV_MOD_PREFIX)
6565 lstrcpyW(newval, value);
6566 ptr = newval + lstrlenW(value);
6567 action |= 0x80000000;
6570 lstrcpyW(ptr, data);
6572 if (flags & ENV_MOD_APPEND)
6574 lstrcatW(newval, value);
6575 action |= 0x40000000;
6578 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6579 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6582 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6586 uirow = MSI_CreateRecord( 3 );
6587 MSI_RecordSetStringW( uirow, 1, name );
6588 MSI_RecordSetStringW( uirow, 2, newval );
6589 MSI_RecordSetInteger( uirow, 3, action );
6590 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6591 msiobj_release( &uirow->hdr );
6593 if (env) RegCloseKey(env);
6594 msi_free(deformatted);
6600 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6604 static const WCHAR ExecSeqQuery[] =
6605 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6606 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6607 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6608 if (rc != ERROR_SUCCESS)
6609 return ERROR_SUCCESS;
6611 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6612 msiobj_release(&view->hdr);
6617 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6619 MSIPACKAGE *package = param;
6620 LPCWSTR name, value, component;
6621 LPWSTR deformatted = NULL;
6630 component = MSI_RecordGetString( rec, 4 );
6631 comp = get_loaded_component( package, component );
6633 return ERROR_SUCCESS;
6637 TRACE("component is disabled\n");
6638 return ERROR_SUCCESS;
6641 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6643 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6644 comp->Action = comp->Installed;
6645 return ERROR_SUCCESS;
6647 comp->Action = INSTALLSTATE_ABSENT;
6649 name = MSI_RecordGetString( rec, 2 );
6650 value = MSI_RecordGetString( rec, 3 );
6652 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6654 r = env_parse_flags( &name, &value, &flags );
6655 if (r != ERROR_SUCCESS)
6658 if (!(flags & ENV_ACT_REMOVE))
6660 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6661 return ERROR_SUCCESS;
6664 if (value && !deformat_string( package, value, &deformatted ))
6665 return ERROR_OUTOFMEMORY;
6667 value = deformatted;
6669 r = open_env_key( flags, &env );
6670 if (r != ERROR_SUCCESS)
6676 if (flags & ENV_MOD_MACHINE)
6677 action |= 0x20000000;
6679 TRACE("Removing %s\n", debugstr_w(name));
6681 res = RegDeleteValueW( env, name );
6682 if (res != ERROR_SUCCESS)
6684 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6689 uirow = MSI_CreateRecord( 3 );
6690 MSI_RecordSetStringW( uirow, 1, name );
6691 MSI_RecordSetStringW( uirow, 2, value );
6692 MSI_RecordSetInteger( uirow, 3, action );
6693 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6694 msiobj_release( &uirow->hdr );
6696 if (env) RegCloseKey( env );
6697 msi_free( deformatted );
6701 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6705 static const WCHAR query[] =
6706 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6707 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6709 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6710 if (rc != ERROR_SUCCESS)
6711 return ERROR_SUCCESS;
6713 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6714 msiobj_release( &view->hdr );
6719 typedef struct tagMSIASSEMBLY
6722 MSICOMPONENT *component;
6723 MSIFEATURE *feature;
6727 LPWSTR display_name;
6732 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6734 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6735 LPVOID pvReserved, HMODULE *phModDll);
6737 static BOOL init_functionpointers(void)
6743 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6745 hmscoree = LoadLibraryA("mscoree.dll");
6748 WARN("mscoree.dll not available\n");
6752 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6753 if (!pLoadLibraryShim)
6755 WARN("LoadLibraryShim not available\n");
6756 FreeLibrary(hmscoree);
6760 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6763 WARN("fusion.dll not available\n");
6764 FreeLibrary(hmscoree);
6768 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6770 FreeLibrary(hmscoree);
6774 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6777 IAssemblyCache *cache;
6780 UINT r = ERROR_FUNCTION_FAILED;
6782 TRACE("installing assembly: %s\n", debugstr_w(path));
6784 uirow = MSI_CreateRecord( 2 );
6785 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6786 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6787 msiobj_release( &uirow->hdr );
6789 if (assembly->feature)
6790 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6792 if (assembly->manifest)
6793 FIXME("Manifest unhandled\n");
6795 if (assembly->application)
6797 FIXME("Assembly should be privately installed\n");
6798 return ERROR_SUCCESS;
6801 if (assembly->attributes == msidbAssemblyAttributesWin32)
6803 FIXME("Win32 assemblies not handled\n");
6804 return ERROR_SUCCESS;
6807 hr = pCreateAssemblyCache(&cache, 0);
6811 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6813 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6818 IAssemblyCache_Release(cache);
6822 typedef struct tagASSEMBLY_LIST
6824 MSIPACKAGE *package;
6825 IAssemblyCache *cache;
6826 struct list *assemblies;
6829 typedef struct tagASSEMBLY_NAME
6837 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6839 ASSEMBLY_NAME *asmname = param;
6840 LPCWSTR name = MSI_RecordGetString(rec, 2);
6841 LPWSTR val = msi_dup_record_field(rec, 3);
6843 static const WCHAR Name[] = {'N','a','m','e',0};
6844 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6845 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6846 static const WCHAR PublicKeyToken[] = {
6847 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6849 if (!strcmpiW(name, Name))
6850 asmname->name = val;
6851 else if (!strcmpiW(name, Version))
6852 asmname->version = val;
6853 else if (!strcmpiW(name, Culture))
6854 asmname->culture = val;
6855 else if (!strcmpiW(name, PublicKeyToken))
6856 asmname->pubkeytoken = val;
6860 return ERROR_SUCCESS;
6863 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6867 *size = lstrlenW(append) + 1;
6868 *str = msi_alloc((*size) * sizeof(WCHAR));
6869 lstrcpyW(*str, append);
6873 (*size) += lstrlenW(append);
6874 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6875 lstrcatW(*str, append);
6878 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6880 static const WCHAR separator[] = {',',' ',0};
6881 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6882 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6883 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6884 static const WCHAR query[] = {
6885 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6886 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6887 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6888 '=','\'','%','s','\'',0};
6891 LPWSTR display_name;
6895 display_name = NULL;
6896 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6898 r = MSI_OpenQuery( db, &view, query, comp->Component );
6899 if (r != ERROR_SUCCESS)
6902 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6903 msiobj_release( &view->hdr );
6907 ERR("No assembly name specified!\n");
6911 append_str( &display_name, &size, name.name );
6915 append_str( &display_name, &size, separator );
6916 append_str( &display_name, &size, Version );
6917 append_str( &display_name, &size, name.version );
6921 append_str( &display_name, &size, separator );
6922 append_str( &display_name, &size, Culture );
6923 append_str( &display_name, &size, name.culture );
6925 if (name.pubkeytoken)
6927 append_str( &display_name, &size, separator );
6928 append_str( &display_name, &size, PublicKeyToken );
6929 append_str( &display_name, &size, name.pubkeytoken );
6932 msi_free( name.name );
6933 msi_free( name.version );
6934 msi_free( name.culture );
6935 msi_free( name.pubkeytoken );
6937 return display_name;
6940 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6942 ASSEMBLY_INFO asminfo;
6947 disp = get_assembly_display_name( db, comp );
6951 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6952 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6954 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6956 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6962 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6964 ASSEMBLY_LIST *list = param;
6965 MSIASSEMBLY *assembly;
6968 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6970 return ERROR_OUTOFMEMORY;
6972 component = MSI_RecordGetString(rec, 1);
6973 assembly->component = get_loaded_component(list->package, component);
6974 if (!assembly->component)
6975 return ERROR_SUCCESS;
6977 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6978 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6980 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6981 assembly->component->Action = assembly->component->Installed;
6982 return ERROR_SUCCESS;
6984 assembly->component->Action = assembly->component->ActionRequest;
6986 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6987 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6989 if (!assembly->file)
6991 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6992 return ERROR_FUNCTION_FAILED;
6995 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6996 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6997 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6999 if (assembly->application)
7002 DWORD size = sizeof(version)/sizeof(WCHAR);
7004 /* FIXME: we should probably check the manifest file here */
7006 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
7007 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
7009 assembly->installed = TRUE;
7013 assembly->installed = check_assembly_installed(list->package->db,
7015 assembly->component);
7017 list_add_head(list->assemblies, &assembly->entry);
7018 return ERROR_SUCCESS;
7021 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
7023 IAssemblyCache *cache = NULL;
7029 static const WCHAR query[] =
7030 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7031 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
7033 r = MSI_DatabaseOpenViewW(package->db, query, &view);
7034 if (r != ERROR_SUCCESS)
7035 return ERROR_SUCCESS;
7037 hr = pCreateAssemblyCache(&cache, 0);
7039 return ERROR_FUNCTION_FAILED;
7041 list.package = package;
7043 list.assemblies = assemblies;
7045 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
7046 msiobj_release(&view->hdr);
7048 IAssemblyCache_Release(cache);
7053 static void free_assemblies(struct list *assemblies)
7055 struct list *item, *cursor;
7057 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
7059 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
7061 list_remove(&assembly->entry);
7062 msi_free(assembly->application);
7063 msi_free(assembly->manifest);
7064 msi_free(assembly->display_name);
7069 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
7071 MSIASSEMBLY *assembly;
7073 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
7075 if (!strcmpW( assembly->file->File, file ))
7085 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
7086 LPWSTR *path, DWORD *attrs, PVOID user)
7088 MSIASSEMBLY *assembly;
7089 WCHAR temppath[MAX_PATH];
7090 struct list *assemblies = user;
7093 if (!find_assembly(assemblies, file, &assembly))
7096 GetTempPathW(MAX_PATH, temppath);
7097 PathAddBackslashW(temppath);
7098 lstrcatW(temppath, assembly->file->FileName);
7100 if (action == MSICABEXTRACT_BEGINEXTRACT)
7102 if (assembly->installed)
7105 *path = strdupW(temppath);
7106 *attrs = assembly->file->Attributes;
7108 else if (action == MSICABEXTRACT_FILEEXTRACTED)
7110 assembly->installed = TRUE;
7112 r = install_assembly(package, assembly, temppath);
7113 if (r != ERROR_SUCCESS)
7114 ERR("Failed to install assembly\n");
7120 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
7123 struct list assemblies = LIST_INIT(assemblies);
7124 MSIASSEMBLY *assembly;
7127 if (!init_functionpointers() || !pCreateAssemblyCache)
7128 return ERROR_FUNCTION_FAILED;
7130 r = load_assemblies(package, &assemblies);
7131 if (r != ERROR_SUCCESS)
7134 if (list_empty(&assemblies))
7137 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
7140 r = ERROR_OUTOFMEMORY;
7144 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
7146 if (assembly->installed && !mi->is_continuous)
7149 if (assembly->file->IsCompressed)
7151 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
7155 r = ready_media(package, assembly->file, mi);
7156 if (r != ERROR_SUCCESS)
7158 ERR("Failed to ready media\n");
7163 data.package = package;
7164 data.cb = installassembly_cb;
7165 data.user = &assemblies;
7167 if (!msi_cabextract(package, mi, &data))
7169 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7170 r = ERROR_FUNCTION_FAILED;
7177 LPWSTR source = resolve_file_source(package, assembly->file);
7179 r = install_assembly(package, assembly, source);
7180 if (r != ERROR_SUCCESS)
7181 ERR("Failed to install assembly\n");
7186 /* FIXME: write Installer assembly reg values */
7190 free_assemblies(&assemblies);
7194 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7196 LPWSTR key, template, id;
7197 UINT r = ERROR_SUCCESS;
7199 id = msi_dup_property( package->db, szProductID );
7203 return ERROR_SUCCESS;
7205 template = msi_dup_property( package->db, szPIDTemplate );
7206 key = msi_dup_property( package->db, szPIDKEY );
7208 if (key && template)
7210 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7211 r = msi_set_property( package->db, szProductID, key );
7213 msi_free( template );
7218 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7221 package->need_reboot = 1;
7222 return ERROR_SUCCESS;
7225 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7227 static const WCHAR szAvailableFreeReg[] =
7228 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7230 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7232 TRACE("%p %d kilobytes\n", package, space);
7234 uirow = MSI_CreateRecord( 1 );
7235 MSI_RecordSetInteger( uirow, 1, space );
7236 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7237 msiobj_release( &uirow->hdr );
7239 return ERROR_SUCCESS;
7242 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7244 FIXME("%p\n", package);
7245 return ERROR_SUCCESS;
7248 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7250 FIXME("%p\n", package);
7251 return ERROR_SUCCESS;
7254 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7259 static const WCHAR driver_query[] = {
7260 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7261 'O','D','B','C','D','r','i','v','e','r',0 };
7263 static const WCHAR translator_query[] = {
7264 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7265 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7267 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7268 if (r == ERROR_SUCCESS)
7271 r = MSI_IterateRecords( view, &count, NULL, package );
7272 msiobj_release( &view->hdr );
7273 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7276 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7277 if (r == ERROR_SUCCESS)
7280 r = MSI_IterateRecords( view, &count, NULL, package );
7281 msiobj_release( &view->hdr );
7282 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7285 return ERROR_SUCCESS;
7288 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7289 LPCSTR action, LPCWSTR table )
7291 static const WCHAR query[] = {
7292 'S','E','L','E','C','T',' ','*',' ',
7293 'F','R','O','M',' ','`','%','s','`',0 };
7294 MSIQUERY *view = NULL;
7298 r = MSI_OpenQuery( package->db, &view, query, table );
7299 if (r == ERROR_SUCCESS)
7301 r = MSI_IterateRecords(view, &count, NULL, package);
7302 msiobj_release(&view->hdr);
7306 FIXME("%s -> %u ignored %s table values\n",
7307 action, count, debugstr_w(table));
7309 return ERROR_SUCCESS;
7312 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7314 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7315 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7318 static UINT ACTION_BindImage( MSIPACKAGE *package )
7320 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7321 return msi_unimplemented_action_stub( package, "BindImage", table );
7324 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7326 static const WCHAR table[] = {
7327 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7328 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7331 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7333 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7334 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7337 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7339 static const WCHAR table[] = {
7340 'M','s','i','A','s','s','e','m','b','l','y',0 };
7341 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7344 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7346 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7347 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7350 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7352 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7353 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7356 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7358 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7359 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7362 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7364 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7365 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7368 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7370 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7371 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7374 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7378 const WCHAR *action;
7379 UINT (*handler)(MSIPACKAGE *);
7383 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7384 { szAppSearch, ACTION_AppSearch },
7385 { szBindImage, ACTION_BindImage },
7386 { szCCPSearch, ACTION_CCPSearch },
7387 { szCostFinalize, ACTION_CostFinalize },
7388 { szCostInitialize, ACTION_CostInitialize },
7389 { szCreateFolders, ACTION_CreateFolders },
7390 { szCreateShortcuts, ACTION_CreateShortcuts },
7391 { szDeleteServices, ACTION_DeleteServices },
7392 { szDisableRollback, ACTION_DisableRollback },
7393 { szDuplicateFiles, ACTION_DuplicateFiles },
7394 { szExecuteAction, ACTION_ExecuteAction },
7395 { szFileCost, ACTION_FileCost },
7396 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7397 { szForceReboot, ACTION_ForceReboot },
7398 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7399 { szInstallExecute, ACTION_InstallExecute },
7400 { szInstallExecuteAgain, ACTION_InstallExecute },
7401 { szInstallFiles, ACTION_InstallFiles},
7402 { szInstallFinalize, ACTION_InstallFinalize },
7403 { szInstallInitialize, ACTION_InstallInitialize },
7404 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7405 { szInstallValidate, ACTION_InstallValidate },
7406 { szIsolateComponents, ACTION_IsolateComponents },
7407 { szLaunchConditions, ACTION_LaunchConditions },
7408 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7409 { szMoveFiles, ACTION_MoveFiles },
7410 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7411 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7412 { szInstallODBC, ACTION_InstallODBC },
7413 { szInstallServices, ACTION_InstallServices },
7414 { szPatchFiles, ACTION_PatchFiles },
7415 { szProcessComponents, ACTION_ProcessComponents },
7416 { szPublishComponents, ACTION_PublishComponents },
7417 { szPublishFeatures, ACTION_PublishFeatures },
7418 { szPublishProduct, ACTION_PublishProduct },
7419 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7420 { szRegisterComPlus, ACTION_RegisterComPlus},
7421 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7422 { szRegisterFonts, ACTION_RegisterFonts },
7423 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7424 { szRegisterProduct, ACTION_RegisterProduct },
7425 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7426 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7427 { szRegisterUser, ACTION_RegisterUser },
7428 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7429 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7430 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7431 { szRemoveFiles, ACTION_RemoveFiles },
7432 { szRemoveFolders, ACTION_RemoveFolders },
7433 { szRemoveIniValues, ACTION_RemoveIniValues },
7434 { szRemoveODBC, ACTION_RemoveODBC },
7435 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7436 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7437 { szResolveSource, ACTION_ResolveSource },
7438 { szRMCCPSearch, ACTION_RMCCPSearch },
7439 { szScheduleReboot, ACTION_ScheduleReboot },
7440 { szSelfRegModules, ACTION_SelfRegModules },
7441 { szSelfUnregModules, ACTION_SelfUnregModules },
7442 { szSetODBCFolders, ACTION_SetODBCFolders },
7443 { szStartServices, ACTION_StartServices },
7444 { szStopServices, ACTION_StopServices },
7445 { szUnpublishComponents, ACTION_UnpublishComponents },
7446 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7447 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7448 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7449 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7450 { szUnregisterFonts, ACTION_UnregisterFonts },
7451 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7452 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7453 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7454 { szValidateProductID, ACTION_ValidateProductID },
7455 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7456 { szWriteIniValues, ACTION_WriteIniValues },
7457 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7461 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7467 while (StandardActions[i].action != NULL)
7469 if (!strcmpW( StandardActions[i].action, action ))
7471 ui_actionstart( package, action );
7472 if (StandardActions[i].handler)
7474 ui_actioninfo( package, action, TRUE, 0 );
7475 *rc = StandardActions[i].handler( package );
7476 ui_actioninfo( package, action, FALSE, *rc );
7480 FIXME("unhandled standard action %s\n", debugstr_w(action));
7481 *rc = ERROR_SUCCESS;
7491 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7493 UINT rc = ERROR_SUCCESS;
7496 TRACE("Performing action (%s)\n", debugstr_w(action));
7498 handled = ACTION_HandleStandardAction(package, action, &rc);
7501 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7505 WARN("unhandled msi action %s\n", debugstr_w(action));
7506 rc = ERROR_FUNCTION_NOT_CALLED;
7512 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7514 UINT rc = ERROR_SUCCESS;
7515 BOOL handled = FALSE;
7517 TRACE("Performing action (%s)\n", debugstr_w(action));
7519 handled = ACTION_HandleStandardAction(package, action, &rc);
7522 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7524 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7529 WARN("unhandled msi action %s\n", debugstr_w(action));
7530 rc = ERROR_FUNCTION_NOT_CALLED;
7536 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7538 UINT rc = ERROR_SUCCESS;
7541 static const WCHAR ExecSeqQuery[] =
7542 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7543 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7544 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7545 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7546 static const WCHAR UISeqQuery[] =
7547 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7548 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7549 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7550 ' ', '=',' ','%','i',0};
7552 if (needs_ui_sequence(package))
7553 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7555 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7559 LPCWSTR action, cond;
7561 TRACE("Running the actions\n");
7563 /* check conditions */
7564 cond = MSI_RecordGetString(row, 2);
7566 /* this is a hack to skip errors in the condition code */
7567 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7569 msiobj_release(&row->hdr);
7570 return ERROR_SUCCESS;
7573 action = MSI_RecordGetString(row, 1);
7576 ERR("failed to fetch action\n");
7577 msiobj_release(&row->hdr);
7578 return ERROR_FUNCTION_FAILED;
7581 if (needs_ui_sequence(package))
7582 rc = ACTION_PerformUIAction(package, action, -1);
7584 rc = ACTION_PerformAction(package, action, -1);
7586 msiobj_release(&row->hdr);
7592 /****************************************************
7593 * TOP level entry points
7594 *****************************************************/
7596 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7597 LPCWSTR szCommandLine )
7602 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7603 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7605 msi_set_property( package->db, szAction, szInstall );
7607 package->script->InWhatSequence = SEQUENCE_INSTALL;
7614 dir = strdupW(szPackagePath);
7615 p = strrchrW(dir, '\\');
7619 file = szPackagePath + (p - dir);
7624 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7625 GetCurrentDirectoryW(MAX_PATH, dir);
7626 lstrcatW(dir, szBackSlash);
7627 file = szPackagePath;
7630 msi_free( package->PackagePath );
7631 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7632 if (!package->PackagePath)
7635 return ERROR_OUTOFMEMORY;
7638 lstrcpyW(package->PackagePath, dir);
7639 lstrcatW(package->PackagePath, file);
7642 msi_set_sourcedir_props(package, FALSE);
7645 msi_parse_command_line( package, szCommandLine, FALSE );
7647 msi_apply_transforms( package );
7648 msi_apply_patches( package );
7650 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7652 TRACE("setting reinstall property\n");
7653 msi_set_property( package->db, szReinstall, szAll );
7656 /* properties may have been added by a transform */
7657 msi_clone_properties( package );
7659 msi_parse_command_line( package, szCommandLine, FALSE );
7660 msi_adjust_privilege_properties( package );
7661 msi_set_context( package );
7663 if (needs_ui_sequence( package))
7665 package->script->InWhatSequence |= SEQUENCE_UI;
7666 rc = ACTION_ProcessUISequence(package);
7667 ui_exists = ui_sequence_exists(package);
7668 if (rc == ERROR_SUCCESS || !ui_exists)
7670 package->script->InWhatSequence |= SEQUENCE_EXEC;
7671 rc = ACTION_ProcessExecSequence(package, ui_exists);
7675 rc = ACTION_ProcessExecSequence(package, FALSE);
7677 package->script->CurrentlyScripting = FALSE;
7679 /* process the ending type action */
7680 if (rc == ERROR_SUCCESS)
7681 ACTION_PerformActionSequence(package, -1);
7682 else if (rc == ERROR_INSTALL_USEREXIT)
7683 ACTION_PerformActionSequence(package, -2);
7684 else if (rc == ERROR_INSTALL_SUSPEND)
7685 ACTION_PerformActionSequence(package, -4);
7687 ACTION_PerformActionSequence(package, -3);
7689 /* finish up running custom actions */
7690 ACTION_FinishCustomActions(package);
7692 if (rc == ERROR_SUCCESS && package->need_reboot)
7693 return ERROR_SUCCESS_REBOOT_REQUIRED;