2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
39 #include "wine/unicode.h"
42 #define REG_PROGRESS_VALUE 13200
43 #define COMPONENT_PROGRESS_VALUE 24000
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 * consts and values used
50 static const WCHAR c_colon[] = {'C',':','\\',0};
52 static const WCHAR szCreateFolders[] =
53 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
54 static const WCHAR szCostFinalize[] =
55 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
56 static const WCHAR szWriteRegistryValues[] =
57 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
58 static const WCHAR szCostInitialize[] =
59 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
60 static const WCHAR szFileCost[] =
61 {'F','i','l','e','C','o','s','t',0};
62 static const WCHAR szInstallInitialize[] =
63 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
64 static const WCHAR szInstallValidate[] =
65 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
66 static const WCHAR szLaunchConditions[] =
67 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
68 static const WCHAR szProcessComponents[] =
69 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
70 static const WCHAR szRegisterTypeLibraries[] =
71 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
72 static const WCHAR szCreateShortcuts[] =
73 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
74 static const WCHAR szPublishProduct[] =
75 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
76 static const WCHAR szWriteIniValues[] =
77 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
78 static const WCHAR szSelfRegModules[] =
79 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
80 static const WCHAR szPublishFeatures[] =
81 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
82 static const WCHAR szRegisterProduct[] =
83 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
84 static const WCHAR szInstallExecute[] =
85 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
86 static const WCHAR szInstallExecuteAgain[] =
87 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
88 static const WCHAR szInstallFinalize[] =
89 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
90 static const WCHAR szForceReboot[] =
91 {'F','o','r','c','e','R','e','b','o','o','t',0};
92 static const WCHAR szResolveSource[] =
93 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
94 static const WCHAR szAllocateRegistrySpace[] =
95 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
96 static const WCHAR szBindImage[] =
97 {'B','i','n','d','I','m','a','g','e',0};
98 static const WCHAR szDeleteServices[] =
99 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
100 static const WCHAR szDisableRollback[] =
101 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
102 static const WCHAR szExecuteAction[] =
103 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
104 static const WCHAR szInstallAdminPackage[] =
105 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
106 static const WCHAR szInstallSFPCatalogFile[] =
107 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
108 static const WCHAR szIsolateComponents[] =
109 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
110 static const WCHAR szMigrateFeatureStates[] =
111 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
112 static const WCHAR szMsiUnpublishAssemblies[] =
113 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
114 static const WCHAR szInstallODBC[] =
115 {'I','n','s','t','a','l','l','O','D','B','C',0};
116 static const WCHAR szInstallServices[] =
117 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
118 static const WCHAR szPatchFiles[] =
119 {'P','a','t','c','h','F','i','l','e','s',0};
120 static const WCHAR szPublishComponents[] =
121 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
122 static const WCHAR szRegisterComPlus[] =
123 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
124 static const WCHAR szRegisterUser[] =
125 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
126 static const WCHAR szRemoveEnvironmentStrings[] =
127 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
128 static const WCHAR szRemoveExistingProducts[] =
129 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
130 static const WCHAR szRemoveFolders[] =
131 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
132 static const WCHAR szRemoveIniValues[] =
133 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
134 static const WCHAR szRemoveODBC[] =
135 {'R','e','m','o','v','e','O','D','B','C',0};
136 static const WCHAR szRemoveRegistryValues[] =
137 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
138 static const WCHAR szRemoveShortcuts[] =
139 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
140 static const WCHAR szRMCCPSearch[] =
141 {'R','M','C','C','P','S','e','a','r','c','h',0};
142 static const WCHAR szScheduleReboot[] =
143 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
144 static const WCHAR szSelfUnregModules[] =
145 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
146 static const WCHAR szSetODBCFolders[] =
147 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
148 static const WCHAR szStartServices[] =
149 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
150 static const WCHAR szStopServices[] =
151 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
152 static const WCHAR szUnpublishComponents[] =
153 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
154 static const WCHAR szUnpublishFeatures[] =
155 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
156 static const WCHAR szUnregisterComPlus[] =
157 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
158 static const WCHAR szUnregisterTypeLibraries[] =
159 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
160 static const WCHAR szValidateProductID[] =
161 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
162 static const WCHAR szWriteEnvironmentStrings[] =
163 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
165 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
167 static const WCHAR Query_t[] =
168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
169 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
170 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
171 ' ','\'','%','s','\'',0};
174 row = MSI_QueryGetRecord( package->db, Query_t, action );
177 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
178 msiobj_release(&row->hdr);
181 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
185 static const WCHAR template_s[]=
186 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
188 static const WCHAR template_e[]=
189 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
190 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
192 static const WCHAR format[] =
193 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
197 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
199 sprintfW(message,template_s,timet,action);
201 sprintfW(message,template_e,timet,action,rc);
203 row = MSI_CreateRecord(1);
204 MSI_RecordSetStringW(row,1,message);
206 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
207 msiobj_release(&row->hdr);
217 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
219 enum parse_state state = state_quote;
222 int ignore, in_quotes = 0, count = 0, len = 0;
224 for (p = str; *p; p++)
229 case state_whitespace:
233 if (!count) goto done;
239 if (in_quotes) count--;
244 if (!count) in_quotes = 0;
256 if (in_quotes) count--;
260 state = state_whitespace;
261 if (!count) goto done;
265 if (!count) in_quotes = 0;
276 if (in_quotes) count--;
280 state = state_whitespace;
281 if (!count || !len) goto done;
286 if (!count) in_quotes = 0;
295 if (!ignore) *out++ = *p;
299 if (!len) *value = 0;
306 static void remove_quotes( WCHAR *str )
309 int len = strlenW( str );
311 while ((p = strchrW( p, '"' )))
313 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
318 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
328 return ERROR_SUCCESS;
333 while (*ptr == ' ') ptr++;
336 ptr2 = strchrW( ptr, '=' );
337 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
340 if (!len) return ERROR_INVALID_COMMAND_LINE;
342 prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
343 memcpy( prop, ptr, len * sizeof(WCHAR) );
345 if (!preserve_case) struprW( prop );
348 while (*ptr2 == ' ') ptr2++;
351 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
352 len = parse_prop( ptr2, val, "es );
355 WARN("unbalanced quotes\n");
358 return ERROR_INVALID_COMMAND_LINE;
360 remove_quotes( val );
361 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
363 r = msi_set_property( package->db, prop, val );
364 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
365 msi_reset_folders( package, TRUE );
373 return ERROR_SUCCESS;
376 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
379 LPWSTR p, *ret = NULL;
385 /* count the number of substrings */
386 for ( pc = str, count = 0; pc; count++ )
388 pc = strchrW( pc, sep );
393 /* allocate space for an array of substring pointers and the substrings */
394 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
395 (lstrlenW(str)+1) * sizeof(WCHAR) );
399 /* copy the string and set the pointers */
400 p = (LPWSTR) &ret[count+1];
402 for( count = 0; (ret[count] = p); count++ )
404 p = strchrW( p, sep );
412 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
414 static const WCHAR szSystemLanguageID[] =
415 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
417 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
418 UINT ret = ERROR_FUNCTION_FAILED;
420 prod_code = msi_dup_property( package->db, szProductCode );
421 patch_product = msi_get_suminfo_product( patch );
423 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
425 if ( strstrW( patch_product, prod_code ) )
430 si = MSI_GetSummaryInformationW( patch, 0 );
433 ERR("no summary information!\n");
437 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
440 ERR("no template property!\n");
441 msiobj_release( &si->hdr );
448 msiobj_release( &si->hdr );
452 langid = msi_dup_property( package->db, szSystemLanguageID );
455 msiobj_release( &si->hdr );
459 p = strchrW( template, ';' );
460 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
462 TRACE("applicable transform\n");
466 /* FIXME: check platform */
468 msiobj_release( &si->hdr );
472 msi_free( patch_product );
473 msi_free( prod_code );
474 msi_free( template );
480 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
481 MSIDATABASE *patch_db, LPCWSTR name )
483 UINT ret = ERROR_FUNCTION_FAILED;
484 IStorage *stg = NULL;
487 TRACE("%p %s\n", package, debugstr_w(name) );
491 ERR("expected a colon in %s\n", debugstr_w(name));
492 return ERROR_FUNCTION_FAILED;
495 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
498 ret = msi_check_transform_applicable( package, stg );
499 if (ret == ERROR_SUCCESS)
500 msi_table_apply_transform( package->db, stg );
502 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
503 IStorage_Release( stg );
506 ERR("failed to open substorage %s\n", debugstr_w(name));
508 return ERROR_SUCCESS;
511 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
513 LPWSTR guid_list, *guids, product_code;
514 UINT i, ret = ERROR_FUNCTION_FAILED;
516 product_code = msi_dup_property( package->db, szProductCode );
519 /* FIXME: the property ProductCode should be written into the DB somewhere */
520 ERR("no product code to check\n");
521 return ERROR_SUCCESS;
524 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
525 guids = msi_split_string( guid_list, ';' );
526 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
528 if (!strcmpW( guids[i], product_code ))
532 msi_free( guid_list );
533 msi_free( product_code );
538 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
541 MSIRECORD *rec = NULL;
546 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
547 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
548 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
549 '`','S','o','u','r','c','e','`',' ','I','S',' ',
550 'N','O','T',' ','N','U','L','L',0};
552 r = MSI_DatabaseOpenViewW(package->db, query, &view);
553 if (r != ERROR_SUCCESS)
556 r = MSI_ViewExecute(view, 0);
557 if (r != ERROR_SUCCESS)
560 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
562 prop = MSI_RecordGetString(rec, 1);
563 patch = msi_dup_property(package->db, szPatch);
564 msi_set_property(package->db, prop, patch);
569 if (rec) msiobj_release(&rec->hdr);
570 msiobj_release(&view->hdr);
575 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
578 UINT r = ERROR_SUCCESS;
581 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
583 return ERROR_OUTOFMEMORY;
585 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
589 return ERROR_OUTOFMEMORY;
595 msi_free( pi->patchcode );
597 return ERROR_PATCH_PACKAGE_INVALID;
600 p = strchrW( p + 1, '}' );
603 msi_free( pi->patchcode );
605 return ERROR_PATCH_PACKAGE_INVALID;
610 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
614 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
616 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
619 msi_free( pi->patchcode );
621 return ERROR_OUTOFMEMORY;
628 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
630 UINT i, r = ERROR_SUCCESS;
633 /* apply substorage transforms */
634 substorage = msi_split_string( patch->transforms, ';' );
635 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
636 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
638 msi_free( substorage );
639 if (r != ERROR_SUCCESS)
642 msi_set_media_source_prop( package );
645 * There might be a CAB file in the patch package,
646 * so append it to the list of storages to search for streams.
648 append_storage_to_db( package->db, patch_db->storage );
650 patch->state = MSIPATCHSTATE_APPLIED;
651 list_add_tail( &package->patches, &patch->entry );
652 return ERROR_SUCCESS;
655 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
657 static const WCHAR dotmsp[] = {'.','m','s','p',0};
658 MSIDATABASE *patch_db = NULL;
659 WCHAR localfile[MAX_PATH];
661 MSIPATCHINFO *patch = NULL;
662 UINT r = ERROR_SUCCESS;
664 TRACE("%p %s\n", package, debugstr_w( file ) );
666 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
667 if ( r != ERROR_SUCCESS )
669 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
673 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
676 msiobj_release( &patch_db->hdr );
677 return ERROR_FUNCTION_FAILED;
680 r = msi_check_patch_applicable( package, si );
681 if (r != ERROR_SUCCESS)
683 TRACE("patch not applicable\n");
688 r = msi_parse_patch_summary( si, &patch );
689 if ( r != ERROR_SUCCESS )
692 r = msi_get_local_package_name( localfile, dotmsp );
693 if ( r != ERROR_SUCCESS )
696 TRACE("copying to local package %s\n", debugstr_w(localfile));
698 if (!CopyFileW( file, localfile, FALSE ))
700 ERR("Unable to copy package (%s -> %s) (error %u)\n",
701 debugstr_w(file), debugstr_w(localfile), GetLastError());
705 patch->localfile = strdupW( localfile );
707 r = msi_apply_patch_db( package, patch_db, patch );
708 if ( r != ERROR_SUCCESS )
709 WARN("patch failed to apply %u\n", r);
712 msiobj_release( &si->hdr );
713 msiobj_release( &patch_db->hdr );
714 if (patch && r != ERROR_SUCCESS)
716 if (patch->localfile)
717 DeleteFileW( patch->localfile );
719 msi_free( patch->patchcode );
720 msi_free( patch->transforms );
721 msi_free( patch->localfile );
727 /* get the PATCH property, and apply all the patches it specifies */
728 static UINT msi_apply_patches( MSIPACKAGE *package )
730 LPWSTR patch_list, *patches;
731 UINT i, r = ERROR_SUCCESS;
733 patch_list = msi_dup_property( package->db, szPatch );
735 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
737 patches = msi_split_string( patch_list, ';' );
738 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
739 r = msi_apply_patch_package( package, patches[i] );
742 msi_free( patch_list );
747 static UINT msi_apply_transforms( MSIPACKAGE *package )
749 static const WCHAR szTransforms[] = {
750 'T','R','A','N','S','F','O','R','M','S',0 };
751 LPWSTR xform_list, *xforms;
752 UINT i, r = ERROR_SUCCESS;
754 xform_list = msi_dup_property( package->db, szTransforms );
755 xforms = msi_split_string( xform_list, ';' );
757 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
759 if (xforms[i][0] == ':')
760 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
765 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
768 WCHAR *p = strrchrW( package->PackagePath, '\\' );
769 DWORD len = p - package->PackagePath + 1;
771 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
774 msi_free( xform_list );
775 return ERROR_OUTOFMEMORY;
777 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
778 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
780 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
781 if (transform != xforms[i]) msi_free( transform );
786 msi_free( xform_list );
791 static BOOL ui_sequence_exists( MSIPACKAGE *package )
796 static const WCHAR ExecSeqQuery [] =
797 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
798 '`','I','n','s','t','a','l','l',
799 'U','I','S','e','q','u','e','n','c','e','`',
800 ' ','W','H','E','R','E',' ',
801 '`','S','e','q','u','e','n','c','e','`',' ',
802 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
803 '`','S','e','q','u','e','n','c','e','`',0};
805 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
806 if (rc == ERROR_SUCCESS)
808 msiobj_release(&view->hdr);
815 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
817 LPWSTR source, check;
819 if (msi_get_property_int( package->db, szInstalled, 0 ))
823 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
824 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
832 db = msi_dup_property( package->db, szOriginalDatabase );
834 return ERROR_OUTOFMEMORY;
836 p = strrchrW( db, '\\' );
839 p = strrchrW( db, '/' );
843 return ERROR_SUCCESS;
848 source = msi_alloc( len * sizeof(WCHAR) );
849 lstrcpynW( source, db, len );
853 check = msi_dup_property( package->db, cszSourceDir );
854 if (!check || replace)
856 UINT r = msi_set_property( package->db, cszSourceDir, source );
857 if (r == ERROR_SUCCESS)
858 msi_reset_folders( package, TRUE );
862 check = msi_dup_property( package->db, cszSOURCEDIR );
863 if (!check || replace)
864 msi_set_property( package->db, cszSOURCEDIR, source );
869 return ERROR_SUCCESS;
872 static BOOL needs_ui_sequence(MSIPACKAGE *package)
874 INT level = msi_get_property_int(package->db, szUILevel, 0);
875 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
878 UINT msi_set_context(MSIPACKAGE *package)
882 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
884 num = msi_get_property_int(package->db, szAllUsers, 0);
885 if (num == 1 || num == 2)
886 package->Context = MSIINSTALLCONTEXT_MACHINE;
888 return ERROR_SUCCESS;
891 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
894 LPCWSTR cond, action;
895 MSIPACKAGE *package = param;
897 action = MSI_RecordGetString(row,1);
900 ERR("Error is retrieving action name\n");
901 return ERROR_FUNCTION_FAILED;
904 /* check conditions */
905 cond = MSI_RecordGetString(row,2);
907 /* this is a hack to skip errors in the condition code */
908 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
910 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
911 return ERROR_SUCCESS;
914 if (needs_ui_sequence(package))
915 rc = ACTION_PerformUIAction(package, action, -1);
917 rc = ACTION_PerformAction(package, action, -1);
919 msi_dialog_check_messages( NULL );
921 if (package->CurrentInstallState != ERROR_SUCCESS)
922 rc = package->CurrentInstallState;
924 if (rc == ERROR_FUNCTION_NOT_CALLED)
927 if (rc != ERROR_SUCCESS)
928 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
933 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
937 static const WCHAR query[] =
938 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
940 ' ','W','H','E','R','E',' ',
941 '`','S','e','q','u','e','n','c','e','`',' ',
942 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
943 '`','S','e','q','u','e','n','c','e','`',0};
945 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
947 r = MSI_OpenQuery( package->db, &view, query, szTable );
948 if (r == ERROR_SUCCESS)
950 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
951 msiobj_release(&view->hdr);
957 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
961 static const WCHAR ExecSeqQuery[] =
962 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
963 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
964 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
965 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
966 'O','R','D','E','R',' ', 'B','Y',' ',
967 '`','S','e','q','u','e','n','c','e','`',0 };
968 static const WCHAR IVQuery[] =
969 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
970 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
971 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
972 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
973 ' ','\'', 'I','n','s','t','a','l','l',
974 'V','a','l','i','d','a','t','e','\'', 0};
977 if (package->script->ExecuteSequenceRun)
979 TRACE("Execute Sequence already Run\n");
980 return ERROR_SUCCESS;
983 package->script->ExecuteSequenceRun = TRUE;
985 /* get the sequence number */
988 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
990 return ERROR_FUNCTION_FAILED;
991 seq = MSI_RecordGetInteger(row,1);
992 msiobj_release(&row->hdr);
995 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
996 if (rc == ERROR_SUCCESS)
998 TRACE("Running the actions\n");
1000 msi_set_property(package->db, cszSourceDir, NULL);
1002 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1003 msiobj_release(&view->hdr);
1009 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1013 static const WCHAR ExecSeqQuery [] =
1014 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1015 '`','I','n','s','t','a','l','l',
1016 'U','I','S','e','q','u','e','n','c','e','`',
1017 ' ','W','H','E','R','E',' ',
1018 '`','S','e','q','u','e','n','c','e','`',' ',
1019 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1020 '`','S','e','q','u','e','n','c','e','`',0};
1022 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1023 if (rc == ERROR_SUCCESS)
1025 TRACE("Running the actions\n");
1027 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1028 msiobj_release(&view->hdr);
1034 /********************************************************
1035 * ACTION helper functions and functions that perform the actions
1036 *******************************************************/
1037 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1038 UINT* rc, UINT script, BOOL force )
1043 arc = ACTION_CustomAction(package, action, script, force);
1045 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1054 * Actual Action Handlers
1057 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1059 MSIPACKAGE *package = param;
1060 LPCWSTR dir, component;
1066 component = MSI_RecordGetString(row, 2);
1068 return ERROR_SUCCESS;
1070 comp = get_loaded_component(package, component);
1072 return ERROR_SUCCESS;
1076 TRACE("component is disabled\n");
1077 return ERROR_SUCCESS;
1080 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1082 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1083 comp->Action = comp->Installed;
1084 return ERROR_SUCCESS;
1086 comp->Action = INSTALLSTATE_LOCAL;
1088 dir = MSI_RecordGetString(row,1);
1091 ERR("Unable to get folder id\n");
1092 return ERROR_SUCCESS;
1095 uirow = MSI_CreateRecord(1);
1096 MSI_RecordSetStringW(uirow, 1, dir);
1097 ui_actiondata(package, szCreateFolders, uirow);
1098 msiobj_release(&uirow->hdr);
1100 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1103 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1104 return ERROR_SUCCESS;
1107 TRACE("Folder is %s\n",debugstr_w(full_path));
1109 if (folder->State == 0)
1110 create_full_pathW(full_path);
1114 msi_free(full_path);
1115 return ERROR_SUCCESS;
1118 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1120 static const WCHAR query[] =
1121 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1122 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1126 /* create all the empty folders specified in the CreateFolder table */
1127 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1128 if (rc != ERROR_SUCCESS)
1129 return ERROR_SUCCESS;
1131 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1132 msiobj_release(&view->hdr);
1137 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1139 MSIPACKAGE *package = param;
1140 LPCWSTR dir, component;
1146 component = MSI_RecordGetString(row, 2);
1148 return ERROR_SUCCESS;
1150 comp = get_loaded_component(package, component);
1152 return ERROR_SUCCESS;
1156 TRACE("component is disabled\n");
1157 return ERROR_SUCCESS;
1160 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1162 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1163 comp->Action = comp->Installed;
1164 return ERROR_SUCCESS;
1166 comp->Action = INSTALLSTATE_ABSENT;
1168 dir = MSI_RecordGetString( row, 1 );
1171 ERR("Unable to get folder id\n");
1172 return ERROR_SUCCESS;
1175 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1178 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1179 return ERROR_SUCCESS;
1182 TRACE("folder is %s\n", debugstr_w(full_path));
1184 uirow = MSI_CreateRecord( 1 );
1185 MSI_RecordSetStringW( uirow, 1, dir );
1186 ui_actiondata( package, szRemoveFolders, uirow );
1187 msiobj_release( &uirow->hdr );
1189 RemoveDirectoryW( full_path );
1192 msi_free( full_path );
1193 return ERROR_SUCCESS;
1196 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1198 static const WCHAR query[] =
1199 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1200 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1205 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1206 if (rc != ERROR_SUCCESS)
1207 return ERROR_SUCCESS;
1209 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1210 msiobj_release( &view->hdr );
1215 static UINT load_component( MSIRECORD *row, LPVOID param )
1217 MSIPACKAGE *package = param;
1220 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1222 return ERROR_FUNCTION_FAILED;
1224 list_add_tail( &package->components, &comp->entry );
1226 /* fill in the data */
1227 comp->Component = msi_dup_record_field( row, 1 );
1229 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1231 comp->ComponentId = msi_dup_record_field( row, 2 );
1232 comp->Directory = msi_dup_record_field( row, 3 );
1233 comp->Attributes = MSI_RecordGetInteger(row,4);
1234 comp->Condition = msi_dup_record_field( row, 5 );
1235 comp->KeyPath = msi_dup_record_field( row, 6 );
1237 comp->Installed = INSTALLSTATE_UNKNOWN;
1238 comp->Action = INSTALLSTATE_UNKNOWN;
1239 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1241 comp->assembly = load_assembly( package, comp );
1242 return ERROR_SUCCESS;
1245 static UINT load_all_components( MSIPACKAGE *package )
1247 static const WCHAR query[] = {
1248 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1249 '`','C','o','m','p','o','n','e','n','t','`',0 };
1253 if (!list_empty(&package->components))
1254 return ERROR_SUCCESS;
1256 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1257 if (r != ERROR_SUCCESS)
1260 r = MSI_IterateRecords(view, NULL, load_component, package);
1261 msiobj_release(&view->hdr);
1266 MSIPACKAGE *package;
1267 MSIFEATURE *feature;
1270 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1274 cl = msi_alloc( sizeof (*cl) );
1276 return ERROR_NOT_ENOUGH_MEMORY;
1277 cl->component = comp;
1278 list_add_tail( &feature->Components, &cl->entry );
1280 return ERROR_SUCCESS;
1283 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1287 fl = msi_alloc( sizeof(*fl) );
1289 return ERROR_NOT_ENOUGH_MEMORY;
1290 fl->feature = child;
1291 list_add_tail( &parent->Children, &fl->entry );
1293 return ERROR_SUCCESS;
1296 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1298 _ilfs* ilfs = param;
1302 component = MSI_RecordGetString(row,1);
1304 /* check to see if the component is already loaded */
1305 comp = get_loaded_component( ilfs->package, component );
1308 ERR("unknown component %s\n", debugstr_w(component));
1309 return ERROR_FUNCTION_FAILED;
1312 add_feature_component( ilfs->feature, comp );
1313 comp->Enabled = TRUE;
1315 return ERROR_SUCCESS;
1318 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1320 MSIFEATURE *feature;
1325 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1327 if ( !strcmpW( feature->Feature, name ) )
1334 static UINT load_feature(MSIRECORD * row, LPVOID param)
1336 MSIPACKAGE* package = param;
1337 MSIFEATURE* feature;
1338 static const WCHAR Query1[] =
1339 {'S','E','L','E','C','T',' ',
1340 '`','C','o','m','p','o','n','e','n','t','_','`',
1341 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1342 'C','o','m','p','o','n','e','n','t','s','`',' ',
1343 'W','H','E','R','E',' ',
1344 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1349 /* fill in the data */
1351 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1353 return ERROR_NOT_ENOUGH_MEMORY;
1355 list_init( &feature->Children );
1356 list_init( &feature->Components );
1358 feature->Feature = msi_dup_record_field( row, 1 );
1360 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1362 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1363 feature->Title = msi_dup_record_field( row, 3 );
1364 feature->Description = msi_dup_record_field( row, 4 );
1366 if (!MSI_RecordIsNull(row,5))
1367 feature->Display = MSI_RecordGetInteger(row,5);
1369 feature->Level= MSI_RecordGetInteger(row,6);
1370 feature->Directory = msi_dup_record_field( row, 7 );
1371 feature->Attributes = MSI_RecordGetInteger(row,8);
1373 feature->Installed = INSTALLSTATE_UNKNOWN;
1374 feature->Action = INSTALLSTATE_UNKNOWN;
1375 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1377 list_add_tail( &package->features, &feature->entry );
1379 /* load feature components */
1381 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1382 if (rc != ERROR_SUCCESS)
1383 return ERROR_SUCCESS;
1385 ilfs.package = package;
1386 ilfs.feature = feature;
1388 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1389 msiobj_release(&view->hdr);
1391 return ERROR_SUCCESS;
1394 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1396 MSIPACKAGE* package = param;
1397 MSIFEATURE *parent, *child;
1399 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1401 return ERROR_FUNCTION_FAILED;
1403 if (!child->Feature_Parent)
1404 return ERROR_SUCCESS;
1406 parent = find_feature_by_name( package, child->Feature_Parent );
1408 return ERROR_FUNCTION_FAILED;
1410 add_feature_child( parent, child );
1411 return ERROR_SUCCESS;
1414 static UINT load_all_features( MSIPACKAGE *package )
1416 static const WCHAR query[] = {
1417 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1418 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1419 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1423 if (!list_empty(&package->features))
1424 return ERROR_SUCCESS;
1426 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1427 if (r != ERROR_SUCCESS)
1430 r = MSI_IterateRecords( view, NULL, load_feature, package );
1431 if (r != ERROR_SUCCESS)
1434 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1435 msiobj_release( &view->hdr );
1440 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1451 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1453 static const WCHAR query[] = {
1454 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1455 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1456 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1457 MSIQUERY *view = NULL;
1458 MSIRECORD *row = NULL;
1461 TRACE("%s\n", debugstr_w(file->File));
1463 r = MSI_OpenQuery(package->db, &view, query, file->File);
1464 if (r != ERROR_SUCCESS)
1467 r = MSI_ViewExecute(view, NULL);
1468 if (r != ERROR_SUCCESS)
1471 r = MSI_ViewFetch(view, &row);
1472 if (r != ERROR_SUCCESS)
1475 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1476 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1477 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1478 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1479 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1482 if (view) msiobj_release(&view->hdr);
1483 if (row) msiobj_release(&row->hdr);
1487 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1490 static const WCHAR query[] = {
1491 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1492 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1493 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1495 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1498 WARN("query failed\n");
1499 return ERROR_FUNCTION_FAILED;
1502 file->disk_id = MSI_RecordGetInteger( row, 1 );
1503 msiobj_release( &row->hdr );
1504 return ERROR_SUCCESS;
1507 static UINT load_file(MSIRECORD *row, LPVOID param)
1509 MSIPACKAGE* package = param;
1513 /* fill in the data */
1515 file = msi_alloc_zero( sizeof (MSIFILE) );
1517 return ERROR_NOT_ENOUGH_MEMORY;
1519 file->File = msi_dup_record_field( row, 1 );
1521 component = MSI_RecordGetString( row, 2 );
1522 file->Component = get_loaded_component( package, component );
1524 if (!file->Component)
1526 WARN("Component not found: %s\n", debugstr_w(component));
1527 msi_free(file->File);
1529 return ERROR_SUCCESS;
1532 file->FileName = msi_dup_record_field( row, 3 );
1533 reduce_to_longfilename( file->FileName );
1535 file->ShortName = msi_dup_record_field( row, 3 );
1536 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1538 file->FileSize = MSI_RecordGetInteger( row, 4 );
1539 file->Version = msi_dup_record_field( row, 5 );
1540 file->Language = msi_dup_record_field( row, 6 );
1541 file->Attributes = MSI_RecordGetInteger( row, 7 );
1542 file->Sequence = MSI_RecordGetInteger( row, 8 );
1544 file->state = msifs_invalid;
1546 /* if the compressed bits are not set in the file attributes,
1547 * then read the information from the package word count property
1549 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1551 file->IsCompressed = FALSE;
1553 else if (file->Attributes &
1554 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1556 file->IsCompressed = TRUE;
1558 else if (file->Attributes & msidbFileAttributesNoncompressed)
1560 file->IsCompressed = FALSE;
1564 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1567 load_file_hash(package, file);
1568 load_file_disk_id(package, file);
1570 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1572 list_add_tail( &package->files, &file->entry );
1574 return ERROR_SUCCESS;
1577 static UINT load_all_files(MSIPACKAGE *package)
1581 static const WCHAR Query[] =
1582 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1583 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1584 '`','S','e','q','u','e','n','c','e','`', 0};
1586 if (!list_empty(&package->files))
1587 return ERROR_SUCCESS;
1589 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1590 if (rc != ERROR_SUCCESS)
1591 return ERROR_SUCCESS;
1593 rc = MSI_IterateRecords(view, NULL, load_file, package);
1594 msiobj_release(&view->hdr);
1596 return ERROR_SUCCESS;
1599 static UINT load_folder( MSIRECORD *row, LPVOID param )
1601 MSIPACKAGE *package = param;
1602 static WCHAR szEmpty[] = { 0 };
1603 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1606 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1608 return ERROR_NOT_ENOUGH_MEMORY;
1610 folder->Directory = msi_dup_record_field( row, 1 );
1612 TRACE("%s\n", debugstr_w(folder->Directory));
1614 p = msi_dup_record_field(row, 3);
1616 /* split src and target dir */
1618 src_short = folder_split_path( p, ':' );
1620 /* split the long and short paths */
1621 tgt_long = folder_split_path( tgt_short, '|' );
1622 src_long = folder_split_path( src_short, '|' );
1624 /* check for no-op dirs */
1625 if (tgt_short && !strcmpW( szDot, tgt_short ))
1626 tgt_short = szEmpty;
1627 if (src_short && !strcmpW( szDot, src_short ))
1628 src_short = szEmpty;
1631 tgt_long = tgt_short;
1634 src_short = tgt_short;
1635 src_long = tgt_long;
1639 src_long = src_short;
1641 /* FIXME: use the target short path too */
1642 folder->TargetDefault = strdupW(tgt_long);
1643 folder->SourceShortPath = strdupW(src_short);
1644 folder->SourceLongPath = strdupW(src_long);
1647 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1648 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1649 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1651 folder->Parent = msi_dup_record_field( row, 2 );
1653 folder->Property = msi_dup_property( package->db, folder->Directory );
1655 list_add_tail( &package->folders, &folder->entry );
1657 TRACE("returning %p\n", folder);
1659 return ERROR_SUCCESS;
1662 static UINT load_all_folders( MSIPACKAGE *package )
1664 static const WCHAR query[] = {
1665 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1666 '`','D','i','r','e','c','t','o','r','y','`',0 };
1670 if (!list_empty(&package->folders))
1671 return ERROR_SUCCESS;
1673 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1674 if (r != ERROR_SUCCESS)
1677 r = MSI_IterateRecords(view, NULL, load_folder, package);
1678 msiobj_release(&view->hdr);
1683 * I am not doing any of the costing functionality yet.
1684 * Mostly looking at doing the Component and Feature loading
1686 * The native MSI does A LOT of modification to tables here. Mostly adding
1687 * a lot of temporary columns to the Feature and Component tables.
1689 * note: Native msi also tracks the short filename. But I am only going to
1690 * track the long ones. Also looking at this directory table
1691 * it appears that the directory table does not get the parents
1692 * resolved base on property only based on their entries in the
1695 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1697 static const WCHAR szCosting[] =
1698 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1700 msi_set_property( package->db, szCosting, szZero );
1701 msi_set_property( package->db, cszRootDrive, c_colon );
1703 load_all_folders( package );
1704 load_all_components( package );
1705 load_all_features( package );
1706 load_all_files( package );
1708 return ERROR_SUCCESS;
1711 static UINT execute_script(MSIPACKAGE *package, UINT script )
1714 UINT rc = ERROR_SUCCESS;
1716 TRACE("Executing Script %i\n",script);
1718 if (!package->script)
1720 ERR("no script!\n");
1721 return ERROR_FUNCTION_FAILED;
1724 for (i = 0; i < package->script->ActionCount[script]; i++)
1727 action = package->script->Actions[script][i];
1728 ui_actionstart(package, action);
1729 TRACE("Executing Action (%s)\n",debugstr_w(action));
1730 rc = ACTION_PerformAction(package, action, script);
1731 if (rc != ERROR_SUCCESS)
1734 msi_free_action_script(package, script);
1738 static UINT ACTION_FileCost(MSIPACKAGE *package)
1740 return ERROR_SUCCESS;
1743 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1748 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1750 if (!comp->ComponentId) continue;
1752 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1753 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1755 if (r != ERROR_SUCCESS)
1756 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1757 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1759 if (r != ERROR_SUCCESS)
1760 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1761 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1763 if (r != ERROR_SUCCESS)
1764 comp->Installed = INSTALLSTATE_ABSENT;
1768 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1770 MSIFEATURE *feature;
1772 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1774 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1776 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1777 feature->Installed = INSTALLSTATE_ABSENT;
1779 feature->Installed = state;
1783 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1785 return (feature->Level > 0 && feature->Level <= level);
1788 static BOOL process_state_property(MSIPACKAGE* package, int level,
1789 LPCWSTR property, INSTALLSTATE state)
1792 MSIFEATURE *feature;
1794 override = msi_dup_property( package->db, property );
1798 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1800 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
1803 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1805 if (!strcmpiW( override, szAll ))
1807 if (feature->Installed != state)
1809 feature->Action = state;
1810 feature->ActionRequest = state;
1815 LPWSTR ptr = override;
1816 LPWSTR ptr2 = strchrW(override,',');
1820 int len = ptr2 - ptr;
1822 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1823 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1825 if (feature->Installed != state)
1827 feature->Action = state;
1828 feature->ActionRequest = state;
1835 ptr2 = strchrW(ptr,',');
1846 static BOOL process_overrides( MSIPACKAGE *package, int level )
1848 static const WCHAR szAddLocal[] =
1849 {'A','D','D','L','O','C','A','L',0};
1850 static const WCHAR szAddSource[] =
1851 {'A','D','D','S','O','U','R','C','E',0};
1852 static const WCHAR szAdvertise[] =
1853 {'A','D','V','E','R','T','I','S','E',0};
1856 /* all these activation/deactivation things happen in order and things
1857 * later on the list override things earlier on the list.
1859 * 0 INSTALLLEVEL processing
1872 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1873 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1874 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1875 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1876 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1879 msi_set_property( package->db, szPreselected, szOne );
1884 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1887 static const WCHAR szlevel[] =
1888 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1889 MSICOMPONENT* component;
1890 MSIFEATURE *feature;
1892 TRACE("Checking Install Level\n");
1894 level = msi_get_property_int(package->db, szlevel, 1);
1896 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1898 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1900 if (!is_feature_selected( feature, level )) continue;
1902 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1904 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1906 feature->Action = INSTALLSTATE_SOURCE;
1907 feature->ActionRequest = INSTALLSTATE_SOURCE;
1909 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1911 feature->Action = INSTALLSTATE_ADVERTISED;
1912 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1916 feature->Action = INSTALLSTATE_LOCAL;
1917 feature->ActionRequest = INSTALLSTATE_LOCAL;
1922 /* disable child features of unselected parent features */
1923 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1927 if (is_feature_selected( feature, level )) continue;
1929 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1931 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1932 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1936 else /* preselected */
1938 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1940 if (!is_feature_selected( feature, level )) continue;
1942 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1944 if (feature->Installed == INSTALLSTATE_ABSENT)
1946 feature->Action = INSTALLSTATE_UNKNOWN;
1947 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1951 feature->Action = feature->Installed;
1952 feature->ActionRequest = feature->Installed;
1958 /* now we want to set component state based based on feature state */
1959 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1963 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1964 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1965 feature->ActionRequest, feature->Action);
1967 if (!is_feature_selected( feature, level )) continue;
1969 /* features with components that have compressed files are made local */
1970 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1972 if (cl->component->ForceLocalState &&
1973 feature->ActionRequest == INSTALLSTATE_SOURCE)
1975 feature->Action = INSTALLSTATE_LOCAL;
1976 feature->ActionRequest = INSTALLSTATE_LOCAL;
1981 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1983 component = cl->component;
1985 switch (feature->ActionRequest)
1987 case INSTALLSTATE_ABSENT:
1988 component->anyAbsent = 1;
1990 case INSTALLSTATE_ADVERTISED:
1991 component->hasAdvertiseFeature = 1;
1993 case INSTALLSTATE_SOURCE:
1994 component->hasSourceFeature = 1;
1996 case INSTALLSTATE_LOCAL:
1997 component->hasLocalFeature = 1;
1999 case INSTALLSTATE_DEFAULT:
2000 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2001 component->hasAdvertiseFeature = 1;
2002 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2003 component->hasSourceFeature = 1;
2005 component->hasLocalFeature = 1;
2013 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2015 /* check if it's local or source */
2016 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2017 (component->hasLocalFeature || component->hasSourceFeature))
2019 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2020 !component->ForceLocalState)
2022 component->Action = INSTALLSTATE_SOURCE;
2023 component->ActionRequest = INSTALLSTATE_SOURCE;
2027 component->Action = INSTALLSTATE_LOCAL;
2028 component->ActionRequest = INSTALLSTATE_LOCAL;
2033 /* if any feature is local, the component must be local too */
2034 if (component->hasLocalFeature)
2036 component->Action = INSTALLSTATE_LOCAL;
2037 component->ActionRequest = INSTALLSTATE_LOCAL;
2040 if (component->hasSourceFeature)
2042 component->Action = INSTALLSTATE_SOURCE;
2043 component->ActionRequest = INSTALLSTATE_SOURCE;
2046 if (component->hasAdvertiseFeature)
2048 component->Action = INSTALLSTATE_ADVERTISED;
2049 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2052 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2053 if (component->anyAbsent &&
2054 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
2056 component->Action = INSTALLSTATE_ABSENT;
2057 component->ActionRequest = INSTALLSTATE_ABSENT;
2061 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2063 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2065 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2066 component->Action = INSTALLSTATE_LOCAL;
2067 component->ActionRequest = INSTALLSTATE_LOCAL;
2070 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2071 component->Installed == INSTALLSTATE_SOURCE &&
2072 component->hasSourceFeature)
2074 component->Action = INSTALLSTATE_UNKNOWN;
2075 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2078 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2079 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2082 return ERROR_SUCCESS;
2085 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2087 MSIPACKAGE *package = param;
2092 name = MSI_RecordGetString(row,1);
2094 f = get_loaded_folder(package, name);
2095 if (!f) return ERROR_SUCCESS;
2097 /* reset the ResolvedTarget */
2098 msi_free(f->ResolvedTarget);
2099 f->ResolvedTarget = NULL;
2101 TRACE("directory %s ...\n", debugstr_w(name));
2102 path = resolve_target_folder( package, name, TRUE, TRUE, NULL );
2103 TRACE("resolves to %s\n", debugstr_w(path));
2106 return ERROR_SUCCESS;
2109 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2111 MSIPACKAGE *package = param;
2113 MSIFEATURE *feature;
2115 name = MSI_RecordGetString( row, 1 );
2117 feature = get_loaded_feature( package, name );
2119 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2123 Condition = MSI_RecordGetString(row,3);
2125 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2127 int level = MSI_RecordGetInteger(row,2);
2128 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2129 feature->Level = level;
2132 return ERROR_SUCCESS;
2135 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2137 static const WCHAR name[] = {'\\',0};
2138 VS_FIXEDFILEINFO *ptr, *ret;
2140 DWORD versize, handle;
2143 TRACE("%s\n", debugstr_w(filename));
2145 versize = GetFileVersionInfoSizeW( filename, &handle );
2149 version = msi_alloc( versize );
2153 GetFileVersionInfoW( filename, 0, versize, version );
2155 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2157 msi_free( version );
2161 ret = msi_alloc( sz );
2162 memcpy( ret, ptr, sz );
2164 msi_free( version );
2168 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2172 msi_parse_version_string( version, &ms, &ls );
2174 if (fi->dwFileVersionMS > ms) return 1;
2175 else if (fi->dwFileVersionMS < ms) return -1;
2176 else if (fi->dwFileVersionLS > ls) return 1;
2177 else if (fi->dwFileVersionLS < ls) return -1;
2181 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2185 msi_parse_version_string( ver1, &ms1, NULL );
2186 msi_parse_version_string( ver2, &ms2, NULL );
2188 if (ms1 > ms2) return 1;
2189 else if (ms1 < ms2) return -1;
2193 DWORD msi_get_disk_file_size( LPCWSTR filename )
2198 TRACE("%s\n", debugstr_w(filename));
2200 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2201 if (file == INVALID_HANDLE_VALUE)
2202 return INVALID_FILE_SIZE;
2204 size = GetFileSize( file, NULL );
2205 CloseHandle( file );
2209 BOOL msi_file_hash_matches( MSIFILE *file )
2212 MSIFILEHASHINFO hash;
2214 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2215 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2216 if (r != ERROR_SUCCESS)
2219 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2222 static WCHAR *get_temp_dir( void )
2225 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2227 GetTempPathW( MAX_PATH, tmp );
2230 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2231 if (CreateDirectoryW( dir, NULL )) break;
2233 return strdupW( dir );
2236 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2238 MSIASSEMBLY *assembly = file->Component->assembly;
2240 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2242 msi_free( file->TargetPath );
2243 if (assembly && !assembly->application)
2245 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2246 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2247 track_tempfile( package, file->TargetPath );
2251 WCHAR *dir = resolve_target_folder( package, file->Component->Directory, FALSE, TRUE, NULL );
2252 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2256 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2259 static UINT calculate_file_cost( MSIPACKAGE *package )
2261 VS_FIXEDFILEINFO *file_version;
2262 WCHAR *font_version;
2265 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2267 MSICOMPONENT *comp = file->Component;
2270 if (!comp->Enabled) continue;
2272 if (file->IsCompressed)
2273 comp->ForceLocalState = TRUE;
2275 set_target_path( package, file );
2277 if ((comp->assembly && !comp->assembly->installed) ||
2278 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2280 comp->Cost += file->FileSize;
2283 file_size = msi_get_disk_file_size( file->TargetPath );
2287 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2289 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2291 comp->Cost += file->FileSize - file_size;
2293 msi_free( file_version );
2296 else if ((font_version = font_version_from_file( file->TargetPath )))
2298 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2300 comp->Cost += file->FileSize - file_size;
2302 msi_free( font_version );
2306 if (file_size != file->FileSize)
2308 comp->Cost += file->FileSize - file_size;
2311 return ERROR_SUCCESS;
2315 * A lot is done in this function aside from just the costing.
2316 * The costing needs to be implemented at some point but for now I am going
2317 * to focus on the directory building
2320 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2322 static const WCHAR ExecSeqQuery[] =
2323 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2324 '`','D','i','r','e','c','t','o','r','y','`',0};
2325 static const WCHAR ConditionQuery[] =
2326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2327 '`','C','o','n','d','i','t','i','o','n','`',0};
2328 static const WCHAR szCosting[] =
2329 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2330 static const WCHAR szlevel[] =
2331 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2332 static const WCHAR szOutOfDiskSpace[] =
2333 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2335 UINT rc = ERROR_SUCCESS;
2339 TRACE("Building Directory properties\n");
2341 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2342 if (rc == ERROR_SUCCESS)
2344 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2346 msiobj_release(&view->hdr);
2349 TRACE("Evaluating component conditions\n");
2350 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2352 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2354 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2355 comp->Enabled = FALSE;
2358 comp->Enabled = TRUE;
2361 /* read components states from the registry */
2362 ACTION_GetComponentInstallStates(package);
2363 ACTION_GetFeatureInstallStates(package);
2365 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2367 TRACE("Evaluating feature conditions\n");
2369 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2370 if (rc == ERROR_SUCCESS)
2372 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2373 msiobj_release( &view->hdr );
2377 TRACE("Calculating file cost\n");
2378 calculate_file_cost( package );
2380 msi_set_property( package->db, szCosting, szOne );
2381 /* set default run level if not set */
2382 level = msi_dup_property( package->db, szlevel );
2384 msi_set_property( package->db, szlevel, szOne );
2387 /* FIXME: check volume disk space */
2388 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2390 return MSI_SetFeatureStates(package);
2393 /* OK this value is "interpreted" and then formatted based on the
2394 first few characters */
2395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2400 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2406 LPWSTR deformated = NULL;
2409 deformat_string(package, &value[2], &deformated);
2411 /* binary value type */
2415 *size = (strlenW(ptr)/2)+1;
2417 *size = strlenW(ptr)/2;
2419 data = msi_alloc(*size);
2425 /* if uneven pad with a zero in front */
2431 data[count] = (BYTE)strtol(byte,NULL,0);
2433 TRACE("Uneven byte count\n");
2441 data[count] = (BYTE)strtol(byte,NULL,0);
2444 msi_free(deformated);
2446 TRACE("Data %i bytes(%i)\n",*size,count);
2453 deformat_string(package, &value[1], &deformated);
2456 *size = sizeof(DWORD);
2457 data = msi_alloc(*size);
2463 if ( (*p < '0') || (*p > '9') )
2469 if (deformated[0] == '-')
2472 TRACE("DWORD %i\n",*(LPDWORD)data);
2474 msi_free(deformated);
2479 static const WCHAR szMulti[] = {'[','~',']',0};
2488 *type=REG_EXPAND_SZ;
2496 if (strstrW(value, szMulti))
2497 *type = REG_MULTI_SZ;
2499 /* remove initial delimiter */
2500 if (!strncmpW(value, szMulti, 3))
2503 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2505 /* add double NULL terminator */
2506 if (*type == REG_MULTI_SZ)
2508 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2509 data = msi_realloc_zero(data, *size);
2515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2522 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2524 *root_key = HKEY_LOCAL_MACHINE;
2529 *root_key = HKEY_CURRENT_USER;
2534 *root_key = HKEY_CLASSES_ROOT;
2538 *root_key = HKEY_CURRENT_USER;
2542 *root_key = HKEY_LOCAL_MACHINE;
2546 *root_key = HKEY_USERS;
2550 ERR("Unknown root %i\n", root);
2557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2559 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2560 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2562 if (is_64bit && package->platform == PLATFORM_INTEL &&
2563 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2568 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2569 path_32node = msi_alloc( size );
2573 memcpy( path_32node, path, len * sizeof(WCHAR) );
2574 path_32node[len] = 0;
2575 strcatW( path_32node, szWow6432Node );
2576 strcatW( path_32node, szBackSlash );
2577 strcatW( path_32node, path + len );
2581 return strdupW( path );
2584 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2586 MSIPACKAGE *package = param;
2587 LPSTR value_data = NULL;
2588 HKEY root_key, hkey;
2590 LPWSTR deformated, uikey, keypath;
2591 LPCWSTR szRoot, component, name, key, value;
2595 BOOL check_first = FALSE;
2598 ui_progress(package,2,0,0,0);
2600 component = MSI_RecordGetString(row, 6);
2601 comp = get_loaded_component(package,component);
2603 return ERROR_SUCCESS;
2607 TRACE("component is disabled\n");
2608 return ERROR_SUCCESS;
2611 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2613 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2614 comp->Action = comp->Installed;
2615 return ERROR_SUCCESS;
2617 comp->Action = INSTALLSTATE_LOCAL;
2619 name = MSI_RecordGetString(row, 4);
2620 if( MSI_RecordIsNull(row,5) && name )
2622 /* null values can have special meanings */
2623 if (name[0]=='-' && name[1] == 0)
2624 return ERROR_SUCCESS;
2625 else if ((name[0]=='+' && name[1] == 0) ||
2626 (name[0] == '*' && name[1] == 0))
2631 root = MSI_RecordGetInteger(row,2);
2632 key = MSI_RecordGetString(row, 3);
2634 szRoot = get_root_key( package, root, &root_key );
2636 return ERROR_SUCCESS;
2638 deformat_string(package, key , &deformated);
2639 size = strlenW(deformated) + strlenW(szRoot) + 1;
2640 uikey = msi_alloc(size*sizeof(WCHAR));
2641 strcpyW(uikey,szRoot);
2642 strcatW(uikey,deformated);
2644 keypath = get_keypath( package, root_key, deformated );
2645 msi_free( deformated );
2646 if (RegCreateKeyW( root_key, keypath, &hkey ))
2648 ERR("Could not create key %s\n", debugstr_w(keypath));
2651 return ERROR_SUCCESS;
2654 value = MSI_RecordGetString(row,5);
2656 value_data = parse_value(package, value, &type, &size);
2659 value_data = (LPSTR)strdupW(szEmpty);
2660 size = sizeof(szEmpty);
2664 deformat_string(package, name, &deformated);
2668 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2670 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2675 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2676 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2678 TRACE("value %s of %s checked already exists\n",
2679 debugstr_w(deformated), debugstr_w(uikey));
2683 TRACE("Checked and setting value %s of %s\n",
2684 debugstr_w(deformated), debugstr_w(uikey));
2685 if (deformated || size)
2686 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2691 uirow = MSI_CreateRecord(3);
2692 MSI_RecordSetStringW(uirow,2,deformated);
2693 MSI_RecordSetStringW(uirow,1,uikey);
2694 if (type == REG_SZ || type == REG_EXPAND_SZ)
2695 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2696 ui_actiondata(package,szWriteRegistryValues,uirow);
2697 msiobj_release( &uirow->hdr );
2699 msi_free(value_data);
2700 msi_free(deformated);
2704 return ERROR_SUCCESS;
2707 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2711 static const WCHAR ExecSeqQuery[] =
2712 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2713 '`','R','e','g','i','s','t','r','y','`',0 };
2715 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2716 if (rc != ERROR_SUCCESS)
2717 return ERROR_SUCCESS;
2719 /* increment progress bar each time action data is sent */
2720 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2722 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2724 msiobj_release(&view->hdr);
2728 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2732 DWORD num_subkeys, num_values;
2736 if ((res = RegDeleteTreeW( hkey_root, key )))
2738 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2743 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2745 if ((res = RegDeleteValueW( hkey, value )))
2747 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2749 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2750 NULL, NULL, NULL, NULL );
2751 RegCloseKey( hkey );
2752 if (!res && !num_subkeys && !num_values)
2754 TRACE("Removing empty key %s\n", debugstr_w(key));
2755 RegDeleteKeyW( hkey_root, key );
2759 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2763 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2765 MSIPACKAGE *package = param;
2766 LPCWSTR component, name, key_str, root_key_str;
2767 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2770 BOOL delete_key = FALSE;
2775 ui_progress( package, 2, 0, 0, 0 );
2777 component = MSI_RecordGetString( row, 6 );
2778 comp = get_loaded_component( package, component );
2780 return ERROR_SUCCESS;
2784 TRACE("component is disabled\n");
2785 return ERROR_SUCCESS;
2788 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2790 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2791 comp->Action = comp->Installed;
2792 return ERROR_SUCCESS;
2794 comp->Action = INSTALLSTATE_ABSENT;
2796 name = MSI_RecordGetString( row, 4 );
2797 if (MSI_RecordIsNull( row, 5 ) && name )
2799 if (name[0] == '+' && !name[1])
2800 return ERROR_SUCCESS;
2801 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2808 root = MSI_RecordGetInteger( row, 2 );
2809 key_str = MSI_RecordGetString( row, 3 );
2811 root_key_str = get_root_key( package, root, &hkey_root );
2813 return ERROR_SUCCESS;
2815 deformat_string( package, key_str, &deformated_key );
2816 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2817 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2818 strcpyW( ui_key_str, root_key_str );
2819 strcatW( ui_key_str, deformated_key );
2821 deformat_string( package, name, &deformated_name );
2823 keypath = get_keypath( package, hkey_root, deformated_key );
2824 msi_free( deformated_key );
2825 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2826 msi_free( keypath );
2828 uirow = MSI_CreateRecord( 2 );
2829 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2830 MSI_RecordSetStringW( uirow, 2, deformated_name );
2832 ui_actiondata( package, szRemoveRegistryValues, uirow );
2833 msiobj_release( &uirow->hdr );
2835 msi_free( ui_key_str );
2836 msi_free( deformated_name );
2837 return ERROR_SUCCESS;
2840 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2842 MSIPACKAGE *package = param;
2843 LPCWSTR component, name, key_str, root_key_str;
2844 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2847 BOOL delete_key = FALSE;
2852 ui_progress( package, 2, 0, 0, 0 );
2854 component = MSI_RecordGetString( row, 5 );
2855 comp = get_loaded_component( package, component );
2857 return ERROR_SUCCESS;
2861 TRACE("component is disabled\n");
2862 return ERROR_SUCCESS;
2865 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2867 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2868 comp->Action = comp->Installed;
2869 return ERROR_SUCCESS;
2871 comp->Action = INSTALLSTATE_LOCAL;
2873 if ((name = MSI_RecordGetString( row, 4 )))
2875 if (name[0] == '-' && !name[1])
2882 root = MSI_RecordGetInteger( row, 2 );
2883 key_str = MSI_RecordGetString( row, 3 );
2885 root_key_str = get_root_key( package, root, &hkey_root );
2887 return ERROR_SUCCESS;
2889 deformat_string( package, key_str, &deformated_key );
2890 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2891 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2892 strcpyW( ui_key_str, root_key_str );
2893 strcatW( ui_key_str, deformated_key );
2895 deformat_string( package, name, &deformated_name );
2897 keypath = get_keypath( package, hkey_root, deformated_key );
2898 msi_free( deformated_key );
2899 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2900 msi_free( keypath );
2902 uirow = MSI_CreateRecord( 2 );
2903 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2904 MSI_RecordSetStringW( uirow, 2, deformated_name );
2906 ui_actiondata( package, szRemoveRegistryValues, uirow );
2907 msiobj_release( &uirow->hdr );
2909 msi_free( ui_key_str );
2910 msi_free( deformated_name );
2911 return ERROR_SUCCESS;
2914 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2918 static const WCHAR registry_query[] =
2919 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2920 '`','R','e','g','i','s','t','r','y','`',0 };
2921 static const WCHAR remove_registry_query[] =
2922 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2923 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2925 /* increment progress bar each time action data is sent */
2926 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2928 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2929 if (rc == ERROR_SUCCESS)
2931 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2932 msiobj_release( &view->hdr );
2933 if (rc != ERROR_SUCCESS)
2937 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2938 if (rc == ERROR_SUCCESS)
2940 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2941 msiobj_release( &view->hdr );
2942 if (rc != ERROR_SUCCESS)
2946 return ERROR_SUCCESS;
2949 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2951 package->script->CurrentlyScripting = TRUE;
2953 return ERROR_SUCCESS;
2957 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2962 static const WCHAR q1[]=
2963 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2964 '`','R','e','g','i','s','t','r','y','`',0};
2967 MSIFEATURE *feature;
2970 TRACE("InstallValidate\n");
2972 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2973 if (rc == ERROR_SUCCESS)
2975 MSI_IterateRecords( view, &progress, NULL, package );
2976 msiobj_release( &view->hdr );
2977 total += progress * REG_PROGRESS_VALUE;
2980 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2981 total += COMPONENT_PROGRESS_VALUE;
2983 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2984 total += file->FileSize;
2986 ui_progress(package,0,total,0,0);
2988 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2990 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2991 debugstr_w(feature->Feature), feature->Installed,
2992 feature->ActionRequest, feature->Action);
2995 return ERROR_SUCCESS;
2998 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3000 MSIPACKAGE* package = param;
3001 LPCWSTR cond = NULL;
3002 LPCWSTR message = NULL;
3005 static const WCHAR title[]=
3006 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3008 cond = MSI_RecordGetString(row,1);
3010 r = MSI_EvaluateConditionW(package,cond);
3011 if (r == MSICONDITION_FALSE)
3013 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3016 message = MSI_RecordGetString(row,2);
3017 deformat_string(package,message,&deformated);
3018 MessageBoxW(NULL,deformated,title,MB_OK);
3019 msi_free(deformated);
3022 return ERROR_INSTALL_FAILURE;
3025 return ERROR_SUCCESS;
3028 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3031 MSIQUERY * view = NULL;
3032 static const WCHAR ExecSeqQuery[] =
3033 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3034 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3036 TRACE("Checking launch conditions\n");
3038 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3039 if (rc != ERROR_SUCCESS)
3040 return ERROR_SUCCESS;
3042 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3043 msiobj_release(&view->hdr);
3048 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3052 return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
3054 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3056 MSIRECORD * row = 0;
3058 LPWSTR deformated,buffer,deformated_name;
3060 static const WCHAR ExecSeqQuery[] =
3061 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3062 '`','R','e','g','i','s','t','r','y','`',' ',
3063 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3064 ' ','=',' ' ,'\'','%','s','\'',0 };
3065 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3066 static const WCHAR fmt2[]=
3067 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3069 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3073 root = MSI_RecordGetInteger(row,2);
3074 key = MSI_RecordGetString(row, 3);
3075 name = MSI_RecordGetString(row, 4);
3076 deformat_string(package, key , &deformated);
3077 deformat_string(package, name, &deformated_name);
3079 len = strlenW(deformated) + 6;
3080 if (deformated_name)
3081 len+=strlenW(deformated_name);
3083 buffer = msi_alloc( len *sizeof(WCHAR));
3085 if (deformated_name)
3086 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3088 sprintfW(buffer,fmt,root,deformated);
3090 msi_free(deformated);
3091 msi_free(deformated_name);
3092 msiobj_release(&row->hdr);
3096 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3098 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3103 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3106 return strdupW( file->TargetPath );
3111 static HKEY openSharedDLLsKey(void)
3114 static const WCHAR path[] =
3115 {'S','o','f','t','w','a','r','e','\\',
3116 'M','i','c','r','o','s','o','f','t','\\',
3117 'W','i','n','d','o','w','s','\\',
3118 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3119 'S','h','a','r','e','d','D','L','L','s',0};
3121 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3125 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3130 DWORD sz = sizeof(count);
3133 hkey = openSharedDLLsKey();
3134 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3135 if (rc != ERROR_SUCCESS)
3141 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3145 hkey = openSharedDLLsKey();
3147 msi_reg_set_val_dword( hkey, path, count );
3149 RegDeleteValueW(hkey,path);
3155 * Return TRUE if the count should be written out and FALSE if not
3157 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3159 MSIFEATURE *feature;
3163 /* only refcount DLLs */
3164 if (comp->KeyPath == NULL ||
3165 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3166 comp->Attributes & msidbComponentAttributesODBCDataSource)
3170 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3171 write = (count > 0);
3173 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3177 /* increment counts */
3178 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3182 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3185 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3187 if ( cl->component == comp )
3192 /* decrement counts */
3193 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3197 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3200 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3202 if ( cl->component == comp )
3207 /* ref count all the files in the component */
3212 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3214 if (file->Component == comp)
3215 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3219 /* add a count for permanent */
3220 if (comp->Attributes & msidbComponentAttributesPermanent)
3223 comp->RefCount = count;
3226 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3229 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3231 WCHAR squished_pc[GUID_SIZE];
3232 WCHAR squished_cc[GUID_SIZE];
3239 squash_guid(package->ProductCode,squished_pc);
3240 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3242 msi_set_sourcedir_props(package, FALSE);
3244 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3248 ui_progress(package,2,0,0,0);
3249 if (!comp->ComponentId)
3252 squash_guid(comp->ComponentId,squished_cc);
3254 msi_free(comp->FullKeypath);
3255 comp->FullKeypath = resolve_keypath( package, comp );
3257 ACTION_RefCountComponent( package, comp );
3259 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3260 debugstr_w(comp->Component),
3261 debugstr_w(squished_cc),
3262 debugstr_w(comp->FullKeypath),
3264 comp->ActionRequest);
3266 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3267 comp->ActionRequest == INSTALLSTATE_SOURCE)
3269 if (!comp->FullKeypath)
3272 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3273 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3276 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3279 if (rc != ERROR_SUCCESS)
3282 if (comp->Attributes & msidbComponentAttributesPermanent)
3284 static const WCHAR szPermKey[] =
3285 { '0','0','0','0','0','0','0','0','0','0','0','0',
3286 '0','0','0','0','0','0','0','0','0','0','0','0',
3287 '0','0','0','0','0','0','0','0',0 };
3289 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3292 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3293 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3299 WCHAR source[MAX_PATH];
3300 WCHAR base[MAX_PATH];
3303 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3304 static const WCHAR query[] = {
3305 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3306 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3307 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3308 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3309 '`','D','i','s','k','I','d','`',0};
3311 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3314 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3315 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3316 ptr2 = strrchrW(source, '\\') + 1;
3317 msiobj_release(&row->hdr);
3319 lstrcpyW(base, package->PackagePath);
3320 ptr = strrchrW(base, '\\');
3323 sourcepath = resolve_file_source(package, file);
3324 ptr = sourcepath + lstrlenW(base);
3325 lstrcpyW(ptr2, ptr);
3326 msi_free(sourcepath);
3328 msi_reg_set_val_str(hkey, squished_pc, source);
3332 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3334 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3335 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3337 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3339 comp->Action = comp->ActionRequest;
3342 uirow = MSI_CreateRecord(3);
3343 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3344 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3345 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3346 ui_actiondata(package,szProcessComponents,uirow);
3347 msiobj_release( &uirow->hdr );
3350 return ERROR_SUCCESS;
3361 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3362 LPWSTR lpszName, LONG_PTR lParam)
3365 typelib_struct *tl_struct = (typelib_struct*) lParam;
3366 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3370 if (!IS_INTRESOURCE(lpszName))
3372 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3376 sz = strlenW(tl_struct->source)+4;
3377 sz *= sizeof(WCHAR);
3379 if ((INT_PTR)lpszName == 1)
3380 tl_struct->path = strdupW(tl_struct->source);
3383 tl_struct->path = msi_alloc(sz);
3384 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3387 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3388 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3391 msi_free(tl_struct->path);
3392 tl_struct->path = NULL;
3397 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3398 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3400 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3404 msi_free(tl_struct->path);
3405 tl_struct->path = NULL;
3407 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3408 ITypeLib_Release(tl_struct->ptLib);
3413 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3415 MSIPACKAGE* package = param;
3419 typelib_struct tl_struct;
3424 component = MSI_RecordGetString(row,3);
3425 comp = get_loaded_component(package,component);
3427 return ERROR_SUCCESS;
3431 TRACE("component is disabled\n");
3432 return ERROR_SUCCESS;
3435 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3437 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3438 comp->Action = comp->Installed;
3439 return ERROR_SUCCESS;
3441 comp->Action = INSTALLSTATE_LOCAL;
3443 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3445 TRACE("component has no key path\n");
3446 return ERROR_SUCCESS;
3448 ui_actiondata( package, szRegisterTypeLibraries, row );
3450 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3454 guid = MSI_RecordGetString(row,1);
3455 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3456 tl_struct.source = strdupW( file->TargetPath );
3457 tl_struct.path = NULL;
3459 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3460 (LONG_PTR)&tl_struct);
3468 helpid = MSI_RecordGetString(row,6);
3470 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3471 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3475 ERR("Failed to register type library %s\n",
3476 debugstr_w(tl_struct.path));
3478 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3480 ITypeLib_Release(tl_struct.ptLib);
3481 msi_free(tl_struct.path);
3484 ERR("Failed to load type library %s\n",
3485 debugstr_w(tl_struct.source));
3487 FreeLibrary(module);
3488 msi_free(tl_struct.source);
3492 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3495 ERR("Failed to load type library: %08x\n", hr);
3496 return ERROR_INSTALL_FAILURE;
3499 ITypeLib_Release(tlib);
3502 return ERROR_SUCCESS;
3505 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3508 * OK this is a bit confusing.. I am given a _Component key and I believe
3509 * that the file that is being registered as a type library is the "key file
3510 * of that component" which I interpret to mean "The file in the KeyPath of
3515 static const WCHAR Query[] =
3516 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3517 '`','T','y','p','e','L','i','b','`',0};
3519 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3520 if (rc != ERROR_SUCCESS)
3521 return ERROR_SUCCESS;
3523 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3524 msiobj_release(&view->hdr);
3528 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3530 MSIPACKAGE *package = param;
3531 LPCWSTR component, guid;
3539 component = MSI_RecordGetString( row, 3 );
3540 comp = get_loaded_component( package, component );
3542 return ERROR_SUCCESS;
3546 TRACE("component is disabled\n");
3547 return ERROR_SUCCESS;
3550 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3552 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3553 comp->Action = comp->Installed;
3554 return ERROR_SUCCESS;
3556 comp->Action = INSTALLSTATE_ABSENT;
3558 ui_actiondata( package, szUnregisterTypeLibraries, row );
3560 guid = MSI_RecordGetString( row, 1 );
3561 CLSIDFromString( (LPCWSTR)guid, &libid );
3562 version = MSI_RecordGetInteger( row, 4 );
3563 language = MSI_RecordGetInteger( row, 2 );
3566 syskind = SYS_WIN64;
3568 syskind = SYS_WIN32;
3571 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3574 WARN("Failed to unregister typelib: %08x\n", hr);
3577 return ERROR_SUCCESS;
3580 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3584 static const WCHAR query[] =
3585 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3586 '`','T','y','p','e','L','i','b','`',0};
3588 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3589 if (rc != ERROR_SUCCESS)
3590 return ERROR_SUCCESS;
3592 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3593 msiobj_release( &view->hdr );
3597 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3599 static const WCHAR szlnk[] = {'.','l','n','k',0};
3600 LPCWSTR directory, extension;
3601 LPWSTR link_folder, link_file, filename;
3603 directory = MSI_RecordGetString( row, 2 );
3604 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3606 /* may be needed because of a bug somewhere else */
3607 create_full_pathW( link_folder );
3609 filename = msi_dup_record_field( row, 3 );
3610 reduce_to_longfilename( filename );
3612 extension = strchrW( filename, '.' );
3613 if (!extension || strcmpiW( extension, szlnk ))
3615 int len = strlenW( filename );
3616 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3617 memcpy( filename + len, szlnk, sizeof(szlnk) );
3619 link_file = build_directory_name( 2, link_folder, filename );
3620 msi_free( link_folder );
3621 msi_free( filename );
3626 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3628 MSIPACKAGE *package = param;
3629 LPWSTR link_file, deformated, path;
3630 LPCWSTR component, target;
3632 IShellLinkW *sl = NULL;
3633 IPersistFile *pf = NULL;
3636 component = MSI_RecordGetString(row, 4);
3637 comp = get_loaded_component(package, component);
3639 return ERROR_SUCCESS;
3643 TRACE("component is disabled\n");
3644 return ERROR_SUCCESS;
3647 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3649 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3650 comp->Action = comp->Installed;
3651 return ERROR_SUCCESS;
3653 comp->Action = INSTALLSTATE_LOCAL;
3655 ui_actiondata(package,szCreateShortcuts,row);
3657 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3658 &IID_IShellLinkW, (LPVOID *) &sl );
3662 ERR("CLSID_ShellLink not available\n");
3666 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3669 ERR("QueryInterface(IID_IPersistFile) failed\n");
3673 target = MSI_RecordGetString(row, 5);
3674 if (strchrW(target, '['))
3676 deformat_string(package, target, &deformated);
3677 IShellLinkW_SetPath(sl,deformated);
3678 msi_free(deformated);
3682 FIXME("poorly handled shortcut format, advertised shortcut\n");
3683 IShellLinkW_SetPath(sl,comp->FullKeypath);
3686 if (!MSI_RecordIsNull(row,6))
3688 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3689 deformat_string(package, arguments, &deformated);
3690 IShellLinkW_SetArguments(sl,deformated);
3691 msi_free(deformated);
3694 if (!MSI_RecordIsNull(row,7))
3696 LPCWSTR description = MSI_RecordGetString(row, 7);
3697 IShellLinkW_SetDescription(sl, description);
3700 if (!MSI_RecordIsNull(row,8))
3701 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3703 if (!MSI_RecordIsNull(row,9))
3706 LPCWSTR icon = MSI_RecordGetString(row, 9);
3708 path = build_icon_path(package, icon);
3709 index = MSI_RecordGetInteger(row,10);
3711 /* no value means 0 */
3712 if (index == MSI_NULL_INTEGER)
3715 IShellLinkW_SetIconLocation(sl, path, index);
3719 if (!MSI_RecordIsNull(row,11))
3720 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3722 if (!MSI_RecordIsNull(row,12))
3724 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3725 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
3727 IShellLinkW_SetWorkingDirectory(sl, path);
3731 link_file = get_link_file(package, row);
3733 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3734 IPersistFile_Save(pf, link_file, FALSE);
3736 msi_free(link_file);
3740 IPersistFile_Release( pf );
3742 IShellLinkW_Release( sl );
3744 return ERROR_SUCCESS;
3747 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3752 static const WCHAR Query[] =
3753 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3754 '`','S','h','o','r','t','c','u','t','`',0};
3756 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3757 if (rc != ERROR_SUCCESS)
3758 return ERROR_SUCCESS;
3760 res = CoInitialize( NULL );
3762 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3763 msiobj_release(&view->hdr);
3771 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3773 MSIPACKAGE *package = param;
3778 component = MSI_RecordGetString( row, 4 );
3779 comp = get_loaded_component( package, component );
3781 return ERROR_SUCCESS;
3785 TRACE("component is disabled\n");
3786 return ERROR_SUCCESS;
3789 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3791 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3792 comp->Action = comp->Installed;
3793 return ERROR_SUCCESS;
3795 comp->Action = INSTALLSTATE_ABSENT;
3797 ui_actiondata( package, szRemoveShortcuts, row );
3799 link_file = get_link_file( package, row );
3801 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3802 if (!DeleteFileW( link_file ))
3804 WARN("Failed to remove shortcut file %u\n", GetLastError());
3806 msi_free( link_file );
3808 return ERROR_SUCCESS;
3811 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3815 static const WCHAR query[] =
3816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3817 '`','S','h','o','r','t','c','u','t','`',0};
3819 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3820 if (rc != ERROR_SUCCESS)
3821 return ERROR_SUCCESS;
3823 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3824 msiobj_release( &view->hdr );
3829 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3831 MSIPACKAGE* package = param;
3839 FileName = MSI_RecordGetString(row,1);
3842 ERR("Unable to get FileName\n");
3843 return ERROR_SUCCESS;
3846 FilePath = build_icon_path(package,FileName);
3848 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3850 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3851 FILE_ATTRIBUTE_NORMAL, NULL);
3853 if (the_file == INVALID_HANDLE_VALUE)
3855 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3857 return ERROR_SUCCESS;
3864 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3865 if (rc != ERROR_SUCCESS)
3867 ERR("Failed to get stream\n");
3868 CloseHandle(the_file);
3869 DeleteFileW(FilePath);
3872 WriteFile(the_file,buffer,sz,&write,NULL);
3873 } while (sz == 1024);
3876 CloseHandle(the_file);
3878 return ERROR_SUCCESS;
3881 static UINT msi_publish_icons(MSIPACKAGE *package)
3886 static const WCHAR query[]= {
3887 'S','E','L','E','C','T',' ','*',' ',
3888 'F','R','O','M',' ','`','I','c','o','n','`',0};
3890 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3891 if (r == ERROR_SUCCESS)
3893 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3894 msiobj_release(&view->hdr);
3897 return ERROR_SUCCESS;
3900 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3906 MSISOURCELISTINFO *info;
3908 r = RegCreateKeyW(hkey, szSourceList, &source);
3909 if (r != ERROR_SUCCESS)
3912 RegCloseKey(source);
3914 buffer = strrchrW(package->PackagePath, '\\') + 1;
3915 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3916 package->Context, MSICODE_PRODUCT,
3917 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3918 if (r != ERROR_SUCCESS)
3921 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3922 package->Context, MSICODE_PRODUCT,
3923 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3924 if (r != ERROR_SUCCESS)
3927 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3928 package->Context, MSICODE_PRODUCT,
3929 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3930 if (r != ERROR_SUCCESS)
3933 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3935 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3936 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3937 info->options, info->value);
3939 MsiSourceListSetInfoW(package->ProductCode, NULL,
3940 info->context, info->options,
3941 info->property, info->value);
3944 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3946 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3947 disk->context, disk->options,
3948 disk->disk_id, disk->volume_label, disk->disk_prompt);
3951 return ERROR_SUCCESS;
3954 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3956 MSIHANDLE hdb, suminfo;
3957 WCHAR guids[MAX_PATH];
3958 WCHAR packcode[SQUISH_GUID_SIZE];
3965 static const WCHAR szProductLanguage[] =
3966 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3967 static const WCHAR szARPProductIcon[] =
3968 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3969 static const WCHAR szProductVersion[] =
3970 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3971 static const WCHAR szAssignment[] =
3972 {'A','s','s','i','g','n','m','e','n','t',0};
3973 static const WCHAR szAdvertiseFlags[] =
3974 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3975 static const WCHAR szClients[] =
3976 {'C','l','i','e','n','t','s',0};
3977 static const WCHAR szColon[] = {':',0};
3979 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3980 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3983 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3984 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3987 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3989 buffer = msi_dup_property(package->db, szARPProductIcon);
3992 LPWSTR path = build_icon_path(package,buffer);
3993 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3998 buffer = msi_dup_property(package->db, szProductVersion);
4001 DWORD verdword = msi_version_str_to_dword(buffer);
4002 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4006 msi_reg_set_val_dword(hkey, szAssignment, 0);
4007 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4008 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4009 msi_reg_set_val_str(hkey, szClients, szColon);
4011 hdb = alloc_msihandle(&package->db->hdr);
4013 return ERROR_NOT_ENOUGH_MEMORY;
4015 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4016 MsiCloseHandle(hdb);
4017 if (r != ERROR_SUCCESS)
4021 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4022 NULL, guids, &size);
4023 if (r != ERROR_SUCCESS)
4026 ptr = strchrW(guids, ';');
4028 squash_guid(guids, packcode);
4029 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4032 MsiCloseHandle(suminfo);
4033 return ERROR_SUCCESS;
4036 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4041 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4043 upgrade = msi_dup_property(package->db, szUpgradeCode);
4045 return ERROR_SUCCESS;
4047 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4049 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4050 if (r != ERROR_SUCCESS)
4055 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4056 if (r != ERROR_SUCCESS)
4060 squash_guid(package->ProductCode, squashed_pc);
4061 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4070 static BOOL msi_check_publish(MSIPACKAGE *package)
4072 MSIFEATURE *feature;
4074 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4076 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4083 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4085 MSIFEATURE *feature;
4087 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4089 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4096 static UINT msi_publish_patches( MSIPACKAGE *package )
4098 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4099 WCHAR patch_squashed[GUID_SIZE];
4100 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4102 MSIPATCHINFO *patch;
4104 WCHAR *p, *all_patches = NULL;
4107 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4108 if (r != ERROR_SUCCESS)
4109 return ERROR_FUNCTION_FAILED;
4111 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4112 if (res != ERROR_SUCCESS)
4114 r = ERROR_FUNCTION_FAILED;
4118 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4119 if (r != ERROR_SUCCESS)
4122 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4124 squash_guid( patch->patchcode, patch_squashed );
4125 len += strlenW( patch_squashed ) + 1;
4128 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4132 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4136 squash_guid( patch->patchcode, p );
4137 p += strlenW( p ) + 1;
4139 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4140 (const BYTE *)patch->transforms,
4141 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4142 if (res != ERROR_SUCCESS)
4145 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4146 if (r != ERROR_SUCCESS)
4149 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4150 (const BYTE *)patch->localfile,
4151 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4152 RegCloseKey( patch_key );
4153 if (res != ERROR_SUCCESS)
4156 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4157 if (res != ERROR_SUCCESS)
4160 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4161 RegCloseKey( patch_key );
4162 if (res != ERROR_SUCCESS)
4166 all_patches[len] = 0;
4167 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4168 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4169 if (res != ERROR_SUCCESS)
4172 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4173 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4174 if (res != ERROR_SUCCESS)
4175 r = ERROR_FUNCTION_FAILED;
4178 RegCloseKey( product_patches_key );
4179 RegCloseKey( patches_key );
4180 RegCloseKey( product_key );
4181 msi_free( all_patches );
4186 * 99% of the work done here is only done for
4187 * advertised installs. However this is where the
4188 * Icon table is processed and written out
4189 * so that is what I am going to do here.
4191 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4194 HKEY hukey = NULL, hudkey = NULL;
4197 if (!list_empty(&package->patches))
4199 rc = msi_publish_patches(package);
4200 if (rc != ERROR_SUCCESS)
4204 /* FIXME: also need to publish if the product is in advertise mode */
4205 if (!msi_check_publish(package))
4206 return ERROR_SUCCESS;
4208 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4210 if (rc != ERROR_SUCCESS)
4213 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4214 NULL, &hudkey, TRUE);
4215 if (rc != ERROR_SUCCESS)
4218 rc = msi_publish_upgrade_code(package);
4219 if (rc != ERROR_SUCCESS)
4222 rc = msi_publish_product_properties(package, hukey);
4223 if (rc != ERROR_SUCCESS)
4226 rc = msi_publish_sourcelist(package, hukey);
4227 if (rc != ERROR_SUCCESS)
4230 rc = msi_publish_icons(package);
4233 uirow = MSI_CreateRecord( 1 );
4234 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4235 ui_actiondata( package, szPublishProduct, uirow );
4236 msiobj_release( &uirow->hdr );
4239 RegCloseKey(hudkey);
4244 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4246 WCHAR *filename, *ptr, *folder, *ret;
4247 const WCHAR *dirprop;
4249 filename = msi_dup_record_field( row, 2 );
4250 if (filename && (ptr = strchrW( filename, '|' )))
4255 dirprop = MSI_RecordGetString( row, 3 );
4258 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4260 folder = msi_dup_property( package->db, dirprop );
4263 folder = msi_dup_property( package->db, szWindowsFolder );
4267 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4268 msi_free( filename );
4272 ret = build_directory_name( 2, folder, ptr );
4274 msi_free( filename );
4279 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4281 MSIPACKAGE *package = param;
4282 LPCWSTR component, section, key, value, identifier;
4283 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4288 component = MSI_RecordGetString(row, 8);
4289 comp = get_loaded_component(package,component);
4291 return ERROR_SUCCESS;
4295 TRACE("component is disabled\n");
4296 return ERROR_SUCCESS;
4299 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4301 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4302 comp->Action = comp->Installed;
4303 return ERROR_SUCCESS;
4305 comp->Action = INSTALLSTATE_LOCAL;
4307 identifier = MSI_RecordGetString(row,1);
4308 section = MSI_RecordGetString(row,4);
4309 key = MSI_RecordGetString(row,5);
4310 value = MSI_RecordGetString(row,6);
4311 action = MSI_RecordGetInteger(row,7);
4313 deformat_string(package,section,&deformated_section);
4314 deformat_string(package,key,&deformated_key);
4315 deformat_string(package,value,&deformated_value);
4317 fullname = get_ini_file_name(package, row);
4321 TRACE("Adding value %s to section %s in %s\n",
4322 debugstr_w(deformated_key), debugstr_w(deformated_section),
4323 debugstr_w(fullname));
4324 WritePrivateProfileStringW(deformated_section, deformated_key,
4325 deformated_value, fullname);
4327 else if (action == 1)
4330 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4331 returned, 10, fullname);
4332 if (returned[0] == 0)
4334 TRACE("Adding value %s to section %s in %s\n",
4335 debugstr_w(deformated_key), debugstr_w(deformated_section),
4336 debugstr_w(fullname));
4338 WritePrivateProfileStringW(deformated_section, deformated_key,
4339 deformated_value, fullname);
4342 else if (action == 3)
4343 FIXME("Append to existing section not yet implemented\n");
4345 uirow = MSI_CreateRecord(4);
4346 MSI_RecordSetStringW(uirow,1,identifier);
4347 MSI_RecordSetStringW(uirow,2,deformated_section);
4348 MSI_RecordSetStringW(uirow,3,deformated_key);
4349 MSI_RecordSetStringW(uirow,4,deformated_value);
4350 ui_actiondata(package,szWriteIniValues,uirow);
4351 msiobj_release( &uirow->hdr );
4354 msi_free(deformated_key);
4355 msi_free(deformated_value);
4356 msi_free(deformated_section);
4357 return ERROR_SUCCESS;
4360 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4364 static const WCHAR ExecSeqQuery[] =
4365 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4366 '`','I','n','i','F','i','l','e','`',0};
4368 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4369 if (rc != ERROR_SUCCESS)
4371 TRACE("no IniFile table\n");
4372 return ERROR_SUCCESS;
4375 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4376 msiobj_release(&view->hdr);
4380 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4382 MSIPACKAGE *package = param;
4383 LPCWSTR component, section, key, value, identifier;
4384 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4389 component = MSI_RecordGetString( row, 8 );
4390 comp = get_loaded_component( package, component );
4392 return ERROR_SUCCESS;
4396 TRACE("component is disabled\n");
4397 return ERROR_SUCCESS;
4400 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4402 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4403 comp->Action = comp->Installed;
4404 return ERROR_SUCCESS;
4406 comp->Action = INSTALLSTATE_ABSENT;
4408 identifier = MSI_RecordGetString( row, 1 );
4409 section = MSI_RecordGetString( row, 4 );
4410 key = MSI_RecordGetString( row, 5 );
4411 value = MSI_RecordGetString( row, 6 );
4412 action = MSI_RecordGetInteger( row, 7 );
4414 deformat_string( package, section, &deformated_section );
4415 deformat_string( package, key, &deformated_key );
4416 deformat_string( package, value, &deformated_value );
4418 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4420 filename = get_ini_file_name( package, row );
4422 TRACE("Removing key %s from section %s in %s\n",
4423 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4425 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4427 WARN("Unable to remove key %u\n", GetLastError());
4429 msi_free( filename );
4432 FIXME("Unsupported action %d\n", action);
4435 uirow = MSI_CreateRecord( 4 );
4436 MSI_RecordSetStringW( uirow, 1, identifier );
4437 MSI_RecordSetStringW( uirow, 2, deformated_section );
4438 MSI_RecordSetStringW( uirow, 3, deformated_key );
4439 MSI_RecordSetStringW( uirow, 4, deformated_value );
4440 ui_actiondata( package, szRemoveIniValues, uirow );
4441 msiobj_release( &uirow->hdr );
4443 msi_free( deformated_key );
4444 msi_free( deformated_value );
4445 msi_free( deformated_section );
4446 return ERROR_SUCCESS;
4449 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4451 MSIPACKAGE *package = param;
4452 LPCWSTR component, section, key, value, identifier;
4453 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4458 component = MSI_RecordGetString( row, 8 );
4459 comp = get_loaded_component( package, component );
4461 return ERROR_SUCCESS;
4465 TRACE("component is disabled\n");
4466 return ERROR_SUCCESS;
4469 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4471 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4472 comp->Action = comp->Installed;
4473 return ERROR_SUCCESS;
4475 comp->Action = INSTALLSTATE_LOCAL;
4477 identifier = MSI_RecordGetString( row, 1 );
4478 section = MSI_RecordGetString( row, 4 );
4479 key = MSI_RecordGetString( row, 5 );
4480 value = MSI_RecordGetString( row, 6 );
4481 action = MSI_RecordGetInteger( row, 7 );
4483 deformat_string( package, section, &deformated_section );
4484 deformat_string( package, key, &deformated_key );
4485 deformat_string( package, value, &deformated_value );
4487 if (action == msidbIniFileActionRemoveLine)
4489 filename = get_ini_file_name( package, row );
4491 TRACE("Removing key %s from section %s in %s\n",
4492 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4494 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4496 WARN("Unable to remove key %u\n", GetLastError());
4498 msi_free( filename );
4501 FIXME("Unsupported action %d\n", action);
4503 uirow = MSI_CreateRecord( 4 );
4504 MSI_RecordSetStringW( uirow, 1, identifier );
4505 MSI_RecordSetStringW( uirow, 2, deformated_section );
4506 MSI_RecordSetStringW( uirow, 3, deformated_key );
4507 MSI_RecordSetStringW( uirow, 4, deformated_value );
4508 ui_actiondata( package, szRemoveIniValues, uirow );
4509 msiobj_release( &uirow->hdr );
4511 msi_free( deformated_key );
4512 msi_free( deformated_value );
4513 msi_free( deformated_section );
4514 return ERROR_SUCCESS;
4517 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4521 static const WCHAR query[] =
4522 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4523 '`','I','n','i','F','i','l','e','`',0};
4524 static const WCHAR remove_query[] =
4525 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4526 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4528 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4529 if (rc == ERROR_SUCCESS)
4531 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4532 msiobj_release( &view->hdr );
4533 if (rc != ERROR_SUCCESS)
4537 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4538 if (rc == ERROR_SUCCESS)
4540 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4541 msiobj_release( &view->hdr );
4542 if (rc != ERROR_SUCCESS)
4546 return ERROR_SUCCESS;
4549 static void register_dll( const WCHAR *dll, BOOL unregister )
4553 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4556 HRESULT (WINAPI *func_ptr)( void );
4557 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4559 func_ptr = (void *)GetProcAddress( hmod, func );
4562 HRESULT hr = func_ptr();
4564 WARN("failed to register dll 0x%08x\n", hr);
4567 WARN("entry point %s not found\n", func);
4568 FreeLibrary( hmod );
4571 WARN("failed to load library %u\n", GetLastError());
4574 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4576 MSIPACKAGE *package = param;
4581 filename = MSI_RecordGetString(row,1);
4582 file = get_loaded_file( package, filename );
4586 ERR("Unable to find file id %s\n",debugstr_w(filename));
4587 return ERROR_SUCCESS;
4590 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4592 register_dll( file->TargetPath, FALSE );
4594 uirow = MSI_CreateRecord( 2 );
4595 MSI_RecordSetStringW( uirow, 1, filename );
4596 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4597 ui_actiondata( package, szSelfRegModules, uirow );
4598 msiobj_release( &uirow->hdr );
4600 return ERROR_SUCCESS;
4603 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4607 static const WCHAR ExecSeqQuery[] =
4608 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4609 '`','S','e','l','f','R','e','g','`',0};
4611 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4612 if (rc != ERROR_SUCCESS)
4614 TRACE("no SelfReg table\n");
4615 return ERROR_SUCCESS;
4618 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4619 msiobj_release(&view->hdr);
4621 return ERROR_SUCCESS;
4624 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4626 MSIPACKAGE *package = param;
4631 filename = MSI_RecordGetString( row, 1 );
4632 file = get_loaded_file( package, filename );
4636 ERR("Unable to find file id %s\n", debugstr_w(filename));
4637 return ERROR_SUCCESS;
4640 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4642 register_dll( file->TargetPath, TRUE );
4644 uirow = MSI_CreateRecord( 2 );
4645 MSI_RecordSetStringW( uirow, 1, filename );
4646 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4647 ui_actiondata( package, szSelfUnregModules, uirow );
4648 msiobj_release( &uirow->hdr );
4650 return ERROR_SUCCESS;
4653 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4657 static const WCHAR query[] =
4658 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4659 '`','S','e','l','f','R','e','g','`',0};
4661 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4662 if (rc != ERROR_SUCCESS)
4664 TRACE("no SelfReg table\n");
4665 return ERROR_SUCCESS;
4668 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4669 msiobj_release( &view->hdr );
4671 return ERROR_SUCCESS;
4674 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4676 MSIFEATURE *feature;
4678 HKEY hkey = NULL, userdata = NULL;
4680 if (!msi_check_publish(package))
4681 return ERROR_SUCCESS;
4683 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4685 if (rc != ERROR_SUCCESS)
4688 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4690 if (rc != ERROR_SUCCESS)
4693 /* here the guids are base 85 encoded */
4694 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4700 BOOL absent = FALSE;
4703 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4704 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4705 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4708 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4712 if (feature->Feature_Parent)
4713 size += strlenW( feature->Feature_Parent )+2;
4715 data = msi_alloc(size * sizeof(WCHAR));
4718 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4720 MSICOMPONENT* component = cl->component;
4724 if (component->ComponentId)
4726 TRACE("From %s\n",debugstr_w(component->ComponentId));
4727 CLSIDFromString(component->ComponentId, &clsid);
4728 encode_base85_guid(&clsid,buf);
4729 TRACE("to %s\n",debugstr_w(buf));
4734 if (feature->Feature_Parent)
4736 static const WCHAR sep[] = {'\2',0};
4738 strcatW(data,feature->Feature_Parent);
4741 msi_reg_set_val_str( userdata, feature->Feature, data );
4745 if (feature->Feature_Parent)
4746 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4749 size += sizeof(WCHAR);
4750 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4751 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4755 size += 2*sizeof(WCHAR);
4756 data = msi_alloc(size);
4759 if (feature->Feature_Parent)
4760 strcpyW( &data[1], feature->Feature_Parent );
4761 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4767 uirow = MSI_CreateRecord( 1 );
4768 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4769 ui_actiondata( package, szPublishFeatures, uirow);
4770 msiobj_release( &uirow->hdr );
4771 /* FIXME: call ui_progress? */
4776 RegCloseKey(userdata);
4780 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4786 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4788 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4790 if (r == ERROR_SUCCESS)
4792 RegDeleteValueW(hkey, feature->Feature);
4796 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4798 if (r == ERROR_SUCCESS)
4800 RegDeleteValueW(hkey, feature->Feature);
4804 uirow = MSI_CreateRecord( 1 );
4805 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4806 ui_actiondata( package, szUnpublishFeatures, uirow );
4807 msiobj_release( &uirow->hdr );
4809 return ERROR_SUCCESS;
4812 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4814 MSIFEATURE *feature;
4816 if (!msi_check_unpublish(package))
4817 return ERROR_SUCCESS;
4819 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4821 msi_unpublish_feature(package, feature);
4824 return ERROR_SUCCESS;
4827 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4831 WCHAR date[9], *val, *buffer;
4832 const WCHAR *prop, *key;
4834 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4835 static const WCHAR szWindowsInstaller[] =
4836 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4837 static const WCHAR modpath_fmt[] =
4838 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4839 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4840 static const WCHAR szModifyPath[] =
4841 {'M','o','d','i','f','y','P','a','t','h',0};
4842 static const WCHAR szUninstallString[] =
4843 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4844 static const WCHAR szEstimatedSize[] =
4845 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4846 static const WCHAR szProductLanguage[] =
4847 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4848 static const WCHAR szProductVersion[] =
4849 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4850 static const WCHAR szDisplayVersion[] =
4851 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4852 static const WCHAR szInstallSource[] =
4853 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4854 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4855 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4856 static const WCHAR szAuthorizedCDFPrefix[] =
4857 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4858 static const WCHAR szARPCONTACT[] =
4859 {'A','R','P','C','O','N','T','A','C','T',0};
4860 static const WCHAR szContact[] =
4861 {'C','o','n','t','a','c','t',0};
4862 static const WCHAR szARPCOMMENTS[] =
4863 {'A','R','P','C','O','M','M','E','N','T','S',0};
4864 static const WCHAR szComments[] =
4865 {'C','o','m','m','e','n','t','s',0};
4866 static const WCHAR szProductName[] =
4867 {'P','r','o','d','u','c','t','N','a','m','e',0};
4868 static const WCHAR szDisplayName[] =
4869 {'D','i','s','p','l','a','y','N','a','m','e',0};
4870 static const WCHAR szARPHELPLINK[] =
4871 {'A','R','P','H','E','L','P','L','I','N','K',0};
4872 static const WCHAR szHelpLink[] =
4873 {'H','e','l','p','L','i','n','k',0};
4874 static const WCHAR szARPHELPTELEPHONE[] =
4875 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4876 static const WCHAR szHelpTelephone[] =
4877 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4878 static const WCHAR szARPINSTALLLOCATION[] =
4879 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4880 static const WCHAR szInstallLocation[] =
4881 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4882 static const WCHAR szManufacturer[] =
4883 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4884 static const WCHAR szPublisher[] =
4885 {'P','u','b','l','i','s','h','e','r',0};
4886 static const WCHAR szARPREADME[] =
4887 {'A','R','P','R','E','A','D','M','E',0};
4888 static const WCHAR szReadme[] =
4889 {'R','e','a','d','M','e',0};
4890 static const WCHAR szARPSIZE[] =
4891 {'A','R','P','S','I','Z','E',0};
4892 static const WCHAR szSize[] =
4893 {'S','i','z','e',0};
4894 static const WCHAR szARPURLINFOABOUT[] =
4895 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4896 static const WCHAR szURLInfoAbout[] =
4897 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4898 static const WCHAR szARPURLUPDATEINFO[] =
4899 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4900 static const WCHAR szURLUpdateInfo[] =
4901 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4903 static const WCHAR *propval[] = {
4904 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4905 szARPCONTACT, szContact,
4906 szARPCOMMENTS, szComments,
4907 szProductName, szDisplayName,
4908 szARPHELPLINK, szHelpLink,
4909 szARPHELPTELEPHONE, szHelpTelephone,
4910 szARPINSTALLLOCATION, szInstallLocation,
4911 cszSourceDir, szInstallSource,
4912 szManufacturer, szPublisher,
4913 szARPREADME, szReadme,
4915 szARPURLINFOABOUT, szURLInfoAbout,
4916 szARPURLUPDATEINFO, szURLUpdateInfo,
4919 const WCHAR **p = propval;
4925 val = msi_dup_property(package->db, prop);
4926 msi_reg_set_val_str(hkey, key, val);
4930 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4932 size = deformat_string(package, modpath_fmt, &buffer);
4933 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4934 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4937 /* FIXME: Write real Estimated Size when we have it */
4938 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4940 GetLocalTime(&systime);
4941 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4942 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4944 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4945 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4947 buffer = msi_dup_property(package->db, szProductVersion);
4948 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4951 DWORD verdword = msi_version_str_to_dword(buffer);
4953 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4954 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4955 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4959 return ERROR_SUCCESS;
4962 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4964 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4966 LPWSTR upgrade_code;
4971 /* FIXME: also need to publish if the product is in advertise mode */
4972 if (!msi_check_publish(package))
4973 return ERROR_SUCCESS;
4975 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4976 if (rc != ERROR_SUCCESS)
4979 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4980 NULL, &props, TRUE);
4981 if (rc != ERROR_SUCCESS)
4984 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4985 msi_free( package->db->localfile );
4986 package->db->localfile = NULL;
4988 rc = msi_publish_install_properties(package, hkey);
4989 if (rc != ERROR_SUCCESS)
4992 rc = msi_publish_install_properties(package, props);
4993 if (rc != ERROR_SUCCESS)
4996 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4999 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5000 squash_guid(package->ProductCode, squashed_pc);
5001 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5002 RegCloseKey(upgrade);
5003 msi_free(upgrade_code);
5007 uirow = MSI_CreateRecord( 1 );
5008 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5009 ui_actiondata( package, szRegisterProduct, uirow );
5010 msiobj_release( &uirow->hdr );
5013 return ERROR_SUCCESS;
5016 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5018 return execute_script(package,INSTALL_SCRIPT);
5021 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5023 WCHAR *upgrade, **features;
5024 BOOL full_uninstall = TRUE;
5025 MSIFEATURE *feature;
5026 MSIPATCHINFO *patch;
5028 static const WCHAR szUpgradeCode[] =
5029 {'U','p','g','r','a','d','e','C','o','d','e',0};
5031 features = msi_split_string(remove, ',');
5034 ERR("REMOVE feature list is empty!\n");
5035 return ERROR_FUNCTION_FAILED;
5038 if (!strcmpW( features[0], szAll ))
5039 full_uninstall = TRUE;
5042 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5044 if (feature->Action != INSTALLSTATE_ABSENT)
5045 full_uninstall = FALSE;
5050 if (!full_uninstall)
5051 return ERROR_SUCCESS;
5053 MSIREG_DeleteProductKey(package->ProductCode);
5054 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5055 MSIREG_DeleteUninstallKey(package);
5057 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5058 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5059 MSIREG_DeleteUserProductKey(package->ProductCode);
5060 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5062 upgrade = msi_dup_property(package->db, szUpgradeCode);
5065 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5066 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5070 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5072 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5075 return ERROR_SUCCESS;
5078 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5083 /* turn off scheduling */
5084 package->script->CurrentlyScripting= FALSE;
5086 /* first do the same as an InstallExecute */
5087 rc = ACTION_InstallExecute(package);
5088 if (rc != ERROR_SUCCESS)
5091 /* then handle Commit Actions */
5092 rc = execute_script(package,COMMIT_SCRIPT);
5093 if (rc != ERROR_SUCCESS)
5096 remove = msi_dup_property(package->db, szRemove);
5098 rc = msi_unpublish_product(package, remove);
5104 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5106 static const WCHAR RunOnce[] = {
5107 'S','o','f','t','w','a','r','e','\\',
5108 'M','i','c','r','o','s','o','f','t','\\',
5109 'W','i','n','d','o','w','s','\\',
5110 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5111 'R','u','n','O','n','c','e',0};
5112 static const WCHAR InstallRunOnce[] = {
5113 'S','o','f','t','w','a','r','e','\\',
5114 'M','i','c','r','o','s','o','f','t','\\',
5115 'W','i','n','d','o','w','s','\\',
5116 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5117 'I','n','s','t','a','l','l','e','r','\\',
5118 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5120 static const WCHAR msiexec_fmt[] = {
5122 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5123 '\"','%','s','\"',0};
5124 static const WCHAR install_fmt[] = {
5125 '/','I',' ','\"','%','s','\"',' ',
5126 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5127 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5128 WCHAR buffer[256], sysdir[MAX_PATH];
5130 WCHAR squished_pc[100];
5132 squash_guid(package->ProductCode,squished_pc);
5134 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5135 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5136 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5139 msi_reg_set_val_str( hkey, squished_pc, buffer );
5142 TRACE("Reboot command %s\n",debugstr_w(buffer));
5144 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5145 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5147 msi_reg_set_val_str( hkey, squished_pc, buffer );
5150 return ERROR_INSTALL_SUSPEND;
5153 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5159 * We are currently doing what should be done here in the top level Install
5160 * however for Administrative and uninstalls this step will be needed
5162 if (!package->PackagePath)
5163 return ERROR_SUCCESS;
5165 msi_set_sourcedir_props(package, TRUE);
5167 attrib = GetFileAttributesW(package->db->path);
5168 if (attrib == INVALID_FILE_ATTRIBUTES)
5174 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5175 package->Context, MSICODE_PRODUCT,
5176 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5177 if (rc == ERROR_MORE_DATA)
5179 prompt = msi_alloc(size * sizeof(WCHAR));
5180 MsiSourceListGetInfoW(package->ProductCode, NULL,
5181 package->Context, MSICODE_PRODUCT,
5182 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5185 prompt = strdupW(package->db->path);
5187 msg = generate_error_string(package,1302,1,prompt);
5188 while(attrib == INVALID_FILE_ATTRIBUTES)
5190 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5193 rc = ERROR_INSTALL_USEREXIT;
5196 attrib = GetFileAttributesW(package->db->path);
5202 return ERROR_SUCCESS;
5207 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5210 LPWSTR buffer, productid = NULL;
5211 UINT i, rc = ERROR_SUCCESS;
5214 static const WCHAR szPropKeys[][80] =
5216 {'P','r','o','d','u','c','t','I','D',0},
5217 {'U','S','E','R','N','A','M','E',0},
5218 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5222 static const WCHAR szRegKeys[][80] =
5224 {'P','r','o','d','u','c','t','I','D',0},
5225 {'R','e','g','O','w','n','e','r',0},
5226 {'R','e','g','C','o','m','p','a','n','y',0},
5230 if (msi_check_unpublish(package))
5232 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5236 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5240 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5242 if (rc != ERROR_SUCCESS)
5245 for( i = 0; szPropKeys[i][0]; i++ )
5247 buffer = msi_dup_property( package->db, szPropKeys[i] );
5248 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5253 uirow = MSI_CreateRecord( 1 );
5254 MSI_RecordSetStringW( uirow, 1, productid );
5255 ui_actiondata( package, szRegisterUser, uirow );
5256 msiobj_release( &uirow->hdr );
5258 msi_free(productid);
5264 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5268 package->script->InWhatSequence |= SEQUENCE_EXEC;
5269 rc = ACTION_ProcessExecSequence(package,FALSE);
5274 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5276 MSIPACKAGE *package = param;
5277 LPCWSTR compgroupid, component, feature, qualifier, text;
5278 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5287 feature = MSI_RecordGetString(rec, 5);
5288 feat = get_loaded_feature(package, feature);
5290 return ERROR_SUCCESS;
5292 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5293 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5294 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5296 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5297 feat->Action = feat->Installed;
5298 return ERROR_SUCCESS;
5301 component = MSI_RecordGetString(rec, 3);
5302 comp = get_loaded_component(package, component);
5304 return ERROR_SUCCESS;
5306 compgroupid = MSI_RecordGetString(rec,1);
5307 qualifier = MSI_RecordGetString(rec,2);
5309 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5310 if (rc != ERROR_SUCCESS)
5313 advertise = create_component_advertise_string( package, comp, feature );
5314 text = MSI_RecordGetString( rec, 4 );
5317 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5318 strcpyW( p, advertise );
5320 msi_free( advertise );
5323 existing = msi_reg_get_val_str( hkey, qualifier );
5325 sz = strlenW( advertise ) + 1;
5328 for (p = existing; *p; p += len)
5330 len = strlenW( p ) + 1;
5331 if (strcmpW( advertise, p )) sz += len;
5334 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5336 rc = ERROR_OUTOFMEMORY;
5342 for (p = existing; *p; p += len)
5344 len = strlenW( p ) + 1;
5345 if (strcmpW( advertise, p ))
5347 memcpy( q, p, len * sizeof(WCHAR) );
5352 strcpyW( q, advertise );
5353 q[strlenW( q ) + 1] = 0;
5355 msi_reg_set_val_multi_str( hkey, qualifier, output );
5360 msi_free( advertise );
5361 msi_free( existing );
5364 uirow = MSI_CreateRecord( 2 );
5365 MSI_RecordSetStringW( uirow, 1, compgroupid );
5366 MSI_RecordSetStringW( uirow, 2, qualifier);
5367 ui_actiondata( package, szPublishComponents, uirow);
5368 msiobj_release( &uirow->hdr );
5369 /* FIXME: call ui_progress? */
5375 * At present I am ignorning the advertised components part of this and only
5376 * focusing on the qualified component sets
5378 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5382 static const WCHAR ExecSeqQuery[] =
5383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5384 '`','P','u','b','l','i','s','h',
5385 'C','o','m','p','o','n','e','n','t','`',0};
5387 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5388 if (rc != ERROR_SUCCESS)
5389 return ERROR_SUCCESS;
5391 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5392 msiobj_release(&view->hdr);
5397 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5399 static const WCHAR szInstallerComponents[] = {
5400 'S','o','f','t','w','a','r','e','\\',
5401 'M','i','c','r','o','s','o','f','t','\\',
5402 'I','n','s','t','a','l','l','e','r','\\',
5403 'C','o','m','p','o','n','e','n','t','s','\\',0};
5405 MSIPACKAGE *package = param;
5406 LPCWSTR compgroupid, component, feature, qualifier;
5410 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5413 feature = MSI_RecordGetString( rec, 5 );
5414 feat = get_loaded_feature( package, feature );
5416 return ERROR_SUCCESS;
5418 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5420 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5421 feat->Action = feat->Installed;
5422 return ERROR_SUCCESS;
5425 component = MSI_RecordGetString( rec, 3 );
5426 comp = get_loaded_component( package, component );
5428 return ERROR_SUCCESS;
5430 compgroupid = MSI_RecordGetString( rec, 1 );
5431 qualifier = MSI_RecordGetString( rec, 2 );
5433 squash_guid( compgroupid, squashed );
5434 strcpyW( keypath, szInstallerComponents );
5435 strcatW( keypath, squashed );
5437 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5438 if (res != ERROR_SUCCESS)
5440 WARN("Unable to delete component key %d\n", res);
5443 uirow = MSI_CreateRecord( 2 );
5444 MSI_RecordSetStringW( uirow, 1, compgroupid );
5445 MSI_RecordSetStringW( uirow, 2, qualifier );
5446 ui_actiondata( package, szUnpublishComponents, uirow );
5447 msiobj_release( &uirow->hdr );
5449 return ERROR_SUCCESS;
5452 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5456 static const WCHAR query[] =
5457 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5458 '`','P','u','b','l','i','s','h',
5459 'C','o','m','p','o','n','e','n','t','`',0};
5461 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5462 if (rc != ERROR_SUCCESS)
5463 return ERROR_SUCCESS;
5465 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5466 msiobj_release( &view->hdr );
5471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5473 MSIPACKAGE *package = param;
5476 SC_HANDLE hscm, service = NULL;
5478 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5479 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5480 DWORD serv_type, start_type, err_control;
5481 SERVICE_DESCRIPTIONW sd = {NULL};
5483 static const WCHAR query[] =
5484 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5485 '`','C','o','m','p','o','n','e','n','t','`',' ',
5486 'W','H','E','R','E',' ',
5487 '`','C','o','m','p','o','n','e','n','t','`',' ',
5488 '=','\'','%','s','\'',0};
5490 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5493 ERR("Failed to open the SC Manager!\n");
5497 comp = MSI_RecordGetString( rec, 12 );
5498 if (!get_loaded_component( package, comp ))
5501 start_type = MSI_RecordGetInteger(rec, 5);
5502 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5505 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5506 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5507 serv_type = MSI_RecordGetInteger(rec, 4);
5508 err_control = MSI_RecordGetInteger(rec, 6);
5509 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5510 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5511 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5512 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5513 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5514 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5516 /* fetch the service path */
5517 row = MSI_QueryGetRecord(package->db, query, comp);
5520 ERR("Control query failed!\n");
5523 key = MSI_RecordGetString(row, 6);
5525 file = get_loaded_file(package, key);
5526 msiobj_release(&row->hdr);
5529 ERR("Failed to load the service file\n");
5533 if (!args || !args[0]) image_path = file->TargetPath;
5536 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5537 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5538 return ERROR_OUTOFMEMORY;
5540 strcpyW(image_path, file->TargetPath);
5541 strcatW(image_path, szSpace);
5542 strcatW(image_path, args);
5544 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5545 start_type, err_control, image_path, load_order,
5546 NULL, depends, serv_name, pass);
5550 if (GetLastError() != ERROR_SERVICE_EXISTS)
5551 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5553 else if (sd.lpDescription)
5555 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5556 WARN("failed to set service description %u\n", GetLastError());
5559 if (image_path != file->TargetPath) msi_free(image_path);
5561 CloseServiceHandle(service);
5562 CloseServiceHandle(hscm);
5565 msi_free(sd.lpDescription);
5566 msi_free(load_order);
5567 msi_free(serv_name);
5572 return ERROR_SUCCESS;
5575 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5579 static const WCHAR ExecSeqQuery[] =
5580 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5581 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5583 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5584 if (rc != ERROR_SUCCESS)
5585 return ERROR_SUCCESS;
5587 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5588 msiobj_release(&view->hdr);
5593 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5594 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5596 LPCWSTR *vector, *temp_vector;
5600 static const WCHAR separator[] = {'[','~',']',0};
5603 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5608 vector = msi_alloc(sizeof(LPWSTR));
5616 vector[*numargs - 1] = p;
5618 if ((q = strstrW(p, separator)))
5622 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5628 vector = temp_vector;
5637 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5639 MSIPACKAGE *package = param;
5642 SC_HANDLE scm = NULL, service = NULL;
5643 LPCWSTR component, *vector = NULL;
5644 LPWSTR name, args, display_name = NULL;
5645 DWORD event, numargs, len;
5646 UINT r = ERROR_FUNCTION_FAILED;
5648 component = MSI_RecordGetString(rec, 6);
5649 comp = get_loaded_component(package, component);
5651 return ERROR_SUCCESS;
5655 TRACE("component is disabled\n");
5656 return ERROR_SUCCESS;
5659 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5661 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5662 comp->Action = comp->Installed;
5663 return ERROR_SUCCESS;
5665 comp->Action = INSTALLSTATE_LOCAL;
5667 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5668 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5669 event = MSI_RecordGetInteger(rec, 3);
5671 if (!(event & msidbServiceControlEventStart))
5677 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5680 ERR("Failed to open the service control manager\n");
5685 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5686 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5688 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5689 GetServiceDisplayNameW( scm, name, display_name, &len );
5692 service = OpenServiceW(scm, name, SERVICE_START);
5695 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5699 vector = msi_service_args_to_vector(args, &numargs);
5701 if (!StartServiceW(service, numargs, vector) &&
5702 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5704 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5711 uirow = MSI_CreateRecord( 2 );
5712 MSI_RecordSetStringW( uirow, 1, display_name );
5713 MSI_RecordSetStringW( uirow, 2, name );
5714 ui_actiondata( package, szStartServices, uirow );
5715 msiobj_release( &uirow->hdr );
5717 CloseServiceHandle(service);
5718 CloseServiceHandle(scm);
5723 msi_free(display_name);
5727 static UINT ACTION_StartServices( MSIPACKAGE *package )
5732 static const WCHAR query[] = {
5733 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5734 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5736 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5737 if (rc != ERROR_SUCCESS)
5738 return ERROR_SUCCESS;
5740 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5741 msiobj_release(&view->hdr);
5746 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5748 DWORD i, needed, count;
5749 ENUM_SERVICE_STATUSW *dependencies;
5753 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5754 0, &needed, &count))
5757 if (GetLastError() != ERROR_MORE_DATA)
5760 dependencies = msi_alloc(needed);
5764 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5765 needed, &needed, &count))
5768 for (i = 0; i < count; i++)
5770 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5771 SERVICE_STOP | SERVICE_QUERY_STATUS);
5775 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5782 msi_free(dependencies);
5786 static UINT stop_service( LPCWSTR name )
5788 SC_HANDLE scm = NULL, service = NULL;
5789 SERVICE_STATUS status;
5790 SERVICE_STATUS_PROCESS ssp;
5793 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5796 WARN("Failed to open the SCM: %d\n", GetLastError());
5800 service = OpenServiceW(scm, name,
5802 SERVICE_QUERY_STATUS |
5803 SERVICE_ENUMERATE_DEPENDENTS);
5806 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5810 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5811 sizeof(SERVICE_STATUS_PROCESS), &needed))
5813 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5817 if (ssp.dwCurrentState == SERVICE_STOPPED)
5820 stop_service_dependents(scm, service);
5822 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5823 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5826 CloseServiceHandle(service);
5827 CloseServiceHandle(scm);
5829 return ERROR_SUCCESS;
5832 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5834 MSIPACKAGE *package = param;
5838 LPWSTR name = NULL, display_name = NULL;
5842 event = MSI_RecordGetInteger( rec, 3 );
5843 if (!(event & msidbServiceControlEventStop))
5844 return ERROR_SUCCESS;
5846 component = MSI_RecordGetString( rec, 6 );
5847 comp = get_loaded_component( package, component );
5849 return ERROR_SUCCESS;
5853 TRACE("component is disabled\n");
5854 return ERROR_SUCCESS;
5857 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5859 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5860 comp->Action = comp->Installed;
5861 return ERROR_SUCCESS;
5863 comp->Action = INSTALLSTATE_ABSENT;
5865 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5868 ERR("Failed to open the service control manager\n");
5873 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5874 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5876 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5877 GetServiceDisplayNameW( scm, name, display_name, &len );
5879 CloseServiceHandle( scm );
5881 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5882 stop_service( name );
5885 uirow = MSI_CreateRecord( 2 );
5886 MSI_RecordSetStringW( uirow, 1, display_name );
5887 MSI_RecordSetStringW( uirow, 2, name );
5888 ui_actiondata( package, szStopServices, uirow );
5889 msiobj_release( &uirow->hdr );
5892 msi_free( display_name );
5893 return ERROR_SUCCESS;
5896 static UINT ACTION_StopServices( MSIPACKAGE *package )
5901 static const WCHAR query[] = {
5902 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5903 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5905 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5906 if (rc != ERROR_SUCCESS)
5907 return ERROR_SUCCESS;
5909 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5910 msiobj_release(&view->hdr);
5915 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5917 MSIPACKAGE *package = param;
5921 LPWSTR name = NULL, display_name = NULL;
5923 SC_HANDLE scm = NULL, service = NULL;
5925 event = MSI_RecordGetInteger( rec, 3 );
5926 if (!(event & msidbServiceControlEventDelete))
5927 return ERROR_SUCCESS;
5929 component = MSI_RecordGetString(rec, 6);
5930 comp = get_loaded_component(package, component);
5932 return ERROR_SUCCESS;
5936 TRACE("component is disabled\n");
5937 return ERROR_SUCCESS;
5940 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5942 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5943 comp->Action = comp->Installed;
5944 return ERROR_SUCCESS;
5946 comp->Action = INSTALLSTATE_ABSENT;
5948 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5949 stop_service( name );
5951 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5954 WARN("Failed to open the SCM: %d\n", GetLastError());
5959 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5960 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5962 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5963 GetServiceDisplayNameW( scm, name, display_name, &len );
5966 service = OpenServiceW( scm, name, DELETE );
5969 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5973 if (!DeleteService( service ))
5974 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5977 uirow = MSI_CreateRecord( 2 );
5978 MSI_RecordSetStringW( uirow, 1, display_name );
5979 MSI_RecordSetStringW( uirow, 2, name );
5980 ui_actiondata( package, szDeleteServices, uirow );
5981 msiobj_release( &uirow->hdr );
5983 CloseServiceHandle( service );
5984 CloseServiceHandle( scm );
5986 msi_free( display_name );
5988 return ERROR_SUCCESS;
5991 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5996 static const WCHAR query[] = {
5997 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5998 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6000 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6001 if (rc != ERROR_SUCCESS)
6002 return ERROR_SUCCESS;
6004 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6005 msiobj_release( &view->hdr );
6010 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6012 MSIPACKAGE *package = param;
6013 LPWSTR driver, driver_path, ptr;
6014 WCHAR outpath[MAX_PATH];
6015 MSIFILE *driver_file = NULL, *setup_file = NULL;
6018 LPCWSTR desc, file_key, component;
6020 UINT r = ERROR_SUCCESS;
6022 static const WCHAR driver_fmt[] = {
6023 'D','r','i','v','e','r','=','%','s',0};
6024 static const WCHAR setup_fmt[] = {
6025 'S','e','t','u','p','=','%','s',0};
6026 static const WCHAR usage_fmt[] = {
6027 'F','i','l','e','U','s','a','g','e','=','1',0};
6029 component = MSI_RecordGetString( rec, 2 );
6030 comp = get_loaded_component( package, component );
6032 return ERROR_SUCCESS;
6036 TRACE("component is disabled\n");
6037 return ERROR_SUCCESS;
6040 desc = MSI_RecordGetString(rec, 3);
6042 file_key = MSI_RecordGetString( rec, 4 );
6043 if (file_key) driver_file = get_loaded_file( package, file_key );
6045 file_key = MSI_RecordGetString( rec, 5 );
6046 if (file_key) setup_file = get_loaded_file( package, file_key );
6050 ERR("ODBC Driver entry not found!\n");
6051 return ERROR_FUNCTION_FAILED;
6054 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6056 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6057 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6059 driver = msi_alloc(len * sizeof(WCHAR));
6061 return ERROR_OUTOFMEMORY;
6064 lstrcpyW(ptr, desc);
6065 ptr += lstrlenW(ptr) + 1;
6067 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6072 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6076 lstrcpyW(ptr, usage_fmt);
6077 ptr += lstrlenW(ptr) + 1;
6080 driver_path = strdupW(driver_file->TargetPath);
6081 ptr = strrchrW(driver_path, '\\');
6082 if (ptr) *ptr = '\0';
6084 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6085 NULL, ODBC_INSTALL_COMPLETE, &usage))
6087 ERR("Failed to install SQL driver!\n");
6088 r = ERROR_FUNCTION_FAILED;
6091 uirow = MSI_CreateRecord( 5 );
6092 MSI_RecordSetStringW( uirow, 1, desc );
6093 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6094 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6095 ui_actiondata( package, szInstallODBC, uirow );
6096 msiobj_release( &uirow->hdr );
6099 msi_free(driver_path);
6104 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6106 MSIPACKAGE *package = param;
6107 LPWSTR translator, translator_path, ptr;
6108 WCHAR outpath[MAX_PATH];
6109 MSIFILE *translator_file = NULL, *setup_file = NULL;
6112 LPCWSTR desc, file_key, component;
6114 UINT r = ERROR_SUCCESS;
6116 static const WCHAR translator_fmt[] = {
6117 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6118 static const WCHAR setup_fmt[] = {
6119 'S','e','t','u','p','=','%','s',0};
6121 component = MSI_RecordGetString( rec, 2 );
6122 comp = get_loaded_component( package, component );
6124 return ERROR_SUCCESS;
6128 TRACE("component is disabled\n");
6129 return ERROR_SUCCESS;
6132 desc = MSI_RecordGetString(rec, 3);
6134 file_key = MSI_RecordGetString( rec, 4 );
6135 if (file_key) translator_file = get_loaded_file( package, file_key );
6137 file_key = MSI_RecordGetString( rec, 5 );
6138 if (file_key) setup_file = get_loaded_file( package, file_key );
6140 if (!translator_file)
6142 ERR("ODBC Translator entry not found!\n");
6143 return ERROR_FUNCTION_FAILED;
6146 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6148 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6150 translator = msi_alloc(len * sizeof(WCHAR));
6152 return ERROR_OUTOFMEMORY;
6155 lstrcpyW(ptr, desc);
6156 ptr += lstrlenW(ptr) + 1;
6158 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6163 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6168 translator_path = strdupW(translator_file->TargetPath);
6169 ptr = strrchrW(translator_path, '\\');
6170 if (ptr) *ptr = '\0';
6172 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6173 NULL, ODBC_INSTALL_COMPLETE, &usage))
6175 ERR("Failed to install SQL translator!\n");
6176 r = ERROR_FUNCTION_FAILED;
6179 uirow = MSI_CreateRecord( 5 );
6180 MSI_RecordSetStringW( uirow, 1, desc );
6181 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6182 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6183 ui_actiondata( package, szInstallODBC, uirow );
6184 msiobj_release( &uirow->hdr );
6186 msi_free(translator);
6187 msi_free(translator_path);
6192 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6194 MSIPACKAGE *package = param;
6197 LPCWSTR desc, driver, component;
6198 WORD request = ODBC_ADD_SYS_DSN;
6201 UINT r = ERROR_SUCCESS;
6204 static const WCHAR attrs_fmt[] = {
6205 'D','S','N','=','%','s',0 };
6207 component = MSI_RecordGetString( rec, 2 );
6208 comp = get_loaded_component( package, component );
6210 return ERROR_SUCCESS;
6214 TRACE("component is disabled\n");
6215 return ERROR_SUCCESS;
6218 desc = MSI_RecordGetString(rec, 3);
6219 driver = MSI_RecordGetString(rec, 4);
6220 registration = MSI_RecordGetInteger(rec, 5);
6222 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6223 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6225 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6226 attrs = msi_alloc(len * sizeof(WCHAR));
6228 return ERROR_OUTOFMEMORY;
6230 len = sprintfW(attrs, attrs_fmt, desc);
6233 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6235 ERR("Failed to install SQL data source!\n");
6236 r = ERROR_FUNCTION_FAILED;
6239 uirow = MSI_CreateRecord( 5 );
6240 MSI_RecordSetStringW( uirow, 1, desc );
6241 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6242 MSI_RecordSetInteger( uirow, 3, request );
6243 ui_actiondata( package, szInstallODBC, uirow );
6244 msiobj_release( &uirow->hdr );
6251 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6256 static const WCHAR driver_query[] = {
6257 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6258 'O','D','B','C','D','r','i','v','e','r',0 };
6260 static const WCHAR translator_query[] = {
6261 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6262 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6264 static const WCHAR source_query[] = {
6265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6266 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6268 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6269 if (rc != ERROR_SUCCESS)
6270 return ERROR_SUCCESS;
6272 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6273 msiobj_release(&view->hdr);
6275 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6276 if (rc != ERROR_SUCCESS)
6277 return ERROR_SUCCESS;
6279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6280 msiobj_release(&view->hdr);
6282 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6283 if (rc != ERROR_SUCCESS)
6284 return ERROR_SUCCESS;
6286 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6287 msiobj_release(&view->hdr);
6292 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6294 MSIPACKAGE *package = param;
6298 LPCWSTR desc, component;
6300 component = MSI_RecordGetString( rec, 2 );
6301 comp = get_loaded_component( package, component );
6303 return ERROR_SUCCESS;
6307 TRACE("component is disabled\n");
6308 return ERROR_SUCCESS;
6311 desc = MSI_RecordGetString( rec, 3 );
6312 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6314 WARN("Failed to remove ODBC driver\n");
6318 FIXME("Usage count reached 0\n");
6321 uirow = MSI_CreateRecord( 2 );
6322 MSI_RecordSetStringW( uirow, 1, desc );
6323 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6324 ui_actiondata( package, szRemoveODBC, uirow );
6325 msiobj_release( &uirow->hdr );
6327 return ERROR_SUCCESS;
6330 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6332 MSIPACKAGE *package = param;
6336 LPCWSTR desc, component;
6338 component = MSI_RecordGetString( rec, 2 );
6339 comp = get_loaded_component( package, component );
6341 return ERROR_SUCCESS;
6345 TRACE("component is disabled\n");
6346 return ERROR_SUCCESS;
6349 desc = MSI_RecordGetString( rec, 3 );
6350 if (!SQLRemoveTranslatorW( desc, &usage ))
6352 WARN("Failed to remove ODBC translator\n");
6356 FIXME("Usage count reached 0\n");
6359 uirow = MSI_CreateRecord( 2 );
6360 MSI_RecordSetStringW( uirow, 1, desc );
6361 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6362 ui_actiondata( package, szRemoveODBC, uirow );
6363 msiobj_release( &uirow->hdr );
6365 return ERROR_SUCCESS;
6368 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6370 MSIPACKAGE *package = param;
6374 LPCWSTR desc, driver, component;
6375 WORD request = ODBC_REMOVE_SYS_DSN;
6379 static const WCHAR attrs_fmt[] = {
6380 'D','S','N','=','%','s',0 };
6382 component = MSI_RecordGetString( rec, 2 );
6383 comp = get_loaded_component( package, component );
6385 return ERROR_SUCCESS;
6389 TRACE("component is disabled\n");
6390 return ERROR_SUCCESS;
6393 desc = MSI_RecordGetString( rec, 3 );
6394 driver = MSI_RecordGetString( rec, 4 );
6395 registration = MSI_RecordGetInteger( rec, 5 );
6397 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6398 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6400 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6401 attrs = msi_alloc( len * sizeof(WCHAR) );
6403 return ERROR_OUTOFMEMORY;
6405 FIXME("Use ODBCSourceAttribute table\n");
6407 len = sprintfW( attrs, attrs_fmt, desc );
6410 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6412 WARN("Failed to remove ODBC data source\n");
6416 uirow = MSI_CreateRecord( 3 );
6417 MSI_RecordSetStringW( uirow, 1, desc );
6418 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6419 MSI_RecordSetInteger( uirow, 3, request );
6420 ui_actiondata( package, szRemoveODBC, uirow );
6421 msiobj_release( &uirow->hdr );
6423 return ERROR_SUCCESS;
6426 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6431 static const WCHAR driver_query[] = {
6432 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6433 'O','D','B','C','D','r','i','v','e','r',0 };
6435 static const WCHAR translator_query[] = {
6436 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6437 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6439 static const WCHAR source_query[] = {
6440 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6441 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6443 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6444 if (rc != ERROR_SUCCESS)
6445 return ERROR_SUCCESS;
6447 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6448 msiobj_release( &view->hdr );
6450 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6451 if (rc != ERROR_SUCCESS)
6452 return ERROR_SUCCESS;
6454 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6455 msiobj_release( &view->hdr );
6457 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6458 if (rc != ERROR_SUCCESS)
6459 return ERROR_SUCCESS;
6461 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6462 msiobj_release( &view->hdr );
6467 #define ENV_ACT_SETALWAYS 0x1
6468 #define ENV_ACT_SETABSENT 0x2
6469 #define ENV_ACT_REMOVE 0x4
6470 #define ENV_ACT_REMOVEMATCH 0x8
6472 #define ENV_MOD_MACHINE 0x20000000
6473 #define ENV_MOD_APPEND 0x40000000
6474 #define ENV_MOD_PREFIX 0x80000000
6475 #define ENV_MOD_MASK 0xC0000000
6477 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6479 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6481 LPCWSTR cptr = *name;
6483 static const WCHAR prefix[] = {'[','~',']',0};
6484 static const int prefix_len = 3;
6490 *flags |= ENV_ACT_SETALWAYS;
6491 else if (*cptr == '+')
6492 *flags |= ENV_ACT_SETABSENT;
6493 else if (*cptr == '-')
6494 *flags |= ENV_ACT_REMOVE;
6495 else if (*cptr == '!')
6496 *flags |= ENV_ACT_REMOVEMATCH;
6497 else if (*cptr == '*')
6498 *flags |= ENV_MOD_MACHINE;
6508 ERR("Missing environment variable\n");
6509 return ERROR_FUNCTION_FAILED;
6514 LPCWSTR ptr = *value;
6515 if (!strncmpW(ptr, prefix, prefix_len))
6517 if (ptr[prefix_len] == szSemiColon[0])
6519 *flags |= ENV_MOD_APPEND;
6520 *value += lstrlenW(prefix);
6527 else if (lstrlenW(*value) >= prefix_len)
6529 ptr += lstrlenW(ptr) - prefix_len;
6530 if (!strcmpW( ptr, prefix ))
6532 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6534 *flags |= ENV_MOD_PREFIX;
6535 /* the "[~]" will be removed by deformat_string */;
6545 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6546 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6547 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6548 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6550 ERR("Invalid flags: %08x\n", *flags);
6551 return ERROR_FUNCTION_FAILED;
6555 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6557 return ERROR_SUCCESS;
6560 static UINT open_env_key( DWORD flags, HKEY *key )
6562 static const WCHAR user_env[] =
6563 {'E','n','v','i','r','o','n','m','e','n','t',0};
6564 static const WCHAR machine_env[] =
6565 {'S','y','s','t','e','m','\\',
6566 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6567 'C','o','n','t','r','o','l','\\',
6568 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6569 'E','n','v','i','r','o','n','m','e','n','t',0};
6574 if (flags & ENV_MOD_MACHINE)
6577 root = HKEY_LOCAL_MACHINE;
6582 root = HKEY_CURRENT_USER;
6585 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6586 if (res != ERROR_SUCCESS)
6588 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6589 return ERROR_FUNCTION_FAILED;
6592 return ERROR_SUCCESS;
6595 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6597 MSIPACKAGE *package = param;
6598 LPCWSTR name, value, component;
6599 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6600 DWORD flags, type, size;
6607 component = MSI_RecordGetString(rec, 4);
6608 comp = get_loaded_component(package, component);
6610 return ERROR_SUCCESS;
6614 TRACE("component is disabled\n");
6615 return ERROR_SUCCESS;
6618 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6620 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6621 comp->Action = comp->Installed;
6622 return ERROR_SUCCESS;
6624 comp->Action = INSTALLSTATE_LOCAL;
6626 name = MSI_RecordGetString(rec, 2);
6627 value = MSI_RecordGetString(rec, 3);
6629 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6631 res = env_parse_flags(&name, &value, &flags);
6632 if (res != ERROR_SUCCESS || !value)
6635 if (value && !deformat_string(package, value, &deformatted))
6637 res = ERROR_OUTOFMEMORY;
6641 value = deformatted;
6643 res = open_env_key( flags, &env );
6644 if (res != ERROR_SUCCESS)
6647 if (flags & ENV_MOD_MACHINE)
6648 action |= 0x20000000;
6652 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6653 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6654 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6657 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6661 /* Nothing to do. */
6664 res = ERROR_SUCCESS;
6668 /* If we are appending but the string was empty, strip ; */
6669 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6671 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6672 newval = strdupW(value);
6675 res = ERROR_OUTOFMEMORY;
6683 /* Contrary to MSDN, +-variable to [~];path works */
6684 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6686 res = ERROR_SUCCESS;
6690 data = msi_alloc(size);
6694 return ERROR_OUTOFMEMORY;
6697 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6698 if (res != ERROR_SUCCESS)
6701 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6704 res = RegDeleteValueW(env, name);
6705 if (res != ERROR_SUCCESS)
6706 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6710 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6711 if (flags & ENV_MOD_MASK)
6715 if (flags & ENV_MOD_APPEND) multiplier++;
6716 if (flags & ENV_MOD_PREFIX) multiplier++;
6717 mod_size = lstrlenW(value) * multiplier;
6718 size += mod_size * sizeof(WCHAR);
6721 newval = msi_alloc(size);
6725 res = ERROR_OUTOFMEMORY;
6729 if (flags & ENV_MOD_PREFIX)
6731 lstrcpyW(newval, value);
6732 ptr = newval + lstrlenW(value);
6733 action |= 0x80000000;
6736 lstrcpyW(ptr, data);
6738 if (flags & ENV_MOD_APPEND)
6740 lstrcatW(newval, value);
6741 action |= 0x40000000;
6744 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6745 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6748 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6752 uirow = MSI_CreateRecord( 3 );
6753 MSI_RecordSetStringW( uirow, 1, name );
6754 MSI_RecordSetStringW( uirow, 2, newval );
6755 MSI_RecordSetInteger( uirow, 3, action );
6756 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6757 msiobj_release( &uirow->hdr );
6759 if (env) RegCloseKey(env);
6760 msi_free(deformatted);
6766 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6770 static const WCHAR ExecSeqQuery[] =
6771 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6772 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6773 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6774 if (rc != ERROR_SUCCESS)
6775 return ERROR_SUCCESS;
6777 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6778 msiobj_release(&view->hdr);
6783 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6785 MSIPACKAGE *package = param;
6786 LPCWSTR name, value, component;
6787 LPWSTR deformatted = NULL;
6796 component = MSI_RecordGetString( rec, 4 );
6797 comp = get_loaded_component( package, component );
6799 return ERROR_SUCCESS;
6803 TRACE("component is disabled\n");
6804 return ERROR_SUCCESS;
6807 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6809 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6810 comp->Action = comp->Installed;
6811 return ERROR_SUCCESS;
6813 comp->Action = INSTALLSTATE_ABSENT;
6815 name = MSI_RecordGetString( rec, 2 );
6816 value = MSI_RecordGetString( rec, 3 );
6818 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6820 r = env_parse_flags( &name, &value, &flags );
6821 if (r != ERROR_SUCCESS)
6824 if (!(flags & ENV_ACT_REMOVE))
6826 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6827 return ERROR_SUCCESS;
6830 if (value && !deformat_string( package, value, &deformatted ))
6831 return ERROR_OUTOFMEMORY;
6833 value = deformatted;
6835 r = open_env_key( flags, &env );
6836 if (r != ERROR_SUCCESS)
6842 if (flags & ENV_MOD_MACHINE)
6843 action |= 0x20000000;
6845 TRACE("Removing %s\n", debugstr_w(name));
6847 res = RegDeleteValueW( env, name );
6848 if (res != ERROR_SUCCESS)
6850 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6855 uirow = MSI_CreateRecord( 3 );
6856 MSI_RecordSetStringW( uirow, 1, name );
6857 MSI_RecordSetStringW( uirow, 2, value );
6858 MSI_RecordSetInteger( uirow, 3, action );
6859 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6860 msiobj_release( &uirow->hdr );
6862 if (env) RegCloseKey( env );
6863 msi_free( deformatted );
6867 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6871 static const WCHAR query[] =
6872 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6873 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6875 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6876 if (rc != ERROR_SUCCESS)
6877 return ERROR_SUCCESS;
6879 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6880 msiobj_release( &view->hdr );
6885 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6887 LPWSTR key, template, id;
6888 UINT r = ERROR_SUCCESS;
6890 id = msi_dup_property( package->db, szProductID );
6894 return ERROR_SUCCESS;
6896 template = msi_dup_property( package->db, szPIDTemplate );
6897 key = msi_dup_property( package->db, szPIDKEY );
6899 if (key && template)
6901 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6902 r = msi_set_property( package->db, szProductID, key );
6904 msi_free( template );
6909 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6912 package->need_reboot = 1;
6913 return ERROR_SUCCESS;
6916 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6918 static const WCHAR szAvailableFreeReg[] =
6919 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6921 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6923 TRACE("%p %d kilobytes\n", package, space);
6925 uirow = MSI_CreateRecord( 1 );
6926 MSI_RecordSetInteger( uirow, 1, space );
6927 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6928 msiobj_release( &uirow->hdr );
6930 return ERROR_SUCCESS;
6933 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6935 FIXME("%p\n", package);
6936 return ERROR_SUCCESS;
6939 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6941 FIXME("%p\n", package);
6942 return ERROR_SUCCESS;
6945 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6950 static const WCHAR driver_query[] = {
6951 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6952 'O','D','B','C','D','r','i','v','e','r',0 };
6954 static const WCHAR translator_query[] = {
6955 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6956 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6958 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6959 if (r == ERROR_SUCCESS)
6962 r = MSI_IterateRecords( view, &count, NULL, package );
6963 msiobj_release( &view->hdr );
6964 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6967 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6968 if (r == ERROR_SUCCESS)
6971 r = MSI_IterateRecords( view, &count, NULL, package );
6972 msiobj_release( &view->hdr );
6973 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6976 return ERROR_SUCCESS;
6979 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6981 MSIPACKAGE *package = param;
6982 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6985 if ((value = msi_dup_property( package->db, property )))
6987 FIXME("remove %s\n", debugstr_w(value));
6990 return ERROR_SUCCESS;
6993 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6998 static const WCHAR query[] =
6999 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7000 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7002 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7003 if (r == ERROR_SUCCESS)
7005 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7006 msiobj_release( &view->hdr );
7008 return ERROR_SUCCESS;
7011 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7013 MSIPACKAGE *package = param;
7014 int attributes = MSI_RecordGetInteger( rec, 5 );
7016 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7018 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7019 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7020 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7021 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7025 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7027 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7028 if (r != ERROR_SUCCESS)
7029 return ERROR_SUCCESS;
7033 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7034 if (r != ERROR_SUCCESS)
7035 return ERROR_SUCCESS;
7037 RegCloseKey( hkey );
7039 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7040 debugstr_w(upgrade_code), debugstr_w(version_min),
7041 debugstr_w(version_max), debugstr_w(language));
7043 return ERROR_SUCCESS;
7046 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7051 static const WCHAR query[] =
7052 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7054 if (msi_get_property_int( package->db, szInstalled, 0 ))
7056 TRACE("product is installed, skipping action\n");
7057 return ERROR_SUCCESS;
7059 if (msi_get_property_int( package->db, szPreselected, 0 ))
7061 TRACE("Preselected property is set, not migrating feature states\n");
7062 return ERROR_SUCCESS;
7065 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7066 if (r == ERROR_SUCCESS)
7068 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7069 msiobj_release( &view->hdr );
7071 return ERROR_SUCCESS;
7074 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7075 LPCSTR action, LPCWSTR table )
7077 static const WCHAR query[] = {
7078 'S','E','L','E','C','T',' ','*',' ',
7079 'F','R','O','M',' ','`','%','s','`',0 };
7080 MSIQUERY *view = NULL;
7084 r = MSI_OpenQuery( package->db, &view, query, table );
7085 if (r == ERROR_SUCCESS)
7087 r = MSI_IterateRecords(view, &count, NULL, package);
7088 msiobj_release(&view->hdr);
7092 FIXME("%s -> %u ignored %s table values\n",
7093 action, count, debugstr_w(table));
7095 return ERROR_SUCCESS;
7098 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7100 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7101 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7104 static UINT ACTION_BindImage( MSIPACKAGE *package )
7106 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7107 return msi_unimplemented_action_stub( package, "BindImage", table );
7110 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7112 static const WCHAR table[] = {
7113 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7114 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7117 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7119 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7120 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7123 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7125 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7126 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7129 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7131 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7132 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7135 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7137 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7138 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7141 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7145 const WCHAR *action;
7146 UINT (*handler)(MSIPACKAGE *);
7150 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7151 { szAppSearch, ACTION_AppSearch },
7152 { szBindImage, ACTION_BindImage },
7153 { szCCPSearch, ACTION_CCPSearch },
7154 { szCostFinalize, ACTION_CostFinalize },
7155 { szCostInitialize, ACTION_CostInitialize },
7156 { szCreateFolders, ACTION_CreateFolders },
7157 { szCreateShortcuts, ACTION_CreateShortcuts },
7158 { szDeleteServices, ACTION_DeleteServices },
7159 { szDisableRollback, ACTION_DisableRollback },
7160 { szDuplicateFiles, ACTION_DuplicateFiles },
7161 { szExecuteAction, ACTION_ExecuteAction },
7162 { szFileCost, ACTION_FileCost },
7163 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7164 { szForceReboot, ACTION_ForceReboot },
7165 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7166 { szInstallExecute, ACTION_InstallExecute },
7167 { szInstallExecuteAgain, ACTION_InstallExecute },
7168 { szInstallFiles, ACTION_InstallFiles},
7169 { szInstallFinalize, ACTION_InstallFinalize },
7170 { szInstallInitialize, ACTION_InstallInitialize },
7171 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7172 { szInstallValidate, ACTION_InstallValidate },
7173 { szIsolateComponents, ACTION_IsolateComponents },
7174 { szLaunchConditions, ACTION_LaunchConditions },
7175 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7176 { szMoveFiles, ACTION_MoveFiles },
7177 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7178 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7179 { szInstallODBC, ACTION_InstallODBC },
7180 { szInstallServices, ACTION_InstallServices },
7181 { szPatchFiles, ACTION_PatchFiles },
7182 { szProcessComponents, ACTION_ProcessComponents },
7183 { szPublishComponents, ACTION_PublishComponents },
7184 { szPublishFeatures, ACTION_PublishFeatures },
7185 { szPublishProduct, ACTION_PublishProduct },
7186 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7187 { szRegisterComPlus, ACTION_RegisterComPlus},
7188 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7189 { szRegisterFonts, ACTION_RegisterFonts },
7190 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7191 { szRegisterProduct, ACTION_RegisterProduct },
7192 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7193 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7194 { szRegisterUser, ACTION_RegisterUser },
7195 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7196 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7197 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7198 { szRemoveFiles, ACTION_RemoveFiles },
7199 { szRemoveFolders, ACTION_RemoveFolders },
7200 { szRemoveIniValues, ACTION_RemoveIniValues },
7201 { szRemoveODBC, ACTION_RemoveODBC },
7202 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7203 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7204 { szResolveSource, ACTION_ResolveSource },
7205 { szRMCCPSearch, ACTION_RMCCPSearch },
7206 { szScheduleReboot, ACTION_ScheduleReboot },
7207 { szSelfRegModules, ACTION_SelfRegModules },
7208 { szSelfUnregModules, ACTION_SelfUnregModules },
7209 { szSetODBCFolders, ACTION_SetODBCFolders },
7210 { szStartServices, ACTION_StartServices },
7211 { szStopServices, ACTION_StopServices },
7212 { szUnpublishComponents, ACTION_UnpublishComponents },
7213 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7214 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7215 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7216 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7217 { szUnregisterFonts, ACTION_UnregisterFonts },
7218 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7219 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7220 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7221 { szValidateProductID, ACTION_ValidateProductID },
7222 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7223 { szWriteIniValues, ACTION_WriteIniValues },
7224 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7228 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7234 while (StandardActions[i].action != NULL)
7236 if (!strcmpW( StandardActions[i].action, action ))
7238 ui_actionstart( package, action );
7239 if (StandardActions[i].handler)
7241 ui_actioninfo( package, action, TRUE, 0 );
7242 *rc = StandardActions[i].handler( package );
7243 ui_actioninfo( package, action, FALSE, *rc );
7247 FIXME("unhandled standard action %s\n", debugstr_w(action));
7248 *rc = ERROR_SUCCESS;
7258 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7260 UINT rc = ERROR_SUCCESS;
7263 TRACE("Performing action (%s)\n", debugstr_w(action));
7265 handled = ACTION_HandleStandardAction(package, action, &rc);
7268 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7272 WARN("unhandled msi action %s\n", debugstr_w(action));
7273 rc = ERROR_FUNCTION_NOT_CALLED;
7279 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7281 UINT rc = ERROR_SUCCESS;
7282 BOOL handled = FALSE;
7284 TRACE("Performing action (%s)\n", debugstr_w(action));
7286 handled = ACTION_HandleStandardAction(package, action, &rc);
7289 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7291 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7296 WARN("unhandled msi action %s\n", debugstr_w(action));
7297 rc = ERROR_FUNCTION_NOT_CALLED;
7303 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7305 UINT rc = ERROR_SUCCESS;
7308 static const WCHAR ExecSeqQuery[] =
7309 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7310 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7311 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7312 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7313 static const WCHAR UISeqQuery[] =
7314 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7315 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7316 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7317 ' ', '=',' ','%','i',0};
7319 if (needs_ui_sequence(package))
7320 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7322 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7326 LPCWSTR action, cond;
7328 TRACE("Running the actions\n");
7330 /* check conditions */
7331 cond = MSI_RecordGetString(row, 2);
7333 /* this is a hack to skip errors in the condition code */
7334 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7336 msiobj_release(&row->hdr);
7337 return ERROR_SUCCESS;
7340 action = MSI_RecordGetString(row, 1);
7343 ERR("failed to fetch action\n");
7344 msiobj_release(&row->hdr);
7345 return ERROR_FUNCTION_FAILED;
7348 if (needs_ui_sequence(package))
7349 rc = ACTION_PerformUIAction(package, action, -1);
7351 rc = ACTION_PerformAction(package, action, -1);
7353 msiobj_release(&row->hdr);
7359 /****************************************************
7360 * TOP level entry points
7361 *****************************************************/
7363 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7364 LPCWSTR szCommandLine )
7369 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7370 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7372 msi_set_property( package->db, szAction, szInstall );
7374 package->script->InWhatSequence = SEQUENCE_INSTALL;
7381 dir = strdupW(szPackagePath);
7382 p = strrchrW(dir, '\\');
7386 file = szPackagePath + (p - dir);
7391 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7392 GetCurrentDirectoryW(MAX_PATH, dir);
7393 lstrcatW(dir, szBackSlash);
7394 file = szPackagePath;
7397 msi_free( package->PackagePath );
7398 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7399 if (!package->PackagePath)
7402 return ERROR_OUTOFMEMORY;
7405 lstrcpyW(package->PackagePath, dir);
7406 lstrcatW(package->PackagePath, file);
7409 msi_set_sourcedir_props(package, FALSE);
7412 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7413 if (rc != ERROR_SUCCESS)
7416 msi_apply_transforms( package );
7417 msi_apply_patches( package );
7419 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7421 TRACE("setting reinstall property\n");
7422 msi_set_property( package->db, szReinstall, szAll );
7425 /* properties may have been added by a transform */
7426 msi_clone_properties( package );
7428 msi_parse_command_line( package, szCommandLine, FALSE );
7429 msi_adjust_privilege_properties( package );
7430 msi_set_context( package );
7432 if (needs_ui_sequence( package))
7434 package->script->InWhatSequence |= SEQUENCE_UI;
7435 rc = ACTION_ProcessUISequence(package);
7436 ui_exists = ui_sequence_exists(package);
7437 if (rc == ERROR_SUCCESS || !ui_exists)
7439 package->script->InWhatSequence |= SEQUENCE_EXEC;
7440 rc = ACTION_ProcessExecSequence(package, ui_exists);
7444 rc = ACTION_ProcessExecSequence(package, FALSE);
7446 package->script->CurrentlyScripting = FALSE;
7448 /* process the ending type action */
7449 if (rc == ERROR_SUCCESS)
7450 ACTION_PerformActionSequence(package, -1);
7451 else if (rc == ERROR_INSTALL_USEREXIT)
7452 ACTION_PerformActionSequence(package, -2);
7453 else if (rc == ERROR_INSTALL_SUSPEND)
7454 ACTION_PerformActionSequence(package, -4);
7456 ACTION_PerformActionSequence(package, -3);
7458 /* finish up running custom actions */
7459 ACTION_FinishCustomActions(package);
7461 if (rc == ERROR_SUCCESS && package->need_reboot)
7462 return ERROR_SUCCESS_REBOOT_REQUIRED;