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 *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 *)&ret, &sz ))
2105 msi_free( version );
2109 msi_free( version );
2113 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2117 msi_parse_version_string( version, &ms, &ls );
2119 if (fi->dwFileVersionMS > ms) return 1;
2120 else if (fi->dwFileVersionMS < ms) return -1;
2121 else if (fi->dwFileVersionLS > ls) return 1;
2122 else if (fi->dwFileVersionLS < ls) return -1;
2126 static DWORD get_disk_file_size( LPCWSTR filename )
2131 TRACE("%s\n", debugstr_w(filename));
2133 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2134 if (file == INVALID_HANDLE_VALUE)
2135 return INVALID_FILE_SIZE;
2137 size = GetFileSize( file, NULL );
2138 CloseHandle( file );
2142 static BOOL hash_matches( MSIFILE *file )
2145 MSIFILEHASHINFO hash;
2147 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2148 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2149 if (r != ERROR_SUCCESS)
2152 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2155 static UINT set_file_install_states( MSIPACKAGE *package )
2157 VS_FIXEDFILEINFO *file_version;
2160 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2162 MSICOMPONENT* comp = file->Component;
2169 if (file->IsCompressed)
2170 comp->ForceLocalState = TRUE;
2172 /* calculate target */
2173 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2174 msi_free(file->TargetPath);
2176 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2178 file->TargetPath = build_directory_name(2, p, file->FileName);
2181 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2183 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2185 file->state = msifs_missing;
2186 comp->Cost += file->FileSize;
2189 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2191 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2192 HIWORD(file_version->dwFileVersionMS),
2193 LOWORD(file_version->dwFileVersionMS),
2194 HIWORD(file_version->dwFileVersionLS),
2195 LOWORD(file_version->dwFileVersionLS));
2197 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2199 file->state = msifs_overwrite;
2200 comp->Cost += file->FileSize;
2204 TRACE("Destination file version equal or greater, not overwriting\n");
2205 file->state = msifs_present;
2207 msi_free( file_version );
2210 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2212 file->state = msifs_overwrite;
2213 comp->Cost += file->FileSize - file_size;
2216 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2218 TRACE("File hashes match, not overwriting\n");
2219 file->state = msifs_present;
2222 file->state = msifs_overwrite;
2223 comp->Cost += file->FileSize - file_size;
2226 return ERROR_SUCCESS;
2230 * A lot is done in this function aside from just the costing.
2231 * The costing needs to be implemented at some point but for now I am going
2232 * to focus on the directory building
2235 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2237 static const WCHAR ExecSeqQuery[] =
2238 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2239 '`','D','i','r','e','c','t','o','r','y','`',0};
2240 static const WCHAR ConditionQuery[] =
2241 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2242 '`','C','o','n','d','i','t','i','o','n','`',0};
2243 static const WCHAR szCosting[] =
2244 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2245 static const WCHAR szlevel[] =
2246 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2247 static const WCHAR szOutOfDiskSpace[] =
2248 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2250 UINT rc = ERROR_SUCCESS;
2254 TRACE("Building Directory properties\n");
2256 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2257 if (rc == ERROR_SUCCESS)
2259 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2261 msiobj_release(&view->hdr);
2264 /* read components states from the registry */
2265 ACTION_GetComponentInstallStates(package);
2266 ACTION_GetFeatureInstallStates(package);
2268 TRACE("Calculating file install states\n");
2269 set_file_install_states( package );
2271 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2273 TRACE("Evaluating feature conditions\n");
2275 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2276 if (rc == ERROR_SUCCESS)
2278 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2279 msiobj_release( &view->hdr );
2282 TRACE("Evaluating component conditions\n");
2284 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2286 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2288 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2289 comp->Enabled = FALSE;
2292 comp->Enabled = TRUE;
2295 msi_set_property( package->db, szCosting, szOne );
2296 /* set default run level if not set */
2297 level = msi_dup_property( package->db, szlevel );
2299 msi_set_property( package->db, szlevel, szOne );
2302 /* FIXME: check volume disk space */
2303 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2305 return MSI_SetFeatureStates(package);
2308 /* OK this value is "interpreted" and then formatted based on the
2309 first few characters */
2310 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2315 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2321 LPWSTR deformated = NULL;
2324 deformat_string(package, &value[2], &deformated);
2326 /* binary value type */
2330 *size = (strlenW(ptr)/2)+1;
2332 *size = strlenW(ptr)/2;
2334 data = msi_alloc(*size);
2340 /* if uneven pad with a zero in front */
2346 data[count] = (BYTE)strtol(byte,NULL,0);
2348 TRACE("Uneven byte count\n");
2356 data[count] = (BYTE)strtol(byte,NULL,0);
2359 msi_free(deformated);
2361 TRACE("Data %i bytes(%i)\n",*size,count);
2368 deformat_string(package, &value[1], &deformated);
2371 *size = sizeof(DWORD);
2372 data = msi_alloc(*size);
2378 if ( (*p < '0') || (*p > '9') )
2384 if (deformated[0] == '-')
2387 TRACE("DWORD %i\n",*(LPDWORD)data);
2389 msi_free(deformated);
2394 static const WCHAR szMulti[] = {'[','~',']',0};
2403 *type=REG_EXPAND_SZ;
2411 if (strstrW(value, szMulti))
2412 *type = REG_MULTI_SZ;
2414 /* remove initial delimiter */
2415 if (!strncmpW(value, szMulti, 3))
2418 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2420 /* add double NULL terminator */
2421 if (*type == REG_MULTI_SZ)
2423 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2424 data = msi_realloc_zero(data, *size);
2430 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2437 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2439 *root_key = HKEY_LOCAL_MACHINE;
2444 *root_key = HKEY_CURRENT_USER;
2449 *root_key = HKEY_CLASSES_ROOT;
2453 *root_key = HKEY_CURRENT_USER;
2457 *root_key = HKEY_LOCAL_MACHINE;
2461 *root_key = HKEY_USERS;
2465 ERR("Unknown root %i\n", root);
2472 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2474 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2475 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2477 if (is_64bit && package->platform == PLATFORM_INTEL &&
2478 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2483 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2484 path_32node = msi_alloc( size );
2488 memcpy( path_32node, path, len * sizeof(WCHAR) );
2489 path_32node[len] = 0;
2490 strcatW( path_32node, szWow6432Node );
2491 strcatW( path_32node, szBackSlash );
2492 strcatW( path_32node, path + len );
2496 return strdupW( path );
2499 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2501 MSIPACKAGE *package = param;
2502 LPSTR value_data = NULL;
2503 HKEY root_key, hkey;
2505 LPWSTR deformated, uikey, keypath;
2506 LPCWSTR szRoot, component, name, key, value;
2510 BOOL check_first = FALSE;
2513 ui_progress(package,2,0,0,0);
2515 component = MSI_RecordGetString(row, 6);
2516 comp = get_loaded_component(package,component);
2518 return ERROR_SUCCESS;
2522 TRACE("component is disabled\n");
2523 return ERROR_SUCCESS;
2526 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2528 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2529 comp->Action = comp->Installed;
2530 return ERROR_SUCCESS;
2532 comp->Action = INSTALLSTATE_LOCAL;
2534 name = MSI_RecordGetString(row, 4);
2535 if( MSI_RecordIsNull(row,5) && name )
2537 /* null values can have special meanings */
2538 if (name[0]=='-' && name[1] == 0)
2539 return ERROR_SUCCESS;
2540 else if ((name[0]=='+' && name[1] == 0) ||
2541 (name[0] == '*' && name[1] == 0))
2546 root = MSI_RecordGetInteger(row,2);
2547 key = MSI_RecordGetString(row, 3);
2549 szRoot = get_root_key( package, root, &root_key );
2551 return ERROR_SUCCESS;
2553 deformat_string(package, key , &deformated);
2554 size = strlenW(deformated) + strlenW(szRoot) + 1;
2555 uikey = msi_alloc(size*sizeof(WCHAR));
2556 strcpyW(uikey,szRoot);
2557 strcatW(uikey,deformated);
2559 keypath = get_keypath( package, root_key, deformated );
2560 msi_free( deformated );
2561 if (RegCreateKeyW( root_key, keypath, &hkey ))
2563 ERR("Could not create key %s\n", debugstr_w(keypath));
2565 return ERROR_SUCCESS;
2568 value = MSI_RecordGetString(row,5);
2570 value_data = parse_value(package, value, &type, &size);
2573 value_data = (LPSTR)strdupW(szEmpty);
2574 size = sizeof(szEmpty);
2578 deformat_string(package, name, &deformated);
2582 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2584 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2589 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2590 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2592 TRACE("value %s of %s checked already exists\n",
2593 debugstr_w(deformated), debugstr_w(uikey));
2597 TRACE("Checked and setting value %s of %s\n",
2598 debugstr_w(deformated), debugstr_w(uikey));
2599 if (deformated || size)
2600 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2605 uirow = MSI_CreateRecord(3);
2606 MSI_RecordSetStringW(uirow,2,deformated);
2607 MSI_RecordSetStringW(uirow,1,uikey);
2608 if (type == REG_SZ || type == REG_EXPAND_SZ)
2609 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2610 ui_actiondata(package,szWriteRegistryValues,uirow);
2611 msiobj_release( &uirow->hdr );
2613 msi_free(value_data);
2614 msi_free(deformated);
2617 return ERROR_SUCCESS;
2620 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2624 static const WCHAR ExecSeqQuery[] =
2625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2626 '`','R','e','g','i','s','t','r','y','`',0 };
2628 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2629 if (rc != ERROR_SUCCESS)
2630 return ERROR_SUCCESS;
2632 /* increment progress bar each time action data is sent */
2633 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2635 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2637 msiobj_release(&view->hdr);
2641 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2645 DWORD num_subkeys, num_values;
2649 if ((res = RegDeleteTreeW( hkey_root, key )))
2651 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2656 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2658 if ((res = RegDeleteValueW( hkey, value )))
2660 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2662 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2663 NULL, NULL, NULL, NULL );
2664 RegCloseKey( hkey );
2666 if (!res && !num_subkeys && !num_values)
2668 TRACE("Removing empty key %s\n", debugstr_w(key));
2669 RegDeleteKeyW( hkey_root, key );
2673 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2677 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2679 MSIPACKAGE *package = param;
2680 LPCWSTR component, name, key_str, root_key_str;
2681 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2684 BOOL delete_key = FALSE;
2689 ui_progress( package, 2, 0, 0, 0 );
2691 component = MSI_RecordGetString( row, 6 );
2692 comp = get_loaded_component( package, component );
2694 return ERROR_SUCCESS;
2698 TRACE("component is disabled\n");
2699 return ERROR_SUCCESS;
2702 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2704 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2705 comp->Action = comp->Installed;
2706 return ERROR_SUCCESS;
2708 comp->Action = INSTALLSTATE_ABSENT;
2710 name = MSI_RecordGetString( row, 4 );
2711 if (MSI_RecordIsNull( row, 5 ) && name )
2713 if (name[0] == '+' && !name[1])
2714 return ERROR_SUCCESS;
2715 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2722 root = MSI_RecordGetInteger( row, 2 );
2723 key_str = MSI_RecordGetString( row, 3 );
2725 root_key_str = get_root_key( package, root, &hkey_root );
2727 return ERROR_SUCCESS;
2729 deformat_string( package, key_str, &deformated_key );
2730 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2731 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2732 strcpyW( ui_key_str, root_key_str );
2733 strcatW( ui_key_str, deformated_key );
2735 deformat_string( package, name, &deformated_name );
2737 keypath = get_keypath( package, hkey_root, deformated_key );
2738 msi_free( deformated_key );
2739 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2740 msi_free( keypath );
2742 uirow = MSI_CreateRecord( 2 );
2743 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2744 MSI_RecordSetStringW( uirow, 2, deformated_name );
2746 ui_actiondata( package, szRemoveRegistryValues, uirow );
2747 msiobj_release( &uirow->hdr );
2749 msi_free( ui_key_str );
2750 msi_free( deformated_name );
2751 return ERROR_SUCCESS;
2754 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2756 MSIPACKAGE *package = param;
2757 LPCWSTR component, name, key_str, root_key_str;
2758 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2761 BOOL delete_key = FALSE;
2766 ui_progress( package, 2, 0, 0, 0 );
2768 component = MSI_RecordGetString( row, 5 );
2769 comp = get_loaded_component( package, component );
2771 return ERROR_SUCCESS;
2775 TRACE("component is disabled\n");
2776 return ERROR_SUCCESS;
2779 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2781 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2782 comp->Action = comp->Installed;
2783 return ERROR_SUCCESS;
2785 comp->Action = INSTALLSTATE_LOCAL;
2787 if ((name = MSI_RecordGetString( row, 4 )))
2789 if (name[0] == '-' && !name[1])
2796 root = MSI_RecordGetInteger( row, 2 );
2797 key_str = MSI_RecordGetString( row, 3 );
2799 root_key_str = get_root_key( package, root, &hkey_root );
2801 return ERROR_SUCCESS;
2803 deformat_string( package, key_str, &deformated_key );
2804 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2805 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2806 strcpyW( ui_key_str, root_key_str );
2807 strcatW( ui_key_str, deformated_key );
2809 deformat_string( package, name, &deformated_name );
2811 keypath = get_keypath( package, hkey_root, deformated_key );
2812 msi_free( deformated_key );
2813 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2814 msi_free( keypath );
2816 uirow = MSI_CreateRecord( 2 );
2817 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2818 MSI_RecordSetStringW( uirow, 2, deformated_name );
2820 ui_actiondata( package, szRemoveRegistryValues, uirow );
2821 msiobj_release( &uirow->hdr );
2823 msi_free( ui_key_str );
2824 msi_free( deformated_name );
2825 return ERROR_SUCCESS;
2828 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2832 static const WCHAR registry_query[] =
2833 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2834 '`','R','e','g','i','s','t','r','y','`',0 };
2835 static const WCHAR remove_registry_query[] =
2836 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2837 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2839 /* increment progress bar each time action data is sent */
2840 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2842 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2843 if (rc == ERROR_SUCCESS)
2845 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2846 msiobj_release( &view->hdr );
2847 if (rc != ERROR_SUCCESS)
2851 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2852 if (rc == ERROR_SUCCESS)
2854 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2855 msiobj_release( &view->hdr );
2856 if (rc != ERROR_SUCCESS)
2860 return ERROR_SUCCESS;
2863 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2865 package->script->CurrentlyScripting = TRUE;
2867 return ERROR_SUCCESS;
2871 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2876 static const WCHAR q1[]=
2877 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2878 '`','R','e','g','i','s','t','r','y','`',0};
2881 MSIFEATURE *feature;
2884 TRACE("InstallValidate\n");
2886 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2887 if (rc == ERROR_SUCCESS)
2889 MSI_IterateRecords( view, &progress, NULL, package );
2890 msiobj_release( &view->hdr );
2891 total += progress * REG_PROGRESS_VALUE;
2894 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2895 total += COMPONENT_PROGRESS_VALUE;
2897 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2898 total += file->FileSize;
2900 ui_progress(package,0,total,0,0);
2902 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2904 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2905 debugstr_w(feature->Feature), feature->Installed,
2906 feature->ActionRequest, feature->Action);
2909 return ERROR_SUCCESS;
2912 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2914 MSIPACKAGE* package = param;
2915 LPCWSTR cond = NULL;
2916 LPCWSTR message = NULL;
2919 static const WCHAR title[]=
2920 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2922 cond = MSI_RecordGetString(row,1);
2924 r = MSI_EvaluateConditionW(package,cond);
2925 if (r == MSICONDITION_FALSE)
2927 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2930 message = MSI_RecordGetString(row,2);
2931 deformat_string(package,message,&deformated);
2932 MessageBoxW(NULL,deformated,title,MB_OK);
2933 msi_free(deformated);
2936 return ERROR_INSTALL_FAILURE;
2939 return ERROR_SUCCESS;
2942 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2945 MSIQUERY * view = NULL;
2946 static const WCHAR ExecSeqQuery[] =
2947 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2948 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2950 TRACE("Checking launch conditions\n");
2952 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2953 if (rc != ERROR_SUCCESS)
2954 return ERROR_SUCCESS;
2956 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2957 msiobj_release(&view->hdr);
2962 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2966 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2968 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2970 MSIRECORD * row = 0;
2972 LPWSTR deformated,buffer,deformated_name;
2974 static const WCHAR ExecSeqQuery[] =
2975 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2976 '`','R','e','g','i','s','t','r','y','`',' ',
2977 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2978 ' ','=',' ' ,'\'','%','s','\'',0 };
2979 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2980 static const WCHAR fmt2[]=
2981 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2983 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2987 root = MSI_RecordGetInteger(row,2);
2988 key = MSI_RecordGetString(row, 3);
2989 name = MSI_RecordGetString(row, 4);
2990 deformat_string(package, key , &deformated);
2991 deformat_string(package, name, &deformated_name);
2993 len = strlenW(deformated) + 6;
2994 if (deformated_name)
2995 len+=strlenW(deformated_name);
2997 buffer = msi_alloc( len *sizeof(WCHAR));
2999 if (deformated_name)
3000 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3002 sprintfW(buffer,fmt,root,deformated);
3004 msi_free(deformated);
3005 msi_free(deformated_name);
3006 msiobj_release(&row->hdr);
3010 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3012 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3017 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3020 return strdupW( file->TargetPath );
3025 static HKEY openSharedDLLsKey(void)
3028 static const WCHAR path[] =
3029 {'S','o','f','t','w','a','r','e','\\',
3030 'M','i','c','r','o','s','o','f','t','\\',
3031 'W','i','n','d','o','w','s','\\',
3032 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3033 'S','h','a','r','e','d','D','L','L','s',0};
3035 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3039 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3044 DWORD sz = sizeof(count);
3047 hkey = openSharedDLLsKey();
3048 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3049 if (rc != ERROR_SUCCESS)
3055 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3059 hkey = openSharedDLLsKey();
3061 msi_reg_set_val_dword( hkey, path, count );
3063 RegDeleteValueW(hkey,path);
3069 * Return TRUE if the count should be written out and FALSE if not
3071 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3073 MSIFEATURE *feature;
3077 /* only refcount DLLs */
3078 if (comp->KeyPath == NULL ||
3079 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3080 comp->Attributes & msidbComponentAttributesODBCDataSource)
3084 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3085 write = (count > 0);
3087 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3091 /* increment counts */
3092 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3096 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3099 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3101 if ( cl->component == comp )
3106 /* decrement counts */
3107 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3111 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3114 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3116 if ( cl->component == comp )
3121 /* ref count all the files in the component */
3126 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3128 if (file->Component == comp)
3129 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3133 /* add a count for permanent */
3134 if (comp->Attributes & msidbComponentAttributesPermanent)
3137 comp->RefCount = count;
3140 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3143 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3145 WCHAR squished_pc[GUID_SIZE];
3146 WCHAR squished_cc[GUID_SIZE];
3153 squash_guid(package->ProductCode,squished_pc);
3154 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3156 msi_set_sourcedir_props(package, FALSE);
3158 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3162 ui_progress(package,2,0,0,0);
3163 if (!comp->ComponentId)
3166 squash_guid(comp->ComponentId,squished_cc);
3168 msi_free(comp->FullKeypath);
3169 comp->FullKeypath = resolve_keypath( package, comp );
3171 ACTION_RefCountComponent( package, comp );
3173 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3174 debugstr_w(comp->Component),
3175 debugstr_w(squished_cc),
3176 debugstr_w(comp->FullKeypath),
3178 comp->ActionRequest);
3180 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3181 comp->ActionRequest == INSTALLSTATE_SOURCE)
3183 if (!comp->FullKeypath)
3186 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3187 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3190 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3193 if (rc != ERROR_SUCCESS)
3196 if (comp->Attributes & msidbComponentAttributesPermanent)
3198 static const WCHAR szPermKey[] =
3199 { '0','0','0','0','0','0','0','0','0','0','0','0',
3200 '0','0','0','0','0','0','0','0','0','0','0','0',
3201 '0','0','0','0','0','0','0','0',0 };
3203 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3206 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3207 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3213 WCHAR source[MAX_PATH];
3214 WCHAR base[MAX_PATH];
3217 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3218 static const WCHAR query[] = {
3219 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3220 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3221 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3222 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3223 '`','D','i','s','k','I','d','`',0};
3225 file = get_loaded_file(package, comp->KeyPath);
3229 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3230 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3231 ptr2 = strrchrW(source, '\\') + 1;
3232 msiobj_release(&row->hdr);
3234 lstrcpyW(base, package->PackagePath);
3235 ptr = strrchrW(base, '\\');
3238 sourcepath = resolve_file_source(package, file);
3239 ptr = sourcepath + lstrlenW(base);
3240 lstrcpyW(ptr2, ptr);
3241 msi_free(sourcepath);
3243 msi_reg_set_val_str(hkey, squished_pc, source);
3247 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3249 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3250 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3252 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3254 comp->Action = comp->ActionRequest;
3257 uirow = MSI_CreateRecord(3);
3258 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3259 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3260 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3261 ui_actiondata(package,szProcessComponents,uirow);
3262 msiobj_release( &uirow->hdr );
3265 return ERROR_SUCCESS;
3276 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3277 LPWSTR lpszName, LONG_PTR lParam)
3280 typelib_struct *tl_struct = (typelib_struct*) lParam;
3281 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3285 if (!IS_INTRESOURCE(lpszName))
3287 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3291 sz = strlenW(tl_struct->source)+4;
3292 sz *= sizeof(WCHAR);
3294 if ((INT_PTR)lpszName == 1)
3295 tl_struct->path = strdupW(tl_struct->source);
3298 tl_struct->path = msi_alloc(sz);
3299 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3302 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3303 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3306 msi_free(tl_struct->path);
3307 tl_struct->path = NULL;
3312 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3313 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3315 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3319 msi_free(tl_struct->path);
3320 tl_struct->path = NULL;
3322 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3323 ITypeLib_Release(tl_struct->ptLib);
3328 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3330 MSIPACKAGE* package = param;
3334 typelib_struct tl_struct;
3339 component = MSI_RecordGetString(row,3);
3340 comp = get_loaded_component(package,component);
3342 return ERROR_SUCCESS;
3346 TRACE("component is disabled\n");
3347 return ERROR_SUCCESS;
3350 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3352 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3353 comp->Action = comp->Installed;
3354 return ERROR_SUCCESS;
3356 comp->Action = INSTALLSTATE_LOCAL;
3358 file = get_loaded_file( package, comp->KeyPath );
3360 return ERROR_SUCCESS;
3362 ui_actiondata( package, szRegisterTypeLibraries, row );
3364 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3368 guid = MSI_RecordGetString(row,1);
3369 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3370 tl_struct.source = strdupW( file->TargetPath );
3371 tl_struct.path = NULL;
3373 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3374 (LONG_PTR)&tl_struct);
3382 helpid = MSI_RecordGetString(row,6);
3385 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3386 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3390 ERR("Failed to register type library %s\n",
3391 debugstr_w(tl_struct.path));
3393 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3395 ITypeLib_Release(tl_struct.ptLib);
3396 msi_free(tl_struct.path);
3399 ERR("Failed to load type library %s\n",
3400 debugstr_w(tl_struct.source));
3402 FreeLibrary(module);
3403 msi_free(tl_struct.source);
3407 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3410 ERR("Failed to load type library: %08x\n", hr);
3411 return ERROR_INSTALL_FAILURE;
3414 ITypeLib_Release(tlib);
3417 return ERROR_SUCCESS;
3420 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3423 * OK this is a bit confusing.. I am given a _Component key and I believe
3424 * that the file that is being registered as a type library is the "key file
3425 * of that component" which I interpret to mean "The file in the KeyPath of
3430 static const WCHAR Query[] =
3431 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3432 '`','T','y','p','e','L','i','b','`',0};
3434 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3435 if (rc != ERROR_SUCCESS)
3436 return ERROR_SUCCESS;
3438 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3439 msiobj_release(&view->hdr);
3443 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3445 MSIPACKAGE *package = param;
3446 LPCWSTR component, guid;
3454 component = MSI_RecordGetString( row, 3 );
3455 comp = get_loaded_component( package, component );
3457 return ERROR_SUCCESS;
3461 TRACE("component is disabled\n");
3462 return ERROR_SUCCESS;
3465 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3467 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3468 comp->Action = comp->Installed;
3469 return ERROR_SUCCESS;
3471 comp->Action = INSTALLSTATE_ABSENT;
3473 ui_actiondata( package, szUnregisterTypeLibraries, row );
3475 guid = MSI_RecordGetString( row, 1 );
3476 CLSIDFromString( (LPCWSTR)guid, &libid );
3477 version = MSI_RecordGetInteger( row, 4 );
3478 language = MSI_RecordGetInteger( row, 2 );
3481 syskind = SYS_WIN64;
3483 syskind = SYS_WIN32;
3486 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3489 WARN("Failed to unregister typelib: %08x\n", hr);
3492 return ERROR_SUCCESS;
3495 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3499 static const WCHAR query[] =
3500 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3501 '`','T','y','p','e','L','i','b','`',0};
3503 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3504 if (rc != ERROR_SUCCESS)
3505 return ERROR_SUCCESS;
3507 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3508 msiobj_release( &view->hdr );
3512 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3514 static const WCHAR szlnk[] = {'.','l','n','k',0};
3515 LPCWSTR directory, extension;
3516 LPWSTR link_folder, link_file, filename;
3518 directory = MSI_RecordGetString( row, 2 );
3519 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3521 /* may be needed because of a bug somewhere else */
3522 create_full_pathW( link_folder );
3524 filename = msi_dup_record_field( row, 3 );
3525 reduce_to_longfilename( filename );
3527 extension = strchrW( filename, '.' );
3528 if (!extension || strcmpiW( extension, szlnk ))
3530 int len = strlenW( filename );
3531 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3532 memcpy( filename + len, szlnk, sizeof(szlnk) );
3534 link_file = build_directory_name( 2, link_folder, filename );
3535 msi_free( link_folder );
3536 msi_free( filename );
3541 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3543 MSIPACKAGE *package = param;
3544 LPWSTR link_file, deformated, path;
3545 LPCWSTR component, target;
3547 IShellLinkW *sl = NULL;
3548 IPersistFile *pf = NULL;
3551 component = MSI_RecordGetString(row, 4);
3552 comp = get_loaded_component(package, component);
3554 return ERROR_SUCCESS;
3558 TRACE("component is disabled\n");
3559 return ERROR_SUCCESS;
3562 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3564 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3565 comp->Action = comp->Installed;
3566 return ERROR_SUCCESS;
3568 comp->Action = INSTALLSTATE_LOCAL;
3570 ui_actiondata(package,szCreateShortcuts,row);
3572 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3573 &IID_IShellLinkW, (LPVOID *) &sl );
3577 ERR("CLSID_ShellLink not available\n");
3581 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3584 ERR("QueryInterface(IID_IPersistFile) failed\n");
3588 target = MSI_RecordGetString(row, 5);
3589 if (strchrW(target, '['))
3591 deformat_string(package, target, &deformated);
3592 IShellLinkW_SetPath(sl,deformated);
3593 msi_free(deformated);
3597 FIXME("poorly handled shortcut format, advertised shortcut\n");
3598 IShellLinkW_SetPath(sl,comp->FullKeypath);
3601 if (!MSI_RecordIsNull(row,6))
3603 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3604 deformat_string(package, arguments, &deformated);
3605 IShellLinkW_SetArguments(sl,deformated);
3606 msi_free(deformated);
3609 if (!MSI_RecordIsNull(row,7))
3611 LPCWSTR description = MSI_RecordGetString(row, 7);
3612 IShellLinkW_SetDescription(sl, description);
3615 if (!MSI_RecordIsNull(row,8))
3616 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3618 if (!MSI_RecordIsNull(row,9))
3621 LPCWSTR icon = MSI_RecordGetString(row, 9);
3623 path = build_icon_path(package, icon);
3624 index = MSI_RecordGetInteger(row,10);
3626 /* no value means 0 */
3627 if (index == MSI_NULL_INTEGER)
3630 IShellLinkW_SetIconLocation(sl, path, index);
3634 if (!MSI_RecordIsNull(row,11))
3635 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3637 if (!MSI_RecordIsNull(row,12))
3639 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3640 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3642 IShellLinkW_SetWorkingDirectory(sl, path);
3646 link_file = get_link_file(package, row);
3648 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3649 IPersistFile_Save(pf, link_file, FALSE);
3651 msi_free(link_file);
3655 IPersistFile_Release( pf );
3657 IShellLinkW_Release( sl );
3659 return ERROR_SUCCESS;
3662 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3667 static const WCHAR Query[] =
3668 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3669 '`','S','h','o','r','t','c','u','t','`',0};
3671 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3672 if (rc != ERROR_SUCCESS)
3673 return ERROR_SUCCESS;
3675 res = CoInitialize( NULL );
3677 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3678 msiobj_release(&view->hdr);
3686 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3688 MSIPACKAGE *package = param;
3693 component = MSI_RecordGetString( row, 4 );
3694 comp = get_loaded_component( package, component );
3696 return ERROR_SUCCESS;
3700 TRACE("component is disabled\n");
3701 return ERROR_SUCCESS;
3704 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3706 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3707 comp->Action = comp->Installed;
3708 return ERROR_SUCCESS;
3710 comp->Action = INSTALLSTATE_ABSENT;
3712 ui_actiondata( package, szRemoveShortcuts, row );
3714 link_file = get_link_file( package, row );
3716 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3717 if (!DeleteFileW( link_file ))
3719 WARN("Failed to remove shortcut file %u\n", GetLastError());
3721 msi_free( link_file );
3723 return ERROR_SUCCESS;
3726 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3730 static const WCHAR query[] =
3731 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3732 '`','S','h','o','r','t','c','u','t','`',0};
3734 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3735 if (rc != ERROR_SUCCESS)
3736 return ERROR_SUCCESS;
3738 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3739 msiobj_release( &view->hdr );
3744 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3746 MSIPACKAGE* package = param;
3754 FileName = MSI_RecordGetString(row,1);
3757 ERR("Unable to get FileName\n");
3758 return ERROR_SUCCESS;
3761 FilePath = build_icon_path(package,FileName);
3763 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3765 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3766 FILE_ATTRIBUTE_NORMAL, NULL);
3768 if (the_file == INVALID_HANDLE_VALUE)
3770 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3772 return ERROR_SUCCESS;
3779 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3780 if (rc != ERROR_SUCCESS)
3782 ERR("Failed to get stream\n");
3783 CloseHandle(the_file);
3784 DeleteFileW(FilePath);
3787 WriteFile(the_file,buffer,sz,&write,NULL);
3788 } while (sz == 1024);
3791 CloseHandle(the_file);
3793 return ERROR_SUCCESS;
3796 static UINT msi_publish_icons(MSIPACKAGE *package)
3801 static const WCHAR query[]= {
3802 'S','E','L','E','C','T',' ','*',' ',
3803 'F','R','O','M',' ','`','I','c','o','n','`',0};
3805 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3806 if (r == ERROR_SUCCESS)
3808 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3809 msiobj_release(&view->hdr);
3812 return ERROR_SUCCESS;
3815 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3821 MSISOURCELISTINFO *info;
3823 r = RegCreateKeyW(hkey, szSourceList, &source);
3824 if (r != ERROR_SUCCESS)
3827 RegCloseKey(source);
3829 buffer = strrchrW(package->PackagePath, '\\') + 1;
3830 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3831 package->Context, MSICODE_PRODUCT,
3832 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3833 if (r != ERROR_SUCCESS)
3836 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3837 package->Context, MSICODE_PRODUCT,
3838 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3839 if (r != ERROR_SUCCESS)
3842 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3843 package->Context, MSICODE_PRODUCT,
3844 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3845 if (r != ERROR_SUCCESS)
3848 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3850 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3851 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3852 info->options, info->value);
3854 MsiSourceListSetInfoW(package->ProductCode, NULL,
3855 info->context, info->options,
3856 info->property, info->value);
3859 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3861 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3862 disk->context, disk->options,
3863 disk->disk_id, disk->volume_label, disk->disk_prompt);
3866 return ERROR_SUCCESS;
3869 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3871 MSIHANDLE hdb, suminfo;
3872 WCHAR guids[MAX_PATH];
3873 WCHAR packcode[SQUISH_GUID_SIZE];
3880 static const WCHAR szProductLanguage[] =
3881 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3882 static const WCHAR szARPProductIcon[] =
3883 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3884 static const WCHAR szProductVersion[] =
3885 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3886 static const WCHAR szAssignment[] =
3887 {'A','s','s','i','g','n','m','e','n','t',0};
3888 static const WCHAR szAdvertiseFlags[] =
3889 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3890 static const WCHAR szClients[] =
3891 {'C','l','i','e','n','t','s',0};
3892 static const WCHAR szColon[] = {':',0};
3894 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3895 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3898 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3899 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3902 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3904 buffer = msi_dup_property(package->db, szARPProductIcon);
3907 LPWSTR path = build_icon_path(package,buffer);
3908 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3913 buffer = msi_dup_property(package->db, szProductVersion);
3916 DWORD verdword = msi_version_str_to_dword(buffer);
3917 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3921 msi_reg_set_val_dword(hkey, szAssignment, 0);
3922 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3923 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3924 msi_reg_set_val_str(hkey, szClients, szColon);
3926 hdb = alloc_msihandle(&package->db->hdr);
3928 return ERROR_NOT_ENOUGH_MEMORY;
3930 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3931 MsiCloseHandle(hdb);
3932 if (r != ERROR_SUCCESS)
3936 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3937 NULL, guids, &size);
3938 if (r != ERROR_SUCCESS)
3941 ptr = strchrW(guids, ';');
3943 squash_guid(guids, packcode);
3944 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3947 MsiCloseHandle(suminfo);
3948 return ERROR_SUCCESS;
3951 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3956 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3958 upgrade = msi_dup_property(package->db, szUpgradeCode);
3960 return ERROR_SUCCESS;
3962 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3964 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3965 if (r != ERROR_SUCCESS)
3970 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3971 if (r != ERROR_SUCCESS)
3975 squash_guid(package->ProductCode, squashed_pc);
3976 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3985 static BOOL msi_check_publish(MSIPACKAGE *package)
3987 MSIFEATURE *feature;
3989 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3991 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3998 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4000 MSIFEATURE *feature;
4002 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4004 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4011 static UINT msi_publish_patches( MSIPACKAGE *package )
4013 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4014 WCHAR patch_squashed[GUID_SIZE];
4015 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4017 MSIPATCHINFO *patch;
4019 WCHAR *p, *all_patches = NULL;
4022 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4023 if (r != ERROR_SUCCESS)
4024 return ERROR_FUNCTION_FAILED;
4026 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4027 if (res != ERROR_SUCCESS)
4029 r = ERROR_FUNCTION_FAILED;
4033 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4034 if (r != ERROR_SUCCESS)
4037 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4039 squash_guid( patch->patchcode, patch_squashed );
4040 len += strlenW( patch_squashed ) + 1;
4043 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4047 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4051 squash_guid( patch->patchcode, p );
4052 p += strlenW( p ) + 1;
4054 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4055 (const BYTE *)patch->transforms,
4056 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4057 if (res != ERROR_SUCCESS)
4060 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4061 if (r != ERROR_SUCCESS)
4064 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4065 (const BYTE *)patch->localfile,
4066 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4067 RegCloseKey( patch_key );
4068 if (res != ERROR_SUCCESS)
4071 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4072 if (res != ERROR_SUCCESS)
4075 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4076 RegCloseKey( patch_key );
4077 if (res != ERROR_SUCCESS)
4081 all_patches[len] = 0;
4082 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4083 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4084 if (res != ERROR_SUCCESS)
4087 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4088 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4089 if (res != ERROR_SUCCESS)
4090 r = ERROR_FUNCTION_FAILED;
4093 RegCloseKey( product_patches_key );
4094 RegCloseKey( patches_key );
4095 RegCloseKey( product_key );
4096 msi_free( all_patches );
4101 * 99% of the work done here is only done for
4102 * advertised installs. However this is where the
4103 * Icon table is processed and written out
4104 * so that is what I am going to do here.
4106 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4109 HKEY hukey = NULL, hudkey = NULL;
4112 if (!list_empty(&package->patches))
4114 rc = msi_publish_patches(package);
4115 if (rc != ERROR_SUCCESS)
4119 /* FIXME: also need to publish if the product is in advertise mode */
4120 if (!msi_check_publish(package))
4121 return ERROR_SUCCESS;
4123 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4125 if (rc != ERROR_SUCCESS)
4128 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4129 NULL, &hudkey, TRUE);
4130 if (rc != ERROR_SUCCESS)
4133 rc = msi_publish_upgrade_code(package);
4134 if (rc != ERROR_SUCCESS)
4137 rc = msi_publish_product_properties(package, hukey);
4138 if (rc != ERROR_SUCCESS)
4141 rc = msi_publish_sourcelist(package, hukey);
4142 if (rc != ERROR_SUCCESS)
4145 rc = msi_publish_icons(package);
4148 uirow = MSI_CreateRecord( 1 );
4149 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4150 ui_actiondata( package, szPublishProduct, uirow );
4151 msiobj_release( &uirow->hdr );
4154 RegCloseKey(hudkey);
4159 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4161 WCHAR *filename, *ptr, *folder, *ret;
4162 const WCHAR *dirprop;
4164 filename = msi_dup_record_field( row, 2 );
4165 if (filename && (ptr = strchrW( filename, '|' )))
4170 dirprop = MSI_RecordGetString( row, 3 );
4173 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4175 folder = msi_dup_property( package->db, dirprop );
4178 folder = msi_dup_property( package->db, szWindowsFolder );
4182 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4183 msi_free( filename );
4187 ret = build_directory_name( 2, folder, ptr );
4189 msi_free( filename );
4194 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4196 MSIPACKAGE *package = param;
4197 LPCWSTR component, section, key, value, identifier;
4198 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4203 component = MSI_RecordGetString(row, 8);
4204 comp = get_loaded_component(package,component);
4206 return ERROR_SUCCESS;
4210 TRACE("component is disabled\n");
4211 return ERROR_SUCCESS;
4214 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4216 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4217 comp->Action = comp->Installed;
4218 return ERROR_SUCCESS;
4220 comp->Action = INSTALLSTATE_LOCAL;
4222 identifier = MSI_RecordGetString(row,1);
4223 section = MSI_RecordGetString(row,4);
4224 key = MSI_RecordGetString(row,5);
4225 value = MSI_RecordGetString(row,6);
4226 action = MSI_RecordGetInteger(row,7);
4228 deformat_string(package,section,&deformated_section);
4229 deformat_string(package,key,&deformated_key);
4230 deformat_string(package,value,&deformated_value);
4232 fullname = get_ini_file_name(package, row);
4236 TRACE("Adding value %s to section %s in %s\n",
4237 debugstr_w(deformated_key), debugstr_w(deformated_section),
4238 debugstr_w(fullname));
4239 WritePrivateProfileStringW(deformated_section, deformated_key,
4240 deformated_value, fullname);
4242 else if (action == 1)
4245 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4246 returned, 10, fullname);
4247 if (returned[0] == 0)
4249 TRACE("Adding value %s to section %s in %s\n",
4250 debugstr_w(deformated_key), debugstr_w(deformated_section),
4251 debugstr_w(fullname));
4253 WritePrivateProfileStringW(deformated_section, deformated_key,
4254 deformated_value, fullname);
4257 else if (action == 3)
4258 FIXME("Append to existing section not yet implemented\n");
4260 uirow = MSI_CreateRecord(4);
4261 MSI_RecordSetStringW(uirow,1,identifier);
4262 MSI_RecordSetStringW(uirow,2,deformated_section);
4263 MSI_RecordSetStringW(uirow,3,deformated_key);
4264 MSI_RecordSetStringW(uirow,4,deformated_value);
4265 ui_actiondata(package,szWriteIniValues,uirow);
4266 msiobj_release( &uirow->hdr );
4269 msi_free(deformated_key);
4270 msi_free(deformated_value);
4271 msi_free(deformated_section);
4272 return ERROR_SUCCESS;
4275 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4279 static const WCHAR ExecSeqQuery[] =
4280 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4281 '`','I','n','i','F','i','l','e','`',0};
4283 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4284 if (rc != ERROR_SUCCESS)
4286 TRACE("no IniFile table\n");
4287 return ERROR_SUCCESS;
4290 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4291 msiobj_release(&view->hdr);
4295 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4297 MSIPACKAGE *package = param;
4298 LPCWSTR component, section, key, value, identifier;
4299 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4304 component = MSI_RecordGetString( row, 8 );
4305 comp = get_loaded_component( package, component );
4307 return ERROR_SUCCESS;
4311 TRACE("component is disabled\n");
4312 return ERROR_SUCCESS;
4315 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4317 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4318 comp->Action = comp->Installed;
4319 return ERROR_SUCCESS;
4321 comp->Action = INSTALLSTATE_ABSENT;
4323 identifier = MSI_RecordGetString( row, 1 );
4324 section = MSI_RecordGetString( row, 4 );
4325 key = MSI_RecordGetString( row, 5 );
4326 value = MSI_RecordGetString( row, 6 );
4327 action = MSI_RecordGetInteger( row, 7 );
4329 deformat_string( package, section, &deformated_section );
4330 deformat_string( package, key, &deformated_key );
4331 deformat_string( package, value, &deformated_value );
4333 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4335 filename = get_ini_file_name( package, row );
4337 TRACE("Removing key %s from section %s in %s\n",
4338 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4340 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4342 WARN("Unable to remove key %u\n", GetLastError());
4344 msi_free( filename );
4347 FIXME("Unsupported action %d\n", action);
4350 uirow = MSI_CreateRecord( 4 );
4351 MSI_RecordSetStringW( uirow, 1, identifier );
4352 MSI_RecordSetStringW( uirow, 2, deformated_section );
4353 MSI_RecordSetStringW( uirow, 3, deformated_key );
4354 MSI_RecordSetStringW( uirow, 4, deformated_value );
4355 ui_actiondata( package, szRemoveIniValues, uirow );
4356 msiobj_release( &uirow->hdr );
4358 msi_free( deformated_key );
4359 msi_free( deformated_value );
4360 msi_free( deformated_section );
4361 return ERROR_SUCCESS;
4364 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4366 MSIPACKAGE *package = param;
4367 LPCWSTR component, section, key, value, identifier;
4368 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4373 component = MSI_RecordGetString( row, 8 );
4374 comp = get_loaded_component( package, component );
4376 return ERROR_SUCCESS;
4380 TRACE("component is disabled\n");
4381 return ERROR_SUCCESS;
4384 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4386 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4387 comp->Action = comp->Installed;
4388 return ERROR_SUCCESS;
4390 comp->Action = INSTALLSTATE_LOCAL;
4392 identifier = MSI_RecordGetString( row, 1 );
4393 section = MSI_RecordGetString( row, 4 );
4394 key = MSI_RecordGetString( row, 5 );
4395 value = MSI_RecordGetString( row, 6 );
4396 action = MSI_RecordGetInteger( row, 7 );
4398 deformat_string( package, section, &deformated_section );
4399 deformat_string( package, key, &deformated_key );
4400 deformat_string( package, value, &deformated_value );
4402 if (action == msidbIniFileActionRemoveLine)
4404 filename = get_ini_file_name( package, row );
4406 TRACE("Removing key %s from section %s in %s\n",
4407 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4409 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4411 WARN("Unable to remove key %u\n", GetLastError());
4413 msi_free( filename );
4416 FIXME("Unsupported action %d\n", action);
4418 uirow = MSI_CreateRecord( 4 );
4419 MSI_RecordSetStringW( uirow, 1, identifier );
4420 MSI_RecordSetStringW( uirow, 2, deformated_section );
4421 MSI_RecordSetStringW( uirow, 3, deformated_key );
4422 MSI_RecordSetStringW( uirow, 4, deformated_value );
4423 ui_actiondata( package, szRemoveIniValues, uirow );
4424 msiobj_release( &uirow->hdr );
4426 msi_free( deformated_key );
4427 msi_free( deformated_value );
4428 msi_free( deformated_section );
4429 return ERROR_SUCCESS;
4432 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4436 static const WCHAR query[] =
4437 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4438 '`','I','n','i','F','i','l','e','`',0};
4439 static const WCHAR remove_query[] =
4440 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4441 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4443 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4444 if (rc == ERROR_SUCCESS)
4446 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4447 msiobj_release( &view->hdr );
4448 if (rc != ERROR_SUCCESS)
4452 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4453 if (rc == ERROR_SUCCESS)
4455 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4456 msiobj_release( &view->hdr );
4457 if (rc != ERROR_SUCCESS)
4461 return ERROR_SUCCESS;
4464 static void register_dll( const WCHAR *dll, BOOL unregister )
4468 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4471 HRESULT (WINAPI *func_ptr)( void );
4472 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4474 func_ptr = (void *)GetProcAddress( hmod, func );
4477 HRESULT hr = func_ptr();
4479 WARN("failed to register dll 0x%08x\n", hr);
4482 WARN("entry point %s not found\n", func);
4483 FreeLibrary( hmod );
4486 WARN("failed to load library %u\n", GetLastError());
4489 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4491 MSIPACKAGE *package = param;
4496 filename = MSI_RecordGetString(row,1);
4497 file = get_loaded_file( package, filename );
4501 ERR("Unable to find file id %s\n",debugstr_w(filename));
4502 return ERROR_SUCCESS;
4505 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4507 register_dll( file->TargetPath, FALSE );
4509 uirow = MSI_CreateRecord( 2 );
4510 MSI_RecordSetStringW( uirow, 1, filename );
4511 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4512 ui_actiondata( package, szSelfRegModules, uirow );
4513 msiobj_release( &uirow->hdr );
4515 return ERROR_SUCCESS;
4518 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4522 static const WCHAR ExecSeqQuery[] =
4523 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4524 '`','S','e','l','f','R','e','g','`',0};
4526 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4527 if (rc != ERROR_SUCCESS)
4529 TRACE("no SelfReg table\n");
4530 return ERROR_SUCCESS;
4533 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4534 msiobj_release(&view->hdr);
4536 return ERROR_SUCCESS;
4539 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4541 MSIPACKAGE *package = param;
4546 filename = MSI_RecordGetString( row, 1 );
4547 file = get_loaded_file( package, filename );
4551 ERR("Unable to find file id %s\n", debugstr_w(filename));
4552 return ERROR_SUCCESS;
4555 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4557 register_dll( file->TargetPath, TRUE );
4559 uirow = MSI_CreateRecord( 2 );
4560 MSI_RecordSetStringW( uirow, 1, filename );
4561 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4562 ui_actiondata( package, szSelfUnregModules, uirow );
4563 msiobj_release( &uirow->hdr );
4565 return ERROR_SUCCESS;
4568 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4572 static const WCHAR query[] =
4573 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4574 '`','S','e','l','f','R','e','g','`',0};
4576 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4577 if (rc != ERROR_SUCCESS)
4579 TRACE("no SelfReg table\n");
4580 return ERROR_SUCCESS;
4583 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4584 msiobj_release( &view->hdr );
4586 return ERROR_SUCCESS;
4589 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4591 MSIFEATURE *feature;
4593 HKEY hkey = NULL, userdata = NULL;
4595 if (!msi_check_publish(package))
4596 return ERROR_SUCCESS;
4598 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4600 if (rc != ERROR_SUCCESS)
4603 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4605 if (rc != ERROR_SUCCESS)
4608 /* here the guids are base 85 encoded */
4609 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4615 BOOL absent = FALSE;
4618 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4619 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4620 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4623 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4627 if (feature->Feature_Parent)
4628 size += strlenW( feature->Feature_Parent )+2;
4630 data = msi_alloc(size * sizeof(WCHAR));
4633 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4635 MSICOMPONENT* component = cl->component;
4639 if (component->ComponentId)
4641 TRACE("From %s\n",debugstr_w(component->ComponentId));
4642 CLSIDFromString(component->ComponentId, &clsid);
4643 encode_base85_guid(&clsid,buf);
4644 TRACE("to %s\n",debugstr_w(buf));
4649 if (feature->Feature_Parent)
4651 static const WCHAR sep[] = {'\2',0};
4653 strcatW(data,feature->Feature_Parent);
4656 msi_reg_set_val_str( userdata, feature->Feature, data );
4660 if (feature->Feature_Parent)
4661 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4664 size += sizeof(WCHAR);
4665 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4666 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4670 size += 2*sizeof(WCHAR);
4671 data = msi_alloc(size);
4674 if (feature->Feature_Parent)
4675 strcpyW( &data[1], feature->Feature_Parent );
4676 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4682 uirow = MSI_CreateRecord( 1 );
4683 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4684 ui_actiondata( package, szPublishFeatures, uirow);
4685 msiobj_release( &uirow->hdr );
4686 /* FIXME: call ui_progress? */
4691 RegCloseKey(userdata);
4695 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4701 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4703 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4705 if (r == ERROR_SUCCESS)
4707 RegDeleteValueW(hkey, feature->Feature);
4711 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4713 if (r == ERROR_SUCCESS)
4715 RegDeleteValueW(hkey, feature->Feature);
4719 uirow = MSI_CreateRecord( 1 );
4720 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4721 ui_actiondata( package, szUnpublishFeatures, uirow );
4722 msiobj_release( &uirow->hdr );
4724 return ERROR_SUCCESS;
4727 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4729 MSIFEATURE *feature;
4731 if (!msi_check_unpublish(package))
4732 return ERROR_SUCCESS;
4734 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4736 msi_unpublish_feature(package, feature);
4739 return ERROR_SUCCESS;
4742 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4746 WCHAR date[9], *val, *buffer;
4747 const WCHAR *prop, *key;
4749 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4750 static const WCHAR szWindowsInstaller[] =
4751 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4752 static const WCHAR modpath_fmt[] =
4753 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4754 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4755 static const WCHAR szModifyPath[] =
4756 {'M','o','d','i','f','y','P','a','t','h',0};
4757 static const WCHAR szUninstallString[] =
4758 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4759 static const WCHAR szEstimatedSize[] =
4760 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4761 static const WCHAR szProductLanguage[] =
4762 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4763 static const WCHAR szProductVersion[] =
4764 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4765 static const WCHAR szDisplayVersion[] =
4766 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4767 static const WCHAR szInstallSource[] =
4768 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4769 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4770 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4771 static const WCHAR szAuthorizedCDFPrefix[] =
4772 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4773 static const WCHAR szARPCONTACT[] =
4774 {'A','R','P','C','O','N','T','A','C','T',0};
4775 static const WCHAR szContact[] =
4776 {'C','o','n','t','a','c','t',0};
4777 static const WCHAR szARPCOMMENTS[] =
4778 {'A','R','P','C','O','M','M','E','N','T','S',0};
4779 static const WCHAR szComments[] =
4780 {'C','o','m','m','e','n','t','s',0};
4781 static const WCHAR szProductName[] =
4782 {'P','r','o','d','u','c','t','N','a','m','e',0};
4783 static const WCHAR szDisplayName[] =
4784 {'D','i','s','p','l','a','y','N','a','m','e',0};
4785 static const WCHAR szARPHELPLINK[] =
4786 {'A','R','P','H','E','L','P','L','I','N','K',0};
4787 static const WCHAR szHelpLink[] =
4788 {'H','e','l','p','L','i','n','k',0};
4789 static const WCHAR szARPHELPTELEPHONE[] =
4790 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4791 static const WCHAR szHelpTelephone[] =
4792 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4793 static const WCHAR szARPINSTALLLOCATION[] =
4794 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4795 static const WCHAR szInstallLocation[] =
4796 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4797 static const WCHAR szManufacturer[] =
4798 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4799 static const WCHAR szPublisher[] =
4800 {'P','u','b','l','i','s','h','e','r',0};
4801 static const WCHAR szARPREADME[] =
4802 {'A','R','P','R','E','A','D','M','E',0};
4803 static const WCHAR szReadme[] =
4804 {'R','e','a','d','M','e',0};
4805 static const WCHAR szARPSIZE[] =
4806 {'A','R','P','S','I','Z','E',0};
4807 static const WCHAR szSize[] =
4808 {'S','i','z','e',0};
4809 static const WCHAR szARPURLINFOABOUT[] =
4810 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4811 static const WCHAR szURLInfoAbout[] =
4812 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4813 static const WCHAR szARPURLUPDATEINFO[] =
4814 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4815 static const WCHAR szURLUpdateInfo[] =
4816 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4818 static const WCHAR *propval[] = {
4819 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4820 szARPCONTACT, szContact,
4821 szARPCOMMENTS, szComments,
4822 szProductName, szDisplayName,
4823 szARPHELPLINK, szHelpLink,
4824 szARPHELPTELEPHONE, szHelpTelephone,
4825 szARPINSTALLLOCATION, szInstallLocation,
4826 cszSourceDir, szInstallSource,
4827 szManufacturer, szPublisher,
4828 szARPREADME, szReadme,
4830 szARPURLINFOABOUT, szURLInfoAbout,
4831 szARPURLUPDATEINFO, szURLUpdateInfo,
4834 const WCHAR **p = propval;
4840 val = msi_dup_property(package->db, prop);
4841 msi_reg_set_val_str(hkey, key, val);
4845 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4847 size = deformat_string(package, modpath_fmt, &buffer);
4848 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4849 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4852 /* FIXME: Write real Estimated Size when we have it */
4853 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4855 GetLocalTime(&systime);
4856 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4857 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4859 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4860 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4862 buffer = msi_dup_property(package->db, szProductVersion);
4863 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4866 DWORD verdword = msi_version_str_to_dword(buffer);
4868 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4869 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4870 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4874 return ERROR_SUCCESS;
4877 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4879 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4881 LPWSTR upgrade_code;
4886 /* FIXME: also need to publish if the product is in advertise mode */
4887 if (!msi_check_publish(package))
4888 return ERROR_SUCCESS;
4890 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4891 if (rc != ERROR_SUCCESS)
4894 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4895 NULL, &props, TRUE);
4896 if (rc != ERROR_SUCCESS)
4899 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4900 msi_free( package->db->localfile );
4901 package->db->localfile = NULL;
4903 rc = msi_publish_install_properties(package, hkey);
4904 if (rc != ERROR_SUCCESS)
4907 rc = msi_publish_install_properties(package, props);
4908 if (rc != ERROR_SUCCESS)
4911 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4914 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4915 squash_guid(package->ProductCode, squashed_pc);
4916 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4917 RegCloseKey(upgrade);
4918 msi_free(upgrade_code);
4922 uirow = MSI_CreateRecord( 1 );
4923 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4924 ui_actiondata( package, szRegisterProduct, uirow );
4925 msiobj_release( &uirow->hdr );
4928 return ERROR_SUCCESS;
4931 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4933 return execute_script(package,INSTALL_SCRIPT);
4936 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4938 WCHAR *upgrade, **features;
4939 BOOL full_uninstall = TRUE;
4940 MSIFEATURE *feature;
4941 MSIPATCHINFO *patch;
4943 static const WCHAR szUpgradeCode[] =
4944 {'U','p','g','r','a','d','e','C','o','d','e',0};
4946 features = msi_split_string(remove, ',');
4949 ERR("REMOVE feature list is empty!\n");
4950 return ERROR_FUNCTION_FAILED;
4953 if (!strcmpW( features[0], szAll ))
4954 full_uninstall = TRUE;
4957 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4959 if (feature->Action != INSTALLSTATE_ABSENT)
4960 full_uninstall = FALSE;
4965 if (!full_uninstall)
4966 return ERROR_SUCCESS;
4968 MSIREG_DeleteProductKey(package->ProductCode);
4969 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4970 MSIREG_DeleteUninstallKey(package);
4972 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4974 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4975 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4979 MSIREG_DeleteUserProductKey(package->ProductCode);
4980 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4983 upgrade = msi_dup_property(package->db, szUpgradeCode);
4986 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4990 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4992 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4995 return ERROR_SUCCESS;
4998 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5003 /* turn off scheduling */
5004 package->script->CurrentlyScripting= FALSE;
5006 /* first do the same as an InstallExecute */
5007 rc = ACTION_InstallExecute(package);
5008 if (rc != ERROR_SUCCESS)
5011 /* then handle Commit Actions */
5012 rc = execute_script(package,COMMIT_SCRIPT);
5013 if (rc != ERROR_SUCCESS)
5016 remove = msi_dup_property(package->db, szRemove);
5018 rc = msi_unpublish_product(package, remove);
5024 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5026 static const WCHAR RunOnce[] = {
5027 'S','o','f','t','w','a','r','e','\\',
5028 'M','i','c','r','o','s','o','f','t','\\',
5029 'W','i','n','d','o','w','s','\\',
5030 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5031 'R','u','n','O','n','c','e',0};
5032 static const WCHAR InstallRunOnce[] = {
5033 'S','o','f','t','w','a','r','e','\\',
5034 'M','i','c','r','o','s','o','f','t','\\',
5035 'W','i','n','d','o','w','s','\\',
5036 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5037 'I','n','s','t','a','l','l','e','r','\\',
5038 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5040 static const WCHAR msiexec_fmt[] = {
5042 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5043 '\"','%','s','\"',0};
5044 static const WCHAR install_fmt[] = {
5045 '/','I',' ','\"','%','s','\"',' ',
5046 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5047 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5048 WCHAR buffer[256], sysdir[MAX_PATH];
5050 WCHAR squished_pc[100];
5052 squash_guid(package->ProductCode,squished_pc);
5054 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5055 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5056 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5059 msi_reg_set_val_str( hkey, squished_pc, buffer );
5062 TRACE("Reboot command %s\n",debugstr_w(buffer));
5064 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5065 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5067 msi_reg_set_val_str( hkey, squished_pc, buffer );
5070 return ERROR_INSTALL_SUSPEND;
5073 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5079 * We are currently doing what should be done here in the top level Install
5080 * however for Administrative and uninstalls this step will be needed
5082 if (!package->PackagePath)
5083 return ERROR_SUCCESS;
5085 msi_set_sourcedir_props(package, TRUE);
5087 attrib = GetFileAttributesW(package->db->path);
5088 if (attrib == INVALID_FILE_ATTRIBUTES)
5094 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5095 package->Context, MSICODE_PRODUCT,
5096 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5097 if (rc == ERROR_MORE_DATA)
5099 prompt = msi_alloc(size * sizeof(WCHAR));
5100 MsiSourceListGetInfoW(package->ProductCode, NULL,
5101 package->Context, MSICODE_PRODUCT,
5102 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5105 prompt = strdupW(package->db->path);
5107 msg = generate_error_string(package,1302,1,prompt);
5108 while(attrib == INVALID_FILE_ATTRIBUTES)
5110 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5113 rc = ERROR_INSTALL_USEREXIT;
5116 attrib = GetFileAttributesW(package->db->path);
5122 return ERROR_SUCCESS;
5127 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5130 LPWSTR buffer, productid = NULL;
5131 UINT i, rc = ERROR_SUCCESS;
5134 static const WCHAR szPropKeys[][80] =
5136 {'P','r','o','d','u','c','t','I','D',0},
5137 {'U','S','E','R','N','A','M','E',0},
5138 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5142 static const WCHAR szRegKeys[][80] =
5144 {'P','r','o','d','u','c','t','I','D',0},
5145 {'R','e','g','O','w','n','e','r',0},
5146 {'R','e','g','C','o','m','p','a','n','y',0},
5150 if (msi_check_unpublish(package))
5152 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5156 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5160 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5162 if (rc != ERROR_SUCCESS)
5165 for( i = 0; szPropKeys[i][0]; i++ )
5167 buffer = msi_dup_property( package->db, szPropKeys[i] );
5168 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5173 uirow = MSI_CreateRecord( 1 );
5174 MSI_RecordSetStringW( uirow, 1, productid );
5175 ui_actiondata( package, szRegisterUser, uirow );
5176 msiobj_release( &uirow->hdr );
5178 msi_free(productid);
5184 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5188 package->script->InWhatSequence |= SEQUENCE_EXEC;
5189 rc = ACTION_ProcessExecSequence(package,FALSE);
5194 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5196 MSIPACKAGE *package = param;
5197 LPCWSTR compgroupid, component, feature, qualifier, text;
5198 LPWSTR advertise = NULL, output = NULL;
5206 feature = MSI_RecordGetString(rec, 5);
5207 feat = get_loaded_feature(package, feature);
5209 return ERROR_SUCCESS;
5211 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5212 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5213 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5215 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5216 feat->Action = feat->Installed;
5217 return ERROR_SUCCESS;
5220 component = MSI_RecordGetString(rec, 3);
5221 comp = get_loaded_component(package, component);
5223 return ERROR_SUCCESS;
5225 compgroupid = MSI_RecordGetString(rec,1);
5226 qualifier = MSI_RecordGetString(rec,2);
5228 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5229 if (rc != ERROR_SUCCESS)
5232 text = MSI_RecordGetString(rec,4);
5233 advertise = create_component_advertise_string(package, comp, feature);
5235 sz = strlenW(advertise);
5238 sz += lstrlenW(text);
5241 sz *= sizeof(WCHAR);
5243 output = msi_alloc_zero(sz);
5244 strcpyW(output,advertise);
5245 msi_free(advertise);
5248 strcatW(output,text);
5250 msi_reg_set_val_multi_str( hkey, qualifier, output );
5257 uirow = MSI_CreateRecord( 2 );
5258 MSI_RecordSetStringW( uirow, 1, compgroupid );
5259 MSI_RecordSetStringW( uirow, 2, qualifier);
5260 ui_actiondata( package, szPublishComponents, uirow);
5261 msiobj_release( &uirow->hdr );
5262 /* FIXME: call ui_progress? */
5268 * At present I am ignorning the advertised components part of this and only
5269 * focusing on the qualified component sets
5271 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5275 static const WCHAR ExecSeqQuery[] =
5276 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5277 '`','P','u','b','l','i','s','h',
5278 'C','o','m','p','o','n','e','n','t','`',0};
5280 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5281 if (rc != ERROR_SUCCESS)
5282 return ERROR_SUCCESS;
5284 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5285 msiobj_release(&view->hdr);
5290 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5292 static const WCHAR szInstallerComponents[] = {
5293 'S','o','f','t','w','a','r','e','\\',
5294 'M','i','c','r','o','s','o','f','t','\\',
5295 'I','n','s','t','a','l','l','e','r','\\',
5296 'C','o','m','p','o','n','e','n','t','s','\\',0};
5298 MSIPACKAGE *package = param;
5299 LPCWSTR compgroupid, component, feature, qualifier;
5303 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5306 feature = MSI_RecordGetString( rec, 5 );
5307 feat = get_loaded_feature( package, feature );
5309 return ERROR_SUCCESS;
5311 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5313 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5314 feat->Action = feat->Installed;
5315 return ERROR_SUCCESS;
5318 component = MSI_RecordGetString( rec, 3 );
5319 comp = get_loaded_component( package, component );
5321 return ERROR_SUCCESS;
5323 compgroupid = MSI_RecordGetString( rec, 1 );
5324 qualifier = MSI_RecordGetString( rec, 2 );
5326 squash_guid( compgroupid, squashed );
5327 strcpyW( keypath, szInstallerComponents );
5328 strcatW( keypath, squashed );
5330 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5331 if (res != ERROR_SUCCESS)
5333 WARN("Unable to delete component key %d\n", res);
5336 uirow = MSI_CreateRecord( 2 );
5337 MSI_RecordSetStringW( uirow, 1, compgroupid );
5338 MSI_RecordSetStringW( uirow, 2, qualifier );
5339 ui_actiondata( package, szUnpublishComponents, uirow );
5340 msiobj_release( &uirow->hdr );
5342 return ERROR_SUCCESS;
5345 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5349 static const WCHAR query[] =
5350 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5351 '`','P','u','b','l','i','s','h',
5352 'C','o','m','p','o','n','e','n','t','`',0};
5354 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5355 if (rc != ERROR_SUCCESS)
5356 return ERROR_SUCCESS;
5358 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5359 msiobj_release( &view->hdr );
5364 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5366 MSIPACKAGE *package = param;
5369 SC_HANDLE hscm, service = NULL;
5371 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5372 LPWSTR depends = NULL, pass = NULL;
5373 DWORD serv_type, start_type;
5375 SERVICE_DESCRIPTIONW sd = {NULL};
5377 static const WCHAR query[] =
5378 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5379 '`','C','o','m','p','o','n','e','n','t','`',' ',
5380 'W','H','E','R','E',' ',
5381 '`','C','o','m','p','o','n','e','n','t','`',' ',
5382 '=','\'','%','s','\'',0};
5384 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5387 ERR("Failed to open the SC Manager!\n");
5391 start_type = MSI_RecordGetInteger(rec, 5);
5392 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5395 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5396 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5397 serv_type = MSI_RecordGetInteger(rec, 4);
5398 err_control = MSI_RecordGetInteger(rec, 6);
5399 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5400 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5401 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5402 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5403 comp = MSI_RecordGetString(rec, 12);
5404 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5406 /* fetch the service path */
5407 row = MSI_QueryGetRecord(package->db, query, comp);
5410 ERR("Control query failed!\n");
5413 key = MSI_RecordGetString(row, 6);
5415 file = get_loaded_file(package, key);
5416 msiobj_release(&row->hdr);
5419 ERR("Failed to load the service file\n");
5423 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5424 start_type, err_control, file->TargetPath,
5425 load_order, NULL, depends, serv_name, pass);
5428 if (GetLastError() != ERROR_SERVICE_EXISTS)
5429 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5431 else if (sd.lpDescription)
5433 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5434 WARN("failed to set service description %u\n", GetLastError());
5438 CloseServiceHandle(service);
5439 CloseServiceHandle(hscm);
5442 msi_free(sd.lpDescription);
5443 msi_free(load_order);
5444 msi_free(serv_name);
5448 return ERROR_SUCCESS;
5451 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5455 static const WCHAR ExecSeqQuery[] =
5456 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5457 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5459 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5460 if (rc != ERROR_SUCCESS)
5461 return ERROR_SUCCESS;
5463 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5464 msiobj_release(&view->hdr);
5469 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5470 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5472 LPCWSTR *vector, *temp_vector;
5476 static const WCHAR separator[] = {'[','~',']',0};
5479 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5484 vector = msi_alloc(sizeof(LPWSTR));
5492 vector[*numargs - 1] = p;
5494 if ((q = strstrW(p, separator)))
5498 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5504 vector = temp_vector;
5513 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5515 MSIPACKAGE *package = param;
5518 SC_HANDLE scm = NULL, service = NULL;
5519 LPCWSTR component, *vector = NULL;
5520 LPWSTR name, args, display_name = NULL;
5521 DWORD event, numargs, len;
5522 UINT r = ERROR_FUNCTION_FAILED;
5524 component = MSI_RecordGetString(rec, 6);
5525 comp = get_loaded_component(package, component);
5527 return ERROR_SUCCESS;
5531 TRACE("component is disabled\n");
5532 return ERROR_SUCCESS;
5535 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5537 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5538 comp->Action = comp->Installed;
5539 return ERROR_SUCCESS;
5541 comp->Action = INSTALLSTATE_LOCAL;
5543 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5544 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5545 event = MSI_RecordGetInteger(rec, 3);
5547 if (!(event & msidbServiceControlEventStart))
5553 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5556 ERR("Failed to open the service control manager\n");
5561 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5562 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5564 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5565 GetServiceDisplayNameW( scm, name, display_name, &len );
5568 service = OpenServiceW(scm, name, SERVICE_START);
5571 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5575 vector = msi_service_args_to_vector(args, &numargs);
5577 if (!StartServiceW(service, numargs, vector) &&
5578 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5580 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5587 uirow = MSI_CreateRecord( 2 );
5588 MSI_RecordSetStringW( uirow, 1, display_name );
5589 MSI_RecordSetStringW( uirow, 2, name );
5590 ui_actiondata( package, szStartServices, uirow );
5591 msiobj_release( &uirow->hdr );
5593 CloseServiceHandle(service);
5594 CloseServiceHandle(scm);
5599 msi_free(display_name);
5603 static UINT ACTION_StartServices( MSIPACKAGE *package )
5608 static const WCHAR query[] = {
5609 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5610 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5612 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5613 if (rc != ERROR_SUCCESS)
5614 return ERROR_SUCCESS;
5616 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5617 msiobj_release(&view->hdr);
5622 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5624 DWORD i, needed, count;
5625 ENUM_SERVICE_STATUSW *dependencies;
5629 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5630 0, &needed, &count))
5633 if (GetLastError() != ERROR_MORE_DATA)
5636 dependencies = msi_alloc(needed);
5640 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5641 needed, &needed, &count))
5644 for (i = 0; i < count; i++)
5646 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5647 SERVICE_STOP | SERVICE_QUERY_STATUS);
5651 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5658 msi_free(dependencies);
5662 static UINT stop_service( LPCWSTR name )
5664 SC_HANDLE scm = NULL, service = NULL;
5665 SERVICE_STATUS status;
5666 SERVICE_STATUS_PROCESS ssp;
5669 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5672 WARN("Failed to open the SCM: %d\n", GetLastError());
5676 service = OpenServiceW(scm, name,
5678 SERVICE_QUERY_STATUS |
5679 SERVICE_ENUMERATE_DEPENDENTS);
5682 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5686 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5687 sizeof(SERVICE_STATUS_PROCESS), &needed))
5689 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5693 if (ssp.dwCurrentState == SERVICE_STOPPED)
5696 stop_service_dependents(scm, service);
5698 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5699 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5702 CloseServiceHandle(service);
5703 CloseServiceHandle(scm);
5705 return ERROR_SUCCESS;
5708 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5710 MSIPACKAGE *package = param;
5714 LPWSTR name = NULL, display_name = NULL;
5718 event = MSI_RecordGetInteger( rec, 3 );
5719 if (!(event & msidbServiceControlEventStop))
5720 return ERROR_SUCCESS;
5722 component = MSI_RecordGetString( rec, 6 );
5723 comp = get_loaded_component( package, component );
5725 return ERROR_SUCCESS;
5729 TRACE("component is disabled\n");
5730 return ERROR_SUCCESS;
5733 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5735 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5736 comp->Action = comp->Installed;
5737 return ERROR_SUCCESS;
5739 comp->Action = INSTALLSTATE_ABSENT;
5741 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5744 ERR("Failed to open the service control manager\n");
5749 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5750 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5752 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5753 GetServiceDisplayNameW( scm, name, display_name, &len );
5755 CloseServiceHandle( scm );
5757 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5758 stop_service( name );
5761 uirow = MSI_CreateRecord( 2 );
5762 MSI_RecordSetStringW( uirow, 1, display_name );
5763 MSI_RecordSetStringW( uirow, 2, name );
5764 ui_actiondata( package, szStopServices, uirow );
5765 msiobj_release( &uirow->hdr );
5768 msi_free( display_name );
5769 return ERROR_SUCCESS;
5772 static UINT ACTION_StopServices( MSIPACKAGE *package )
5777 static const WCHAR query[] = {
5778 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5779 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5781 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5782 if (rc != ERROR_SUCCESS)
5783 return ERROR_SUCCESS;
5785 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5786 msiobj_release(&view->hdr);
5791 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5793 MSIPACKAGE *package = param;
5797 LPWSTR name = NULL, display_name = NULL;
5799 SC_HANDLE scm = NULL, service = NULL;
5801 event = MSI_RecordGetInteger( rec, 3 );
5802 if (!(event & msidbServiceControlEventDelete))
5803 return ERROR_SUCCESS;
5805 component = MSI_RecordGetString(rec, 6);
5806 comp = get_loaded_component(package, component);
5808 return ERROR_SUCCESS;
5812 TRACE("component is disabled\n");
5813 return ERROR_SUCCESS;
5816 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5818 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5819 comp->Action = comp->Installed;
5820 return ERROR_SUCCESS;
5822 comp->Action = INSTALLSTATE_ABSENT;
5824 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5825 stop_service( name );
5827 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5830 WARN("Failed to open the SCM: %d\n", GetLastError());
5835 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5836 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5838 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5839 GetServiceDisplayNameW( scm, name, display_name, &len );
5842 service = OpenServiceW( scm, name, DELETE );
5845 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5849 if (!DeleteService( service ))
5850 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5853 uirow = MSI_CreateRecord( 2 );
5854 MSI_RecordSetStringW( uirow, 1, display_name );
5855 MSI_RecordSetStringW( uirow, 2, name );
5856 ui_actiondata( package, szDeleteServices, uirow );
5857 msiobj_release( &uirow->hdr );
5859 CloseServiceHandle( service );
5860 CloseServiceHandle( scm );
5862 msi_free( display_name );
5864 return ERROR_SUCCESS;
5867 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5872 static const WCHAR query[] = {
5873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5874 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5876 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5877 if (rc != ERROR_SUCCESS)
5878 return ERROR_SUCCESS;
5880 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5881 msiobj_release( &view->hdr );
5886 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5890 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5892 if (!strcmpW( file->File, filename ))
5899 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5901 MSIPACKAGE *package = param;
5902 LPWSTR driver, driver_path, ptr;
5903 WCHAR outpath[MAX_PATH];
5904 MSIFILE *driver_file = NULL, *setup_file = NULL;
5906 LPCWSTR desc, file_key;
5908 UINT r = ERROR_SUCCESS;
5910 static const WCHAR driver_fmt[] = {
5911 'D','r','i','v','e','r','=','%','s',0};
5912 static const WCHAR setup_fmt[] = {
5913 'S','e','t','u','p','=','%','s',0};
5914 static const WCHAR usage_fmt[] = {
5915 'F','i','l','e','U','s','a','g','e','=','1',0};
5917 desc = MSI_RecordGetString(rec, 3);
5919 file_key = MSI_RecordGetString( rec, 4 );
5920 if (file_key) driver_file = msi_find_file( package, file_key );
5922 file_key = MSI_RecordGetString( rec, 5 );
5923 if (file_key) setup_file = msi_find_file( package, file_key );
5927 ERR("ODBC Driver entry not found!\n");
5928 return ERROR_FUNCTION_FAILED;
5931 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5933 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5934 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5936 driver = msi_alloc(len * sizeof(WCHAR));
5938 return ERROR_OUTOFMEMORY;
5941 lstrcpyW(ptr, desc);
5942 ptr += lstrlenW(ptr) + 1;
5944 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5949 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5953 lstrcpyW(ptr, usage_fmt);
5954 ptr += lstrlenW(ptr) + 1;
5957 driver_path = strdupW(driver_file->TargetPath);
5958 ptr = strrchrW(driver_path, '\\');
5959 if (ptr) *ptr = '\0';
5961 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5962 NULL, ODBC_INSTALL_COMPLETE, &usage))
5964 ERR("Failed to install SQL driver!\n");
5965 r = ERROR_FUNCTION_FAILED;
5968 uirow = MSI_CreateRecord( 5 );
5969 MSI_RecordSetStringW( uirow, 1, desc );
5970 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5971 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5972 ui_actiondata( package, szInstallODBC, uirow );
5973 msiobj_release( &uirow->hdr );
5976 msi_free(driver_path);
5981 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5983 MSIPACKAGE *package = param;
5984 LPWSTR translator, translator_path, ptr;
5985 WCHAR outpath[MAX_PATH];
5986 MSIFILE *translator_file = NULL, *setup_file = NULL;
5988 LPCWSTR desc, file_key;
5990 UINT r = ERROR_SUCCESS;
5992 static const WCHAR translator_fmt[] = {
5993 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5994 static const WCHAR setup_fmt[] = {
5995 'S','e','t','u','p','=','%','s',0};
5997 desc = MSI_RecordGetString(rec, 3);
5999 file_key = MSI_RecordGetString( rec, 4 );
6000 if (file_key) translator_file = msi_find_file( package, file_key );
6002 file_key = MSI_RecordGetString( rec, 5 );
6003 if (file_key) setup_file = msi_find_file( package, file_key );
6005 if (!translator_file)
6007 ERR("ODBC Translator entry not found!\n");
6008 return ERROR_FUNCTION_FAILED;
6011 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6013 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6015 translator = msi_alloc(len * sizeof(WCHAR));
6017 return ERROR_OUTOFMEMORY;
6020 lstrcpyW(ptr, desc);
6021 ptr += lstrlenW(ptr) + 1;
6023 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6028 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6033 translator_path = strdupW(translator_file->TargetPath);
6034 ptr = strrchrW(translator_path, '\\');
6035 if (ptr) *ptr = '\0';
6037 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6038 NULL, ODBC_INSTALL_COMPLETE, &usage))
6040 ERR("Failed to install SQL translator!\n");
6041 r = ERROR_FUNCTION_FAILED;
6044 uirow = MSI_CreateRecord( 5 );
6045 MSI_RecordSetStringW( uirow, 1, desc );
6046 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6047 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6048 ui_actiondata( package, szInstallODBC, uirow );
6049 msiobj_release( &uirow->hdr );
6051 msi_free(translator);
6052 msi_free(translator_path);
6057 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6059 MSIPACKAGE *package = param;
6061 LPCWSTR desc, driver;
6062 WORD request = ODBC_ADD_SYS_DSN;
6065 UINT r = ERROR_SUCCESS;
6068 static const WCHAR attrs_fmt[] = {
6069 'D','S','N','=','%','s',0 };
6071 desc = MSI_RecordGetString(rec, 3);
6072 driver = MSI_RecordGetString(rec, 4);
6073 registration = MSI_RecordGetInteger(rec, 5);
6075 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6076 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6078 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6079 attrs = msi_alloc(len * sizeof(WCHAR));
6081 return ERROR_OUTOFMEMORY;
6083 len = sprintfW(attrs, attrs_fmt, desc);
6086 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6088 ERR("Failed to install SQL data source!\n");
6089 r = ERROR_FUNCTION_FAILED;
6092 uirow = MSI_CreateRecord( 5 );
6093 MSI_RecordSetStringW( uirow, 1, desc );
6094 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6095 MSI_RecordSetInteger( uirow, 3, request );
6096 ui_actiondata( package, szInstallODBC, uirow );
6097 msiobj_release( &uirow->hdr );
6104 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6109 static const WCHAR driver_query[] = {
6110 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6111 'O','D','B','C','D','r','i','v','e','r',0 };
6113 static const WCHAR translator_query[] = {
6114 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6115 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6117 static const WCHAR source_query[] = {
6118 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6119 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6121 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6122 if (rc != ERROR_SUCCESS)
6123 return ERROR_SUCCESS;
6125 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6126 msiobj_release(&view->hdr);
6128 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6129 if (rc != ERROR_SUCCESS)
6130 return ERROR_SUCCESS;
6132 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6133 msiobj_release(&view->hdr);
6135 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6136 if (rc != ERROR_SUCCESS)
6137 return ERROR_SUCCESS;
6139 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6140 msiobj_release(&view->hdr);
6145 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6147 MSIPACKAGE *package = param;
6152 desc = MSI_RecordGetString( rec, 3 );
6153 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6155 WARN("Failed to remove ODBC driver\n");
6159 FIXME("Usage count reached 0\n");
6162 uirow = MSI_CreateRecord( 2 );
6163 MSI_RecordSetStringW( uirow, 1, desc );
6164 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165 ui_actiondata( package, szRemoveODBC, uirow );
6166 msiobj_release( &uirow->hdr );
6168 return ERROR_SUCCESS;
6171 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6173 MSIPACKAGE *package = param;
6178 desc = MSI_RecordGetString( rec, 3 );
6179 if (!SQLRemoveTranslatorW( desc, &usage ))
6181 WARN("Failed to remove ODBC translator\n");
6185 FIXME("Usage count reached 0\n");
6188 uirow = MSI_CreateRecord( 2 );
6189 MSI_RecordSetStringW( uirow, 1, desc );
6190 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6191 ui_actiondata( package, szRemoveODBC, uirow );
6192 msiobj_release( &uirow->hdr );
6194 return ERROR_SUCCESS;
6197 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6199 MSIPACKAGE *package = param;
6202 LPCWSTR desc, driver;
6203 WORD request = ODBC_REMOVE_SYS_DSN;
6207 static const WCHAR attrs_fmt[] = {
6208 'D','S','N','=','%','s',0 };
6210 desc = MSI_RecordGetString( rec, 3 );
6211 driver = MSI_RecordGetString( rec, 4 );
6212 registration = MSI_RecordGetInteger( rec, 5 );
6214 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6215 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6217 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6218 attrs = msi_alloc( len * sizeof(WCHAR) );
6220 return ERROR_OUTOFMEMORY;
6222 FIXME("Use ODBCSourceAttribute table\n");
6224 len = sprintfW( attrs, attrs_fmt, desc );
6227 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6229 WARN("Failed to remove ODBC data source\n");
6233 uirow = MSI_CreateRecord( 3 );
6234 MSI_RecordSetStringW( uirow, 1, desc );
6235 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6236 MSI_RecordSetInteger( uirow, 3, request );
6237 ui_actiondata( package, szRemoveODBC, uirow );
6238 msiobj_release( &uirow->hdr );
6240 return ERROR_SUCCESS;
6243 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6248 static const WCHAR driver_query[] = {
6249 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6250 'O','D','B','C','D','r','i','v','e','r',0 };
6252 static const WCHAR translator_query[] = {
6253 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6254 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6256 static const WCHAR source_query[] = {
6257 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6258 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6260 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6261 if (rc != ERROR_SUCCESS)
6262 return ERROR_SUCCESS;
6264 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6265 msiobj_release( &view->hdr );
6267 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6268 if (rc != ERROR_SUCCESS)
6269 return ERROR_SUCCESS;
6271 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6272 msiobj_release( &view->hdr );
6274 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6275 if (rc != ERROR_SUCCESS)
6276 return ERROR_SUCCESS;
6278 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6279 msiobj_release( &view->hdr );
6284 #define ENV_ACT_SETALWAYS 0x1
6285 #define ENV_ACT_SETABSENT 0x2
6286 #define ENV_ACT_REMOVE 0x4
6287 #define ENV_ACT_REMOVEMATCH 0x8
6289 #define ENV_MOD_MACHINE 0x20000000
6290 #define ENV_MOD_APPEND 0x40000000
6291 #define ENV_MOD_PREFIX 0x80000000
6292 #define ENV_MOD_MASK 0xC0000000
6294 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6296 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6298 LPCWSTR cptr = *name;
6300 static const WCHAR prefix[] = {'[','~',']',0};
6301 static const int prefix_len = 3;
6307 *flags |= ENV_ACT_SETALWAYS;
6308 else if (*cptr == '+')
6309 *flags |= ENV_ACT_SETABSENT;
6310 else if (*cptr == '-')
6311 *flags |= ENV_ACT_REMOVE;
6312 else if (*cptr == '!')
6313 *flags |= ENV_ACT_REMOVEMATCH;
6314 else if (*cptr == '*')
6315 *flags |= ENV_MOD_MACHINE;
6325 ERR("Missing environment variable\n");
6326 return ERROR_FUNCTION_FAILED;
6331 LPCWSTR ptr = *value;
6332 if (!strncmpW(ptr, prefix, prefix_len))
6334 if (ptr[prefix_len] == szSemiColon[0])
6336 *flags |= ENV_MOD_APPEND;
6337 *value += lstrlenW(prefix);
6344 else if (lstrlenW(*value) >= prefix_len)
6346 ptr += lstrlenW(ptr) - prefix_len;
6347 if (!strcmpW( ptr, prefix ))
6349 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6351 *flags |= ENV_MOD_PREFIX;
6352 /* the "[~]" will be removed by deformat_string */;
6362 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6363 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6364 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6365 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6367 ERR("Invalid flags: %08x\n", *flags);
6368 return ERROR_FUNCTION_FAILED;
6372 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6374 return ERROR_SUCCESS;
6377 static UINT open_env_key( DWORD flags, HKEY *key )
6379 static const WCHAR user_env[] =
6380 {'E','n','v','i','r','o','n','m','e','n','t',0};
6381 static const WCHAR machine_env[] =
6382 {'S','y','s','t','e','m','\\',
6383 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6384 'C','o','n','t','r','o','l','\\',
6385 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6386 'E','n','v','i','r','o','n','m','e','n','t',0};
6391 if (flags & ENV_MOD_MACHINE)
6394 root = HKEY_LOCAL_MACHINE;
6399 root = HKEY_CURRENT_USER;
6402 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6403 if (res != ERROR_SUCCESS)
6405 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6406 return ERROR_FUNCTION_FAILED;
6409 return ERROR_SUCCESS;
6412 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6414 MSIPACKAGE *package = param;
6415 LPCWSTR name, value, component;
6416 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6417 DWORD flags, type, size;
6424 component = MSI_RecordGetString(rec, 4);
6425 comp = get_loaded_component(package, component);
6427 return ERROR_SUCCESS;
6431 TRACE("component is disabled\n");
6432 return ERROR_SUCCESS;
6435 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6437 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6438 comp->Action = comp->Installed;
6439 return ERROR_SUCCESS;
6441 comp->Action = INSTALLSTATE_LOCAL;
6443 name = MSI_RecordGetString(rec, 2);
6444 value = MSI_RecordGetString(rec, 3);
6446 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6448 res = env_parse_flags(&name, &value, &flags);
6449 if (res != ERROR_SUCCESS || !value)
6452 if (value && !deformat_string(package, value, &deformatted))
6454 res = ERROR_OUTOFMEMORY;
6458 value = deformatted;
6460 res = open_env_key( flags, &env );
6461 if (res != ERROR_SUCCESS)
6464 if (flags & ENV_MOD_MACHINE)
6465 action |= 0x20000000;
6469 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6470 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6471 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6474 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6478 /* Nothing to do. */
6481 res = ERROR_SUCCESS;
6485 /* If we are appending but the string was empty, strip ; */
6486 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6488 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6489 newval = strdupW(value);
6492 res = ERROR_OUTOFMEMORY;
6500 /* Contrary to MSDN, +-variable to [~];path works */
6501 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6503 res = ERROR_SUCCESS;
6507 data = msi_alloc(size);
6511 return ERROR_OUTOFMEMORY;
6514 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6515 if (res != ERROR_SUCCESS)
6518 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6521 res = RegDeleteValueW(env, name);
6522 if (res != ERROR_SUCCESS)
6523 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6527 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6528 if (flags & ENV_MOD_MASK)
6532 if (flags & ENV_MOD_APPEND) multiplier++;
6533 if (flags & ENV_MOD_PREFIX) multiplier++;
6534 mod_size = lstrlenW(value) * multiplier;
6535 size += mod_size * sizeof(WCHAR);
6538 newval = msi_alloc(size);
6542 res = ERROR_OUTOFMEMORY;
6546 if (flags & ENV_MOD_PREFIX)
6548 lstrcpyW(newval, value);
6549 ptr = newval + lstrlenW(value);
6550 action |= 0x80000000;
6553 lstrcpyW(ptr, data);
6555 if (flags & ENV_MOD_APPEND)
6557 lstrcatW(newval, value);
6558 action |= 0x40000000;
6561 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6562 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6565 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6569 uirow = MSI_CreateRecord( 3 );
6570 MSI_RecordSetStringW( uirow, 1, name );
6571 MSI_RecordSetStringW( uirow, 2, newval );
6572 MSI_RecordSetInteger( uirow, 3, action );
6573 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6574 msiobj_release( &uirow->hdr );
6576 if (env) RegCloseKey(env);
6577 msi_free(deformatted);
6583 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6587 static const WCHAR ExecSeqQuery[] =
6588 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6589 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6590 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6591 if (rc != ERROR_SUCCESS)
6592 return ERROR_SUCCESS;
6594 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6595 msiobj_release(&view->hdr);
6600 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6602 MSIPACKAGE *package = param;
6603 LPCWSTR name, value, component;
6604 LPWSTR deformatted = NULL;
6613 component = MSI_RecordGetString( rec, 4 );
6614 comp = get_loaded_component( package, component );
6616 return ERROR_SUCCESS;
6620 TRACE("component is disabled\n");
6621 return ERROR_SUCCESS;
6624 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6626 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6627 comp->Action = comp->Installed;
6628 return ERROR_SUCCESS;
6630 comp->Action = INSTALLSTATE_ABSENT;
6632 name = MSI_RecordGetString( rec, 2 );
6633 value = MSI_RecordGetString( rec, 3 );
6635 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6637 r = env_parse_flags( &name, &value, &flags );
6638 if (r != ERROR_SUCCESS)
6641 if (!(flags & ENV_ACT_REMOVE))
6643 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6644 return ERROR_SUCCESS;
6647 if (value && !deformat_string( package, value, &deformatted ))
6648 return ERROR_OUTOFMEMORY;
6650 value = deformatted;
6652 r = open_env_key( flags, &env );
6653 if (r != ERROR_SUCCESS)
6659 if (flags & ENV_MOD_MACHINE)
6660 action |= 0x20000000;
6662 TRACE("Removing %s\n", debugstr_w(name));
6664 res = RegDeleteValueW( env, name );
6665 if (res != ERROR_SUCCESS)
6667 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6672 uirow = MSI_CreateRecord( 3 );
6673 MSI_RecordSetStringW( uirow, 1, name );
6674 MSI_RecordSetStringW( uirow, 2, value );
6675 MSI_RecordSetInteger( uirow, 3, action );
6676 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6677 msiobj_release( &uirow->hdr );
6679 if (env) RegCloseKey( env );
6680 msi_free( deformatted );
6684 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6688 static const WCHAR query[] =
6689 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6690 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6692 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6693 if (rc != ERROR_SUCCESS)
6694 return ERROR_SUCCESS;
6696 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6697 msiobj_release( &view->hdr );
6702 typedef struct tagMSIASSEMBLY
6705 MSICOMPONENT *component;
6706 MSIFEATURE *feature;
6710 LPWSTR display_name;
6715 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6717 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6718 LPVOID pvReserved, HMODULE *phModDll);
6720 static BOOL init_functionpointers(void)
6726 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6728 hmscoree = LoadLibraryA("mscoree.dll");
6731 WARN("mscoree.dll not available\n");
6735 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6736 if (!pLoadLibraryShim)
6738 WARN("LoadLibraryShim not available\n");
6739 FreeLibrary(hmscoree);
6743 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6746 WARN("fusion.dll not available\n");
6747 FreeLibrary(hmscoree);
6751 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6753 FreeLibrary(hmscoree);
6757 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6760 IAssemblyCache *cache;
6763 UINT r = ERROR_FUNCTION_FAILED;
6765 TRACE("installing assembly: %s\n", debugstr_w(path));
6767 uirow = MSI_CreateRecord( 2 );
6768 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6769 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6770 msiobj_release( &uirow->hdr );
6772 if (assembly->feature)
6773 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6775 if (assembly->manifest)
6776 FIXME("Manifest unhandled\n");
6778 if (assembly->application)
6780 FIXME("Assembly should be privately installed\n");
6781 return ERROR_SUCCESS;
6784 if (assembly->attributes == msidbAssemblyAttributesWin32)
6786 FIXME("Win32 assemblies not handled\n");
6787 return ERROR_SUCCESS;
6790 hr = pCreateAssemblyCache(&cache, 0);
6794 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6796 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6801 IAssemblyCache_Release(cache);
6805 typedef struct tagASSEMBLY_LIST
6807 MSIPACKAGE *package;
6808 IAssemblyCache *cache;
6809 struct list *assemblies;
6812 typedef struct tagASSEMBLY_NAME
6820 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6822 ASSEMBLY_NAME *asmname = param;
6823 LPCWSTR name = MSI_RecordGetString(rec, 2);
6824 LPWSTR val = msi_dup_record_field(rec, 3);
6826 static const WCHAR Name[] = {'N','a','m','e',0};
6827 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6828 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6829 static const WCHAR PublicKeyToken[] = {
6830 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6832 if (!strcmpiW(name, Name))
6833 asmname->name = val;
6834 else if (!strcmpiW(name, Version))
6835 asmname->version = val;
6836 else if (!strcmpiW(name, Culture))
6837 asmname->culture = val;
6838 else if (!strcmpiW(name, PublicKeyToken))
6839 asmname->pubkeytoken = val;
6843 return ERROR_SUCCESS;
6846 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6850 *size = lstrlenW(append) + 1;
6851 *str = msi_alloc((*size) * sizeof(WCHAR));
6852 lstrcpyW(*str, append);
6856 (*size) += lstrlenW(append);
6857 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6858 lstrcatW(*str, append);
6861 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6863 static const WCHAR separator[] = {',',' ',0};
6864 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6865 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6866 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6867 static const WCHAR query[] = {
6868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6869 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6870 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6871 '=','\'','%','s','\'',0};
6874 LPWSTR display_name;
6878 display_name = NULL;
6879 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6881 r = MSI_OpenQuery( db, &view, query, comp->Component );
6882 if (r != ERROR_SUCCESS)
6885 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6886 msiobj_release( &view->hdr );
6890 ERR("No assembly name specified!\n");
6894 append_str( &display_name, &size, name.name );
6898 append_str( &display_name, &size, separator );
6899 append_str( &display_name, &size, Version );
6900 append_str( &display_name, &size, name.version );
6904 append_str( &display_name, &size, separator );
6905 append_str( &display_name, &size, Culture );
6906 append_str( &display_name, &size, name.culture );
6908 if (name.pubkeytoken)
6910 append_str( &display_name, &size, separator );
6911 append_str( &display_name, &size, PublicKeyToken );
6912 append_str( &display_name, &size, name.pubkeytoken );
6915 msi_free( name.name );
6916 msi_free( name.version );
6917 msi_free( name.culture );
6918 msi_free( name.pubkeytoken );
6920 return display_name;
6923 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6925 ASSEMBLY_INFO asminfo;
6930 disp = get_assembly_display_name( db, comp );
6934 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6935 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6937 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6939 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6945 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6947 ASSEMBLY_LIST *list = param;
6948 MSIASSEMBLY *assembly;
6951 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6953 return ERROR_OUTOFMEMORY;
6955 component = MSI_RecordGetString(rec, 1);
6956 assembly->component = get_loaded_component(list->package, component);
6957 if (!assembly->component)
6958 return ERROR_SUCCESS;
6960 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6961 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6963 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6964 assembly->component->Action = assembly->component->Installed;
6965 return ERROR_SUCCESS;
6967 assembly->component->Action = assembly->component->ActionRequest;
6969 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6970 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6972 if (!assembly->file)
6974 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6975 return ERROR_FUNCTION_FAILED;
6978 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6979 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6980 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6982 if (assembly->application)
6985 DWORD size = sizeof(version)/sizeof(WCHAR);
6987 /* FIXME: we should probably check the manifest file here */
6989 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6990 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6992 assembly->installed = TRUE;
6996 assembly->installed = check_assembly_installed(list->package->db,
6998 assembly->component);
7000 list_add_head(list->assemblies, &assembly->entry);
7001 return ERROR_SUCCESS;
7004 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
7006 IAssemblyCache *cache = NULL;
7012 static const WCHAR query[] =
7013 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7014 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
7016 r = MSI_DatabaseOpenViewW(package->db, query, &view);
7017 if (r != ERROR_SUCCESS)
7018 return ERROR_SUCCESS;
7020 hr = pCreateAssemblyCache(&cache, 0);
7022 return ERROR_FUNCTION_FAILED;
7024 list.package = package;
7026 list.assemblies = assemblies;
7028 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
7029 msiobj_release(&view->hdr);
7031 IAssemblyCache_Release(cache);
7036 static void free_assemblies(struct list *assemblies)
7038 struct list *item, *cursor;
7040 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
7042 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
7044 list_remove(&assembly->entry);
7045 msi_free(assembly->application);
7046 msi_free(assembly->manifest);
7047 msi_free(assembly->display_name);
7052 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
7054 MSIASSEMBLY *assembly;
7056 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
7058 if (!strcmpW( assembly->file->File, file ))
7068 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
7069 LPWSTR *path, DWORD *attrs, PVOID user)
7071 MSIASSEMBLY *assembly;
7072 WCHAR temppath[MAX_PATH];
7073 struct list *assemblies = user;
7076 if (!find_assembly(assemblies, file, &assembly))
7079 GetTempPathW(MAX_PATH, temppath);
7080 PathAddBackslashW(temppath);
7081 lstrcatW(temppath, assembly->file->FileName);
7083 if (action == MSICABEXTRACT_BEGINEXTRACT)
7085 if (assembly->installed)
7088 *path = strdupW(temppath);
7089 *attrs = assembly->file->Attributes;
7091 else if (action == MSICABEXTRACT_FILEEXTRACTED)
7093 assembly->installed = TRUE;
7095 r = install_assembly(package, assembly, temppath);
7096 if (r != ERROR_SUCCESS)
7097 ERR("Failed to install assembly\n");
7103 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
7106 struct list assemblies = LIST_INIT(assemblies);
7107 MSIASSEMBLY *assembly;
7110 if (!init_functionpointers() || !pCreateAssemblyCache)
7111 return ERROR_FUNCTION_FAILED;
7113 r = load_assemblies(package, &assemblies);
7114 if (r != ERROR_SUCCESS)
7117 if (list_empty(&assemblies))
7120 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
7123 r = ERROR_OUTOFMEMORY;
7127 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
7129 if (assembly->installed && !mi->is_continuous)
7132 if (assembly->file->IsCompressed)
7134 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
7138 r = ready_media(package, assembly->file, mi);
7139 if (r != ERROR_SUCCESS)
7141 ERR("Failed to ready media\n");
7146 data.package = package;
7147 data.cb = installassembly_cb;
7148 data.user = &assemblies;
7150 if (!msi_cabextract(package, mi, &data))
7152 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7153 r = ERROR_FUNCTION_FAILED;
7160 LPWSTR source = resolve_file_source(package, assembly->file);
7162 r = install_assembly(package, assembly, source);
7163 if (r != ERROR_SUCCESS)
7164 ERR("Failed to install assembly\n");
7169 /* FIXME: write Installer assembly reg values */
7173 free_assemblies(&assemblies);
7177 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7179 LPWSTR key, template, id;
7180 UINT r = ERROR_SUCCESS;
7182 id = msi_dup_property( package->db, szProductID );
7186 return ERROR_SUCCESS;
7188 template = msi_dup_property( package->db, szPIDTemplate );
7189 key = msi_dup_property( package->db, szPIDKEY );
7191 if (key && template)
7193 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7194 r = msi_set_property( package->db, szProductID, key );
7196 msi_free( template );
7201 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7204 package->need_reboot = 1;
7205 return ERROR_SUCCESS;
7208 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7210 static const WCHAR szAvailableFreeReg[] =
7211 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7213 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7215 TRACE("%p %d kilobytes\n", package, space);
7217 uirow = MSI_CreateRecord( 1 );
7218 MSI_RecordSetInteger( uirow, 1, space );
7219 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7220 msiobj_release( &uirow->hdr );
7222 return ERROR_SUCCESS;
7225 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7227 FIXME("%p\n", package);
7228 return ERROR_SUCCESS;
7231 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7233 FIXME("%p\n", package);
7234 return ERROR_SUCCESS;
7237 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7242 static const WCHAR driver_query[] = {
7243 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7244 'O','D','B','C','D','r','i','v','e','r',0 };
7246 static const WCHAR translator_query[] = {
7247 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7248 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7250 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7251 if (r == ERROR_SUCCESS)
7254 r = MSI_IterateRecords( view, &count, NULL, package );
7255 msiobj_release( &view->hdr );
7256 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7259 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7260 if (r == ERROR_SUCCESS)
7263 r = MSI_IterateRecords( view, &count, NULL, package );
7264 msiobj_release( &view->hdr );
7265 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7268 return ERROR_SUCCESS;
7271 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7272 LPCSTR action, LPCWSTR table )
7274 static const WCHAR query[] = {
7275 'S','E','L','E','C','T',' ','*',' ',
7276 'F','R','O','M',' ','`','%','s','`',0 };
7277 MSIQUERY *view = NULL;
7281 r = MSI_OpenQuery( package->db, &view, query, table );
7282 if (r == ERROR_SUCCESS)
7284 r = MSI_IterateRecords(view, &count, NULL, package);
7285 msiobj_release(&view->hdr);
7289 FIXME("%s -> %u ignored %s table values\n",
7290 action, count, debugstr_w(table));
7292 return ERROR_SUCCESS;
7295 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7297 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7298 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7301 static UINT ACTION_BindImage( MSIPACKAGE *package )
7303 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7304 return msi_unimplemented_action_stub( package, "BindImage", table );
7307 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7309 static const WCHAR table[] = {
7310 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7311 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7314 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7316 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7317 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7320 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7322 static const WCHAR table[] = {
7323 'M','s','i','A','s','s','e','m','b','l','y',0 };
7324 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7327 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7329 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7330 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7333 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7335 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7336 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7339 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7341 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7342 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7345 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7347 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7348 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7351 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7353 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7354 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7357 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7361 const WCHAR *action;
7362 UINT (*handler)(MSIPACKAGE *);
7366 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7367 { szAppSearch, ACTION_AppSearch },
7368 { szBindImage, ACTION_BindImage },
7369 { szCCPSearch, ACTION_CCPSearch },
7370 { szCostFinalize, ACTION_CostFinalize },
7371 { szCostInitialize, ACTION_CostInitialize },
7372 { szCreateFolders, ACTION_CreateFolders },
7373 { szCreateShortcuts, ACTION_CreateShortcuts },
7374 { szDeleteServices, ACTION_DeleteServices },
7375 { szDisableRollback, ACTION_DisableRollback },
7376 { szDuplicateFiles, ACTION_DuplicateFiles },
7377 { szExecuteAction, ACTION_ExecuteAction },
7378 { szFileCost, ACTION_FileCost },
7379 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7380 { szForceReboot, ACTION_ForceReboot },
7381 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7382 { szInstallExecute, ACTION_InstallExecute },
7383 { szInstallExecuteAgain, ACTION_InstallExecute },
7384 { szInstallFiles, ACTION_InstallFiles},
7385 { szInstallFinalize, ACTION_InstallFinalize },
7386 { szInstallInitialize, ACTION_InstallInitialize },
7387 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7388 { szInstallValidate, ACTION_InstallValidate },
7389 { szIsolateComponents, ACTION_IsolateComponents },
7390 { szLaunchConditions, ACTION_LaunchConditions },
7391 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7392 { szMoveFiles, ACTION_MoveFiles },
7393 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7394 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7395 { szInstallODBC, ACTION_InstallODBC },
7396 { szInstallServices, ACTION_InstallServices },
7397 { szPatchFiles, ACTION_PatchFiles },
7398 { szProcessComponents, ACTION_ProcessComponents },
7399 { szPublishComponents, ACTION_PublishComponents },
7400 { szPublishFeatures, ACTION_PublishFeatures },
7401 { szPublishProduct, ACTION_PublishProduct },
7402 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7403 { szRegisterComPlus, ACTION_RegisterComPlus},
7404 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7405 { szRegisterFonts, ACTION_RegisterFonts },
7406 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7407 { szRegisterProduct, ACTION_RegisterProduct },
7408 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7409 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7410 { szRegisterUser, ACTION_RegisterUser },
7411 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7412 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7413 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7414 { szRemoveFiles, ACTION_RemoveFiles },
7415 { szRemoveFolders, ACTION_RemoveFolders },
7416 { szRemoveIniValues, ACTION_RemoveIniValues },
7417 { szRemoveODBC, ACTION_RemoveODBC },
7418 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7419 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7420 { szResolveSource, ACTION_ResolveSource },
7421 { szRMCCPSearch, ACTION_RMCCPSearch },
7422 { szScheduleReboot, ACTION_ScheduleReboot },
7423 { szSelfRegModules, ACTION_SelfRegModules },
7424 { szSelfUnregModules, ACTION_SelfUnregModules },
7425 { szSetODBCFolders, ACTION_SetODBCFolders },
7426 { szStartServices, ACTION_StartServices },
7427 { szStopServices, ACTION_StopServices },
7428 { szUnpublishComponents, ACTION_UnpublishComponents },
7429 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7430 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7431 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7432 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7433 { szUnregisterFonts, ACTION_UnregisterFonts },
7434 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7435 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7436 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7437 { szValidateProductID, ACTION_ValidateProductID },
7438 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7439 { szWriteIniValues, ACTION_WriteIniValues },
7440 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7444 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7450 while (StandardActions[i].action != NULL)
7452 if (!strcmpW( StandardActions[i].action, action ))
7454 ui_actionstart( package, action );
7455 if (StandardActions[i].handler)
7457 ui_actioninfo( package, action, TRUE, 0 );
7458 *rc = StandardActions[i].handler( package );
7459 ui_actioninfo( package, action, FALSE, *rc );
7463 FIXME("unhandled standard action %s\n", debugstr_w(action));
7464 *rc = ERROR_SUCCESS;
7474 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7476 UINT rc = ERROR_SUCCESS;
7479 TRACE("Performing action (%s)\n", debugstr_w(action));
7481 handled = ACTION_HandleStandardAction(package, action, &rc);
7484 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7488 WARN("unhandled msi action %s\n", debugstr_w(action));
7489 rc = ERROR_FUNCTION_NOT_CALLED;
7495 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7497 UINT rc = ERROR_SUCCESS;
7498 BOOL handled = FALSE;
7500 TRACE("Performing action (%s)\n", debugstr_w(action));
7502 handled = ACTION_HandleStandardAction(package, action, &rc);
7505 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7507 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7512 WARN("unhandled msi action %s\n", debugstr_w(action));
7513 rc = ERROR_FUNCTION_NOT_CALLED;
7519 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7521 UINT rc = ERROR_SUCCESS;
7524 static const WCHAR ExecSeqQuery[] =
7525 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7526 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7527 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7528 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7529 static const WCHAR UISeqQuery[] =
7530 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7531 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7532 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7533 ' ', '=',' ','%','i',0};
7535 if (needs_ui_sequence(package))
7536 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7538 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7542 LPCWSTR action, cond;
7544 TRACE("Running the actions\n");
7546 /* check conditions */
7547 cond = MSI_RecordGetString(row, 2);
7549 /* this is a hack to skip errors in the condition code */
7550 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7552 msiobj_release(&row->hdr);
7553 return ERROR_SUCCESS;
7556 action = MSI_RecordGetString(row, 1);
7559 ERR("failed to fetch action\n");
7560 msiobj_release(&row->hdr);
7561 return ERROR_FUNCTION_FAILED;
7564 if (needs_ui_sequence(package))
7565 rc = ACTION_PerformUIAction(package, action, -1);
7567 rc = ACTION_PerformAction(package, action, -1);
7569 msiobj_release(&row->hdr);
7575 /****************************************************
7576 * TOP level entry points
7577 *****************************************************/
7579 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7580 LPCWSTR szCommandLine )
7585 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7586 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7588 msi_set_property( package->db, szAction, szInstall );
7590 package->script->InWhatSequence = SEQUENCE_INSTALL;
7597 dir = strdupW(szPackagePath);
7598 p = strrchrW(dir, '\\');
7602 file = szPackagePath + (p - dir);
7607 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7608 GetCurrentDirectoryW(MAX_PATH, dir);
7609 lstrcatW(dir, szBackSlash);
7610 file = szPackagePath;
7613 msi_free( package->PackagePath );
7614 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7615 if (!package->PackagePath)
7618 return ERROR_OUTOFMEMORY;
7621 lstrcpyW(package->PackagePath, dir);
7622 lstrcatW(package->PackagePath, file);
7625 msi_set_sourcedir_props(package, FALSE);
7628 msi_parse_command_line( package, szCommandLine, FALSE );
7630 msi_apply_transforms( package );
7631 msi_apply_patches( package );
7633 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7635 TRACE("setting reinstall property\n");
7636 msi_set_property( package->db, szReinstall, szAll );
7639 /* properties may have been added by a transform */
7640 msi_clone_properties( package );
7642 msi_parse_command_line( package, szCommandLine, FALSE );
7643 msi_adjust_privilege_properties( package );
7644 msi_set_context( package );
7646 if (needs_ui_sequence( package))
7648 package->script->InWhatSequence |= SEQUENCE_UI;
7649 rc = ACTION_ProcessUISequence(package);
7650 ui_exists = ui_sequence_exists(package);
7651 if (rc == ERROR_SUCCESS || !ui_exists)
7653 package->script->InWhatSequence |= SEQUENCE_EXEC;
7654 rc = ACTION_ProcessExecSequence(package, ui_exists);
7658 rc = ACTION_ProcessExecSequence(package, FALSE);
7660 package->script->CurrentlyScripting = FALSE;
7662 /* process the ending type action */
7663 if (rc == ERROR_SUCCESS)
7664 ACTION_PerformActionSequence(package, -1);
7665 else if (rc == ERROR_INSTALL_USEREXIT)
7666 ACTION_PerformActionSequence(package, -2);
7667 else if (rc == ERROR_INSTALL_SUSPEND)
7668 ACTION_PerformActionSequence(package, -4);
7670 ACTION_PerformActionSequence(package, -3);
7672 /* finish up running custom actions */
7673 ACTION_FinishCustomActions(package);
7675 if (rc == ERROR_SUCCESS && package->need_reboot)
7676 return ERROR_SUCCESS_REBOOT_REQUIRED;