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);
3154 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3156 MSIFEATURE *feature;
3160 /* only refcount DLLs */
3161 if (comp->KeyPath == NULL ||
3163 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3164 comp->Attributes & msidbComponentAttributesODBCDataSource)
3168 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3169 write = (count > 0);
3171 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3175 /* increment counts */
3176 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3180 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3183 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3185 if ( cl->component == comp )
3190 /* decrement counts */
3191 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3195 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3198 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3200 if ( cl->component == comp )
3205 /* ref count all the files in the component */
3210 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3212 if (file->Component == comp)
3213 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3217 /* add a count for permanent */
3218 if (comp->Attributes & msidbComponentAttributesPermanent)
3221 comp->RefCount = count;
3224 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3227 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3229 WCHAR squished_pc[GUID_SIZE];
3230 WCHAR squished_cc[GUID_SIZE];
3237 squash_guid(package->ProductCode,squished_pc);
3238 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3240 msi_set_sourcedir_props(package, FALSE);
3242 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3246 ui_progress(package,2,0,0,0);
3247 if (!comp->ComponentId)
3250 squash_guid(comp->ComponentId,squished_cc);
3252 msi_free(comp->FullKeypath);
3255 const WCHAR prefixW[] = {'<','\\',0};
3256 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3258 comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3259 if (comp->FullKeypath)
3261 strcpyW( comp->FullKeypath, prefixW );
3262 strcatW( comp->FullKeypath, comp->assembly->display_name );
3265 else comp->FullKeypath = resolve_keypath( package, comp );
3267 ACTION_RefCountComponent( package, comp );
3269 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3270 debugstr_w(comp->Component),
3271 debugstr_w(squished_cc),
3272 debugstr_w(comp->FullKeypath),
3274 comp->ActionRequest);
3276 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3277 comp->ActionRequest == INSTALLSTATE_SOURCE)
3279 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3280 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3282 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3284 if (rc != ERROR_SUCCESS)
3287 if (comp->Attributes & msidbComponentAttributesPermanent)
3289 static const WCHAR szPermKey[] =
3290 { '0','0','0','0','0','0','0','0','0','0','0','0',
3291 '0','0','0','0','0','0','0','0','0','0','0','0',
3292 '0','0','0','0','0','0','0','0',0 };
3294 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3297 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3298 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3304 WCHAR source[MAX_PATH];
3305 WCHAR base[MAX_PATH];
3308 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3309 static const WCHAR query[] = {
3310 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3311 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3312 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3313 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3314 '`','D','i','s','k','I','d','`',0};
3316 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3319 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3320 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3321 ptr2 = strrchrW(source, '\\') + 1;
3322 msiobj_release(&row->hdr);
3324 lstrcpyW(base, package->PackagePath);
3325 ptr = strrchrW(base, '\\');
3328 sourcepath = resolve_file_source(package, file);
3329 ptr = sourcepath + lstrlenW(base);
3330 lstrcpyW(ptr2, ptr);
3331 msi_free(sourcepath);
3333 msi_reg_set_val_str(hkey, squished_pc, source);
3337 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3339 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3340 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3342 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3344 comp->Action = comp->ActionRequest;
3347 uirow = MSI_CreateRecord(3);
3348 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3349 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3350 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3351 ui_actiondata(package,szProcessComponents,uirow);
3352 msiobj_release( &uirow->hdr );
3355 return ERROR_SUCCESS;
3366 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3367 LPWSTR lpszName, LONG_PTR lParam)
3370 typelib_struct *tl_struct = (typelib_struct*) lParam;
3371 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3375 if (!IS_INTRESOURCE(lpszName))
3377 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3381 sz = strlenW(tl_struct->source)+4;
3382 sz *= sizeof(WCHAR);
3384 if ((INT_PTR)lpszName == 1)
3385 tl_struct->path = strdupW(tl_struct->source);
3388 tl_struct->path = msi_alloc(sz);
3389 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3392 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3393 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3396 msi_free(tl_struct->path);
3397 tl_struct->path = NULL;
3402 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3403 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3405 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3409 msi_free(tl_struct->path);
3410 tl_struct->path = NULL;
3412 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3413 ITypeLib_Release(tl_struct->ptLib);
3418 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3420 MSIPACKAGE* package = param;
3424 typelib_struct tl_struct;
3429 component = MSI_RecordGetString(row,3);
3430 comp = get_loaded_component(package,component);
3432 return ERROR_SUCCESS;
3436 TRACE("component is disabled\n");
3437 return ERROR_SUCCESS;
3440 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3442 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3443 comp->Action = comp->Installed;
3444 return ERROR_SUCCESS;
3446 comp->Action = INSTALLSTATE_LOCAL;
3448 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3450 TRACE("component has no key path\n");
3451 return ERROR_SUCCESS;
3453 ui_actiondata( package, szRegisterTypeLibraries, row );
3455 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3459 guid = MSI_RecordGetString(row,1);
3460 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3461 tl_struct.source = strdupW( file->TargetPath );
3462 tl_struct.path = NULL;
3464 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3465 (LONG_PTR)&tl_struct);
3473 helpid = MSI_RecordGetString(row,6);
3475 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3476 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3480 ERR("Failed to register type library %s\n",
3481 debugstr_w(tl_struct.path));
3483 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3485 ITypeLib_Release(tl_struct.ptLib);
3486 msi_free(tl_struct.path);
3489 ERR("Failed to load type library %s\n",
3490 debugstr_w(tl_struct.source));
3492 FreeLibrary(module);
3493 msi_free(tl_struct.source);
3497 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3500 ERR("Failed to load type library: %08x\n", hr);
3501 return ERROR_INSTALL_FAILURE;
3504 ITypeLib_Release(tlib);
3507 return ERROR_SUCCESS;
3510 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3513 * OK this is a bit confusing.. I am given a _Component key and I believe
3514 * that the file that is being registered as a type library is the "key file
3515 * of that component" which I interpret to mean "The file in the KeyPath of
3520 static const WCHAR Query[] =
3521 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3522 '`','T','y','p','e','L','i','b','`',0};
3524 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3525 if (rc != ERROR_SUCCESS)
3526 return ERROR_SUCCESS;
3528 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3529 msiobj_release(&view->hdr);
3533 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3535 MSIPACKAGE *package = param;
3536 LPCWSTR component, guid;
3544 component = MSI_RecordGetString( row, 3 );
3545 comp = get_loaded_component( package, component );
3547 return ERROR_SUCCESS;
3551 TRACE("component is disabled\n");
3552 return ERROR_SUCCESS;
3555 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3557 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3558 comp->Action = comp->Installed;
3559 return ERROR_SUCCESS;
3561 comp->Action = INSTALLSTATE_ABSENT;
3563 ui_actiondata( package, szUnregisterTypeLibraries, row );
3565 guid = MSI_RecordGetString( row, 1 );
3566 CLSIDFromString( (LPCWSTR)guid, &libid );
3567 version = MSI_RecordGetInteger( row, 4 );
3568 language = MSI_RecordGetInteger( row, 2 );
3571 syskind = SYS_WIN64;
3573 syskind = SYS_WIN32;
3576 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3579 WARN("Failed to unregister typelib: %08x\n", hr);
3582 return ERROR_SUCCESS;
3585 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3589 static const WCHAR query[] =
3590 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3591 '`','T','y','p','e','L','i','b','`',0};
3593 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3594 if (rc != ERROR_SUCCESS)
3595 return ERROR_SUCCESS;
3597 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3598 msiobj_release( &view->hdr );
3602 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3604 static const WCHAR szlnk[] = {'.','l','n','k',0};
3605 LPCWSTR directory, extension;
3606 LPWSTR link_folder, link_file, filename;
3608 directory = MSI_RecordGetString( row, 2 );
3609 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3611 /* may be needed because of a bug somewhere else */
3612 create_full_pathW( link_folder );
3614 filename = msi_dup_record_field( row, 3 );
3615 reduce_to_longfilename( filename );
3617 extension = strchrW( filename, '.' );
3618 if (!extension || strcmpiW( extension, szlnk ))
3620 int len = strlenW( filename );
3621 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3622 memcpy( filename + len, szlnk, sizeof(szlnk) );
3624 link_file = build_directory_name( 2, link_folder, filename );
3625 msi_free( link_folder );
3626 msi_free( filename );
3631 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3633 MSIPACKAGE *package = param;
3634 LPWSTR link_file, deformated, path;
3635 LPCWSTR component, target;
3637 IShellLinkW *sl = NULL;
3638 IPersistFile *pf = NULL;
3641 component = MSI_RecordGetString(row, 4);
3642 comp = get_loaded_component(package, component);
3644 return ERROR_SUCCESS;
3648 TRACE("component is disabled\n");
3649 return ERROR_SUCCESS;
3652 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3654 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3655 comp->Action = comp->Installed;
3656 return ERROR_SUCCESS;
3658 comp->Action = INSTALLSTATE_LOCAL;
3660 ui_actiondata(package,szCreateShortcuts,row);
3662 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3663 &IID_IShellLinkW, (LPVOID *) &sl );
3667 ERR("CLSID_ShellLink not available\n");
3671 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3674 ERR("QueryInterface(IID_IPersistFile) failed\n");
3678 target = MSI_RecordGetString(row, 5);
3679 if (strchrW(target, '['))
3681 deformat_string(package, target, &deformated);
3682 IShellLinkW_SetPath(sl,deformated);
3683 msi_free(deformated);
3687 FIXME("poorly handled shortcut format, advertised shortcut\n");
3688 IShellLinkW_SetPath(sl,comp->FullKeypath);
3691 if (!MSI_RecordIsNull(row,6))
3693 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3694 deformat_string(package, arguments, &deformated);
3695 IShellLinkW_SetArguments(sl,deformated);
3696 msi_free(deformated);
3699 if (!MSI_RecordIsNull(row,7))
3701 LPCWSTR description = MSI_RecordGetString(row, 7);
3702 IShellLinkW_SetDescription(sl, description);
3705 if (!MSI_RecordIsNull(row,8))
3706 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3708 if (!MSI_RecordIsNull(row,9))
3711 LPCWSTR icon = MSI_RecordGetString(row, 9);
3713 path = build_icon_path(package, icon);
3714 index = MSI_RecordGetInteger(row,10);
3716 /* no value means 0 */
3717 if (index == MSI_NULL_INTEGER)
3720 IShellLinkW_SetIconLocation(sl, path, index);
3724 if (!MSI_RecordIsNull(row,11))
3725 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3727 if (!MSI_RecordIsNull(row,12))
3729 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3730 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
3732 IShellLinkW_SetWorkingDirectory(sl, path);
3736 link_file = get_link_file(package, row);
3738 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3739 IPersistFile_Save(pf, link_file, FALSE);
3741 msi_free(link_file);
3745 IPersistFile_Release( pf );
3747 IShellLinkW_Release( sl );
3749 return ERROR_SUCCESS;
3752 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3757 static const WCHAR Query[] =
3758 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3759 '`','S','h','o','r','t','c','u','t','`',0};
3761 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3762 if (rc != ERROR_SUCCESS)
3763 return ERROR_SUCCESS;
3765 res = CoInitialize( NULL );
3767 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3768 msiobj_release(&view->hdr);
3776 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3778 MSIPACKAGE *package = param;
3783 component = MSI_RecordGetString( row, 4 );
3784 comp = get_loaded_component( package, component );
3786 return ERROR_SUCCESS;
3790 TRACE("component is disabled\n");
3791 return ERROR_SUCCESS;
3794 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3796 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3797 comp->Action = comp->Installed;
3798 return ERROR_SUCCESS;
3800 comp->Action = INSTALLSTATE_ABSENT;
3802 ui_actiondata( package, szRemoveShortcuts, row );
3804 link_file = get_link_file( package, row );
3806 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3807 if (!DeleteFileW( link_file ))
3809 WARN("Failed to remove shortcut file %u\n", GetLastError());
3811 msi_free( link_file );
3813 return ERROR_SUCCESS;
3816 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3820 static const WCHAR query[] =
3821 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3822 '`','S','h','o','r','t','c','u','t','`',0};
3824 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3825 if (rc != ERROR_SUCCESS)
3826 return ERROR_SUCCESS;
3828 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3829 msiobj_release( &view->hdr );
3834 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3836 MSIPACKAGE* package = param;
3844 FileName = MSI_RecordGetString(row,1);
3847 ERR("Unable to get FileName\n");
3848 return ERROR_SUCCESS;
3851 FilePath = build_icon_path(package,FileName);
3853 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3855 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3856 FILE_ATTRIBUTE_NORMAL, NULL);
3858 if (the_file == INVALID_HANDLE_VALUE)
3860 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3862 return ERROR_SUCCESS;
3869 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3870 if (rc != ERROR_SUCCESS)
3872 ERR("Failed to get stream\n");
3873 CloseHandle(the_file);
3874 DeleteFileW(FilePath);
3877 WriteFile(the_file,buffer,sz,&write,NULL);
3878 } while (sz == 1024);
3881 CloseHandle(the_file);
3883 return ERROR_SUCCESS;
3886 static UINT msi_publish_icons(MSIPACKAGE *package)
3891 static const WCHAR query[]= {
3892 'S','E','L','E','C','T',' ','*',' ',
3893 'F','R','O','M',' ','`','I','c','o','n','`',0};
3895 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3896 if (r == ERROR_SUCCESS)
3898 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3899 msiobj_release(&view->hdr);
3902 return ERROR_SUCCESS;
3905 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3911 MSISOURCELISTINFO *info;
3913 r = RegCreateKeyW(hkey, szSourceList, &source);
3914 if (r != ERROR_SUCCESS)
3917 RegCloseKey(source);
3919 buffer = strrchrW(package->PackagePath, '\\') + 1;
3920 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3921 package->Context, MSICODE_PRODUCT,
3922 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3923 if (r != ERROR_SUCCESS)
3926 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3927 package->Context, MSICODE_PRODUCT,
3928 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3929 if (r != ERROR_SUCCESS)
3932 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3933 package->Context, MSICODE_PRODUCT,
3934 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3935 if (r != ERROR_SUCCESS)
3938 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3940 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3941 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3942 info->options, info->value);
3944 MsiSourceListSetInfoW(package->ProductCode, NULL,
3945 info->context, info->options,
3946 info->property, info->value);
3949 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3951 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3952 disk->context, disk->options,
3953 disk->disk_id, disk->volume_label, disk->disk_prompt);
3956 return ERROR_SUCCESS;
3959 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3961 MSIHANDLE hdb, suminfo;
3962 WCHAR guids[MAX_PATH];
3963 WCHAR packcode[SQUISH_GUID_SIZE];
3970 static const WCHAR szProductLanguage[] =
3971 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3972 static const WCHAR szARPProductIcon[] =
3973 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3974 static const WCHAR szProductVersion[] =
3975 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3976 static const WCHAR szAssignment[] =
3977 {'A','s','s','i','g','n','m','e','n','t',0};
3978 static const WCHAR szAdvertiseFlags[] =
3979 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3980 static const WCHAR szClients[] =
3981 {'C','l','i','e','n','t','s',0};
3982 static const WCHAR szColon[] = {':',0};
3984 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3985 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3988 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3989 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3992 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3994 buffer = msi_dup_property(package->db, szARPProductIcon);
3997 LPWSTR path = build_icon_path(package,buffer);
3998 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4003 buffer = msi_dup_property(package->db, szProductVersion);
4006 DWORD verdword = msi_version_str_to_dword(buffer);
4007 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4011 msi_reg_set_val_dword(hkey, szAssignment, 0);
4012 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4013 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4014 msi_reg_set_val_str(hkey, szClients, szColon);
4016 hdb = alloc_msihandle(&package->db->hdr);
4018 return ERROR_NOT_ENOUGH_MEMORY;
4020 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4021 MsiCloseHandle(hdb);
4022 if (r != ERROR_SUCCESS)
4026 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4027 NULL, guids, &size);
4028 if (r != ERROR_SUCCESS)
4031 ptr = strchrW(guids, ';');
4033 squash_guid(guids, packcode);
4034 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4037 MsiCloseHandle(suminfo);
4038 return ERROR_SUCCESS;
4041 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4046 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4048 upgrade = msi_dup_property(package->db, szUpgradeCode);
4050 return ERROR_SUCCESS;
4052 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4054 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4055 if (r != ERROR_SUCCESS)
4060 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4061 if (r != ERROR_SUCCESS)
4065 squash_guid(package->ProductCode, squashed_pc);
4066 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4075 static BOOL msi_check_publish(MSIPACKAGE *package)
4077 MSIFEATURE *feature;
4079 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4081 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4088 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4090 MSIFEATURE *feature;
4092 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4094 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4101 static UINT msi_publish_patches( MSIPACKAGE *package )
4103 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4104 WCHAR patch_squashed[GUID_SIZE];
4105 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4107 MSIPATCHINFO *patch;
4109 WCHAR *p, *all_patches = NULL;
4112 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4113 if (r != ERROR_SUCCESS)
4114 return ERROR_FUNCTION_FAILED;
4116 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4117 if (res != ERROR_SUCCESS)
4119 r = ERROR_FUNCTION_FAILED;
4123 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4124 if (r != ERROR_SUCCESS)
4127 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4129 squash_guid( patch->patchcode, patch_squashed );
4130 len += strlenW( patch_squashed ) + 1;
4133 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4137 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4141 squash_guid( patch->patchcode, p );
4142 p += strlenW( p ) + 1;
4144 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4145 (const BYTE *)patch->transforms,
4146 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4147 if (res != ERROR_SUCCESS)
4150 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4151 if (r != ERROR_SUCCESS)
4154 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4155 (const BYTE *)patch->localfile,
4156 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4157 RegCloseKey( patch_key );
4158 if (res != ERROR_SUCCESS)
4161 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4162 if (res != ERROR_SUCCESS)
4165 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4166 RegCloseKey( patch_key );
4167 if (res != ERROR_SUCCESS)
4171 all_patches[len] = 0;
4172 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4173 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4174 if (res != ERROR_SUCCESS)
4177 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4178 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4179 if (res != ERROR_SUCCESS)
4180 r = ERROR_FUNCTION_FAILED;
4183 RegCloseKey( product_patches_key );
4184 RegCloseKey( patches_key );
4185 RegCloseKey( product_key );
4186 msi_free( all_patches );
4191 * 99% of the work done here is only done for
4192 * advertised installs. However this is where the
4193 * Icon table is processed and written out
4194 * so that is what I am going to do here.
4196 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4199 HKEY hukey = NULL, hudkey = NULL;
4202 if (!list_empty(&package->patches))
4204 rc = msi_publish_patches(package);
4205 if (rc != ERROR_SUCCESS)
4209 /* FIXME: also need to publish if the product is in advertise mode */
4210 if (!msi_check_publish(package))
4211 return ERROR_SUCCESS;
4213 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4215 if (rc != ERROR_SUCCESS)
4218 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4219 NULL, &hudkey, TRUE);
4220 if (rc != ERROR_SUCCESS)
4223 rc = msi_publish_upgrade_code(package);
4224 if (rc != ERROR_SUCCESS)
4227 rc = msi_publish_product_properties(package, hukey);
4228 if (rc != ERROR_SUCCESS)
4231 rc = msi_publish_sourcelist(package, hukey);
4232 if (rc != ERROR_SUCCESS)
4235 rc = msi_publish_icons(package);
4238 uirow = MSI_CreateRecord( 1 );
4239 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4240 ui_actiondata( package, szPublishProduct, uirow );
4241 msiobj_release( &uirow->hdr );
4244 RegCloseKey(hudkey);
4249 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4251 WCHAR *filename, *ptr, *folder, *ret;
4252 const WCHAR *dirprop;
4254 filename = msi_dup_record_field( row, 2 );
4255 if (filename && (ptr = strchrW( filename, '|' )))
4260 dirprop = MSI_RecordGetString( row, 3 );
4263 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4265 folder = msi_dup_property( package->db, dirprop );
4268 folder = msi_dup_property( package->db, szWindowsFolder );
4272 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4273 msi_free( filename );
4277 ret = build_directory_name( 2, folder, ptr );
4279 msi_free( filename );
4284 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4286 MSIPACKAGE *package = param;
4287 LPCWSTR component, section, key, value, identifier;
4288 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4293 component = MSI_RecordGetString(row, 8);
4294 comp = get_loaded_component(package,component);
4296 return ERROR_SUCCESS;
4300 TRACE("component is disabled\n");
4301 return ERROR_SUCCESS;
4304 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4306 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4307 comp->Action = comp->Installed;
4308 return ERROR_SUCCESS;
4310 comp->Action = INSTALLSTATE_LOCAL;
4312 identifier = MSI_RecordGetString(row,1);
4313 section = MSI_RecordGetString(row,4);
4314 key = MSI_RecordGetString(row,5);
4315 value = MSI_RecordGetString(row,6);
4316 action = MSI_RecordGetInteger(row,7);
4318 deformat_string(package,section,&deformated_section);
4319 deformat_string(package,key,&deformated_key);
4320 deformat_string(package,value,&deformated_value);
4322 fullname = get_ini_file_name(package, row);
4326 TRACE("Adding value %s to section %s in %s\n",
4327 debugstr_w(deformated_key), debugstr_w(deformated_section),
4328 debugstr_w(fullname));
4329 WritePrivateProfileStringW(deformated_section, deformated_key,
4330 deformated_value, fullname);
4332 else if (action == 1)
4335 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4336 returned, 10, fullname);
4337 if (returned[0] == 0)
4339 TRACE("Adding value %s to section %s in %s\n",
4340 debugstr_w(deformated_key), debugstr_w(deformated_section),
4341 debugstr_w(fullname));
4343 WritePrivateProfileStringW(deformated_section, deformated_key,
4344 deformated_value, fullname);
4347 else if (action == 3)
4348 FIXME("Append to existing section not yet implemented\n");
4350 uirow = MSI_CreateRecord(4);
4351 MSI_RecordSetStringW(uirow,1,identifier);
4352 MSI_RecordSetStringW(uirow,2,deformated_section);
4353 MSI_RecordSetStringW(uirow,3,deformated_key);
4354 MSI_RecordSetStringW(uirow,4,deformated_value);
4355 ui_actiondata(package,szWriteIniValues,uirow);
4356 msiobj_release( &uirow->hdr );
4359 msi_free(deformated_key);
4360 msi_free(deformated_value);
4361 msi_free(deformated_section);
4362 return ERROR_SUCCESS;
4365 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4369 static const WCHAR ExecSeqQuery[] =
4370 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4371 '`','I','n','i','F','i','l','e','`',0};
4373 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4374 if (rc != ERROR_SUCCESS)
4376 TRACE("no IniFile table\n");
4377 return ERROR_SUCCESS;
4380 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4381 msiobj_release(&view->hdr);
4385 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4387 MSIPACKAGE *package = param;
4388 LPCWSTR component, section, key, value, identifier;
4389 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4394 component = MSI_RecordGetString( row, 8 );
4395 comp = get_loaded_component( package, component );
4397 return ERROR_SUCCESS;
4401 TRACE("component is disabled\n");
4402 return ERROR_SUCCESS;
4405 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4407 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4408 comp->Action = comp->Installed;
4409 return ERROR_SUCCESS;
4411 comp->Action = INSTALLSTATE_ABSENT;
4413 identifier = MSI_RecordGetString( row, 1 );
4414 section = MSI_RecordGetString( row, 4 );
4415 key = MSI_RecordGetString( row, 5 );
4416 value = MSI_RecordGetString( row, 6 );
4417 action = MSI_RecordGetInteger( row, 7 );
4419 deformat_string( package, section, &deformated_section );
4420 deformat_string( package, key, &deformated_key );
4421 deformat_string( package, value, &deformated_value );
4423 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4425 filename = get_ini_file_name( package, row );
4427 TRACE("Removing key %s from section %s in %s\n",
4428 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4430 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4432 WARN("Unable to remove key %u\n", GetLastError());
4434 msi_free( filename );
4437 FIXME("Unsupported action %d\n", action);
4440 uirow = MSI_CreateRecord( 4 );
4441 MSI_RecordSetStringW( uirow, 1, identifier );
4442 MSI_RecordSetStringW( uirow, 2, deformated_section );
4443 MSI_RecordSetStringW( uirow, 3, deformated_key );
4444 MSI_RecordSetStringW( uirow, 4, deformated_value );
4445 ui_actiondata( package, szRemoveIniValues, uirow );
4446 msiobj_release( &uirow->hdr );
4448 msi_free( deformated_key );
4449 msi_free( deformated_value );
4450 msi_free( deformated_section );
4451 return ERROR_SUCCESS;
4454 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4456 MSIPACKAGE *package = param;
4457 LPCWSTR component, section, key, value, identifier;
4458 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4463 component = MSI_RecordGetString( row, 8 );
4464 comp = get_loaded_component( package, component );
4466 return ERROR_SUCCESS;
4470 TRACE("component is disabled\n");
4471 return ERROR_SUCCESS;
4474 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4476 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4477 comp->Action = comp->Installed;
4478 return ERROR_SUCCESS;
4480 comp->Action = INSTALLSTATE_LOCAL;
4482 identifier = MSI_RecordGetString( row, 1 );
4483 section = MSI_RecordGetString( row, 4 );
4484 key = MSI_RecordGetString( row, 5 );
4485 value = MSI_RecordGetString( row, 6 );
4486 action = MSI_RecordGetInteger( row, 7 );
4488 deformat_string( package, section, &deformated_section );
4489 deformat_string( package, key, &deformated_key );
4490 deformat_string( package, value, &deformated_value );
4492 if (action == msidbIniFileActionRemoveLine)
4494 filename = get_ini_file_name( package, row );
4496 TRACE("Removing key %s from section %s in %s\n",
4497 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4499 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4501 WARN("Unable to remove key %u\n", GetLastError());
4503 msi_free( filename );
4506 FIXME("Unsupported action %d\n", action);
4508 uirow = MSI_CreateRecord( 4 );
4509 MSI_RecordSetStringW( uirow, 1, identifier );
4510 MSI_RecordSetStringW( uirow, 2, deformated_section );
4511 MSI_RecordSetStringW( uirow, 3, deformated_key );
4512 MSI_RecordSetStringW( uirow, 4, deformated_value );
4513 ui_actiondata( package, szRemoveIniValues, uirow );
4514 msiobj_release( &uirow->hdr );
4516 msi_free( deformated_key );
4517 msi_free( deformated_value );
4518 msi_free( deformated_section );
4519 return ERROR_SUCCESS;
4522 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4526 static const WCHAR query[] =
4527 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4528 '`','I','n','i','F','i','l','e','`',0};
4529 static const WCHAR remove_query[] =
4530 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4531 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4533 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4534 if (rc == ERROR_SUCCESS)
4536 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4537 msiobj_release( &view->hdr );
4538 if (rc != ERROR_SUCCESS)
4542 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4543 if (rc == ERROR_SUCCESS)
4545 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4546 msiobj_release( &view->hdr );
4547 if (rc != ERROR_SUCCESS)
4551 return ERROR_SUCCESS;
4554 static void register_dll( const WCHAR *dll, BOOL unregister )
4558 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4561 HRESULT (WINAPI *func_ptr)( void );
4562 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4564 func_ptr = (void *)GetProcAddress( hmod, func );
4567 HRESULT hr = func_ptr();
4569 WARN("failed to register dll 0x%08x\n", hr);
4572 WARN("entry point %s not found\n", func);
4573 FreeLibrary( hmod );
4576 WARN("failed to load library %u\n", GetLastError());
4579 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4581 MSIPACKAGE *package = param;
4586 filename = MSI_RecordGetString(row,1);
4587 file = get_loaded_file( package, filename );
4591 ERR("Unable to find file id %s\n",debugstr_w(filename));
4592 return ERROR_SUCCESS;
4595 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4597 register_dll( file->TargetPath, FALSE );
4599 uirow = MSI_CreateRecord( 2 );
4600 MSI_RecordSetStringW( uirow, 1, filename );
4601 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4602 ui_actiondata( package, szSelfRegModules, uirow );
4603 msiobj_release( &uirow->hdr );
4605 return ERROR_SUCCESS;
4608 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4612 static const WCHAR ExecSeqQuery[] =
4613 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4614 '`','S','e','l','f','R','e','g','`',0};
4616 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4617 if (rc != ERROR_SUCCESS)
4619 TRACE("no SelfReg table\n");
4620 return ERROR_SUCCESS;
4623 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4624 msiobj_release(&view->hdr);
4626 return ERROR_SUCCESS;
4629 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4631 MSIPACKAGE *package = param;
4636 filename = MSI_RecordGetString( row, 1 );
4637 file = get_loaded_file( package, filename );
4641 ERR("Unable to find file id %s\n", debugstr_w(filename));
4642 return ERROR_SUCCESS;
4645 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4647 register_dll( file->TargetPath, TRUE );
4649 uirow = MSI_CreateRecord( 2 );
4650 MSI_RecordSetStringW( uirow, 1, filename );
4651 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4652 ui_actiondata( package, szSelfUnregModules, uirow );
4653 msiobj_release( &uirow->hdr );
4655 return ERROR_SUCCESS;
4658 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4662 static const WCHAR query[] =
4663 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4664 '`','S','e','l','f','R','e','g','`',0};
4666 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4667 if (rc != ERROR_SUCCESS)
4669 TRACE("no SelfReg table\n");
4670 return ERROR_SUCCESS;
4673 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4674 msiobj_release( &view->hdr );
4676 return ERROR_SUCCESS;
4679 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4681 MSIFEATURE *feature;
4683 HKEY hkey = NULL, userdata = NULL;
4685 if (!msi_check_publish(package))
4686 return ERROR_SUCCESS;
4688 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4690 if (rc != ERROR_SUCCESS)
4693 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4695 if (rc != ERROR_SUCCESS)
4698 /* here the guids are base 85 encoded */
4699 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4705 BOOL absent = FALSE;
4708 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4709 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4710 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4713 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4717 if (feature->Feature_Parent)
4718 size += strlenW( feature->Feature_Parent )+2;
4720 data = msi_alloc(size * sizeof(WCHAR));
4723 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4725 MSICOMPONENT* component = cl->component;
4729 if (component->ComponentId)
4731 TRACE("From %s\n",debugstr_w(component->ComponentId));
4732 CLSIDFromString(component->ComponentId, &clsid);
4733 encode_base85_guid(&clsid,buf);
4734 TRACE("to %s\n",debugstr_w(buf));
4739 if (feature->Feature_Parent)
4741 static const WCHAR sep[] = {'\2',0};
4743 strcatW(data,feature->Feature_Parent);
4746 msi_reg_set_val_str( userdata, feature->Feature, data );
4750 if (feature->Feature_Parent)
4751 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4754 size += sizeof(WCHAR);
4755 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4756 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4760 size += 2*sizeof(WCHAR);
4761 data = msi_alloc(size);
4764 if (feature->Feature_Parent)
4765 strcpyW( &data[1], feature->Feature_Parent );
4766 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4772 uirow = MSI_CreateRecord( 1 );
4773 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4774 ui_actiondata( package, szPublishFeatures, uirow);
4775 msiobj_release( &uirow->hdr );
4776 /* FIXME: call ui_progress? */
4781 RegCloseKey(userdata);
4785 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4791 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4793 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4795 if (r == ERROR_SUCCESS)
4797 RegDeleteValueW(hkey, feature->Feature);
4801 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4803 if (r == ERROR_SUCCESS)
4805 RegDeleteValueW(hkey, feature->Feature);
4809 uirow = MSI_CreateRecord( 1 );
4810 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4811 ui_actiondata( package, szUnpublishFeatures, uirow );
4812 msiobj_release( &uirow->hdr );
4814 return ERROR_SUCCESS;
4817 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4819 MSIFEATURE *feature;
4821 if (!msi_check_unpublish(package))
4822 return ERROR_SUCCESS;
4824 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4826 msi_unpublish_feature(package, feature);
4829 return ERROR_SUCCESS;
4832 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4836 WCHAR date[9], *val, *buffer;
4837 const WCHAR *prop, *key;
4839 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4840 static const WCHAR szWindowsInstaller[] =
4841 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4842 static const WCHAR modpath_fmt[] =
4843 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4844 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4845 static const WCHAR szModifyPath[] =
4846 {'M','o','d','i','f','y','P','a','t','h',0};
4847 static const WCHAR szUninstallString[] =
4848 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4849 static const WCHAR szEstimatedSize[] =
4850 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4851 static const WCHAR szProductLanguage[] =
4852 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4853 static const WCHAR szProductVersion[] =
4854 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4855 static const WCHAR szDisplayVersion[] =
4856 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4857 static const WCHAR szInstallSource[] =
4858 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4859 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4860 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4861 static const WCHAR szAuthorizedCDFPrefix[] =
4862 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4863 static const WCHAR szARPCONTACT[] =
4864 {'A','R','P','C','O','N','T','A','C','T',0};
4865 static const WCHAR szContact[] =
4866 {'C','o','n','t','a','c','t',0};
4867 static const WCHAR szARPCOMMENTS[] =
4868 {'A','R','P','C','O','M','M','E','N','T','S',0};
4869 static const WCHAR szComments[] =
4870 {'C','o','m','m','e','n','t','s',0};
4871 static const WCHAR szProductName[] =
4872 {'P','r','o','d','u','c','t','N','a','m','e',0};
4873 static const WCHAR szDisplayName[] =
4874 {'D','i','s','p','l','a','y','N','a','m','e',0};
4875 static const WCHAR szARPHELPLINK[] =
4876 {'A','R','P','H','E','L','P','L','I','N','K',0};
4877 static const WCHAR szHelpLink[] =
4878 {'H','e','l','p','L','i','n','k',0};
4879 static const WCHAR szARPHELPTELEPHONE[] =
4880 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4881 static const WCHAR szHelpTelephone[] =
4882 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4883 static const WCHAR szARPINSTALLLOCATION[] =
4884 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4885 static const WCHAR szInstallLocation[] =
4886 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4887 static const WCHAR szManufacturer[] =
4888 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4889 static const WCHAR szPublisher[] =
4890 {'P','u','b','l','i','s','h','e','r',0};
4891 static const WCHAR szARPREADME[] =
4892 {'A','R','P','R','E','A','D','M','E',0};
4893 static const WCHAR szReadme[] =
4894 {'R','e','a','d','M','e',0};
4895 static const WCHAR szARPSIZE[] =
4896 {'A','R','P','S','I','Z','E',0};
4897 static const WCHAR szSize[] =
4898 {'S','i','z','e',0};
4899 static const WCHAR szARPURLINFOABOUT[] =
4900 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4901 static const WCHAR szURLInfoAbout[] =
4902 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4903 static const WCHAR szARPURLUPDATEINFO[] =
4904 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4905 static const WCHAR szURLUpdateInfo[] =
4906 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4908 static const WCHAR *propval[] = {
4909 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4910 szARPCONTACT, szContact,
4911 szARPCOMMENTS, szComments,
4912 szProductName, szDisplayName,
4913 szARPHELPLINK, szHelpLink,
4914 szARPHELPTELEPHONE, szHelpTelephone,
4915 szARPINSTALLLOCATION, szInstallLocation,
4916 cszSourceDir, szInstallSource,
4917 szManufacturer, szPublisher,
4918 szARPREADME, szReadme,
4920 szARPURLINFOABOUT, szURLInfoAbout,
4921 szARPURLUPDATEINFO, szURLUpdateInfo,
4924 const WCHAR **p = propval;
4930 val = msi_dup_property(package->db, prop);
4931 msi_reg_set_val_str(hkey, key, val);
4935 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4937 size = deformat_string(package, modpath_fmt, &buffer);
4938 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4939 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4942 /* FIXME: Write real Estimated Size when we have it */
4943 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4945 GetLocalTime(&systime);
4946 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4947 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4949 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4950 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4952 buffer = msi_dup_property(package->db, szProductVersion);
4953 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4956 DWORD verdword = msi_version_str_to_dword(buffer);
4958 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4959 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4960 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4964 return ERROR_SUCCESS;
4967 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4969 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4971 LPWSTR upgrade_code;
4976 /* FIXME: also need to publish if the product is in advertise mode */
4977 if (!msi_check_publish(package))
4978 return ERROR_SUCCESS;
4980 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4981 if (rc != ERROR_SUCCESS)
4984 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4985 NULL, &props, TRUE);
4986 if (rc != ERROR_SUCCESS)
4989 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4990 msi_free( package->db->localfile );
4991 package->db->localfile = NULL;
4993 rc = msi_publish_install_properties(package, hkey);
4994 if (rc != ERROR_SUCCESS)
4997 rc = msi_publish_install_properties(package, props);
4998 if (rc != ERROR_SUCCESS)
5001 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5004 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5005 squash_guid(package->ProductCode, squashed_pc);
5006 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5007 RegCloseKey(upgrade);
5008 msi_free(upgrade_code);
5012 uirow = MSI_CreateRecord( 1 );
5013 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5014 ui_actiondata( package, szRegisterProduct, uirow );
5015 msiobj_release( &uirow->hdr );
5018 return ERROR_SUCCESS;
5021 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5023 return execute_script(package,INSTALL_SCRIPT);
5026 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5028 WCHAR *upgrade, **features;
5029 BOOL full_uninstall = TRUE;
5030 MSIFEATURE *feature;
5031 MSIPATCHINFO *patch;
5033 static const WCHAR szUpgradeCode[] =
5034 {'U','p','g','r','a','d','e','C','o','d','e',0};
5036 features = msi_split_string(remove, ',');
5039 ERR("REMOVE feature list is empty!\n");
5040 return ERROR_FUNCTION_FAILED;
5043 if (!strcmpW( features[0], szAll ))
5044 full_uninstall = TRUE;
5047 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5049 if (feature->Action != INSTALLSTATE_ABSENT)
5050 full_uninstall = FALSE;
5055 if (!full_uninstall)
5056 return ERROR_SUCCESS;
5058 MSIREG_DeleteProductKey(package->ProductCode);
5059 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5060 MSIREG_DeleteUninstallKey(package);
5062 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5063 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5064 MSIREG_DeleteUserProductKey(package->ProductCode);
5065 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5067 upgrade = msi_dup_property(package->db, szUpgradeCode);
5070 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5071 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5075 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5077 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5080 return ERROR_SUCCESS;
5083 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5088 /* turn off scheduling */
5089 package->script->CurrentlyScripting= FALSE;
5091 /* first do the same as an InstallExecute */
5092 rc = ACTION_InstallExecute(package);
5093 if (rc != ERROR_SUCCESS)
5096 /* then handle Commit Actions */
5097 rc = execute_script(package,COMMIT_SCRIPT);
5098 if (rc != ERROR_SUCCESS)
5101 remove = msi_dup_property(package->db, szRemove);
5103 rc = msi_unpublish_product(package, remove);
5109 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5111 static const WCHAR RunOnce[] = {
5112 'S','o','f','t','w','a','r','e','\\',
5113 'M','i','c','r','o','s','o','f','t','\\',
5114 'W','i','n','d','o','w','s','\\',
5115 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5116 'R','u','n','O','n','c','e',0};
5117 static const WCHAR InstallRunOnce[] = {
5118 'S','o','f','t','w','a','r','e','\\',
5119 'M','i','c','r','o','s','o','f','t','\\',
5120 'W','i','n','d','o','w','s','\\',
5121 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5122 'I','n','s','t','a','l','l','e','r','\\',
5123 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5125 static const WCHAR msiexec_fmt[] = {
5127 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5128 '\"','%','s','\"',0};
5129 static const WCHAR install_fmt[] = {
5130 '/','I',' ','\"','%','s','\"',' ',
5131 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5132 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5133 WCHAR buffer[256], sysdir[MAX_PATH];
5135 WCHAR squished_pc[100];
5137 squash_guid(package->ProductCode,squished_pc);
5139 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5140 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5141 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5144 msi_reg_set_val_str( hkey, squished_pc, buffer );
5147 TRACE("Reboot command %s\n",debugstr_w(buffer));
5149 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5150 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5152 msi_reg_set_val_str( hkey, squished_pc, buffer );
5155 return ERROR_INSTALL_SUSPEND;
5158 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5164 * We are currently doing what should be done here in the top level Install
5165 * however for Administrative and uninstalls this step will be needed
5167 if (!package->PackagePath)
5168 return ERROR_SUCCESS;
5170 msi_set_sourcedir_props(package, TRUE);
5172 attrib = GetFileAttributesW(package->db->path);
5173 if (attrib == INVALID_FILE_ATTRIBUTES)
5179 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5180 package->Context, MSICODE_PRODUCT,
5181 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5182 if (rc == ERROR_MORE_DATA)
5184 prompt = msi_alloc(size * sizeof(WCHAR));
5185 MsiSourceListGetInfoW(package->ProductCode, NULL,
5186 package->Context, MSICODE_PRODUCT,
5187 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5190 prompt = strdupW(package->db->path);
5192 msg = generate_error_string(package,1302,1,prompt);
5193 while(attrib == INVALID_FILE_ATTRIBUTES)
5195 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5198 rc = ERROR_INSTALL_USEREXIT;
5201 attrib = GetFileAttributesW(package->db->path);
5207 return ERROR_SUCCESS;
5212 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5215 LPWSTR buffer, productid = NULL;
5216 UINT i, rc = ERROR_SUCCESS;
5219 static const WCHAR szPropKeys[][80] =
5221 {'P','r','o','d','u','c','t','I','D',0},
5222 {'U','S','E','R','N','A','M','E',0},
5223 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5227 static const WCHAR szRegKeys[][80] =
5229 {'P','r','o','d','u','c','t','I','D',0},
5230 {'R','e','g','O','w','n','e','r',0},
5231 {'R','e','g','C','o','m','p','a','n','y',0},
5235 if (msi_check_unpublish(package))
5237 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5241 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5245 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5247 if (rc != ERROR_SUCCESS)
5250 for( i = 0; szPropKeys[i][0]; i++ )
5252 buffer = msi_dup_property( package->db, szPropKeys[i] );
5253 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5258 uirow = MSI_CreateRecord( 1 );
5259 MSI_RecordSetStringW( uirow, 1, productid );
5260 ui_actiondata( package, szRegisterUser, uirow );
5261 msiobj_release( &uirow->hdr );
5263 msi_free(productid);
5269 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5273 package->script->InWhatSequence |= SEQUENCE_EXEC;
5274 rc = ACTION_ProcessExecSequence(package,FALSE);
5279 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5281 MSIPACKAGE *package = param;
5282 LPCWSTR compgroupid, component, feature, qualifier, text;
5283 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5292 feature = MSI_RecordGetString(rec, 5);
5293 feat = get_loaded_feature(package, feature);
5295 return ERROR_SUCCESS;
5297 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5298 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5299 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5301 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5302 feat->Action = feat->Installed;
5303 return ERROR_SUCCESS;
5306 component = MSI_RecordGetString(rec, 3);
5307 comp = get_loaded_component(package, component);
5309 return ERROR_SUCCESS;
5311 compgroupid = MSI_RecordGetString(rec,1);
5312 qualifier = MSI_RecordGetString(rec,2);
5314 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5315 if (rc != ERROR_SUCCESS)
5318 advertise = create_component_advertise_string( package, comp, feature );
5319 text = MSI_RecordGetString( rec, 4 );
5322 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5323 strcpyW( p, advertise );
5325 msi_free( advertise );
5328 existing = msi_reg_get_val_str( hkey, qualifier );
5330 sz = strlenW( advertise ) + 1;
5333 for (p = existing; *p; p += len)
5335 len = strlenW( p ) + 1;
5336 if (strcmpW( advertise, p )) sz += len;
5339 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5341 rc = ERROR_OUTOFMEMORY;
5347 for (p = existing; *p; p += len)
5349 len = strlenW( p ) + 1;
5350 if (strcmpW( advertise, p ))
5352 memcpy( q, p, len * sizeof(WCHAR) );
5357 strcpyW( q, advertise );
5358 q[strlenW( q ) + 1] = 0;
5360 msi_reg_set_val_multi_str( hkey, qualifier, output );
5365 msi_free( advertise );
5366 msi_free( existing );
5369 uirow = MSI_CreateRecord( 2 );
5370 MSI_RecordSetStringW( uirow, 1, compgroupid );
5371 MSI_RecordSetStringW( uirow, 2, qualifier);
5372 ui_actiondata( package, szPublishComponents, uirow);
5373 msiobj_release( &uirow->hdr );
5374 /* FIXME: call ui_progress? */
5380 * At present I am ignorning the advertised components part of this and only
5381 * focusing on the qualified component sets
5383 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5387 static const WCHAR ExecSeqQuery[] =
5388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5389 '`','P','u','b','l','i','s','h',
5390 'C','o','m','p','o','n','e','n','t','`',0};
5392 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5393 if (rc != ERROR_SUCCESS)
5394 return ERROR_SUCCESS;
5396 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5397 msiobj_release(&view->hdr);
5402 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5404 static const WCHAR szInstallerComponents[] = {
5405 'S','o','f','t','w','a','r','e','\\',
5406 'M','i','c','r','o','s','o','f','t','\\',
5407 'I','n','s','t','a','l','l','e','r','\\',
5408 'C','o','m','p','o','n','e','n','t','s','\\',0};
5410 MSIPACKAGE *package = param;
5411 LPCWSTR compgroupid, component, feature, qualifier;
5415 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5418 feature = MSI_RecordGetString( rec, 5 );
5419 feat = get_loaded_feature( package, feature );
5421 return ERROR_SUCCESS;
5423 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5425 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5426 feat->Action = feat->Installed;
5427 return ERROR_SUCCESS;
5430 component = MSI_RecordGetString( rec, 3 );
5431 comp = get_loaded_component( package, component );
5433 return ERROR_SUCCESS;
5435 compgroupid = MSI_RecordGetString( rec, 1 );
5436 qualifier = MSI_RecordGetString( rec, 2 );
5438 squash_guid( compgroupid, squashed );
5439 strcpyW( keypath, szInstallerComponents );
5440 strcatW( keypath, squashed );
5442 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5443 if (res != ERROR_SUCCESS)
5445 WARN("Unable to delete component key %d\n", res);
5448 uirow = MSI_CreateRecord( 2 );
5449 MSI_RecordSetStringW( uirow, 1, compgroupid );
5450 MSI_RecordSetStringW( uirow, 2, qualifier );
5451 ui_actiondata( package, szUnpublishComponents, uirow );
5452 msiobj_release( &uirow->hdr );
5454 return ERROR_SUCCESS;
5457 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5461 static const WCHAR query[] =
5462 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5463 '`','P','u','b','l','i','s','h',
5464 'C','o','m','p','o','n','e','n','t','`',0};
5466 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5467 if (rc != ERROR_SUCCESS)
5468 return ERROR_SUCCESS;
5470 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5471 msiobj_release( &view->hdr );
5476 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5478 MSIPACKAGE *package = param;
5481 SC_HANDLE hscm, service = NULL;
5483 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5484 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5485 DWORD serv_type, start_type, err_control;
5486 SERVICE_DESCRIPTIONW sd = {NULL};
5488 static const WCHAR query[] =
5489 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5490 '`','C','o','m','p','o','n','e','n','t','`',' ',
5491 'W','H','E','R','E',' ',
5492 '`','C','o','m','p','o','n','e','n','t','`',' ',
5493 '=','\'','%','s','\'',0};
5495 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5498 ERR("Failed to open the SC Manager!\n");
5502 comp = MSI_RecordGetString( rec, 12 );
5503 if (!get_loaded_component( package, comp ))
5506 start_type = MSI_RecordGetInteger(rec, 5);
5507 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5510 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5511 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5512 serv_type = MSI_RecordGetInteger(rec, 4);
5513 err_control = MSI_RecordGetInteger(rec, 6);
5514 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5515 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5516 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5517 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5518 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5519 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5521 /* fetch the service path */
5522 row = MSI_QueryGetRecord(package->db, query, comp);
5525 ERR("Control query failed!\n");
5528 key = MSI_RecordGetString(row, 6);
5530 file = get_loaded_file(package, key);
5531 msiobj_release(&row->hdr);
5534 ERR("Failed to load the service file\n");
5538 if (!args || !args[0]) image_path = file->TargetPath;
5541 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5542 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5543 return ERROR_OUTOFMEMORY;
5545 strcpyW(image_path, file->TargetPath);
5546 strcatW(image_path, szSpace);
5547 strcatW(image_path, args);
5549 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5550 start_type, err_control, image_path, load_order,
5551 NULL, depends, serv_name, pass);
5555 if (GetLastError() != ERROR_SERVICE_EXISTS)
5556 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5558 else if (sd.lpDescription)
5560 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5561 WARN("failed to set service description %u\n", GetLastError());
5564 if (image_path != file->TargetPath) msi_free(image_path);
5566 CloseServiceHandle(service);
5567 CloseServiceHandle(hscm);
5570 msi_free(sd.lpDescription);
5571 msi_free(load_order);
5572 msi_free(serv_name);
5577 return ERROR_SUCCESS;
5580 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5584 static const WCHAR ExecSeqQuery[] =
5585 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5586 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5588 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5589 if (rc != ERROR_SUCCESS)
5590 return ERROR_SUCCESS;
5592 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5593 msiobj_release(&view->hdr);
5598 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5599 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5601 LPCWSTR *vector, *temp_vector;
5605 static const WCHAR separator[] = {'[','~',']',0};
5608 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5613 vector = msi_alloc(sizeof(LPWSTR));
5621 vector[*numargs - 1] = p;
5623 if ((q = strstrW(p, separator)))
5627 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5633 vector = temp_vector;
5642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5644 MSIPACKAGE *package = param;
5647 SC_HANDLE scm = NULL, service = NULL;
5648 LPCWSTR component, *vector = NULL;
5649 LPWSTR name, args, display_name = NULL;
5650 DWORD event, numargs, len;
5651 UINT r = ERROR_FUNCTION_FAILED;
5653 component = MSI_RecordGetString(rec, 6);
5654 comp = get_loaded_component(package, component);
5656 return ERROR_SUCCESS;
5660 TRACE("component is disabled\n");
5661 return ERROR_SUCCESS;
5664 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5666 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5667 comp->Action = comp->Installed;
5668 return ERROR_SUCCESS;
5670 comp->Action = INSTALLSTATE_LOCAL;
5672 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5673 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5674 event = MSI_RecordGetInteger(rec, 3);
5676 if (!(event & msidbServiceControlEventStart))
5682 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5685 ERR("Failed to open the service control manager\n");
5690 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5691 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5693 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5694 GetServiceDisplayNameW( scm, name, display_name, &len );
5697 service = OpenServiceW(scm, name, SERVICE_START);
5700 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5704 vector = msi_service_args_to_vector(args, &numargs);
5706 if (!StartServiceW(service, numargs, vector) &&
5707 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5709 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5716 uirow = MSI_CreateRecord( 2 );
5717 MSI_RecordSetStringW( uirow, 1, display_name );
5718 MSI_RecordSetStringW( uirow, 2, name );
5719 ui_actiondata( package, szStartServices, uirow );
5720 msiobj_release( &uirow->hdr );
5722 CloseServiceHandle(service);
5723 CloseServiceHandle(scm);
5728 msi_free(display_name);
5732 static UINT ACTION_StartServices( MSIPACKAGE *package )
5737 static const WCHAR query[] = {
5738 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5739 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5741 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5742 if (rc != ERROR_SUCCESS)
5743 return ERROR_SUCCESS;
5745 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5746 msiobj_release(&view->hdr);
5751 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5753 DWORD i, needed, count;
5754 ENUM_SERVICE_STATUSW *dependencies;
5758 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5759 0, &needed, &count))
5762 if (GetLastError() != ERROR_MORE_DATA)
5765 dependencies = msi_alloc(needed);
5769 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5770 needed, &needed, &count))
5773 for (i = 0; i < count; i++)
5775 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5776 SERVICE_STOP | SERVICE_QUERY_STATUS);
5780 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5787 msi_free(dependencies);
5791 static UINT stop_service( LPCWSTR name )
5793 SC_HANDLE scm = NULL, service = NULL;
5794 SERVICE_STATUS status;
5795 SERVICE_STATUS_PROCESS ssp;
5798 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5801 WARN("Failed to open the SCM: %d\n", GetLastError());
5805 service = OpenServiceW(scm, name,
5807 SERVICE_QUERY_STATUS |
5808 SERVICE_ENUMERATE_DEPENDENTS);
5811 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5815 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5816 sizeof(SERVICE_STATUS_PROCESS), &needed))
5818 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5822 if (ssp.dwCurrentState == SERVICE_STOPPED)
5825 stop_service_dependents(scm, service);
5827 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5828 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5831 CloseServiceHandle(service);
5832 CloseServiceHandle(scm);
5834 return ERROR_SUCCESS;
5837 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5839 MSIPACKAGE *package = param;
5843 LPWSTR name = NULL, display_name = NULL;
5847 event = MSI_RecordGetInteger( rec, 3 );
5848 if (!(event & msidbServiceControlEventStop))
5849 return ERROR_SUCCESS;
5851 component = MSI_RecordGetString( rec, 6 );
5852 comp = get_loaded_component( package, component );
5854 return ERROR_SUCCESS;
5858 TRACE("component is disabled\n");
5859 return ERROR_SUCCESS;
5862 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5864 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5865 comp->Action = comp->Installed;
5866 return ERROR_SUCCESS;
5868 comp->Action = INSTALLSTATE_ABSENT;
5870 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5873 ERR("Failed to open the service control manager\n");
5878 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5879 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5881 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5882 GetServiceDisplayNameW( scm, name, display_name, &len );
5884 CloseServiceHandle( scm );
5886 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5887 stop_service( name );
5890 uirow = MSI_CreateRecord( 2 );
5891 MSI_RecordSetStringW( uirow, 1, display_name );
5892 MSI_RecordSetStringW( uirow, 2, name );
5893 ui_actiondata( package, szStopServices, uirow );
5894 msiobj_release( &uirow->hdr );
5897 msi_free( display_name );
5898 return ERROR_SUCCESS;
5901 static UINT ACTION_StopServices( MSIPACKAGE *package )
5906 static const WCHAR query[] = {
5907 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5908 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5910 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5911 if (rc != ERROR_SUCCESS)
5912 return ERROR_SUCCESS;
5914 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5915 msiobj_release(&view->hdr);
5920 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5922 MSIPACKAGE *package = param;
5926 LPWSTR name = NULL, display_name = NULL;
5928 SC_HANDLE scm = NULL, service = NULL;
5930 event = MSI_RecordGetInteger( rec, 3 );
5931 if (!(event & msidbServiceControlEventDelete))
5932 return ERROR_SUCCESS;
5934 component = MSI_RecordGetString(rec, 6);
5935 comp = get_loaded_component(package, component);
5937 return ERROR_SUCCESS;
5941 TRACE("component is disabled\n");
5942 return ERROR_SUCCESS;
5945 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5947 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5948 comp->Action = comp->Installed;
5949 return ERROR_SUCCESS;
5951 comp->Action = INSTALLSTATE_ABSENT;
5953 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5954 stop_service( name );
5956 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5959 WARN("Failed to open the SCM: %d\n", GetLastError());
5964 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5965 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5967 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5968 GetServiceDisplayNameW( scm, name, display_name, &len );
5971 service = OpenServiceW( scm, name, DELETE );
5974 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5978 if (!DeleteService( service ))
5979 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5982 uirow = MSI_CreateRecord( 2 );
5983 MSI_RecordSetStringW( uirow, 1, display_name );
5984 MSI_RecordSetStringW( uirow, 2, name );
5985 ui_actiondata( package, szDeleteServices, uirow );
5986 msiobj_release( &uirow->hdr );
5988 CloseServiceHandle( service );
5989 CloseServiceHandle( scm );
5991 msi_free( display_name );
5993 return ERROR_SUCCESS;
5996 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6001 static const WCHAR query[] = {
6002 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6003 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6005 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6006 if (rc != ERROR_SUCCESS)
6007 return ERROR_SUCCESS;
6009 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6010 msiobj_release( &view->hdr );
6015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6017 MSIPACKAGE *package = param;
6018 LPWSTR driver, driver_path, ptr;
6019 WCHAR outpath[MAX_PATH];
6020 MSIFILE *driver_file = NULL, *setup_file = NULL;
6023 LPCWSTR desc, file_key, component;
6025 UINT r = ERROR_SUCCESS;
6027 static const WCHAR driver_fmt[] = {
6028 'D','r','i','v','e','r','=','%','s',0};
6029 static const WCHAR setup_fmt[] = {
6030 'S','e','t','u','p','=','%','s',0};
6031 static const WCHAR usage_fmt[] = {
6032 'F','i','l','e','U','s','a','g','e','=','1',0};
6034 component = MSI_RecordGetString( rec, 2 );
6035 comp = get_loaded_component( package, component );
6037 return ERROR_SUCCESS;
6041 TRACE("component is disabled\n");
6042 return ERROR_SUCCESS;
6045 desc = MSI_RecordGetString(rec, 3);
6047 file_key = MSI_RecordGetString( rec, 4 );
6048 if (file_key) driver_file = get_loaded_file( package, file_key );
6050 file_key = MSI_RecordGetString( rec, 5 );
6051 if (file_key) setup_file = get_loaded_file( package, file_key );
6055 ERR("ODBC Driver entry not found!\n");
6056 return ERROR_FUNCTION_FAILED;
6059 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6061 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6062 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6064 driver = msi_alloc(len * sizeof(WCHAR));
6066 return ERROR_OUTOFMEMORY;
6069 lstrcpyW(ptr, desc);
6070 ptr += lstrlenW(ptr) + 1;
6072 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6077 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6081 lstrcpyW(ptr, usage_fmt);
6082 ptr += lstrlenW(ptr) + 1;
6085 driver_path = strdupW(driver_file->TargetPath);
6086 ptr = strrchrW(driver_path, '\\');
6087 if (ptr) *ptr = '\0';
6089 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6090 NULL, ODBC_INSTALL_COMPLETE, &usage))
6092 ERR("Failed to install SQL driver!\n");
6093 r = ERROR_FUNCTION_FAILED;
6096 uirow = MSI_CreateRecord( 5 );
6097 MSI_RecordSetStringW( uirow, 1, desc );
6098 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6099 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6100 ui_actiondata( package, szInstallODBC, uirow );
6101 msiobj_release( &uirow->hdr );
6104 msi_free(driver_path);
6109 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6111 MSIPACKAGE *package = param;
6112 LPWSTR translator, translator_path, ptr;
6113 WCHAR outpath[MAX_PATH];
6114 MSIFILE *translator_file = NULL, *setup_file = NULL;
6117 LPCWSTR desc, file_key, component;
6119 UINT r = ERROR_SUCCESS;
6121 static const WCHAR translator_fmt[] = {
6122 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6123 static const WCHAR setup_fmt[] = {
6124 'S','e','t','u','p','=','%','s',0};
6126 component = MSI_RecordGetString( rec, 2 );
6127 comp = get_loaded_component( package, component );
6129 return ERROR_SUCCESS;
6133 TRACE("component is disabled\n");
6134 return ERROR_SUCCESS;
6137 desc = MSI_RecordGetString(rec, 3);
6139 file_key = MSI_RecordGetString( rec, 4 );
6140 if (file_key) translator_file = get_loaded_file( package, file_key );
6142 file_key = MSI_RecordGetString( rec, 5 );
6143 if (file_key) setup_file = get_loaded_file( package, file_key );
6145 if (!translator_file)
6147 ERR("ODBC Translator entry not found!\n");
6148 return ERROR_FUNCTION_FAILED;
6151 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6153 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6155 translator = msi_alloc(len * sizeof(WCHAR));
6157 return ERROR_OUTOFMEMORY;
6160 lstrcpyW(ptr, desc);
6161 ptr += lstrlenW(ptr) + 1;
6163 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6168 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6173 translator_path = strdupW(translator_file->TargetPath);
6174 ptr = strrchrW(translator_path, '\\');
6175 if (ptr) *ptr = '\0';
6177 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6178 NULL, ODBC_INSTALL_COMPLETE, &usage))
6180 ERR("Failed to install SQL translator!\n");
6181 r = ERROR_FUNCTION_FAILED;
6184 uirow = MSI_CreateRecord( 5 );
6185 MSI_RecordSetStringW( uirow, 1, desc );
6186 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6187 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6188 ui_actiondata( package, szInstallODBC, uirow );
6189 msiobj_release( &uirow->hdr );
6191 msi_free(translator);
6192 msi_free(translator_path);
6197 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6199 MSIPACKAGE *package = param;
6202 LPCWSTR desc, driver, component;
6203 WORD request = ODBC_ADD_SYS_DSN;
6206 UINT r = ERROR_SUCCESS;
6209 static const WCHAR attrs_fmt[] = {
6210 'D','S','N','=','%','s',0 };
6212 component = MSI_RecordGetString( rec, 2 );
6213 comp = get_loaded_component( package, component );
6215 return ERROR_SUCCESS;
6219 TRACE("component is disabled\n");
6220 return ERROR_SUCCESS;
6223 desc = MSI_RecordGetString(rec, 3);
6224 driver = MSI_RecordGetString(rec, 4);
6225 registration = MSI_RecordGetInteger(rec, 5);
6227 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6228 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6230 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6231 attrs = msi_alloc(len * sizeof(WCHAR));
6233 return ERROR_OUTOFMEMORY;
6235 len = sprintfW(attrs, attrs_fmt, desc);
6238 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6240 ERR("Failed to install SQL data source!\n");
6241 r = ERROR_FUNCTION_FAILED;
6244 uirow = MSI_CreateRecord( 5 );
6245 MSI_RecordSetStringW( uirow, 1, desc );
6246 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6247 MSI_RecordSetInteger( uirow, 3, request );
6248 ui_actiondata( package, szInstallODBC, uirow );
6249 msiobj_release( &uirow->hdr );
6256 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6261 static const WCHAR driver_query[] = {
6262 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6263 'O','D','B','C','D','r','i','v','e','r',0 };
6265 static const WCHAR translator_query[] = {
6266 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6267 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6269 static const WCHAR source_query[] = {
6270 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6271 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6273 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6274 if (rc != ERROR_SUCCESS)
6275 return ERROR_SUCCESS;
6277 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6278 msiobj_release(&view->hdr);
6280 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6281 if (rc != ERROR_SUCCESS)
6282 return ERROR_SUCCESS;
6284 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6285 msiobj_release(&view->hdr);
6287 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6288 if (rc != ERROR_SUCCESS)
6289 return ERROR_SUCCESS;
6291 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6292 msiobj_release(&view->hdr);
6297 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6299 MSIPACKAGE *package = param;
6303 LPCWSTR desc, component;
6305 component = MSI_RecordGetString( rec, 2 );
6306 comp = get_loaded_component( package, component );
6308 return ERROR_SUCCESS;
6312 TRACE("component is disabled\n");
6313 return ERROR_SUCCESS;
6316 desc = MSI_RecordGetString( rec, 3 );
6317 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6319 WARN("Failed to remove ODBC driver\n");
6323 FIXME("Usage count reached 0\n");
6326 uirow = MSI_CreateRecord( 2 );
6327 MSI_RecordSetStringW( uirow, 1, desc );
6328 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6329 ui_actiondata( package, szRemoveODBC, uirow );
6330 msiobj_release( &uirow->hdr );
6332 return ERROR_SUCCESS;
6335 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6337 MSIPACKAGE *package = param;
6341 LPCWSTR desc, component;
6343 component = MSI_RecordGetString( rec, 2 );
6344 comp = get_loaded_component( package, component );
6346 return ERROR_SUCCESS;
6350 TRACE("component is disabled\n");
6351 return ERROR_SUCCESS;
6354 desc = MSI_RecordGetString( rec, 3 );
6355 if (!SQLRemoveTranslatorW( desc, &usage ))
6357 WARN("Failed to remove ODBC translator\n");
6361 FIXME("Usage count reached 0\n");
6364 uirow = MSI_CreateRecord( 2 );
6365 MSI_RecordSetStringW( uirow, 1, desc );
6366 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6367 ui_actiondata( package, szRemoveODBC, uirow );
6368 msiobj_release( &uirow->hdr );
6370 return ERROR_SUCCESS;
6373 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6375 MSIPACKAGE *package = param;
6379 LPCWSTR desc, driver, component;
6380 WORD request = ODBC_REMOVE_SYS_DSN;
6384 static const WCHAR attrs_fmt[] = {
6385 'D','S','N','=','%','s',0 };
6387 component = MSI_RecordGetString( rec, 2 );
6388 comp = get_loaded_component( package, component );
6390 return ERROR_SUCCESS;
6394 TRACE("component is disabled\n");
6395 return ERROR_SUCCESS;
6398 desc = MSI_RecordGetString( rec, 3 );
6399 driver = MSI_RecordGetString( rec, 4 );
6400 registration = MSI_RecordGetInteger( rec, 5 );
6402 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6403 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6405 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6406 attrs = msi_alloc( len * sizeof(WCHAR) );
6408 return ERROR_OUTOFMEMORY;
6410 FIXME("Use ODBCSourceAttribute table\n");
6412 len = sprintfW( attrs, attrs_fmt, desc );
6415 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6417 WARN("Failed to remove ODBC data source\n");
6421 uirow = MSI_CreateRecord( 3 );
6422 MSI_RecordSetStringW( uirow, 1, desc );
6423 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6424 MSI_RecordSetInteger( uirow, 3, request );
6425 ui_actiondata( package, szRemoveODBC, uirow );
6426 msiobj_release( &uirow->hdr );
6428 return ERROR_SUCCESS;
6431 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6436 static const WCHAR driver_query[] = {
6437 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6438 'O','D','B','C','D','r','i','v','e','r',0 };
6440 static const WCHAR translator_query[] = {
6441 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6442 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6444 static const WCHAR source_query[] = {
6445 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6446 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6448 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6449 if (rc != ERROR_SUCCESS)
6450 return ERROR_SUCCESS;
6452 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6453 msiobj_release( &view->hdr );
6455 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6456 if (rc != ERROR_SUCCESS)
6457 return ERROR_SUCCESS;
6459 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6460 msiobj_release( &view->hdr );
6462 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6463 if (rc != ERROR_SUCCESS)
6464 return ERROR_SUCCESS;
6466 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6467 msiobj_release( &view->hdr );
6472 #define ENV_ACT_SETALWAYS 0x1
6473 #define ENV_ACT_SETABSENT 0x2
6474 #define ENV_ACT_REMOVE 0x4
6475 #define ENV_ACT_REMOVEMATCH 0x8
6477 #define ENV_MOD_MACHINE 0x20000000
6478 #define ENV_MOD_APPEND 0x40000000
6479 #define ENV_MOD_PREFIX 0x80000000
6480 #define ENV_MOD_MASK 0xC0000000
6482 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6484 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6486 LPCWSTR cptr = *name;
6488 static const WCHAR prefix[] = {'[','~',']',0};
6489 static const int prefix_len = 3;
6495 *flags |= ENV_ACT_SETALWAYS;
6496 else if (*cptr == '+')
6497 *flags |= ENV_ACT_SETABSENT;
6498 else if (*cptr == '-')
6499 *flags |= ENV_ACT_REMOVE;
6500 else if (*cptr == '!')
6501 *flags |= ENV_ACT_REMOVEMATCH;
6502 else if (*cptr == '*')
6503 *flags |= ENV_MOD_MACHINE;
6513 ERR("Missing environment variable\n");
6514 return ERROR_FUNCTION_FAILED;
6519 LPCWSTR ptr = *value;
6520 if (!strncmpW(ptr, prefix, prefix_len))
6522 if (ptr[prefix_len] == szSemiColon[0])
6524 *flags |= ENV_MOD_APPEND;
6525 *value += lstrlenW(prefix);
6532 else if (lstrlenW(*value) >= prefix_len)
6534 ptr += lstrlenW(ptr) - prefix_len;
6535 if (!strcmpW( ptr, prefix ))
6537 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6539 *flags |= ENV_MOD_PREFIX;
6540 /* the "[~]" will be removed by deformat_string */;
6550 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6551 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6552 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6553 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6555 ERR("Invalid flags: %08x\n", *flags);
6556 return ERROR_FUNCTION_FAILED;
6560 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6562 return ERROR_SUCCESS;
6565 static UINT open_env_key( DWORD flags, HKEY *key )
6567 static const WCHAR user_env[] =
6568 {'E','n','v','i','r','o','n','m','e','n','t',0};
6569 static const WCHAR machine_env[] =
6570 {'S','y','s','t','e','m','\\',
6571 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6572 'C','o','n','t','r','o','l','\\',
6573 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6574 'E','n','v','i','r','o','n','m','e','n','t',0};
6579 if (flags & ENV_MOD_MACHINE)
6582 root = HKEY_LOCAL_MACHINE;
6587 root = HKEY_CURRENT_USER;
6590 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6591 if (res != ERROR_SUCCESS)
6593 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6594 return ERROR_FUNCTION_FAILED;
6597 return ERROR_SUCCESS;
6600 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6602 MSIPACKAGE *package = param;
6603 LPCWSTR name, value, component;
6604 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6605 DWORD flags, type, size;
6612 component = MSI_RecordGetString(rec, 4);
6613 comp = get_loaded_component(package, component);
6615 return ERROR_SUCCESS;
6619 TRACE("component is disabled\n");
6620 return ERROR_SUCCESS;
6623 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6625 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6626 comp->Action = comp->Installed;
6627 return ERROR_SUCCESS;
6629 comp->Action = INSTALLSTATE_LOCAL;
6631 name = MSI_RecordGetString(rec, 2);
6632 value = MSI_RecordGetString(rec, 3);
6634 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6636 res = env_parse_flags(&name, &value, &flags);
6637 if (res != ERROR_SUCCESS || !value)
6640 if (value && !deformat_string(package, value, &deformatted))
6642 res = ERROR_OUTOFMEMORY;
6646 value = deformatted;
6648 res = open_env_key( flags, &env );
6649 if (res != ERROR_SUCCESS)
6652 if (flags & ENV_MOD_MACHINE)
6653 action |= 0x20000000;
6657 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6658 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6659 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6662 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6666 /* Nothing to do. */
6669 res = ERROR_SUCCESS;
6673 /* If we are appending but the string was empty, strip ; */
6674 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6676 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6677 newval = strdupW(value);
6680 res = ERROR_OUTOFMEMORY;
6688 /* Contrary to MSDN, +-variable to [~];path works */
6689 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6691 res = ERROR_SUCCESS;
6695 data = msi_alloc(size);
6699 return ERROR_OUTOFMEMORY;
6702 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6703 if (res != ERROR_SUCCESS)
6706 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6709 res = RegDeleteValueW(env, name);
6710 if (res != ERROR_SUCCESS)
6711 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6715 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6716 if (flags & ENV_MOD_MASK)
6720 if (flags & ENV_MOD_APPEND) multiplier++;
6721 if (flags & ENV_MOD_PREFIX) multiplier++;
6722 mod_size = lstrlenW(value) * multiplier;
6723 size += mod_size * sizeof(WCHAR);
6726 newval = msi_alloc(size);
6730 res = ERROR_OUTOFMEMORY;
6734 if (flags & ENV_MOD_PREFIX)
6736 lstrcpyW(newval, value);
6737 ptr = newval + lstrlenW(value);
6738 action |= 0x80000000;
6741 lstrcpyW(ptr, data);
6743 if (flags & ENV_MOD_APPEND)
6745 lstrcatW(newval, value);
6746 action |= 0x40000000;
6749 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6750 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6753 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6757 uirow = MSI_CreateRecord( 3 );
6758 MSI_RecordSetStringW( uirow, 1, name );
6759 MSI_RecordSetStringW( uirow, 2, newval );
6760 MSI_RecordSetInteger( uirow, 3, action );
6761 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6762 msiobj_release( &uirow->hdr );
6764 if (env) RegCloseKey(env);
6765 msi_free(deformatted);
6771 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6775 static const WCHAR ExecSeqQuery[] =
6776 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6777 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6778 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6779 if (rc != ERROR_SUCCESS)
6780 return ERROR_SUCCESS;
6782 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6783 msiobj_release(&view->hdr);
6788 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6790 MSIPACKAGE *package = param;
6791 LPCWSTR name, value, component;
6792 LPWSTR deformatted = NULL;
6801 component = MSI_RecordGetString( rec, 4 );
6802 comp = get_loaded_component( package, component );
6804 return ERROR_SUCCESS;
6808 TRACE("component is disabled\n");
6809 return ERROR_SUCCESS;
6812 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6814 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6815 comp->Action = comp->Installed;
6816 return ERROR_SUCCESS;
6818 comp->Action = INSTALLSTATE_ABSENT;
6820 name = MSI_RecordGetString( rec, 2 );
6821 value = MSI_RecordGetString( rec, 3 );
6823 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6825 r = env_parse_flags( &name, &value, &flags );
6826 if (r != ERROR_SUCCESS)
6829 if (!(flags & ENV_ACT_REMOVE))
6831 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6832 return ERROR_SUCCESS;
6835 if (value && !deformat_string( package, value, &deformatted ))
6836 return ERROR_OUTOFMEMORY;
6838 value = deformatted;
6840 r = open_env_key( flags, &env );
6841 if (r != ERROR_SUCCESS)
6847 if (flags & ENV_MOD_MACHINE)
6848 action |= 0x20000000;
6850 TRACE("Removing %s\n", debugstr_w(name));
6852 res = RegDeleteValueW( env, name );
6853 if (res != ERROR_SUCCESS)
6855 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6860 uirow = MSI_CreateRecord( 3 );
6861 MSI_RecordSetStringW( uirow, 1, name );
6862 MSI_RecordSetStringW( uirow, 2, value );
6863 MSI_RecordSetInteger( uirow, 3, action );
6864 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6865 msiobj_release( &uirow->hdr );
6867 if (env) RegCloseKey( env );
6868 msi_free( deformatted );
6872 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6876 static const WCHAR query[] =
6877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6878 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6880 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6881 if (rc != ERROR_SUCCESS)
6882 return ERROR_SUCCESS;
6884 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6885 msiobj_release( &view->hdr );
6890 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6892 LPWSTR key, template, id;
6893 UINT r = ERROR_SUCCESS;
6895 id = msi_dup_property( package->db, szProductID );
6899 return ERROR_SUCCESS;
6901 template = msi_dup_property( package->db, szPIDTemplate );
6902 key = msi_dup_property( package->db, szPIDKEY );
6904 if (key && template)
6906 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6907 r = msi_set_property( package->db, szProductID, key );
6909 msi_free( template );
6914 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6917 package->need_reboot = 1;
6918 return ERROR_SUCCESS;
6921 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6923 static const WCHAR szAvailableFreeReg[] =
6924 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6926 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6928 TRACE("%p %d kilobytes\n", package, space);
6930 uirow = MSI_CreateRecord( 1 );
6931 MSI_RecordSetInteger( uirow, 1, space );
6932 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6933 msiobj_release( &uirow->hdr );
6935 return ERROR_SUCCESS;
6938 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6940 FIXME("%p\n", package);
6941 return ERROR_SUCCESS;
6944 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6946 FIXME("%p\n", package);
6947 return ERROR_SUCCESS;
6950 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6955 static const WCHAR driver_query[] = {
6956 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6957 'O','D','B','C','D','r','i','v','e','r',0 };
6959 static const WCHAR translator_query[] = {
6960 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6961 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6963 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6964 if (r == ERROR_SUCCESS)
6967 r = MSI_IterateRecords( view, &count, NULL, package );
6968 msiobj_release( &view->hdr );
6969 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6972 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6973 if (r == ERROR_SUCCESS)
6976 r = MSI_IterateRecords( view, &count, NULL, package );
6977 msiobj_release( &view->hdr );
6978 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6981 return ERROR_SUCCESS;
6984 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6986 MSIPACKAGE *package = param;
6987 const WCHAR *property = MSI_RecordGetString( rec, 1 );
6990 if ((value = msi_dup_property( package->db, property )))
6992 FIXME("remove %s\n", debugstr_w(value));
6995 return ERROR_SUCCESS;
6998 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7003 static const WCHAR query[] =
7004 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7005 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7007 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7008 if (r == ERROR_SUCCESS)
7010 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7011 msiobj_release( &view->hdr );
7013 return ERROR_SUCCESS;
7016 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7018 MSIPACKAGE *package = param;
7019 int attributes = MSI_RecordGetInteger( rec, 5 );
7021 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7023 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7024 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7025 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7026 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7030 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7032 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7033 if (r != ERROR_SUCCESS)
7034 return ERROR_SUCCESS;
7038 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7039 if (r != ERROR_SUCCESS)
7040 return ERROR_SUCCESS;
7042 RegCloseKey( hkey );
7044 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7045 debugstr_w(upgrade_code), debugstr_w(version_min),
7046 debugstr_w(version_max), debugstr_w(language));
7048 return ERROR_SUCCESS;
7051 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7056 static const WCHAR query[] =
7057 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7059 if (msi_get_property_int( package->db, szInstalled, 0 ))
7061 TRACE("product is installed, skipping action\n");
7062 return ERROR_SUCCESS;
7064 if (msi_get_property_int( package->db, szPreselected, 0 ))
7066 TRACE("Preselected property is set, not migrating feature states\n");
7067 return ERROR_SUCCESS;
7070 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7071 if (r == ERROR_SUCCESS)
7073 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7074 msiobj_release( &view->hdr );
7076 return ERROR_SUCCESS;
7079 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7080 LPCSTR action, LPCWSTR table )
7082 static const WCHAR query[] = {
7083 'S','E','L','E','C','T',' ','*',' ',
7084 'F','R','O','M',' ','`','%','s','`',0 };
7085 MSIQUERY *view = NULL;
7089 r = MSI_OpenQuery( package->db, &view, query, table );
7090 if (r == ERROR_SUCCESS)
7092 r = MSI_IterateRecords(view, &count, NULL, package);
7093 msiobj_release(&view->hdr);
7097 FIXME("%s -> %u ignored %s table values\n",
7098 action, count, debugstr_w(table));
7100 return ERROR_SUCCESS;
7103 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7105 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7106 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7109 static UINT ACTION_BindImage( MSIPACKAGE *package )
7111 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7112 return msi_unimplemented_action_stub( package, "BindImage", table );
7115 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7117 static const WCHAR table[] = {
7118 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7119 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7122 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7124 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7125 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7128 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7130 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7131 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7134 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7136 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7137 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7140 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7142 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7143 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7146 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7150 const WCHAR *action;
7151 UINT (*handler)(MSIPACKAGE *);
7155 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7156 { szAppSearch, ACTION_AppSearch },
7157 { szBindImage, ACTION_BindImage },
7158 { szCCPSearch, ACTION_CCPSearch },
7159 { szCostFinalize, ACTION_CostFinalize },
7160 { szCostInitialize, ACTION_CostInitialize },
7161 { szCreateFolders, ACTION_CreateFolders },
7162 { szCreateShortcuts, ACTION_CreateShortcuts },
7163 { szDeleteServices, ACTION_DeleteServices },
7164 { szDisableRollback, ACTION_DisableRollback },
7165 { szDuplicateFiles, ACTION_DuplicateFiles },
7166 { szExecuteAction, ACTION_ExecuteAction },
7167 { szFileCost, ACTION_FileCost },
7168 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7169 { szForceReboot, ACTION_ForceReboot },
7170 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7171 { szInstallExecute, ACTION_InstallExecute },
7172 { szInstallExecuteAgain, ACTION_InstallExecute },
7173 { szInstallFiles, ACTION_InstallFiles},
7174 { szInstallFinalize, ACTION_InstallFinalize },
7175 { szInstallInitialize, ACTION_InstallInitialize },
7176 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7177 { szInstallValidate, ACTION_InstallValidate },
7178 { szIsolateComponents, ACTION_IsolateComponents },
7179 { szLaunchConditions, ACTION_LaunchConditions },
7180 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7181 { szMoveFiles, ACTION_MoveFiles },
7182 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7183 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7184 { szInstallODBC, ACTION_InstallODBC },
7185 { szInstallServices, ACTION_InstallServices },
7186 { szPatchFiles, ACTION_PatchFiles },
7187 { szProcessComponents, ACTION_ProcessComponents },
7188 { szPublishComponents, ACTION_PublishComponents },
7189 { szPublishFeatures, ACTION_PublishFeatures },
7190 { szPublishProduct, ACTION_PublishProduct },
7191 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7192 { szRegisterComPlus, ACTION_RegisterComPlus},
7193 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7194 { szRegisterFonts, ACTION_RegisterFonts },
7195 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7196 { szRegisterProduct, ACTION_RegisterProduct },
7197 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7198 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7199 { szRegisterUser, ACTION_RegisterUser },
7200 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7201 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7202 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7203 { szRemoveFiles, ACTION_RemoveFiles },
7204 { szRemoveFolders, ACTION_RemoveFolders },
7205 { szRemoveIniValues, ACTION_RemoveIniValues },
7206 { szRemoveODBC, ACTION_RemoveODBC },
7207 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7208 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7209 { szResolveSource, ACTION_ResolveSource },
7210 { szRMCCPSearch, ACTION_RMCCPSearch },
7211 { szScheduleReboot, ACTION_ScheduleReboot },
7212 { szSelfRegModules, ACTION_SelfRegModules },
7213 { szSelfUnregModules, ACTION_SelfUnregModules },
7214 { szSetODBCFolders, ACTION_SetODBCFolders },
7215 { szStartServices, ACTION_StartServices },
7216 { szStopServices, ACTION_StopServices },
7217 { szUnpublishComponents, ACTION_UnpublishComponents },
7218 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7219 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7220 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7221 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7222 { szUnregisterFonts, ACTION_UnregisterFonts },
7223 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7224 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7225 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7226 { szValidateProductID, ACTION_ValidateProductID },
7227 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7228 { szWriteIniValues, ACTION_WriteIniValues },
7229 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7233 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7239 while (StandardActions[i].action != NULL)
7241 if (!strcmpW( StandardActions[i].action, action ))
7243 ui_actionstart( package, action );
7244 if (StandardActions[i].handler)
7246 ui_actioninfo( package, action, TRUE, 0 );
7247 *rc = StandardActions[i].handler( package );
7248 ui_actioninfo( package, action, FALSE, *rc );
7252 FIXME("unhandled standard action %s\n", debugstr_w(action));
7253 *rc = ERROR_SUCCESS;
7263 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7265 UINT rc = ERROR_SUCCESS;
7268 TRACE("Performing action (%s)\n", debugstr_w(action));
7270 handled = ACTION_HandleStandardAction(package, action, &rc);
7273 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7277 WARN("unhandled msi action %s\n", debugstr_w(action));
7278 rc = ERROR_FUNCTION_NOT_CALLED;
7284 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7286 UINT rc = ERROR_SUCCESS;
7287 BOOL handled = FALSE;
7289 TRACE("Performing action (%s)\n", debugstr_w(action));
7291 handled = ACTION_HandleStandardAction(package, action, &rc);
7294 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7296 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7301 WARN("unhandled msi action %s\n", debugstr_w(action));
7302 rc = ERROR_FUNCTION_NOT_CALLED;
7308 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7310 UINT rc = ERROR_SUCCESS;
7313 static const WCHAR ExecSeqQuery[] =
7314 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7315 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7316 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7317 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7318 static const WCHAR UISeqQuery[] =
7319 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7320 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7321 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7322 ' ', '=',' ','%','i',0};
7324 if (needs_ui_sequence(package))
7325 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7327 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7331 LPCWSTR action, cond;
7333 TRACE("Running the actions\n");
7335 /* check conditions */
7336 cond = MSI_RecordGetString(row, 2);
7338 /* this is a hack to skip errors in the condition code */
7339 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7341 msiobj_release(&row->hdr);
7342 return ERROR_SUCCESS;
7345 action = MSI_RecordGetString(row, 1);
7348 ERR("failed to fetch action\n");
7349 msiobj_release(&row->hdr);
7350 return ERROR_FUNCTION_FAILED;
7353 if (needs_ui_sequence(package))
7354 rc = ACTION_PerformUIAction(package, action, -1);
7356 rc = ACTION_PerformAction(package, action, -1);
7358 msiobj_release(&row->hdr);
7364 /****************************************************
7365 * TOP level entry points
7366 *****************************************************/
7368 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7369 LPCWSTR szCommandLine )
7374 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7375 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7377 msi_set_property( package->db, szAction, szInstall );
7379 package->script->InWhatSequence = SEQUENCE_INSTALL;
7386 dir = strdupW(szPackagePath);
7387 p = strrchrW(dir, '\\');
7391 file = szPackagePath + (p - dir);
7396 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7397 GetCurrentDirectoryW(MAX_PATH, dir);
7398 lstrcatW(dir, szBackSlash);
7399 file = szPackagePath;
7402 msi_free( package->PackagePath );
7403 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7404 if (!package->PackagePath)
7407 return ERROR_OUTOFMEMORY;
7410 lstrcpyW(package->PackagePath, dir);
7411 lstrcatW(package->PackagePath, file);
7414 msi_set_sourcedir_props(package, FALSE);
7417 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7418 if (rc != ERROR_SUCCESS)
7421 msi_apply_transforms( package );
7422 msi_apply_patches( package );
7424 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7426 TRACE("setting reinstall property\n");
7427 msi_set_property( package->db, szReinstall, szAll );
7430 /* properties may have been added by a transform */
7431 msi_clone_properties( package );
7433 msi_parse_command_line( package, szCommandLine, FALSE );
7434 msi_adjust_privilege_properties( package );
7435 msi_set_context( package );
7437 if (needs_ui_sequence( package))
7439 package->script->InWhatSequence |= SEQUENCE_UI;
7440 rc = ACTION_ProcessUISequence(package);
7441 ui_exists = ui_sequence_exists(package);
7442 if (rc == ERROR_SUCCESS || !ui_exists)
7444 package->script->InWhatSequence |= SEQUENCE_EXEC;
7445 rc = ACTION_ProcessExecSequence(package, ui_exists);
7449 rc = ACTION_ProcessExecSequence(package, FALSE);
7451 package->script->CurrentlyScripting = FALSE;
7453 /* process the ending type action */
7454 if (rc == ERROR_SUCCESS)
7455 ACTION_PerformActionSequence(package, -1);
7456 else if (rc == ERROR_INSTALL_USEREXIT)
7457 ACTION_PerformActionSequence(package, -2);
7458 else if (rc == ERROR_INSTALL_SUSPEND)
7459 ACTION_PerformActionSequence(package, -4);
7461 ACTION_PerformActionSequence(package, -3);
7463 /* finish up running custom actions */
7464 ACTION_FinishCustomActions(package);
7466 if (rc == ERROR_SUCCESS && package->need_reboot)
7467 return ERROR_SUCCESS_REBOOT_REQUIRED;