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);
3257 const WCHAR prefixW[] = {'<','\\',0};
3258 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3260 comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3261 if (comp->FullKeypath)
3263 strcpyW( comp->FullKeypath, prefixW );
3264 strcatW( comp->FullKeypath, comp->assembly->display_name );
3267 else comp->FullKeypath = resolve_keypath( package, comp );
3269 ACTION_RefCountComponent( package, comp );
3271 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3272 debugstr_w(comp->Component),
3273 debugstr_w(squished_cc),
3274 debugstr_w(comp->FullKeypath),
3276 comp->ActionRequest);
3278 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3279 comp->ActionRequest == INSTALLSTATE_SOURCE)
3281 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3282 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3284 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3286 if (rc != ERROR_SUCCESS)
3289 if (comp->Attributes & msidbComponentAttributesPermanent)
3291 static const WCHAR szPermKey[] =
3292 { '0','0','0','0','0','0','0','0','0','0','0','0',
3293 '0','0','0','0','0','0','0','0','0','0','0','0',
3294 '0','0','0','0','0','0','0','0',0 };
3296 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3299 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3300 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3306 WCHAR source[MAX_PATH];
3307 WCHAR base[MAX_PATH];
3310 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3311 static const WCHAR query[] = {
3312 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3313 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3314 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3315 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3316 '`','D','i','s','k','I','d','`',0};
3318 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3321 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3322 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3323 ptr2 = strrchrW(source, '\\') + 1;
3324 msiobj_release(&row->hdr);
3326 lstrcpyW(base, package->PackagePath);
3327 ptr = strrchrW(base, '\\');
3330 sourcepath = resolve_file_source(package, file);
3331 ptr = sourcepath + lstrlenW(base);
3332 lstrcpyW(ptr2, ptr);
3333 msi_free(sourcepath);
3335 msi_reg_set_val_str(hkey, squished_pc, source);
3339 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3341 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3342 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3344 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3346 comp->Action = comp->ActionRequest;
3349 uirow = MSI_CreateRecord(3);
3350 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3351 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3352 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3353 ui_actiondata(package,szProcessComponents,uirow);
3354 msiobj_release( &uirow->hdr );
3357 return ERROR_SUCCESS;
3368 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3369 LPWSTR lpszName, LONG_PTR lParam)
3372 typelib_struct *tl_struct = (typelib_struct*) lParam;
3373 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3377 if (!IS_INTRESOURCE(lpszName))
3379 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3383 sz = strlenW(tl_struct->source)+4;
3384 sz *= sizeof(WCHAR);
3386 if ((INT_PTR)lpszName == 1)
3387 tl_struct->path = strdupW(tl_struct->source);
3390 tl_struct->path = msi_alloc(sz);
3391 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3394 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3395 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3398 msi_free(tl_struct->path);
3399 tl_struct->path = NULL;
3404 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3405 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3407 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3411 msi_free(tl_struct->path);
3412 tl_struct->path = NULL;
3414 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3415 ITypeLib_Release(tl_struct->ptLib);
3420 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3422 MSIPACKAGE* package = param;
3426 typelib_struct tl_struct;
3431 component = MSI_RecordGetString(row,3);
3432 comp = get_loaded_component(package,component);
3434 return ERROR_SUCCESS;
3438 TRACE("component is disabled\n");
3439 return ERROR_SUCCESS;
3442 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3444 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3445 comp->Action = comp->Installed;
3446 return ERROR_SUCCESS;
3448 comp->Action = INSTALLSTATE_LOCAL;
3450 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3452 TRACE("component has no key path\n");
3453 return ERROR_SUCCESS;
3455 ui_actiondata( package, szRegisterTypeLibraries, row );
3457 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3461 guid = MSI_RecordGetString(row,1);
3462 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3463 tl_struct.source = strdupW( file->TargetPath );
3464 tl_struct.path = NULL;
3466 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3467 (LONG_PTR)&tl_struct);
3475 helpid = MSI_RecordGetString(row,6);
3477 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3478 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3482 ERR("Failed to register type library %s\n",
3483 debugstr_w(tl_struct.path));
3485 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3487 ITypeLib_Release(tl_struct.ptLib);
3488 msi_free(tl_struct.path);
3491 ERR("Failed to load type library %s\n",
3492 debugstr_w(tl_struct.source));
3494 FreeLibrary(module);
3495 msi_free(tl_struct.source);
3499 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3502 ERR("Failed to load type library: %08x\n", hr);
3503 return ERROR_INSTALL_FAILURE;
3506 ITypeLib_Release(tlib);
3509 return ERROR_SUCCESS;
3512 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3515 * OK this is a bit confusing.. I am given a _Component key and I believe
3516 * that the file that is being registered as a type library is the "key file
3517 * of that component" which I interpret to mean "The file in the KeyPath of
3522 static const WCHAR Query[] =
3523 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3524 '`','T','y','p','e','L','i','b','`',0};
3526 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3527 if (rc != ERROR_SUCCESS)
3528 return ERROR_SUCCESS;
3530 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3531 msiobj_release(&view->hdr);
3535 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3537 MSIPACKAGE *package = param;
3538 LPCWSTR component, guid;
3546 component = MSI_RecordGetString( row, 3 );
3547 comp = get_loaded_component( package, component );
3549 return ERROR_SUCCESS;
3553 TRACE("component is disabled\n");
3554 return ERROR_SUCCESS;
3557 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3559 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3560 comp->Action = comp->Installed;
3561 return ERROR_SUCCESS;
3563 comp->Action = INSTALLSTATE_ABSENT;
3565 ui_actiondata( package, szUnregisterTypeLibraries, row );
3567 guid = MSI_RecordGetString( row, 1 );
3568 CLSIDFromString( (LPCWSTR)guid, &libid );
3569 version = MSI_RecordGetInteger( row, 4 );
3570 language = MSI_RecordGetInteger( row, 2 );
3573 syskind = SYS_WIN64;
3575 syskind = SYS_WIN32;
3578 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3581 WARN("Failed to unregister typelib: %08x\n", hr);
3584 return ERROR_SUCCESS;
3587 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3591 static const WCHAR query[] =
3592 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3593 '`','T','y','p','e','L','i','b','`',0};
3595 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3596 if (rc != ERROR_SUCCESS)
3597 return ERROR_SUCCESS;
3599 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3600 msiobj_release( &view->hdr );
3604 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3606 static const WCHAR szlnk[] = {'.','l','n','k',0};
3607 LPCWSTR directory, extension;
3608 LPWSTR link_folder, link_file, filename;
3610 directory = MSI_RecordGetString( row, 2 );
3611 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3613 /* may be needed because of a bug somewhere else */
3614 create_full_pathW( link_folder );
3616 filename = msi_dup_record_field( row, 3 );
3617 reduce_to_longfilename( filename );
3619 extension = strchrW( filename, '.' );
3620 if (!extension || strcmpiW( extension, szlnk ))
3622 int len = strlenW( filename );
3623 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3624 memcpy( filename + len, szlnk, sizeof(szlnk) );
3626 link_file = build_directory_name( 2, link_folder, filename );
3627 msi_free( link_folder );
3628 msi_free( filename );
3633 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3635 MSIPACKAGE *package = param;
3636 LPWSTR link_file, deformated, path;
3637 LPCWSTR component, target;
3639 IShellLinkW *sl = NULL;
3640 IPersistFile *pf = NULL;
3643 component = MSI_RecordGetString(row, 4);
3644 comp = get_loaded_component(package, component);
3646 return ERROR_SUCCESS;
3650 TRACE("component is disabled\n");
3651 return ERROR_SUCCESS;
3654 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3656 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3657 comp->Action = comp->Installed;
3658 return ERROR_SUCCESS;
3660 comp->Action = INSTALLSTATE_LOCAL;
3662 ui_actiondata(package,szCreateShortcuts,row);
3664 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3665 &IID_IShellLinkW, (LPVOID *) &sl );
3669 ERR("CLSID_ShellLink not available\n");
3673 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3676 ERR("QueryInterface(IID_IPersistFile) failed\n");
3680 target = MSI_RecordGetString(row, 5);
3681 if (strchrW(target, '['))
3683 deformat_string(package, target, &deformated);
3684 IShellLinkW_SetPath(sl,deformated);
3685 msi_free(deformated);
3689 FIXME("poorly handled shortcut format, advertised shortcut\n");
3690 IShellLinkW_SetPath(sl,comp->FullKeypath);
3693 if (!MSI_RecordIsNull(row,6))
3695 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3696 deformat_string(package, arguments, &deformated);
3697 IShellLinkW_SetArguments(sl,deformated);
3698 msi_free(deformated);
3701 if (!MSI_RecordIsNull(row,7))
3703 LPCWSTR description = MSI_RecordGetString(row, 7);
3704 IShellLinkW_SetDescription(sl, description);
3707 if (!MSI_RecordIsNull(row,8))
3708 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3710 if (!MSI_RecordIsNull(row,9))
3713 LPCWSTR icon = MSI_RecordGetString(row, 9);
3715 path = build_icon_path(package, icon);
3716 index = MSI_RecordGetInteger(row,10);
3718 /* no value means 0 */
3719 if (index == MSI_NULL_INTEGER)
3722 IShellLinkW_SetIconLocation(sl, path, index);
3726 if (!MSI_RecordIsNull(row,11))
3727 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3729 if (!MSI_RecordIsNull(row,12))
3731 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3732 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
3734 IShellLinkW_SetWorkingDirectory(sl, path);
3738 link_file = get_link_file(package, row);
3740 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3741 IPersistFile_Save(pf, link_file, FALSE);
3743 msi_free(link_file);
3747 IPersistFile_Release( pf );
3749 IShellLinkW_Release( sl );
3751 return ERROR_SUCCESS;
3754 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3759 static const WCHAR Query[] =
3760 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3761 '`','S','h','o','r','t','c','u','t','`',0};
3763 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3764 if (rc != ERROR_SUCCESS)
3765 return ERROR_SUCCESS;
3767 res = CoInitialize( NULL );
3769 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3770 msiobj_release(&view->hdr);
3778 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3780 MSIPACKAGE *package = param;
3785 component = MSI_RecordGetString( row, 4 );
3786 comp = get_loaded_component( package, component );
3788 return ERROR_SUCCESS;
3792 TRACE("component is disabled\n");
3793 return ERROR_SUCCESS;
3796 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3798 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3799 comp->Action = comp->Installed;
3800 return ERROR_SUCCESS;
3802 comp->Action = INSTALLSTATE_ABSENT;
3804 ui_actiondata( package, szRemoveShortcuts, row );
3806 link_file = get_link_file( package, row );
3808 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3809 if (!DeleteFileW( link_file ))
3811 WARN("Failed to remove shortcut file %u\n", GetLastError());
3813 msi_free( link_file );
3815 return ERROR_SUCCESS;
3818 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3822 static const WCHAR query[] =
3823 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3824 '`','S','h','o','r','t','c','u','t','`',0};
3826 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3827 if (rc != ERROR_SUCCESS)
3828 return ERROR_SUCCESS;
3830 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3831 msiobj_release( &view->hdr );
3836 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3838 MSIPACKAGE* package = param;
3846 FileName = MSI_RecordGetString(row,1);
3849 ERR("Unable to get FileName\n");
3850 return ERROR_SUCCESS;
3853 FilePath = build_icon_path(package,FileName);
3855 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3857 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3858 FILE_ATTRIBUTE_NORMAL, NULL);
3860 if (the_file == INVALID_HANDLE_VALUE)
3862 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3864 return ERROR_SUCCESS;
3871 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3872 if (rc != ERROR_SUCCESS)
3874 ERR("Failed to get stream\n");
3875 CloseHandle(the_file);
3876 DeleteFileW(FilePath);
3879 WriteFile(the_file,buffer,sz,&write,NULL);
3880 } while (sz == 1024);
3883 CloseHandle(the_file);
3885 return ERROR_SUCCESS;
3888 static UINT msi_publish_icons(MSIPACKAGE *package)
3893 static const WCHAR query[]= {
3894 'S','E','L','E','C','T',' ','*',' ',
3895 'F','R','O','M',' ','`','I','c','o','n','`',0};
3897 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3898 if (r == ERROR_SUCCESS)
3900 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3901 msiobj_release(&view->hdr);
3904 return ERROR_SUCCESS;
3907 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3913 MSISOURCELISTINFO *info;
3915 r = RegCreateKeyW(hkey, szSourceList, &source);
3916 if (r != ERROR_SUCCESS)
3919 RegCloseKey(source);
3921 buffer = strrchrW(package->PackagePath, '\\') + 1;
3922 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3923 package->Context, MSICODE_PRODUCT,
3924 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3925 if (r != ERROR_SUCCESS)
3928 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3929 package->Context, MSICODE_PRODUCT,
3930 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3931 if (r != ERROR_SUCCESS)
3934 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3935 package->Context, MSICODE_PRODUCT,
3936 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3937 if (r != ERROR_SUCCESS)
3940 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3942 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3943 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3944 info->options, info->value);
3946 MsiSourceListSetInfoW(package->ProductCode, NULL,
3947 info->context, info->options,
3948 info->property, info->value);
3951 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3953 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3954 disk->context, disk->options,
3955 disk->disk_id, disk->volume_label, disk->disk_prompt);
3958 return ERROR_SUCCESS;
3961 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3963 MSIHANDLE hdb, suminfo;
3964 WCHAR guids[MAX_PATH];
3965 WCHAR packcode[SQUISH_GUID_SIZE];
3972 static const WCHAR szProductLanguage[] =
3973 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3974 static const WCHAR szARPProductIcon[] =
3975 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3976 static const WCHAR szProductVersion[] =
3977 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3978 static const WCHAR szAssignment[] =
3979 {'A','s','s','i','g','n','m','e','n','t',0};
3980 static const WCHAR szAdvertiseFlags[] =
3981 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3982 static const WCHAR szClients[] =
3983 {'C','l','i','e','n','t','s',0};
3984 static const WCHAR szColon[] = {':',0};
3986 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3987 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3990 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3991 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3994 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3996 buffer = msi_dup_property(package->db, szARPProductIcon);
3999 LPWSTR path = build_icon_path(package,buffer);
4000 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4005 buffer = msi_dup_property(package->db, szProductVersion);
4008 DWORD verdword = msi_version_str_to_dword(buffer);
4009 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4013 msi_reg_set_val_dword(hkey, szAssignment, 0);
4014 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4015 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4016 msi_reg_set_val_str(hkey, szClients, szColon);
4018 hdb = alloc_msihandle(&package->db->hdr);
4020 return ERROR_NOT_ENOUGH_MEMORY;
4022 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4023 MsiCloseHandle(hdb);
4024 if (r != ERROR_SUCCESS)
4028 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4029 NULL, guids, &size);
4030 if (r != ERROR_SUCCESS)
4033 ptr = strchrW(guids, ';');
4035 squash_guid(guids, packcode);
4036 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4039 MsiCloseHandle(suminfo);
4040 return ERROR_SUCCESS;
4043 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4048 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4050 upgrade = msi_dup_property(package->db, szUpgradeCode);
4052 return ERROR_SUCCESS;
4054 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4056 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4057 if (r != ERROR_SUCCESS)
4062 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4063 if (r != ERROR_SUCCESS)
4067 squash_guid(package->ProductCode, squashed_pc);
4068 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4077 static BOOL msi_check_publish(MSIPACKAGE *package)
4079 MSIFEATURE *feature;
4081 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4083 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4090 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4092 MSIFEATURE *feature;
4094 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4096 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4103 static UINT msi_publish_patches( MSIPACKAGE *package )
4105 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4106 WCHAR patch_squashed[GUID_SIZE];
4107 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4109 MSIPATCHINFO *patch;
4111 WCHAR *p, *all_patches = NULL;
4114 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4115 if (r != ERROR_SUCCESS)
4116 return ERROR_FUNCTION_FAILED;
4118 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4119 if (res != ERROR_SUCCESS)
4121 r = ERROR_FUNCTION_FAILED;
4125 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4126 if (r != ERROR_SUCCESS)
4129 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4131 squash_guid( patch->patchcode, patch_squashed );
4132 len += strlenW( patch_squashed ) + 1;
4135 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4139 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4143 squash_guid( patch->patchcode, p );
4144 p += strlenW( p ) + 1;
4146 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4147 (const BYTE *)patch->transforms,
4148 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4149 if (res != ERROR_SUCCESS)
4152 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4153 if (r != ERROR_SUCCESS)
4156 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4157 (const BYTE *)patch->localfile,
4158 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4159 RegCloseKey( patch_key );
4160 if (res != ERROR_SUCCESS)
4163 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4164 if (res != ERROR_SUCCESS)
4167 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4168 RegCloseKey( patch_key );
4169 if (res != ERROR_SUCCESS)
4173 all_patches[len] = 0;
4174 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4175 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4176 if (res != ERROR_SUCCESS)
4179 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4180 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4181 if (res != ERROR_SUCCESS)
4182 r = ERROR_FUNCTION_FAILED;
4185 RegCloseKey( product_patches_key );
4186 RegCloseKey( patches_key );
4187 RegCloseKey( product_key );
4188 msi_free( all_patches );
4193 * 99% of the work done here is only done for
4194 * advertised installs. However this is where the
4195 * Icon table is processed and written out
4196 * so that is what I am going to do here.
4198 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4201 HKEY hukey = NULL, hudkey = NULL;
4204 if (!list_empty(&package->patches))
4206 rc = msi_publish_patches(package);
4207 if (rc != ERROR_SUCCESS)
4211 /* FIXME: also need to publish if the product is in advertise mode */
4212 if (!msi_check_publish(package))
4213 return ERROR_SUCCESS;
4215 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4217 if (rc != ERROR_SUCCESS)
4220 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4221 NULL, &hudkey, TRUE);
4222 if (rc != ERROR_SUCCESS)
4225 rc = msi_publish_upgrade_code(package);
4226 if (rc != ERROR_SUCCESS)
4229 rc = msi_publish_product_properties(package, hukey);
4230 if (rc != ERROR_SUCCESS)
4233 rc = msi_publish_sourcelist(package, hukey);
4234 if (rc != ERROR_SUCCESS)
4237 rc = msi_publish_icons(package);
4240 uirow = MSI_CreateRecord( 1 );
4241 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4242 ui_actiondata( package, szPublishProduct, uirow );
4243 msiobj_release( &uirow->hdr );
4246 RegCloseKey(hudkey);
4251 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4253 WCHAR *filename, *ptr, *folder, *ret;
4254 const WCHAR *dirprop;
4256 filename = msi_dup_record_field( row, 2 );
4257 if (filename && (ptr = strchrW( filename, '|' )))
4262 dirprop = MSI_RecordGetString( row, 3 );
4265 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4267 folder = msi_dup_property( package->db, dirprop );
4270 folder = msi_dup_property( package->db, szWindowsFolder );
4274 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4275 msi_free( filename );
4279 ret = build_directory_name( 2, folder, ptr );
4281 msi_free( filename );
4286 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4288 MSIPACKAGE *package = param;
4289 LPCWSTR component, section, key, value, identifier;
4290 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4295 component = MSI_RecordGetString(row, 8);
4296 comp = get_loaded_component(package,component);
4298 return ERROR_SUCCESS;
4302 TRACE("component is disabled\n");
4303 return ERROR_SUCCESS;
4306 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4308 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4309 comp->Action = comp->Installed;
4310 return ERROR_SUCCESS;
4312 comp->Action = INSTALLSTATE_LOCAL;
4314 identifier = MSI_RecordGetString(row,1);
4315 section = MSI_RecordGetString(row,4);
4316 key = MSI_RecordGetString(row,5);
4317 value = MSI_RecordGetString(row,6);
4318 action = MSI_RecordGetInteger(row,7);
4320 deformat_string(package,section,&deformated_section);
4321 deformat_string(package,key,&deformated_key);
4322 deformat_string(package,value,&deformated_value);
4324 fullname = get_ini_file_name(package, row);
4328 TRACE("Adding value %s to section %s in %s\n",
4329 debugstr_w(deformated_key), debugstr_w(deformated_section),
4330 debugstr_w(fullname));
4331 WritePrivateProfileStringW(deformated_section, deformated_key,
4332 deformated_value, fullname);
4334 else if (action == 1)
4337 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4338 returned, 10, fullname);
4339 if (returned[0] == 0)
4341 TRACE("Adding value %s to section %s in %s\n",
4342 debugstr_w(deformated_key), debugstr_w(deformated_section),
4343 debugstr_w(fullname));
4345 WritePrivateProfileStringW(deformated_section, deformated_key,
4346 deformated_value, fullname);
4349 else if (action == 3)
4350 FIXME("Append to existing section not yet implemented\n");
4352 uirow = MSI_CreateRecord(4);
4353 MSI_RecordSetStringW(uirow,1,identifier);
4354 MSI_RecordSetStringW(uirow,2,deformated_section);
4355 MSI_RecordSetStringW(uirow,3,deformated_key);
4356 MSI_RecordSetStringW(uirow,4,deformated_value);
4357 ui_actiondata(package,szWriteIniValues,uirow);
4358 msiobj_release( &uirow->hdr );
4361 msi_free(deformated_key);
4362 msi_free(deformated_value);
4363 msi_free(deformated_section);
4364 return ERROR_SUCCESS;
4367 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4371 static const WCHAR ExecSeqQuery[] =
4372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4373 '`','I','n','i','F','i','l','e','`',0};
4375 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4376 if (rc != ERROR_SUCCESS)
4378 TRACE("no IniFile table\n");
4379 return ERROR_SUCCESS;
4382 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4383 msiobj_release(&view->hdr);
4387 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4389 MSIPACKAGE *package = param;
4390 LPCWSTR component, section, key, value, identifier;
4391 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4396 component = MSI_RecordGetString( row, 8 );
4397 comp = get_loaded_component( package, component );
4399 return ERROR_SUCCESS;
4403 TRACE("component is disabled\n");
4404 return ERROR_SUCCESS;
4407 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4409 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4410 comp->Action = comp->Installed;
4411 return ERROR_SUCCESS;
4413 comp->Action = INSTALLSTATE_ABSENT;
4415 identifier = MSI_RecordGetString( row, 1 );
4416 section = MSI_RecordGetString( row, 4 );
4417 key = MSI_RecordGetString( row, 5 );
4418 value = MSI_RecordGetString( row, 6 );
4419 action = MSI_RecordGetInteger( row, 7 );
4421 deformat_string( package, section, &deformated_section );
4422 deformat_string( package, key, &deformated_key );
4423 deformat_string( package, value, &deformated_value );
4425 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4427 filename = get_ini_file_name( package, row );
4429 TRACE("Removing key %s from section %s in %s\n",
4430 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4432 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4434 WARN("Unable to remove key %u\n", GetLastError());
4436 msi_free( filename );
4439 FIXME("Unsupported action %d\n", action);
4442 uirow = MSI_CreateRecord( 4 );
4443 MSI_RecordSetStringW( uirow, 1, identifier );
4444 MSI_RecordSetStringW( uirow, 2, deformated_section );
4445 MSI_RecordSetStringW( uirow, 3, deformated_key );
4446 MSI_RecordSetStringW( uirow, 4, deformated_value );
4447 ui_actiondata( package, szRemoveIniValues, uirow );
4448 msiobj_release( &uirow->hdr );
4450 msi_free( deformated_key );
4451 msi_free( deformated_value );
4452 msi_free( deformated_section );
4453 return ERROR_SUCCESS;
4456 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4458 MSIPACKAGE *package = param;
4459 LPCWSTR component, section, key, value, identifier;
4460 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4465 component = MSI_RecordGetString( row, 8 );
4466 comp = get_loaded_component( package, component );
4468 return ERROR_SUCCESS;
4472 TRACE("component is disabled\n");
4473 return ERROR_SUCCESS;
4476 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4478 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4479 comp->Action = comp->Installed;
4480 return ERROR_SUCCESS;
4482 comp->Action = INSTALLSTATE_LOCAL;
4484 identifier = MSI_RecordGetString( row, 1 );
4485 section = MSI_RecordGetString( row, 4 );
4486 key = MSI_RecordGetString( row, 5 );
4487 value = MSI_RecordGetString( row, 6 );
4488 action = MSI_RecordGetInteger( row, 7 );
4490 deformat_string( package, section, &deformated_section );
4491 deformat_string( package, key, &deformated_key );
4492 deformat_string( package, value, &deformated_value );
4494 if (action == msidbIniFileActionRemoveLine)
4496 filename = get_ini_file_name( package, row );
4498 TRACE("Removing key %s from section %s in %s\n",
4499 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4501 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4503 WARN("Unable to remove key %u\n", GetLastError());
4505 msi_free( filename );
4508 FIXME("Unsupported action %d\n", action);
4510 uirow = MSI_CreateRecord( 4 );
4511 MSI_RecordSetStringW( uirow, 1, identifier );
4512 MSI_RecordSetStringW( uirow, 2, deformated_section );
4513 MSI_RecordSetStringW( uirow, 3, deformated_key );
4514 MSI_RecordSetStringW( uirow, 4, deformated_value );
4515 ui_actiondata( package, szRemoveIniValues, uirow );
4516 msiobj_release( &uirow->hdr );
4518 msi_free( deformated_key );
4519 msi_free( deformated_value );
4520 msi_free( deformated_section );
4521 return ERROR_SUCCESS;
4524 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4528 static const WCHAR query[] =
4529 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4530 '`','I','n','i','F','i','l','e','`',0};
4531 static const WCHAR remove_query[] =
4532 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4533 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4535 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4536 if (rc == ERROR_SUCCESS)
4538 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4539 msiobj_release( &view->hdr );
4540 if (rc != ERROR_SUCCESS)
4544 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4545 if (rc == ERROR_SUCCESS)
4547 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4548 msiobj_release( &view->hdr );
4549 if (rc != ERROR_SUCCESS)
4553 return ERROR_SUCCESS;
4556 static void register_dll( const WCHAR *dll, BOOL unregister )
4560 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4563 HRESULT (WINAPI *func_ptr)( void );
4564 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4566 func_ptr = (void *)GetProcAddress( hmod, func );
4569 HRESULT hr = func_ptr();
4571 WARN("failed to register dll 0x%08x\n", hr);
4574 WARN("entry point %s not found\n", func);
4575 FreeLibrary( hmod );
4578 WARN("failed to load library %u\n", GetLastError());
4581 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4583 MSIPACKAGE *package = param;
4588 filename = MSI_RecordGetString(row,1);
4589 file = get_loaded_file( package, filename );
4593 ERR("Unable to find file id %s\n",debugstr_w(filename));
4594 return ERROR_SUCCESS;
4597 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4599 register_dll( file->TargetPath, FALSE );
4601 uirow = MSI_CreateRecord( 2 );
4602 MSI_RecordSetStringW( uirow, 1, filename );
4603 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4604 ui_actiondata( package, szSelfRegModules, uirow );
4605 msiobj_release( &uirow->hdr );
4607 return ERROR_SUCCESS;
4610 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4614 static const WCHAR ExecSeqQuery[] =
4615 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4616 '`','S','e','l','f','R','e','g','`',0};
4618 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4619 if (rc != ERROR_SUCCESS)
4621 TRACE("no SelfReg table\n");
4622 return ERROR_SUCCESS;
4625 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4626 msiobj_release(&view->hdr);
4628 return ERROR_SUCCESS;
4631 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4633 MSIPACKAGE *package = param;
4638 filename = MSI_RecordGetString( row, 1 );
4639 file = get_loaded_file( package, filename );
4643 ERR("Unable to find file id %s\n", debugstr_w(filename));
4644 return ERROR_SUCCESS;
4647 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4649 register_dll( file->TargetPath, TRUE );
4651 uirow = MSI_CreateRecord( 2 );
4652 MSI_RecordSetStringW( uirow, 1, filename );
4653 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4654 ui_actiondata( package, szSelfUnregModules, uirow );
4655 msiobj_release( &uirow->hdr );
4657 return ERROR_SUCCESS;
4660 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4664 static const WCHAR query[] =
4665 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4666 '`','S','e','l','f','R','e','g','`',0};
4668 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4669 if (rc != ERROR_SUCCESS)
4671 TRACE("no SelfReg table\n");
4672 return ERROR_SUCCESS;
4675 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4676 msiobj_release( &view->hdr );
4678 return ERROR_SUCCESS;
4681 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4683 MSIFEATURE *feature;
4685 HKEY hkey = NULL, userdata = NULL;
4687 if (!msi_check_publish(package))
4688 return ERROR_SUCCESS;
4690 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4692 if (rc != ERROR_SUCCESS)
4695 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4697 if (rc != ERROR_SUCCESS)
4700 /* here the guids are base 85 encoded */
4701 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4707 BOOL absent = FALSE;
4710 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4711 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4712 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4715 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4719 if (feature->Feature_Parent)
4720 size += strlenW( feature->Feature_Parent )+2;
4722 data = msi_alloc(size * sizeof(WCHAR));
4725 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4727 MSICOMPONENT* component = cl->component;
4731 if (component->ComponentId)
4733 TRACE("From %s\n",debugstr_w(component->ComponentId));
4734 CLSIDFromString(component->ComponentId, &clsid);
4735 encode_base85_guid(&clsid,buf);
4736 TRACE("to %s\n",debugstr_w(buf));
4741 if (feature->Feature_Parent)
4743 static const WCHAR sep[] = {'\2',0};
4745 strcatW(data,feature->Feature_Parent);
4748 msi_reg_set_val_str( userdata, feature->Feature, data );
4752 if (feature->Feature_Parent)
4753 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4756 size += sizeof(WCHAR);
4757 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4758 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4762 size += 2*sizeof(WCHAR);
4763 data = msi_alloc(size);
4766 if (feature->Feature_Parent)
4767 strcpyW( &data[1], feature->Feature_Parent );
4768 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4774 uirow = MSI_CreateRecord( 1 );
4775 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4776 ui_actiondata( package, szPublishFeatures, uirow);
4777 msiobj_release( &uirow->hdr );
4778 /* FIXME: call ui_progress? */
4783 RegCloseKey(userdata);
4787 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4793 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4795 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4797 if (r == ERROR_SUCCESS)
4799 RegDeleteValueW(hkey, feature->Feature);
4803 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4805 if (r == ERROR_SUCCESS)
4807 RegDeleteValueW(hkey, feature->Feature);
4811 uirow = MSI_CreateRecord( 1 );
4812 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4813 ui_actiondata( package, szUnpublishFeatures, uirow );
4814 msiobj_release( &uirow->hdr );
4816 return ERROR_SUCCESS;
4819 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4821 MSIFEATURE *feature;
4823 if (!msi_check_unpublish(package))
4824 return ERROR_SUCCESS;
4826 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4828 msi_unpublish_feature(package, feature);
4831 return ERROR_SUCCESS;
4834 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4838 WCHAR date[9], *val, *buffer;
4839 const WCHAR *prop, *key;
4841 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4842 static const WCHAR szWindowsInstaller[] =
4843 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4844 static const WCHAR modpath_fmt[] =
4845 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4846 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4847 static const WCHAR szModifyPath[] =
4848 {'M','o','d','i','f','y','P','a','t','h',0};
4849 static const WCHAR szUninstallString[] =
4850 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4851 static const WCHAR szEstimatedSize[] =
4852 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4853 static const WCHAR szProductLanguage[] =
4854 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4855 static const WCHAR szProductVersion[] =
4856 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4857 static const WCHAR szDisplayVersion[] =
4858 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4859 static const WCHAR szInstallSource[] =
4860 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4861 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4862 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4863 static const WCHAR szAuthorizedCDFPrefix[] =
4864 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4865 static const WCHAR szARPCONTACT[] =
4866 {'A','R','P','C','O','N','T','A','C','T',0};
4867 static const WCHAR szContact[] =
4868 {'C','o','n','t','a','c','t',0};
4869 static const WCHAR szARPCOMMENTS[] =
4870 {'A','R','P','C','O','M','M','E','N','T','S',0};
4871 static const WCHAR szComments[] =
4872 {'C','o','m','m','e','n','t','s',0};
4873 static const WCHAR szProductName[] =
4874 {'P','r','o','d','u','c','t','N','a','m','e',0};
4875 static const WCHAR szDisplayName[] =
4876 {'D','i','s','p','l','a','y','N','a','m','e',0};
4877 static const WCHAR szARPHELPLINK[] =
4878 {'A','R','P','H','E','L','P','L','I','N','K',0};
4879 static const WCHAR szHelpLink[] =
4880 {'H','e','l','p','L','i','n','k',0};
4881 static const WCHAR szARPHELPTELEPHONE[] =
4882 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4883 static const WCHAR szHelpTelephone[] =
4884 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4885 static const WCHAR szARPINSTALLLOCATION[] =
4886 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4887 static const WCHAR szInstallLocation[] =
4888 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4889 static const WCHAR szManufacturer[] =
4890 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4891 static const WCHAR szPublisher[] =
4892 {'P','u','b','l','i','s','h','e','r',0};
4893 static const WCHAR szARPREADME[] =
4894 {'A','R','P','R','E','A','D','M','E',0};
4895 static const WCHAR szReadme[] =
4896 {'R','e','a','d','M','e',0};
4897 static const WCHAR szARPSIZE[] =
4898 {'A','R','P','S','I','Z','E',0};
4899 static const WCHAR szSize[] =
4900 {'S','i','z','e',0};
4901 static const WCHAR szARPURLINFOABOUT[] =
4902 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4903 static const WCHAR szURLInfoAbout[] =
4904 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4905 static const WCHAR szARPURLUPDATEINFO[] =
4906 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4907 static const WCHAR szURLUpdateInfo[] =
4908 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4910 static const WCHAR *propval[] = {
4911 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4912 szARPCONTACT, szContact,
4913 szARPCOMMENTS, szComments,
4914 szProductName, szDisplayName,
4915 szARPHELPLINK, szHelpLink,
4916 szARPHELPTELEPHONE, szHelpTelephone,
4917 szARPINSTALLLOCATION, szInstallLocation,
4918 cszSourceDir, szInstallSource,
4919 szManufacturer, szPublisher,
4920 szARPREADME, szReadme,
4922 szARPURLINFOABOUT, szURLInfoAbout,
4923 szARPURLUPDATEINFO, szURLUpdateInfo,
4926 const WCHAR **p = propval;
4932 val = msi_dup_property(package->db, prop);
4933 msi_reg_set_val_str(hkey, key, val);
4937 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4939 size = deformat_string(package, modpath_fmt, &buffer);
4940 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4941 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4944 /* FIXME: Write real Estimated Size when we have it */
4945 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4947 GetLocalTime(&systime);
4948 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4949 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4951 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4952 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4954 buffer = msi_dup_property(package->db, szProductVersion);
4955 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4958 DWORD verdword = msi_version_str_to_dword(buffer);
4960 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4961 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4962 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4966 return ERROR_SUCCESS;
4969 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4971 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4973 LPWSTR upgrade_code;
4978 /* FIXME: also need to publish if the product is in advertise mode */
4979 if (!msi_check_publish(package))
4980 return ERROR_SUCCESS;
4982 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4983 if (rc != ERROR_SUCCESS)
4986 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4987 NULL, &props, TRUE);
4988 if (rc != ERROR_SUCCESS)
4991 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4992 msi_free( package->db->localfile );
4993 package->db->localfile = NULL;
4995 rc = msi_publish_install_properties(package, hkey);
4996 if (rc != ERROR_SUCCESS)
4999 rc = msi_publish_install_properties(package, props);
5000 if (rc != ERROR_SUCCESS)
5003 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5006 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5007 squash_guid(package->ProductCode, squashed_pc);
5008 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5009 RegCloseKey(upgrade);
5010 msi_free(upgrade_code);
5014 uirow = MSI_CreateRecord( 1 );
5015 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5016 ui_actiondata( package, szRegisterProduct, uirow );
5017 msiobj_release( &uirow->hdr );
5020 return ERROR_SUCCESS;
5023 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5025 return execute_script(package,INSTALL_SCRIPT);
5028 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5030 WCHAR *upgrade, **features;
5031 BOOL full_uninstall = TRUE;
5032 MSIFEATURE *feature;
5033 MSIPATCHINFO *patch;
5035 static const WCHAR szUpgradeCode[] =
5036 {'U','p','g','r','a','d','e','C','o','d','e',0};
5038 features = msi_split_string(remove, ',');
5041 ERR("REMOVE feature list is empty!\n");
5042 return ERROR_FUNCTION_FAILED;
5045 if (!strcmpW( features[0], szAll ))
5046 full_uninstall = TRUE;
5049 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5051 if (feature->Action != INSTALLSTATE_ABSENT)
5052 full_uninstall = FALSE;
5057 if (!full_uninstall)
5058 return ERROR_SUCCESS;
5060 MSIREG_DeleteProductKey(package->ProductCode);
5061 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5062 MSIREG_DeleteUninstallKey(package);
5064 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5065 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5066 MSIREG_DeleteUserProductKey(package->ProductCode);
5067 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5069 upgrade = msi_dup_property(package->db, szUpgradeCode);
5072 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5073 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5077 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5079 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5082 return ERROR_SUCCESS;
5085 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5090 /* turn off scheduling */
5091 package->script->CurrentlyScripting= FALSE;
5093 /* first do the same as an InstallExecute */
5094 rc = ACTION_InstallExecute(package);
5095 if (rc != ERROR_SUCCESS)
5098 /* then handle Commit Actions */
5099 rc = execute_script(package,COMMIT_SCRIPT);
5100 if (rc != ERROR_SUCCESS)
5103 remove = msi_dup_property(package->db, szRemove);
5105 rc = msi_unpublish_product(package, remove);
5111 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5113 static const WCHAR RunOnce[] = {
5114 'S','o','f','t','w','a','r','e','\\',
5115 'M','i','c','r','o','s','o','f','t','\\',
5116 'W','i','n','d','o','w','s','\\',
5117 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5118 'R','u','n','O','n','c','e',0};
5119 static const WCHAR InstallRunOnce[] = {
5120 'S','o','f','t','w','a','r','e','\\',
5121 'M','i','c','r','o','s','o','f','t','\\',
5122 'W','i','n','d','o','w','s','\\',
5123 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5124 'I','n','s','t','a','l','l','e','r','\\',
5125 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5127 static const WCHAR msiexec_fmt[] = {
5129 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5130 '\"','%','s','\"',0};
5131 static const WCHAR install_fmt[] = {
5132 '/','I',' ','\"','%','s','\"',' ',
5133 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5134 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5135 WCHAR buffer[256], sysdir[MAX_PATH];
5137 WCHAR squished_pc[100];
5139 squash_guid(package->ProductCode,squished_pc);
5141 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5142 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5143 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5146 msi_reg_set_val_str( hkey, squished_pc, buffer );
5149 TRACE("Reboot command %s\n",debugstr_w(buffer));
5151 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5152 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5154 msi_reg_set_val_str( hkey, squished_pc, buffer );
5157 return ERROR_INSTALL_SUSPEND;
5160 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5166 * We are currently doing what should be done here in the top level Install
5167 * however for Administrative and uninstalls this step will be needed
5169 if (!package->PackagePath)
5170 return ERROR_SUCCESS;
5172 msi_set_sourcedir_props(package, TRUE);
5174 attrib = GetFileAttributesW(package->db->path);
5175 if (attrib == INVALID_FILE_ATTRIBUTES)
5181 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5182 package->Context, MSICODE_PRODUCT,
5183 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5184 if (rc == ERROR_MORE_DATA)
5186 prompt = msi_alloc(size * sizeof(WCHAR));
5187 MsiSourceListGetInfoW(package->ProductCode, NULL,
5188 package->Context, MSICODE_PRODUCT,
5189 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5192 prompt = strdupW(package->db->path);
5194 msg = generate_error_string(package,1302,1,prompt);
5195 while(attrib == INVALID_FILE_ATTRIBUTES)
5197 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5200 rc = ERROR_INSTALL_USEREXIT;
5203 attrib = GetFileAttributesW(package->db->path);
5209 return ERROR_SUCCESS;
5214 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5217 LPWSTR buffer, productid = NULL;
5218 UINT i, rc = ERROR_SUCCESS;
5221 static const WCHAR szPropKeys[][80] =
5223 {'P','r','o','d','u','c','t','I','D',0},
5224 {'U','S','E','R','N','A','M','E',0},
5225 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5229 static const WCHAR szRegKeys[][80] =
5231 {'P','r','o','d','u','c','t','I','D',0},
5232 {'R','e','g','O','w','n','e','r',0},
5233 {'R','e','g','C','o','m','p','a','n','y',0},
5237 if (msi_check_unpublish(package))
5239 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5243 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5247 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5249 if (rc != ERROR_SUCCESS)
5252 for( i = 0; szPropKeys[i][0]; i++ )
5254 buffer = msi_dup_property( package->db, szPropKeys[i] );
5255 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5260 uirow = MSI_CreateRecord( 1 );
5261 MSI_RecordSetStringW( uirow, 1, productid );
5262 ui_actiondata( package, szRegisterUser, uirow );
5263 msiobj_release( &uirow->hdr );
5265 msi_free(productid);
5271 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5275 package->script->InWhatSequence |= SEQUENCE_EXEC;
5276 rc = ACTION_ProcessExecSequence(package,FALSE);
5281 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5283 MSIPACKAGE *package = param;
5284 LPCWSTR compgroupid, component, feature, qualifier, text;
5285 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5294 feature = MSI_RecordGetString(rec, 5);
5295 feat = get_loaded_feature(package, feature);
5297 return ERROR_SUCCESS;
5299 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5300 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5301 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5303 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5304 feat->Action = feat->Installed;
5305 return ERROR_SUCCESS;
5308 component = MSI_RecordGetString(rec, 3);
5309 comp = get_loaded_component(package, component);
5311 return ERROR_SUCCESS;
5313 compgroupid = MSI_RecordGetString(rec,1);
5314 qualifier = MSI_RecordGetString(rec,2);
5316 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5317 if (rc != ERROR_SUCCESS)
5320 advertise = create_component_advertise_string( package, comp, feature );
5321 text = MSI_RecordGetString( rec, 4 );
5324 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5325 strcpyW( p, advertise );
5327 msi_free( advertise );
5330 existing = msi_reg_get_val_str( hkey, qualifier );
5332 sz = strlenW( advertise ) + 1;
5335 for (p = existing; *p; p += len)
5337 len = strlenW( p ) + 1;
5338 if (strcmpW( advertise, p )) sz += len;
5341 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5343 rc = ERROR_OUTOFMEMORY;
5349 for (p = existing; *p; p += len)
5351 len = strlenW( p ) + 1;
5352 if (strcmpW( advertise, p ))
5354 memcpy( q, p, len * sizeof(WCHAR) );
5359 strcpyW( q, advertise );
5360 q[strlenW( q ) + 1] = 0;
5362 msi_reg_set_val_multi_str( hkey, qualifier, output );
5367 msi_free( advertise );
5368 msi_free( existing );
5371 uirow = MSI_CreateRecord( 2 );
5372 MSI_RecordSetStringW( uirow, 1, compgroupid );
5373 MSI_RecordSetStringW( uirow, 2, qualifier);
5374 ui_actiondata( package, szPublishComponents, uirow);
5375 msiobj_release( &uirow->hdr );
5376 /* FIXME: call ui_progress? */
5382 * At present I am ignorning the advertised components part of this and only
5383 * focusing on the qualified component sets
5385 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5389 static const WCHAR ExecSeqQuery[] =
5390 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5391 '`','P','u','b','l','i','s','h',
5392 'C','o','m','p','o','n','e','n','t','`',0};
5394 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5395 if (rc != ERROR_SUCCESS)
5396 return ERROR_SUCCESS;
5398 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5399 msiobj_release(&view->hdr);
5404 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5406 static const WCHAR szInstallerComponents[] = {
5407 'S','o','f','t','w','a','r','e','\\',
5408 'M','i','c','r','o','s','o','f','t','\\',
5409 'I','n','s','t','a','l','l','e','r','\\',
5410 'C','o','m','p','o','n','e','n','t','s','\\',0};
5412 MSIPACKAGE *package = param;
5413 LPCWSTR compgroupid, component, feature, qualifier;
5417 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5420 feature = MSI_RecordGetString( rec, 5 );
5421 feat = get_loaded_feature( package, feature );
5423 return ERROR_SUCCESS;
5425 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5427 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5428 feat->Action = feat->Installed;
5429 return ERROR_SUCCESS;
5432 component = MSI_RecordGetString( rec, 3 );
5433 comp = get_loaded_component( package, component );
5435 return ERROR_SUCCESS;
5437 compgroupid = MSI_RecordGetString( rec, 1 );
5438 qualifier = MSI_RecordGetString( rec, 2 );
5440 squash_guid( compgroupid, squashed );
5441 strcpyW( keypath, szInstallerComponents );
5442 strcatW( keypath, squashed );
5444 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5445 if (res != ERROR_SUCCESS)
5447 WARN("Unable to delete component key %d\n", res);
5450 uirow = MSI_CreateRecord( 2 );
5451 MSI_RecordSetStringW( uirow, 1, compgroupid );
5452 MSI_RecordSetStringW( uirow, 2, qualifier );
5453 ui_actiondata( package, szUnpublishComponents, uirow );
5454 msiobj_release( &uirow->hdr );
5456 return ERROR_SUCCESS;
5459 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5463 static const WCHAR query[] =
5464 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5465 '`','P','u','b','l','i','s','h',
5466 'C','o','m','p','o','n','e','n','t','`',0};
5468 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5469 if (rc != ERROR_SUCCESS)
5470 return ERROR_SUCCESS;
5472 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5473 msiobj_release( &view->hdr );
5478 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5480 MSIPACKAGE *package = param;
5483 SC_HANDLE hscm, service = NULL;
5485 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5486 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5487 DWORD serv_type, start_type, err_control;
5488 SERVICE_DESCRIPTIONW sd = {NULL};
5490 static const WCHAR query[] =
5491 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5492 '`','C','o','m','p','o','n','e','n','t','`',' ',
5493 'W','H','E','R','E',' ',
5494 '`','C','o','m','p','o','n','e','n','t','`',' ',
5495 '=','\'','%','s','\'',0};
5497 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5500 ERR("Failed to open the SC Manager!\n");
5504 comp = MSI_RecordGetString( rec, 12 );
5505 if (!get_loaded_component( package, comp ))
5508 start_type = MSI_RecordGetInteger(rec, 5);
5509 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5512 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5513 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5514 serv_type = MSI_RecordGetInteger(rec, 4);
5515 err_control = MSI_RecordGetInteger(rec, 6);
5516 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5517 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5518 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5519 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5520 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5521 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5523 /* fetch the service path */
5524 row = MSI_QueryGetRecord(package->db, query, comp);
5527 ERR("Control query failed!\n");
5530 key = MSI_RecordGetString(row, 6);
5532 file = get_loaded_file(package, key);
5533 msiobj_release(&row->hdr);
5536 ERR("Failed to load the service file\n");
5540 if (!args || !args[0]) image_path = file->TargetPath;
5543 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5544 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5545 return ERROR_OUTOFMEMORY;
5547 strcpyW(image_path, file->TargetPath);
5548 strcatW(image_path, szSpace);
5549 strcatW(image_path, args);
5551 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5552 start_type, err_control, image_path, load_order,
5553 NULL, depends, serv_name, pass);
5557 if (GetLastError() != ERROR_SERVICE_EXISTS)
5558 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5560 else if (sd.lpDescription)
5562 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5563 WARN("failed to set service description %u\n", GetLastError());
5566 if (image_path != file->TargetPath) msi_free(image_path);
5568 CloseServiceHandle(service);
5569 CloseServiceHandle(hscm);
5572 msi_free(sd.lpDescription);
5573 msi_free(load_order);
5574 msi_free(serv_name);
5579 return ERROR_SUCCESS;
5582 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5586 static const WCHAR ExecSeqQuery[] =
5587 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5588 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5590 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5591 if (rc != ERROR_SUCCESS)
5592 return ERROR_SUCCESS;
5594 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5595 msiobj_release(&view->hdr);
5600 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5601 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5603 LPCWSTR *vector, *temp_vector;
5607 static const WCHAR separator[] = {'[','~',']',0};
5610 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5615 vector = msi_alloc(sizeof(LPWSTR));
5623 vector[*numargs - 1] = p;
5625 if ((q = strstrW(p, separator)))
5629 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5635 vector = temp_vector;
5644 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5646 MSIPACKAGE *package = param;
5649 SC_HANDLE scm = NULL, service = NULL;
5650 LPCWSTR component, *vector = NULL;
5651 LPWSTR name, args, display_name = NULL;
5652 DWORD event, numargs, len;
5653 UINT r = ERROR_FUNCTION_FAILED;
5655 component = MSI_RecordGetString(rec, 6);
5656 comp = get_loaded_component(package, component);
5658 return ERROR_SUCCESS;
5662 TRACE("component is disabled\n");
5663 return ERROR_SUCCESS;
5666 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5668 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5669 comp->Action = comp->Installed;
5670 return ERROR_SUCCESS;
5672 comp->Action = INSTALLSTATE_LOCAL;
5674 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5675 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5676 event = MSI_RecordGetInteger(rec, 3);
5678 if (!(event & msidbServiceControlEventStart))
5684 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5687 ERR("Failed to open the service control manager\n");
5692 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5693 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5695 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5696 GetServiceDisplayNameW( scm, name, display_name, &len );
5699 service = OpenServiceW(scm, name, SERVICE_START);
5702 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5706 vector = msi_service_args_to_vector(args, &numargs);
5708 if (!StartServiceW(service, numargs, vector) &&
5709 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5711 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5718 uirow = MSI_CreateRecord( 2 );
5719 MSI_RecordSetStringW( uirow, 1, display_name );
5720 MSI_RecordSetStringW( uirow, 2, name );
5721 ui_actiondata( package, szStartServices, uirow );
5722 msiobj_release( &uirow->hdr );
5724 CloseServiceHandle(service);
5725 CloseServiceHandle(scm);
5730 msi_free(display_name);
5734 static UINT ACTION_StartServices( MSIPACKAGE *package )
5739 static const WCHAR query[] = {
5740 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5741 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5743 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5744 if (rc != ERROR_SUCCESS)
5745 return ERROR_SUCCESS;
5747 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5748 msiobj_release(&view->hdr);
5753 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5755 DWORD i, needed, count;
5756 ENUM_SERVICE_STATUSW *dependencies;
5760 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5761 0, &needed, &count))
5764 if (GetLastError() != ERROR_MORE_DATA)
5767 dependencies = msi_alloc(needed);
5771 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5772 needed, &needed, &count))
5775 for (i = 0; i < count; i++)
5777 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5778 SERVICE_STOP | SERVICE_QUERY_STATUS);
5782 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5789 msi_free(dependencies);
5793 static UINT stop_service( LPCWSTR name )
5795 SC_HANDLE scm = NULL, service = NULL;
5796 SERVICE_STATUS status;
5797 SERVICE_STATUS_PROCESS ssp;
5800 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5803 WARN("Failed to open the SCM: %d\n", GetLastError());
5807 service = OpenServiceW(scm, name,
5809 SERVICE_QUERY_STATUS |
5810 SERVICE_ENUMERATE_DEPENDENTS);
5813 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5817 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5818 sizeof(SERVICE_STATUS_PROCESS), &needed))
5820 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5824 if (ssp.dwCurrentState == SERVICE_STOPPED)
5827 stop_service_dependents(scm, service);
5829 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5830 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5833 CloseServiceHandle(service);
5834 CloseServiceHandle(scm);
5836 return ERROR_SUCCESS;
5839 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5841 MSIPACKAGE *package = param;
5845 LPWSTR name = NULL, display_name = NULL;
5849 event = MSI_RecordGetInteger( rec, 3 );
5850 if (!(event & msidbServiceControlEventStop))
5851 return ERROR_SUCCESS;
5853 component = MSI_RecordGetString( rec, 6 );
5854 comp = get_loaded_component( package, component );
5856 return ERROR_SUCCESS;
5860 TRACE("component is disabled\n");
5861 return ERROR_SUCCESS;
5864 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5866 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5867 comp->Action = comp->Installed;
5868 return ERROR_SUCCESS;
5870 comp->Action = INSTALLSTATE_ABSENT;
5872 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5875 ERR("Failed to open the service control manager\n");
5880 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5881 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5883 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5884 GetServiceDisplayNameW( scm, name, display_name, &len );
5886 CloseServiceHandle( scm );
5888 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5889 stop_service( name );
5892 uirow = MSI_CreateRecord( 2 );
5893 MSI_RecordSetStringW( uirow, 1, display_name );
5894 MSI_RecordSetStringW( uirow, 2, name );
5895 ui_actiondata( package, szStopServices, uirow );
5896 msiobj_release( &uirow->hdr );
5899 msi_free( display_name );
5900 return ERROR_SUCCESS;
5903 static UINT ACTION_StopServices( MSIPACKAGE *package )
5908 static const WCHAR query[] = {
5909 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5910 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5912 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5913 if (rc != ERROR_SUCCESS)
5914 return ERROR_SUCCESS;
5916 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5917 msiobj_release(&view->hdr);
5922 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5924 MSIPACKAGE *package = param;
5928 LPWSTR name = NULL, display_name = NULL;
5930 SC_HANDLE scm = NULL, service = NULL;
5932 event = MSI_RecordGetInteger( rec, 3 );
5933 if (!(event & msidbServiceControlEventDelete))
5934 return ERROR_SUCCESS;
5936 component = MSI_RecordGetString(rec, 6);
5937 comp = get_loaded_component(package, component);
5939 return ERROR_SUCCESS;
5943 TRACE("component is disabled\n");
5944 return ERROR_SUCCESS;
5947 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5949 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5950 comp->Action = comp->Installed;
5951 return ERROR_SUCCESS;
5953 comp->Action = INSTALLSTATE_ABSENT;
5955 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5956 stop_service( name );
5958 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5961 WARN("Failed to open the SCM: %d\n", GetLastError());
5966 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5967 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5969 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5970 GetServiceDisplayNameW( scm, name, display_name, &len );
5973 service = OpenServiceW( scm, name, DELETE );
5976 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5980 if (!DeleteService( service ))
5981 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5984 uirow = MSI_CreateRecord( 2 );
5985 MSI_RecordSetStringW( uirow, 1, display_name );
5986 MSI_RecordSetStringW( uirow, 2, name );
5987 ui_actiondata( package, szDeleteServices, uirow );
5988 msiobj_release( &uirow->hdr );
5990 CloseServiceHandle( service );
5991 CloseServiceHandle( scm );
5993 msi_free( display_name );
5995 return ERROR_SUCCESS;
5998 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6003 static const WCHAR query[] = {
6004 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6005 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6007 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6008 if (rc != ERROR_SUCCESS)
6009 return ERROR_SUCCESS;
6011 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6012 msiobj_release( &view->hdr );
6017 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6019 MSIPACKAGE *package = param;
6020 LPWSTR driver, driver_path, ptr;
6021 WCHAR outpath[MAX_PATH];
6022 MSIFILE *driver_file = NULL, *setup_file = NULL;
6025 LPCWSTR desc, file_key, component;
6027 UINT r = ERROR_SUCCESS;
6029 static const WCHAR driver_fmt[] = {
6030 'D','r','i','v','e','r','=','%','s',0};
6031 static const WCHAR setup_fmt[] = {
6032 'S','e','t','u','p','=','%','s',0};
6033 static const WCHAR usage_fmt[] = {
6034 'F','i','l','e','U','s','a','g','e','=','1',0};
6036 component = MSI_RecordGetString( rec, 2 );
6037 comp = get_loaded_component( package, component );
6039 return ERROR_SUCCESS;
6043 TRACE("component is disabled\n");
6044 return ERROR_SUCCESS;
6047 desc = MSI_RecordGetString(rec, 3);
6049 file_key = MSI_RecordGetString( rec, 4 );
6050 if (file_key) driver_file = get_loaded_file( package, file_key );
6052 file_key = MSI_RecordGetString( rec, 5 );
6053 if (file_key) setup_file = get_loaded_file( package, file_key );
6057 ERR("ODBC Driver entry not found!\n");
6058 return ERROR_FUNCTION_FAILED;
6061 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6063 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6064 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6066 driver = msi_alloc(len * sizeof(WCHAR));
6068 return ERROR_OUTOFMEMORY;
6071 lstrcpyW(ptr, desc);
6072 ptr += lstrlenW(ptr) + 1;
6074 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6079 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6083 lstrcpyW(ptr, usage_fmt);
6084 ptr += lstrlenW(ptr) + 1;
6087 driver_path = strdupW(driver_file->TargetPath);
6088 ptr = strrchrW(driver_path, '\\');
6089 if (ptr) *ptr = '\0';
6091 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6092 NULL, ODBC_INSTALL_COMPLETE, &usage))
6094 ERR("Failed to install SQL driver!\n");
6095 r = ERROR_FUNCTION_FAILED;
6098 uirow = MSI_CreateRecord( 5 );
6099 MSI_RecordSetStringW( uirow, 1, desc );
6100 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6101 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6102 ui_actiondata( package, szInstallODBC, uirow );
6103 msiobj_release( &uirow->hdr );
6106 msi_free(driver_path);
6111 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6113 MSIPACKAGE *package = param;
6114 LPWSTR translator, translator_path, ptr;
6115 WCHAR outpath[MAX_PATH];
6116 MSIFILE *translator_file = NULL, *setup_file = NULL;
6119 LPCWSTR desc, file_key, component;
6121 UINT r = ERROR_SUCCESS;
6123 static const WCHAR translator_fmt[] = {
6124 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6125 static const WCHAR setup_fmt[] = {
6126 'S','e','t','u','p','=','%','s',0};
6128 component = MSI_RecordGetString( rec, 2 );
6129 comp = get_loaded_component( package, component );
6131 return ERROR_SUCCESS;
6135 TRACE("component is disabled\n");
6136 return ERROR_SUCCESS;
6139 desc = MSI_RecordGetString(rec, 3);
6141 file_key = MSI_RecordGetString( rec, 4 );
6142 if (file_key) translator_file = get_loaded_file( package, file_key );
6144 file_key = MSI_RecordGetString( rec, 5 );
6145 if (file_key) setup_file = get_loaded_file( package, file_key );
6147 if (!translator_file)
6149 ERR("ODBC Translator entry not found!\n");
6150 return ERROR_FUNCTION_FAILED;
6153 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6155 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6157 translator = msi_alloc(len * sizeof(WCHAR));
6159 return ERROR_OUTOFMEMORY;
6162 lstrcpyW(ptr, desc);
6163 ptr += lstrlenW(ptr) + 1;
6165 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6170 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6175 translator_path = strdupW(translator_file->TargetPath);
6176 ptr = strrchrW(translator_path, '\\');
6177 if (ptr) *ptr = '\0';
6179 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6180 NULL, ODBC_INSTALL_COMPLETE, &usage))
6182 ERR("Failed to install SQL translator!\n");
6183 r = ERROR_FUNCTION_FAILED;
6186 uirow = MSI_CreateRecord( 5 );
6187 MSI_RecordSetStringW( uirow, 1, desc );
6188 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6189 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6190 ui_actiondata( package, szInstallODBC, uirow );
6191 msiobj_release( &uirow->hdr );
6193 msi_free(translator);
6194 msi_free(translator_path);
6199 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6201 MSIPACKAGE *package = param;
6204 LPCWSTR desc, driver, component;
6205 WORD request = ODBC_ADD_SYS_DSN;
6208 UINT r = ERROR_SUCCESS;
6211 static const WCHAR attrs_fmt[] = {
6212 'D','S','N','=','%','s',0 };
6214 component = MSI_RecordGetString( rec, 2 );
6215 comp = get_loaded_component( package, component );
6217 return ERROR_SUCCESS;
6221 TRACE("component is disabled\n");
6222 return ERROR_SUCCESS;
6225 desc = MSI_RecordGetString(rec, 3);
6226 driver = MSI_RecordGetString(rec, 4);
6227 registration = MSI_RecordGetInteger(rec, 5);
6229 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6230 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6232 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6233 attrs = msi_alloc(len * sizeof(WCHAR));
6235 return ERROR_OUTOFMEMORY;
6237 len = sprintfW(attrs, attrs_fmt, desc);
6240 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6242 ERR("Failed to install SQL data source!\n");
6243 r = ERROR_FUNCTION_FAILED;
6246 uirow = MSI_CreateRecord( 5 );
6247 MSI_RecordSetStringW( uirow, 1, desc );
6248 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6249 MSI_RecordSetInteger( uirow, 3, request );
6250 ui_actiondata( package, szInstallODBC, uirow );
6251 msiobj_release( &uirow->hdr );
6258 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6263 static const WCHAR driver_query[] = {
6264 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6265 'O','D','B','C','D','r','i','v','e','r',0 };
6267 static const WCHAR translator_query[] = {
6268 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6269 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6271 static const WCHAR source_query[] = {
6272 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6273 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6275 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6276 if (rc != ERROR_SUCCESS)
6277 return ERROR_SUCCESS;
6279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6280 msiobj_release(&view->hdr);
6282 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6283 if (rc != ERROR_SUCCESS)
6284 return ERROR_SUCCESS;
6286 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6287 msiobj_release(&view->hdr);
6289 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6290 if (rc != ERROR_SUCCESS)
6291 return ERROR_SUCCESS;
6293 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6294 msiobj_release(&view->hdr);
6299 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6301 MSIPACKAGE *package = param;
6305 LPCWSTR desc, component;
6307 component = MSI_RecordGetString( rec, 2 );
6308 comp = get_loaded_component( package, component );
6310 return ERROR_SUCCESS;
6314 TRACE("component is disabled\n");
6315 return ERROR_SUCCESS;
6318 desc = MSI_RecordGetString( rec, 3 );
6319 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6321 WARN("Failed to remove ODBC driver\n");
6325 FIXME("Usage count reached 0\n");
6328 uirow = MSI_CreateRecord( 2 );
6329 MSI_RecordSetStringW( uirow, 1, desc );
6330 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6331 ui_actiondata( package, szRemoveODBC, uirow );
6332 msiobj_release( &uirow->hdr );
6334 return ERROR_SUCCESS;
6337 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6339 MSIPACKAGE *package = param;
6343 LPCWSTR desc, component;
6345 component = MSI_RecordGetString( rec, 2 );
6346 comp = get_loaded_component( package, component );
6348 return ERROR_SUCCESS;
6352 TRACE("component is disabled\n");
6353 return ERROR_SUCCESS;
6356 desc = MSI_RecordGetString( rec, 3 );
6357 if (!SQLRemoveTranslatorW( desc, &usage ))
6359 WARN("Failed to remove ODBC translator\n");
6363 FIXME("Usage count reached 0\n");
6366 uirow = MSI_CreateRecord( 2 );
6367 MSI_RecordSetStringW( uirow, 1, desc );
6368 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6369 ui_actiondata( package, szRemoveODBC, uirow );
6370 msiobj_release( &uirow->hdr );
6372 return ERROR_SUCCESS;
6375 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6377 MSIPACKAGE *package = param;
6381 LPCWSTR desc, driver, component;
6382 WORD request = ODBC_REMOVE_SYS_DSN;
6386 static const WCHAR attrs_fmt[] = {
6387 'D','S','N','=','%','s',0 };
6389 component = MSI_RecordGetString( rec, 2 );
6390 comp = get_loaded_component( package, component );
6392 return ERROR_SUCCESS;
6396 TRACE("component is disabled\n");
6397 return ERROR_SUCCESS;
6400 desc = MSI_RecordGetString( rec, 3 );
6401 driver = MSI_RecordGetString( rec, 4 );
6402 registration = MSI_RecordGetInteger( rec, 5 );
6404 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6405 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6407 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6408 attrs = msi_alloc( len * sizeof(WCHAR) );
6410 return ERROR_OUTOFMEMORY;
6412 FIXME("Use ODBCSourceAttribute table\n");
6414 len = sprintfW( attrs, attrs_fmt, desc );
6417 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6419 WARN("Failed to remove ODBC data source\n");
6423 uirow = MSI_CreateRecord( 3 );
6424 MSI_RecordSetStringW( uirow, 1, desc );
6425 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6426 MSI_RecordSetInteger( uirow, 3, request );
6427 ui_actiondata( package, szRemoveODBC, uirow );
6428 msiobj_release( &uirow->hdr );
6430 return ERROR_SUCCESS;
6433 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6438 static const WCHAR driver_query[] = {
6439 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6440 'O','D','B','C','D','r','i','v','e','r',0 };
6442 static const WCHAR translator_query[] = {
6443 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6444 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6446 static const WCHAR source_query[] = {
6447 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6448 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6450 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6451 if (rc != ERROR_SUCCESS)
6452 return ERROR_SUCCESS;
6454 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6455 msiobj_release( &view->hdr );
6457 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6458 if (rc != ERROR_SUCCESS)
6459 return ERROR_SUCCESS;
6461 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6462 msiobj_release( &view->hdr );
6464 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6465 if (rc != ERROR_SUCCESS)
6466 return ERROR_SUCCESS;
6468 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6469 msiobj_release( &view->hdr );
6474 #define ENV_ACT_SETALWAYS 0x1
6475 #define ENV_ACT_SETABSENT 0x2
6476 #define ENV_ACT_REMOVE 0x4
6477 #define ENV_ACT_REMOVEMATCH 0x8
6479 #define ENV_MOD_MACHINE 0x20000000
6480 #define ENV_MOD_APPEND 0x40000000
6481 #define ENV_MOD_PREFIX 0x80000000
6482 #define ENV_MOD_MASK 0xC0000000
6484 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6486 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6488 LPCWSTR cptr = *name;
6490 static const WCHAR prefix[] = {'[','~',']',0};
6491 static const int prefix_len = 3;
6497 *flags |= ENV_ACT_SETALWAYS;
6498 else if (*cptr == '+')
6499 *flags |= ENV_ACT_SETABSENT;
6500 else if (*cptr == '-')
6501 *flags |= ENV_ACT_REMOVE;
6502 else if (*cptr == '!')
6503 *flags |= ENV_ACT_REMOVEMATCH;
6504 else if (*cptr == '*')
6505 *flags |= ENV_MOD_MACHINE;
6515 ERR("Missing environment variable\n");
6516 return ERROR_FUNCTION_FAILED;
6521 LPCWSTR ptr = *value;
6522 if (!strncmpW(ptr, prefix, prefix_len))
6524 if (ptr[prefix_len] == szSemiColon[0])
6526 *flags |= ENV_MOD_APPEND;
6527 *value += lstrlenW(prefix);
6534 else if (lstrlenW(*value) >= prefix_len)
6536 ptr += lstrlenW(ptr) - prefix_len;
6537 if (!strcmpW( ptr, prefix ))
6539 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6541 *flags |= ENV_MOD_PREFIX;
6542 /* the "[~]" will be removed by deformat_string */;
6552 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6553 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6554 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6555 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6557 ERR("Invalid flags: %08x\n", *flags);
6558 return ERROR_FUNCTION_FAILED;
6562 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6564 return ERROR_SUCCESS;
6567 static UINT open_env_key( DWORD flags, HKEY *key )
6569 static const WCHAR user_env[] =
6570 {'E','n','v','i','r','o','n','m','e','n','t',0};
6571 static const WCHAR machine_env[] =
6572 {'S','y','s','t','e','m','\\',
6573 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6574 'C','o','n','t','r','o','l','\\',
6575 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6576 'E','n','v','i','r','o','n','m','e','n','t',0};
6581 if (flags & ENV_MOD_MACHINE)
6584 root = HKEY_LOCAL_MACHINE;
6589 root = HKEY_CURRENT_USER;
6592 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6593 if (res != ERROR_SUCCESS)
6595 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6596 return ERROR_FUNCTION_FAILED;
6599 return ERROR_SUCCESS;
6602 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6604 MSIPACKAGE *package = param;
6605 LPCWSTR name, value, component;
6606 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6607 DWORD flags, type, size;
6614 component = MSI_RecordGetString(rec, 4);
6615 comp = get_loaded_component(package, component);
6617 return ERROR_SUCCESS;
6621 TRACE("component is disabled\n");
6622 return ERROR_SUCCESS;
6625 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6627 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6628 comp->Action = comp->Installed;
6629 return ERROR_SUCCESS;
6631 comp->Action = INSTALLSTATE_LOCAL;
6633 name = MSI_RecordGetString(rec, 2);
6634 value = MSI_RecordGetString(rec, 3);
6636 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6638 res = env_parse_flags(&name, &value, &flags);
6639 if (res != ERROR_SUCCESS || !value)
6642 if (value && !deformat_string(package, value, &deformatted))
6644 res = ERROR_OUTOFMEMORY;
6648 value = deformatted;
6650 res = open_env_key( flags, &env );
6651 if (res != ERROR_SUCCESS)
6654 if (flags & ENV_MOD_MACHINE)
6655 action |= 0x20000000;
6659 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6660 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6661 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6664 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6668 /* Nothing to do. */
6671 res = ERROR_SUCCESS;
6675 /* If we are appending but the string was empty, strip ; */
6676 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6678 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6679 newval = strdupW(value);
6682 res = ERROR_OUTOFMEMORY;
6690 /* Contrary to MSDN, +-variable to [~];path works */
6691 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6693 res = ERROR_SUCCESS;
6697 data = msi_alloc(size);
6701 return ERROR_OUTOFMEMORY;
6704 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6705 if (res != ERROR_SUCCESS)
6708 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6711 res = RegDeleteValueW(env, name);
6712 if (res != ERROR_SUCCESS)
6713 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6717 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6718 if (flags & ENV_MOD_MASK)
6722 if (flags & ENV_MOD_APPEND) multiplier++;
6723 if (flags & ENV_MOD_PREFIX) multiplier++;
6724 mod_size = lstrlenW(value) * multiplier;
6725 size += mod_size * sizeof(WCHAR);
6728 newval = msi_alloc(size);
6732 res = ERROR_OUTOFMEMORY;
6736 if (flags & ENV_MOD_PREFIX)
6738 lstrcpyW(newval, value);
6739 ptr = newval + lstrlenW(value);
6740 action |= 0x80000000;
6743 lstrcpyW(ptr, data);
6745 if (flags & ENV_MOD_APPEND)
6747 lstrcatW(newval, value);
6748 action |= 0x40000000;
6751 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6752 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6755 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6759 uirow = MSI_CreateRecord( 3 );
6760 MSI_RecordSetStringW( uirow, 1, name );
6761 MSI_RecordSetStringW( uirow, 2, newval );
6762 MSI_RecordSetInteger( uirow, 3, action );
6763 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6764 msiobj_release( &uirow->hdr );
6766 if (env) RegCloseKey(env);
6767 msi_free(deformatted);
6773 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6777 static const WCHAR ExecSeqQuery[] =
6778 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6779 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6780 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6781 if (rc != ERROR_SUCCESS)
6782 return ERROR_SUCCESS;
6784 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6785 msiobj_release(&view->hdr);
6790 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6792 MSIPACKAGE *package = param;
6793 LPCWSTR name, value, component;
6794 LPWSTR deformatted = NULL;
6803 component = MSI_RecordGetString( rec, 4 );
6804 comp = get_loaded_component( package, component );
6806 return ERROR_SUCCESS;
6810 TRACE("component is disabled\n");
6811 return ERROR_SUCCESS;
6814 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6816 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6817 comp->Action = comp->Installed;
6818 return ERROR_SUCCESS;
6820 comp->Action = INSTALLSTATE_ABSENT;
6822 name = MSI_RecordGetString( rec, 2 );
6823 value = MSI_RecordGetString( rec, 3 );
6825 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6827 r = env_parse_flags( &name, &value, &flags );
6828 if (r != ERROR_SUCCESS)
6831 if (!(flags & ENV_ACT_REMOVE))
6833 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6834 return ERROR_SUCCESS;
6837 if (value && !deformat_string( package, value, &deformatted ))
6838 return ERROR_OUTOFMEMORY;
6840 value = deformatted;
6842 r = open_env_key( flags, &env );
6843 if (r != ERROR_SUCCESS)
6849 if (flags & ENV_MOD_MACHINE)
6850 action |= 0x20000000;
6852 TRACE("Removing %s\n", debugstr_w(name));
6854 res = RegDeleteValueW( env, name );
6855 if (res != ERROR_SUCCESS)
6857 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6862 uirow = MSI_CreateRecord( 3 );
6863 MSI_RecordSetStringW( uirow, 1, name );
6864 MSI_RecordSetStringW( uirow, 2, value );
6865 MSI_RecordSetInteger( uirow, 3, action );
6866 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6867 msiobj_release( &uirow->hdr );
6869 if (env) RegCloseKey( env );
6870 msi_free( deformatted );
6874 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6878 static const WCHAR query[] =
6879 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6880 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6882 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6883 if (rc != ERROR_SUCCESS)
6884 return ERROR_SUCCESS;
6886 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6887 msiobj_release( &view->hdr );
6892 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6894 LPWSTR key, template, id;
6895 UINT r = ERROR_SUCCESS;
6897 id = msi_dup_property( package->db, szProductID );
6901 return ERROR_SUCCESS;
6903 template = msi_dup_property( package->db, szPIDTemplate );
6904 key = msi_dup_property( package->db, szPIDKEY );
6906 if (key && template)
6908 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6909 r = msi_set_property( package->db, szProductID, key );
6911 msi_free( template );
6916 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6919 package->need_reboot = 1;
6920 return ERROR_SUCCESS;
6923 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6925 static const WCHAR szAvailableFreeReg[] =
6926 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6928 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6930 TRACE("%p %d kilobytes\n", package, space);
6932 uirow = MSI_CreateRecord( 1 );
6933 MSI_RecordSetInteger( uirow, 1, space );
6934 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6935 msiobj_release( &uirow->hdr );
6937 return ERROR_SUCCESS;
6940 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6942 FIXME("%p\n", package);
6943 return ERROR_SUCCESS;
6946 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6948 FIXME("%p\n", package);
6949 return ERROR_SUCCESS;
6952 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6957 static const WCHAR driver_query[] = {
6958 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6959 'O','D','B','C','D','r','i','v','e','r',0 };
6961 static const WCHAR translator_query[] = {
6962 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6963 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6965 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6966 if (r == ERROR_SUCCESS)
6969 r = MSI_IterateRecords( view, &count, NULL, package );
6970 msiobj_release( &view->hdr );
6971 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6974 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6975 if (r == ERROR_SUCCESS)
6978 r = MSI_IterateRecords( view, &count, NULL, package );
6979 msiobj_release( &view->hdr );
6980 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6983 return ERROR_SUCCESS;
6986 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6988 MSIPACKAGE *package = param;
6989 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6992 if ((value = msi_dup_property( package->db, property )))
6994 FIXME("remove %s\n", debugstr_w(value));
6997 return ERROR_SUCCESS;
7000 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7005 static const WCHAR query[] =
7006 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7007 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7009 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7010 if (r == ERROR_SUCCESS)
7012 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7013 msiobj_release( &view->hdr );
7015 return ERROR_SUCCESS;
7018 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7020 MSIPACKAGE *package = param;
7021 int attributes = MSI_RecordGetInteger( rec, 5 );
7023 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7025 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7026 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7027 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7028 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7032 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7034 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7035 if (r != ERROR_SUCCESS)
7036 return ERROR_SUCCESS;
7040 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7041 if (r != ERROR_SUCCESS)
7042 return ERROR_SUCCESS;
7044 RegCloseKey( hkey );
7046 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7047 debugstr_w(upgrade_code), debugstr_w(version_min),
7048 debugstr_w(version_max), debugstr_w(language));
7050 return ERROR_SUCCESS;
7053 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7058 static const WCHAR query[] =
7059 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7061 if (msi_get_property_int( package->db, szInstalled, 0 ))
7063 TRACE("product is installed, skipping action\n");
7064 return ERROR_SUCCESS;
7066 if (msi_get_property_int( package->db, szPreselected, 0 ))
7068 TRACE("Preselected property is set, not migrating feature states\n");
7069 return ERROR_SUCCESS;
7072 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7073 if (r == ERROR_SUCCESS)
7075 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7076 msiobj_release( &view->hdr );
7078 return ERROR_SUCCESS;
7081 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7082 LPCSTR action, LPCWSTR table )
7084 static const WCHAR query[] = {
7085 'S','E','L','E','C','T',' ','*',' ',
7086 'F','R','O','M',' ','`','%','s','`',0 };
7087 MSIQUERY *view = NULL;
7091 r = MSI_OpenQuery( package->db, &view, query, table );
7092 if (r == ERROR_SUCCESS)
7094 r = MSI_IterateRecords(view, &count, NULL, package);
7095 msiobj_release(&view->hdr);
7099 FIXME("%s -> %u ignored %s table values\n",
7100 action, count, debugstr_w(table));
7102 return ERROR_SUCCESS;
7105 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7107 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7108 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7111 static UINT ACTION_BindImage( MSIPACKAGE *package )
7113 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7114 return msi_unimplemented_action_stub( package, "BindImage", table );
7117 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7119 static const WCHAR table[] = {
7120 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7121 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7124 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7126 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7127 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7130 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7132 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7133 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7136 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7138 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7139 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7142 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7144 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7145 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7148 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7152 const WCHAR *action;
7153 UINT (*handler)(MSIPACKAGE *);
7157 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7158 { szAppSearch, ACTION_AppSearch },
7159 { szBindImage, ACTION_BindImage },
7160 { szCCPSearch, ACTION_CCPSearch },
7161 { szCostFinalize, ACTION_CostFinalize },
7162 { szCostInitialize, ACTION_CostInitialize },
7163 { szCreateFolders, ACTION_CreateFolders },
7164 { szCreateShortcuts, ACTION_CreateShortcuts },
7165 { szDeleteServices, ACTION_DeleteServices },
7166 { szDisableRollback, ACTION_DisableRollback },
7167 { szDuplicateFiles, ACTION_DuplicateFiles },
7168 { szExecuteAction, ACTION_ExecuteAction },
7169 { szFileCost, ACTION_FileCost },
7170 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7171 { szForceReboot, ACTION_ForceReboot },
7172 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7173 { szInstallExecute, ACTION_InstallExecute },
7174 { szInstallExecuteAgain, ACTION_InstallExecute },
7175 { szInstallFiles, ACTION_InstallFiles},
7176 { szInstallFinalize, ACTION_InstallFinalize },
7177 { szInstallInitialize, ACTION_InstallInitialize },
7178 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7179 { szInstallValidate, ACTION_InstallValidate },
7180 { szIsolateComponents, ACTION_IsolateComponents },
7181 { szLaunchConditions, ACTION_LaunchConditions },
7182 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7183 { szMoveFiles, ACTION_MoveFiles },
7184 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7185 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7186 { szInstallODBC, ACTION_InstallODBC },
7187 { szInstallServices, ACTION_InstallServices },
7188 { szPatchFiles, ACTION_PatchFiles },
7189 { szProcessComponents, ACTION_ProcessComponents },
7190 { szPublishComponents, ACTION_PublishComponents },
7191 { szPublishFeatures, ACTION_PublishFeatures },
7192 { szPublishProduct, ACTION_PublishProduct },
7193 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7194 { szRegisterComPlus, ACTION_RegisterComPlus},
7195 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7196 { szRegisterFonts, ACTION_RegisterFonts },
7197 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7198 { szRegisterProduct, ACTION_RegisterProduct },
7199 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7200 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7201 { szRegisterUser, ACTION_RegisterUser },
7202 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7203 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7204 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7205 { szRemoveFiles, ACTION_RemoveFiles },
7206 { szRemoveFolders, ACTION_RemoveFolders },
7207 { szRemoveIniValues, ACTION_RemoveIniValues },
7208 { szRemoveODBC, ACTION_RemoveODBC },
7209 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7210 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7211 { szResolveSource, ACTION_ResolveSource },
7212 { szRMCCPSearch, ACTION_RMCCPSearch },
7213 { szScheduleReboot, ACTION_ScheduleReboot },
7214 { szSelfRegModules, ACTION_SelfRegModules },
7215 { szSelfUnregModules, ACTION_SelfUnregModules },
7216 { szSetODBCFolders, ACTION_SetODBCFolders },
7217 { szStartServices, ACTION_StartServices },
7218 { szStopServices, ACTION_StopServices },
7219 { szUnpublishComponents, ACTION_UnpublishComponents },
7220 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7221 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7222 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7223 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7224 { szUnregisterFonts, ACTION_UnregisterFonts },
7225 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7226 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7227 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7228 { szValidateProductID, ACTION_ValidateProductID },
7229 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7230 { szWriteIniValues, ACTION_WriteIniValues },
7231 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7235 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7241 while (StandardActions[i].action != NULL)
7243 if (!strcmpW( StandardActions[i].action, action ))
7245 ui_actionstart( package, action );
7246 if (StandardActions[i].handler)
7248 ui_actioninfo( package, action, TRUE, 0 );
7249 *rc = StandardActions[i].handler( package );
7250 ui_actioninfo( package, action, FALSE, *rc );
7254 FIXME("unhandled standard action %s\n", debugstr_w(action));
7255 *rc = ERROR_SUCCESS;
7265 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7267 UINT rc = ERROR_SUCCESS;
7270 TRACE("Performing action (%s)\n", debugstr_w(action));
7272 handled = ACTION_HandleStandardAction(package, action, &rc);
7275 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7279 WARN("unhandled msi action %s\n", debugstr_w(action));
7280 rc = ERROR_FUNCTION_NOT_CALLED;
7286 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7288 UINT rc = ERROR_SUCCESS;
7289 BOOL handled = FALSE;
7291 TRACE("Performing action (%s)\n", debugstr_w(action));
7293 handled = ACTION_HandleStandardAction(package, action, &rc);
7296 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7298 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7303 WARN("unhandled msi action %s\n", debugstr_w(action));
7304 rc = ERROR_FUNCTION_NOT_CALLED;
7310 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7312 UINT rc = ERROR_SUCCESS;
7315 static const WCHAR ExecSeqQuery[] =
7316 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7317 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7318 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7319 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7320 static const WCHAR UISeqQuery[] =
7321 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7322 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7323 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7324 ' ', '=',' ','%','i',0};
7326 if (needs_ui_sequence(package))
7327 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7329 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7333 LPCWSTR action, cond;
7335 TRACE("Running the actions\n");
7337 /* check conditions */
7338 cond = MSI_RecordGetString(row, 2);
7340 /* this is a hack to skip errors in the condition code */
7341 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7343 msiobj_release(&row->hdr);
7344 return ERROR_SUCCESS;
7347 action = MSI_RecordGetString(row, 1);
7350 ERR("failed to fetch action\n");
7351 msiobj_release(&row->hdr);
7352 return ERROR_FUNCTION_FAILED;
7355 if (needs_ui_sequence(package))
7356 rc = ACTION_PerformUIAction(package, action, -1);
7358 rc = ACTION_PerformAction(package, action, -1);
7360 msiobj_release(&row->hdr);
7366 /****************************************************
7367 * TOP level entry points
7368 *****************************************************/
7370 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7371 LPCWSTR szCommandLine )
7376 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7377 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7379 msi_set_property( package->db, szAction, szInstall );
7381 package->script->InWhatSequence = SEQUENCE_INSTALL;
7388 dir = strdupW(szPackagePath);
7389 p = strrchrW(dir, '\\');
7393 file = szPackagePath + (p - dir);
7398 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7399 GetCurrentDirectoryW(MAX_PATH, dir);
7400 lstrcatW(dir, szBackSlash);
7401 file = szPackagePath;
7404 msi_free( package->PackagePath );
7405 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7406 if (!package->PackagePath)
7409 return ERROR_OUTOFMEMORY;
7412 lstrcpyW(package->PackagePath, dir);
7413 lstrcatW(package->PackagePath, file);
7416 msi_set_sourcedir_props(package, FALSE);
7419 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7420 if (rc != ERROR_SUCCESS)
7423 msi_apply_transforms( package );
7424 msi_apply_patches( package );
7426 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7428 TRACE("setting reinstall property\n");
7429 msi_set_property( package->db, szReinstall, szAll );
7432 /* properties may have been added by a transform */
7433 msi_clone_properties( package );
7435 msi_parse_command_line( package, szCommandLine, FALSE );
7436 msi_adjust_privilege_properties( package );
7437 msi_set_context( package );
7439 if (needs_ui_sequence( package))
7441 package->script->InWhatSequence |= SEQUENCE_UI;
7442 rc = ACTION_ProcessUISequence(package);
7443 ui_exists = ui_sequence_exists(package);
7444 if (rc == ERROR_SUCCESS || !ui_exists)
7446 package->script->InWhatSequence |= SEQUENCE_EXEC;
7447 rc = ACTION_ProcessExecSequence(package, ui_exists);
7451 rc = ACTION_ProcessExecSequence(package, FALSE);
7453 package->script->CurrentlyScripting = FALSE;
7455 /* process the ending type action */
7456 if (rc == ERROR_SUCCESS)
7457 ACTION_PerformActionSequence(package, -1);
7458 else if (rc == ERROR_INSTALL_USEREXIT)
7459 ACTION_PerformActionSequence(package, -2);
7460 else if (rc == ERROR_INSTALL_SUSPEND)
7461 ACTION_PerformActionSequence(package, -4);
7463 ACTION_PerformActionSequence(package, -3);
7465 /* finish up running custom actions */
7466 ACTION_FinishCustomActions(package);
7468 if (rc == ERROR_SUCCESS && package->need_reboot)
7469 return ERROR_SUCCESS_REBOOT_REQUIRED;