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 static 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 static DWORD 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 static BOOL 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 set_file_install_states( 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 file->state = msifs_missing;
2281 comp->Cost += file->FileSize;
2286 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2288 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2289 HIWORD(file_version->dwFileVersionMS),
2290 LOWORD(file_version->dwFileVersionMS),
2291 HIWORD(file_version->dwFileVersionLS),
2292 LOWORD(file_version->dwFileVersionLS));
2294 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2296 file->state = msifs_overwrite;
2297 comp->Cost += file->FileSize;
2301 TRACE("Destination file version equal or greater, not overwriting\n");
2302 file->state = msifs_present;
2304 msi_free( file_version );
2307 else if ((font_version = font_version_from_file( file->TargetPath )))
2309 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
2311 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2313 file->state = msifs_overwrite;
2314 comp->Cost += file->FileSize;
2318 TRACE("Destination file version equal or greater, not overwriting\n");
2319 file->state = msifs_present;
2321 msi_free( font_version );
2325 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2327 file->state = msifs_overwrite;
2328 comp->Cost += file->FileSize - file_size;
2331 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2333 TRACE("File hashes match, not overwriting\n");
2334 file->state = msifs_present;
2337 file->state = msifs_overwrite;
2338 comp->Cost += file->FileSize - file_size;
2341 return ERROR_SUCCESS;
2345 * A lot is done in this function aside from just the costing.
2346 * The costing needs to be implemented at some point but for now I am going
2347 * to focus on the directory building
2350 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2352 static const WCHAR ExecSeqQuery[] =
2353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2354 '`','D','i','r','e','c','t','o','r','y','`',0};
2355 static const WCHAR ConditionQuery[] =
2356 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2357 '`','C','o','n','d','i','t','i','o','n','`',0};
2358 static const WCHAR szCosting[] =
2359 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2360 static const WCHAR szlevel[] =
2361 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2362 static const WCHAR szOutOfDiskSpace[] =
2363 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2365 UINT rc = ERROR_SUCCESS;
2369 TRACE("Building Directory properties\n");
2371 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2372 if (rc == ERROR_SUCCESS)
2374 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2376 msiobj_release(&view->hdr);
2379 TRACE("Evaluating component conditions\n");
2380 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2382 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2384 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2385 comp->Enabled = FALSE;
2388 comp->Enabled = TRUE;
2391 /* read components states from the registry */
2392 ACTION_GetComponentInstallStates(package);
2393 ACTION_GetFeatureInstallStates(package);
2395 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2397 TRACE("Evaluating feature conditions\n");
2399 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2400 if (rc == ERROR_SUCCESS)
2402 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2403 msiobj_release( &view->hdr );
2407 TRACE("Calculating file install states\n");
2408 set_file_install_states( package );
2410 msi_set_property( package->db, szCosting, szOne );
2411 /* set default run level if not set */
2412 level = msi_dup_property( package->db, szlevel );
2414 msi_set_property( package->db, szlevel, szOne );
2417 /* FIXME: check volume disk space */
2418 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2420 return MSI_SetFeatureStates(package);
2423 /* OK this value is "interpreted" and then formatted based on the
2424 first few characters */
2425 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2430 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2436 LPWSTR deformated = NULL;
2439 deformat_string(package, &value[2], &deformated);
2441 /* binary value type */
2445 *size = (strlenW(ptr)/2)+1;
2447 *size = strlenW(ptr)/2;
2449 data = msi_alloc(*size);
2455 /* if uneven pad with a zero in front */
2461 data[count] = (BYTE)strtol(byte,NULL,0);
2463 TRACE("Uneven byte count\n");
2471 data[count] = (BYTE)strtol(byte,NULL,0);
2474 msi_free(deformated);
2476 TRACE("Data %i bytes(%i)\n",*size,count);
2483 deformat_string(package, &value[1], &deformated);
2486 *size = sizeof(DWORD);
2487 data = msi_alloc(*size);
2493 if ( (*p < '0') || (*p > '9') )
2499 if (deformated[0] == '-')
2502 TRACE("DWORD %i\n",*(LPDWORD)data);
2504 msi_free(deformated);
2509 static const WCHAR szMulti[] = {'[','~',']',0};
2518 *type=REG_EXPAND_SZ;
2526 if (strstrW(value, szMulti))
2527 *type = REG_MULTI_SZ;
2529 /* remove initial delimiter */
2530 if (!strncmpW(value, szMulti, 3))
2533 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2535 /* add double NULL terminator */
2536 if (*type == REG_MULTI_SZ)
2538 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2539 data = msi_realloc_zero(data, *size);
2545 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2552 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2554 *root_key = HKEY_LOCAL_MACHINE;
2559 *root_key = HKEY_CURRENT_USER;
2564 *root_key = HKEY_CLASSES_ROOT;
2568 *root_key = HKEY_CURRENT_USER;
2572 *root_key = HKEY_LOCAL_MACHINE;
2576 *root_key = HKEY_USERS;
2580 ERR("Unknown root %i\n", root);
2587 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2589 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2590 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2592 if (is_64bit && package->platform == PLATFORM_INTEL &&
2593 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2598 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2599 path_32node = msi_alloc( size );
2603 memcpy( path_32node, path, len * sizeof(WCHAR) );
2604 path_32node[len] = 0;
2605 strcatW( path_32node, szWow6432Node );
2606 strcatW( path_32node, szBackSlash );
2607 strcatW( path_32node, path + len );
2611 return strdupW( path );
2614 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2616 MSIPACKAGE *package = param;
2617 LPSTR value_data = NULL;
2618 HKEY root_key, hkey;
2620 LPWSTR deformated, uikey, keypath;
2621 LPCWSTR szRoot, component, name, key, value;
2625 BOOL check_first = FALSE;
2628 ui_progress(package,2,0,0,0);
2630 component = MSI_RecordGetString(row, 6);
2631 comp = get_loaded_component(package,component);
2633 return ERROR_SUCCESS;
2637 TRACE("component is disabled\n");
2638 return ERROR_SUCCESS;
2641 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2643 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2644 comp->Action = comp->Installed;
2645 return ERROR_SUCCESS;
2647 comp->Action = INSTALLSTATE_LOCAL;
2649 name = MSI_RecordGetString(row, 4);
2650 if( MSI_RecordIsNull(row,5) && name )
2652 /* null values can have special meanings */
2653 if (name[0]=='-' && name[1] == 0)
2654 return ERROR_SUCCESS;
2655 else if ((name[0]=='+' && name[1] == 0) ||
2656 (name[0] == '*' && name[1] == 0))
2661 root = MSI_RecordGetInteger(row,2);
2662 key = MSI_RecordGetString(row, 3);
2664 szRoot = get_root_key( package, root, &root_key );
2666 return ERROR_SUCCESS;
2668 deformat_string(package, key , &deformated);
2669 size = strlenW(deformated) + strlenW(szRoot) + 1;
2670 uikey = msi_alloc(size*sizeof(WCHAR));
2671 strcpyW(uikey,szRoot);
2672 strcatW(uikey,deformated);
2674 keypath = get_keypath( package, root_key, deformated );
2675 msi_free( deformated );
2676 if (RegCreateKeyW( root_key, keypath, &hkey ))
2678 ERR("Could not create key %s\n", debugstr_w(keypath));
2681 return ERROR_SUCCESS;
2684 value = MSI_RecordGetString(row,5);
2686 value_data = parse_value(package, value, &type, &size);
2689 value_data = (LPSTR)strdupW(szEmpty);
2690 size = sizeof(szEmpty);
2694 deformat_string(package, name, &deformated);
2698 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2700 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2705 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2706 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2708 TRACE("value %s of %s checked already exists\n",
2709 debugstr_w(deformated), debugstr_w(uikey));
2713 TRACE("Checked and setting value %s of %s\n",
2714 debugstr_w(deformated), debugstr_w(uikey));
2715 if (deformated || size)
2716 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2721 uirow = MSI_CreateRecord(3);
2722 MSI_RecordSetStringW(uirow,2,deformated);
2723 MSI_RecordSetStringW(uirow,1,uikey);
2724 if (type == REG_SZ || type == REG_EXPAND_SZ)
2725 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2726 ui_actiondata(package,szWriteRegistryValues,uirow);
2727 msiobj_release( &uirow->hdr );
2729 msi_free(value_data);
2730 msi_free(deformated);
2734 return ERROR_SUCCESS;
2737 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2741 static const WCHAR ExecSeqQuery[] =
2742 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2743 '`','R','e','g','i','s','t','r','y','`',0 };
2745 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2746 if (rc != ERROR_SUCCESS)
2747 return ERROR_SUCCESS;
2749 /* increment progress bar each time action data is sent */
2750 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2752 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2754 msiobj_release(&view->hdr);
2758 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2762 DWORD num_subkeys, num_values;
2766 if ((res = RegDeleteTreeW( hkey_root, key )))
2768 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2773 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2775 if ((res = RegDeleteValueW( hkey, value )))
2777 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2779 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2780 NULL, NULL, NULL, NULL );
2781 RegCloseKey( hkey );
2782 if (!res && !num_subkeys && !num_values)
2784 TRACE("Removing empty key %s\n", debugstr_w(key));
2785 RegDeleteKeyW( hkey_root, key );
2789 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
2793 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2795 MSIPACKAGE *package = param;
2796 LPCWSTR component, name, key_str, root_key_str;
2797 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2800 BOOL delete_key = FALSE;
2805 ui_progress( package, 2, 0, 0, 0 );
2807 component = MSI_RecordGetString( row, 6 );
2808 comp = get_loaded_component( package, component );
2810 return ERROR_SUCCESS;
2814 TRACE("component is disabled\n");
2815 return ERROR_SUCCESS;
2818 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2820 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2821 comp->Action = comp->Installed;
2822 return ERROR_SUCCESS;
2824 comp->Action = INSTALLSTATE_ABSENT;
2826 name = MSI_RecordGetString( row, 4 );
2827 if (MSI_RecordIsNull( row, 5 ) && name )
2829 if (name[0] == '+' && !name[1])
2830 return ERROR_SUCCESS;
2831 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2838 root = MSI_RecordGetInteger( row, 2 );
2839 key_str = MSI_RecordGetString( row, 3 );
2841 root_key_str = get_root_key( package, root, &hkey_root );
2843 return ERROR_SUCCESS;
2845 deformat_string( package, key_str, &deformated_key );
2846 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2847 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2848 strcpyW( ui_key_str, root_key_str );
2849 strcatW( ui_key_str, deformated_key );
2851 deformat_string( package, name, &deformated_name );
2853 keypath = get_keypath( package, hkey_root, deformated_key );
2854 msi_free( deformated_key );
2855 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2856 msi_free( keypath );
2858 uirow = MSI_CreateRecord( 2 );
2859 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2860 MSI_RecordSetStringW( uirow, 2, deformated_name );
2862 ui_actiondata( package, szRemoveRegistryValues, uirow );
2863 msiobj_release( &uirow->hdr );
2865 msi_free( ui_key_str );
2866 msi_free( deformated_name );
2867 return ERROR_SUCCESS;
2870 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2872 MSIPACKAGE *package = param;
2873 LPCWSTR component, name, key_str, root_key_str;
2874 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2877 BOOL delete_key = FALSE;
2882 ui_progress( package, 2, 0, 0, 0 );
2884 component = MSI_RecordGetString( row, 5 );
2885 comp = get_loaded_component( package, component );
2887 return ERROR_SUCCESS;
2891 TRACE("component is disabled\n");
2892 return ERROR_SUCCESS;
2895 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2897 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2898 comp->Action = comp->Installed;
2899 return ERROR_SUCCESS;
2901 comp->Action = INSTALLSTATE_LOCAL;
2903 if ((name = MSI_RecordGetString( row, 4 )))
2905 if (name[0] == '-' && !name[1])
2912 root = MSI_RecordGetInteger( row, 2 );
2913 key_str = MSI_RecordGetString( row, 3 );
2915 root_key_str = get_root_key( package, root, &hkey_root );
2917 return ERROR_SUCCESS;
2919 deformat_string( package, key_str, &deformated_key );
2920 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2921 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2922 strcpyW( ui_key_str, root_key_str );
2923 strcatW( ui_key_str, deformated_key );
2925 deformat_string( package, name, &deformated_name );
2927 keypath = get_keypath( package, hkey_root, deformated_key );
2928 msi_free( deformated_key );
2929 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2930 msi_free( keypath );
2932 uirow = MSI_CreateRecord( 2 );
2933 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2934 MSI_RecordSetStringW( uirow, 2, deformated_name );
2936 ui_actiondata( package, szRemoveRegistryValues, uirow );
2937 msiobj_release( &uirow->hdr );
2939 msi_free( ui_key_str );
2940 msi_free( deformated_name );
2941 return ERROR_SUCCESS;
2944 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2948 static const WCHAR registry_query[] =
2949 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2950 '`','R','e','g','i','s','t','r','y','`',0 };
2951 static const WCHAR remove_registry_query[] =
2952 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2953 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2955 /* increment progress bar each time action data is sent */
2956 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2958 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2959 if (rc == ERROR_SUCCESS)
2961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2962 msiobj_release( &view->hdr );
2963 if (rc != ERROR_SUCCESS)
2967 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2968 if (rc == ERROR_SUCCESS)
2970 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2971 msiobj_release( &view->hdr );
2972 if (rc != ERROR_SUCCESS)
2976 return ERROR_SUCCESS;
2979 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2981 package->script->CurrentlyScripting = TRUE;
2983 return ERROR_SUCCESS;
2987 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2992 static const WCHAR q1[]=
2993 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2994 '`','R','e','g','i','s','t','r','y','`',0};
2997 MSIFEATURE *feature;
3000 TRACE("InstallValidate\n");
3002 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3003 if (rc == ERROR_SUCCESS)
3005 MSI_IterateRecords( view, &progress, NULL, package );
3006 msiobj_release( &view->hdr );
3007 total += progress * REG_PROGRESS_VALUE;
3010 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3011 total += COMPONENT_PROGRESS_VALUE;
3013 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3014 total += file->FileSize;
3016 ui_progress(package,0,total,0,0);
3018 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3020 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3021 debugstr_w(feature->Feature), feature->Installed,
3022 feature->ActionRequest, feature->Action);
3025 return ERROR_SUCCESS;
3028 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3030 MSIPACKAGE* package = param;
3031 LPCWSTR cond = NULL;
3032 LPCWSTR message = NULL;
3035 static const WCHAR title[]=
3036 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3038 cond = MSI_RecordGetString(row,1);
3040 r = MSI_EvaluateConditionW(package,cond);
3041 if (r == MSICONDITION_FALSE)
3043 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3046 message = MSI_RecordGetString(row,2);
3047 deformat_string(package,message,&deformated);
3048 MessageBoxW(NULL,deformated,title,MB_OK);
3049 msi_free(deformated);
3052 return ERROR_INSTALL_FAILURE;
3055 return ERROR_SUCCESS;
3058 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3061 MSIQUERY * view = NULL;
3062 static const WCHAR ExecSeqQuery[] =
3063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3064 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3066 TRACE("Checking launch conditions\n");
3068 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3069 if (rc != ERROR_SUCCESS)
3070 return ERROR_SUCCESS;
3072 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3073 msiobj_release(&view->hdr);
3078 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3082 return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
3084 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3086 MSIRECORD * row = 0;
3088 LPWSTR deformated,buffer,deformated_name;
3090 static const WCHAR ExecSeqQuery[] =
3091 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3092 '`','R','e','g','i','s','t','r','y','`',' ',
3093 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3094 ' ','=',' ' ,'\'','%','s','\'',0 };
3095 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3096 static const WCHAR fmt2[]=
3097 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3099 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3103 root = MSI_RecordGetInteger(row,2);
3104 key = MSI_RecordGetString(row, 3);
3105 name = MSI_RecordGetString(row, 4);
3106 deformat_string(package, key , &deformated);
3107 deformat_string(package, name, &deformated_name);
3109 len = strlenW(deformated) + 6;
3110 if (deformated_name)
3111 len+=strlenW(deformated_name);
3113 buffer = msi_alloc( len *sizeof(WCHAR));
3115 if (deformated_name)
3116 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3118 sprintfW(buffer,fmt,root,deformated);
3120 msi_free(deformated);
3121 msi_free(deformated_name);
3122 msiobj_release(&row->hdr);
3126 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3128 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3133 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3136 return strdupW( file->TargetPath );
3141 static HKEY openSharedDLLsKey(void)
3144 static const WCHAR path[] =
3145 {'S','o','f','t','w','a','r','e','\\',
3146 'M','i','c','r','o','s','o','f','t','\\',
3147 'W','i','n','d','o','w','s','\\',
3148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3149 'S','h','a','r','e','d','D','L','L','s',0};
3151 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3155 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3160 DWORD sz = sizeof(count);
3163 hkey = openSharedDLLsKey();
3164 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3165 if (rc != ERROR_SUCCESS)
3171 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3175 hkey = openSharedDLLsKey();
3177 msi_reg_set_val_dword( hkey, path, count );
3179 RegDeleteValueW(hkey,path);
3185 * Return TRUE if the count should be written out and FALSE if not
3187 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3189 MSIFEATURE *feature;
3193 /* only refcount DLLs */
3194 if (comp->KeyPath == NULL ||
3195 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3196 comp->Attributes & msidbComponentAttributesODBCDataSource)
3200 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3201 write = (count > 0);
3203 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3207 /* increment counts */
3208 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3212 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3215 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3217 if ( cl->component == comp )
3222 /* decrement counts */
3223 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3227 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3230 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3232 if ( cl->component == comp )
3237 /* ref count all the files in the component */
3242 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3244 if (file->Component == comp)
3245 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3249 /* add a count for permanent */
3250 if (comp->Attributes & msidbComponentAttributesPermanent)
3253 comp->RefCount = count;
3256 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3259 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3261 WCHAR squished_pc[GUID_SIZE];
3262 WCHAR squished_cc[GUID_SIZE];
3269 squash_guid(package->ProductCode,squished_pc);
3270 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3272 msi_set_sourcedir_props(package, FALSE);
3274 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3278 ui_progress(package,2,0,0,0);
3279 if (!comp->ComponentId)
3282 squash_guid(comp->ComponentId,squished_cc);
3284 msi_free(comp->FullKeypath);
3285 comp->FullKeypath = resolve_keypath( package, comp );
3287 ACTION_RefCountComponent( package, comp );
3289 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3290 debugstr_w(comp->Component),
3291 debugstr_w(squished_cc),
3292 debugstr_w(comp->FullKeypath),
3294 comp->ActionRequest);
3296 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3297 comp->ActionRequest == INSTALLSTATE_SOURCE)
3299 if (!comp->FullKeypath)
3302 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3303 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3306 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3309 if (rc != ERROR_SUCCESS)
3312 if (comp->Attributes & msidbComponentAttributesPermanent)
3314 static const WCHAR szPermKey[] =
3315 { '0','0','0','0','0','0','0','0','0','0','0','0',
3316 '0','0','0','0','0','0','0','0','0','0','0','0',
3317 '0','0','0','0','0','0','0','0',0 };
3319 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3322 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3323 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3329 WCHAR source[MAX_PATH];
3330 WCHAR base[MAX_PATH];
3333 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3334 static const WCHAR query[] = {
3335 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3336 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3337 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3338 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3339 '`','D','i','s','k','I','d','`',0};
3341 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3344 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3345 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3346 ptr2 = strrchrW(source, '\\') + 1;
3347 msiobj_release(&row->hdr);
3349 lstrcpyW(base, package->PackagePath);
3350 ptr = strrchrW(base, '\\');
3353 sourcepath = resolve_file_source(package, file);
3354 ptr = sourcepath + lstrlenW(base);
3355 lstrcpyW(ptr2, ptr);
3356 msi_free(sourcepath);
3358 msi_reg_set_val_str(hkey, squished_pc, source);
3362 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3364 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3365 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3367 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3369 comp->Action = comp->ActionRequest;
3372 uirow = MSI_CreateRecord(3);
3373 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3374 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3375 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3376 ui_actiondata(package,szProcessComponents,uirow);
3377 msiobj_release( &uirow->hdr );
3380 return ERROR_SUCCESS;
3391 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3392 LPWSTR lpszName, LONG_PTR lParam)
3395 typelib_struct *tl_struct = (typelib_struct*) lParam;
3396 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3400 if (!IS_INTRESOURCE(lpszName))
3402 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3406 sz = strlenW(tl_struct->source)+4;
3407 sz *= sizeof(WCHAR);
3409 if ((INT_PTR)lpszName == 1)
3410 tl_struct->path = strdupW(tl_struct->source);
3413 tl_struct->path = msi_alloc(sz);
3414 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3417 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3418 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3421 msi_free(tl_struct->path);
3422 tl_struct->path = NULL;
3427 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3428 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3430 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3434 msi_free(tl_struct->path);
3435 tl_struct->path = NULL;
3437 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3438 ITypeLib_Release(tl_struct->ptLib);
3443 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3445 MSIPACKAGE* package = param;
3449 typelib_struct tl_struct;
3454 component = MSI_RecordGetString(row,3);
3455 comp = get_loaded_component(package,component);
3457 return ERROR_SUCCESS;
3461 TRACE("component is disabled\n");
3462 return ERROR_SUCCESS;
3465 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3467 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3468 comp->Action = comp->Installed;
3469 return ERROR_SUCCESS;
3471 comp->Action = INSTALLSTATE_LOCAL;
3473 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3475 TRACE("component has no key path\n");
3476 return ERROR_SUCCESS;
3478 ui_actiondata( package, szRegisterTypeLibraries, row );
3480 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3484 guid = MSI_RecordGetString(row,1);
3485 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3486 tl_struct.source = strdupW( file->TargetPath );
3487 tl_struct.path = NULL;
3489 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3490 (LONG_PTR)&tl_struct);
3498 helpid = MSI_RecordGetString(row,6);
3500 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3501 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3505 ERR("Failed to register type library %s\n",
3506 debugstr_w(tl_struct.path));
3508 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3510 ITypeLib_Release(tl_struct.ptLib);
3511 msi_free(tl_struct.path);
3514 ERR("Failed to load type library %s\n",
3515 debugstr_w(tl_struct.source));
3517 FreeLibrary(module);
3518 msi_free(tl_struct.source);
3522 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3525 ERR("Failed to load type library: %08x\n", hr);
3526 return ERROR_INSTALL_FAILURE;
3529 ITypeLib_Release(tlib);
3532 return ERROR_SUCCESS;
3535 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3538 * OK this is a bit confusing.. I am given a _Component key and I believe
3539 * that the file that is being registered as a type library is the "key file
3540 * of that component" which I interpret to mean "The file in the KeyPath of
3545 static const WCHAR Query[] =
3546 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3547 '`','T','y','p','e','L','i','b','`',0};
3549 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3550 if (rc != ERROR_SUCCESS)
3551 return ERROR_SUCCESS;
3553 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3554 msiobj_release(&view->hdr);
3558 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3560 MSIPACKAGE *package = param;
3561 LPCWSTR component, guid;
3569 component = MSI_RecordGetString( row, 3 );
3570 comp = get_loaded_component( package, component );
3572 return ERROR_SUCCESS;
3576 TRACE("component is disabled\n");
3577 return ERROR_SUCCESS;
3580 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3582 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3583 comp->Action = comp->Installed;
3584 return ERROR_SUCCESS;
3586 comp->Action = INSTALLSTATE_ABSENT;
3588 ui_actiondata( package, szUnregisterTypeLibraries, row );
3590 guid = MSI_RecordGetString( row, 1 );
3591 CLSIDFromString( (LPCWSTR)guid, &libid );
3592 version = MSI_RecordGetInteger( row, 4 );
3593 language = MSI_RecordGetInteger( row, 2 );
3596 syskind = SYS_WIN64;
3598 syskind = SYS_WIN32;
3601 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3604 WARN("Failed to unregister typelib: %08x\n", hr);
3607 return ERROR_SUCCESS;
3610 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3614 static const WCHAR query[] =
3615 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3616 '`','T','y','p','e','L','i','b','`',0};
3618 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3619 if (rc != ERROR_SUCCESS)
3620 return ERROR_SUCCESS;
3622 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3623 msiobj_release( &view->hdr );
3627 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3629 static const WCHAR szlnk[] = {'.','l','n','k',0};
3630 LPCWSTR directory, extension;
3631 LPWSTR link_folder, link_file, filename;
3633 directory = MSI_RecordGetString( row, 2 );
3634 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3636 /* may be needed because of a bug somewhere else */
3637 create_full_pathW( link_folder );
3639 filename = msi_dup_record_field( row, 3 );
3640 reduce_to_longfilename( filename );
3642 extension = strchrW( filename, '.' );
3643 if (!extension || strcmpiW( extension, szlnk ))
3645 int len = strlenW( filename );
3646 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3647 memcpy( filename + len, szlnk, sizeof(szlnk) );
3649 link_file = build_directory_name( 2, link_folder, filename );
3650 msi_free( link_folder );
3651 msi_free( filename );
3656 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3658 MSIPACKAGE *package = param;
3659 LPWSTR link_file, deformated, path;
3660 LPCWSTR component, target;
3662 IShellLinkW *sl = NULL;
3663 IPersistFile *pf = NULL;
3666 component = MSI_RecordGetString(row, 4);
3667 comp = get_loaded_component(package, component);
3669 return ERROR_SUCCESS;
3673 TRACE("component is disabled\n");
3674 return ERROR_SUCCESS;
3677 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3679 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3680 comp->Action = comp->Installed;
3681 return ERROR_SUCCESS;
3683 comp->Action = INSTALLSTATE_LOCAL;
3685 ui_actiondata(package,szCreateShortcuts,row);
3687 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3688 &IID_IShellLinkW, (LPVOID *) &sl );
3692 ERR("CLSID_ShellLink not available\n");
3696 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3699 ERR("QueryInterface(IID_IPersistFile) failed\n");
3703 target = MSI_RecordGetString(row, 5);
3704 if (strchrW(target, '['))
3706 deformat_string(package, target, &deformated);
3707 IShellLinkW_SetPath(sl,deformated);
3708 msi_free(deformated);
3712 FIXME("poorly handled shortcut format, advertised shortcut\n");
3713 IShellLinkW_SetPath(sl,comp->FullKeypath);
3716 if (!MSI_RecordIsNull(row,6))
3718 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3719 deformat_string(package, arguments, &deformated);
3720 IShellLinkW_SetArguments(sl,deformated);
3721 msi_free(deformated);
3724 if (!MSI_RecordIsNull(row,7))
3726 LPCWSTR description = MSI_RecordGetString(row, 7);
3727 IShellLinkW_SetDescription(sl, description);
3730 if (!MSI_RecordIsNull(row,8))
3731 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3733 if (!MSI_RecordIsNull(row,9))
3736 LPCWSTR icon = MSI_RecordGetString(row, 9);
3738 path = build_icon_path(package, icon);
3739 index = MSI_RecordGetInteger(row,10);
3741 /* no value means 0 */
3742 if (index == MSI_NULL_INTEGER)
3745 IShellLinkW_SetIconLocation(sl, path, index);
3749 if (!MSI_RecordIsNull(row,11))
3750 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3752 if (!MSI_RecordIsNull(row,12))
3754 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3755 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
3757 IShellLinkW_SetWorkingDirectory(sl, path);
3761 link_file = get_link_file(package, row);
3763 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3764 IPersistFile_Save(pf, link_file, FALSE);
3766 msi_free(link_file);
3770 IPersistFile_Release( pf );
3772 IShellLinkW_Release( sl );
3774 return ERROR_SUCCESS;
3777 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3782 static const WCHAR Query[] =
3783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3784 '`','S','h','o','r','t','c','u','t','`',0};
3786 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3787 if (rc != ERROR_SUCCESS)
3788 return ERROR_SUCCESS;
3790 res = CoInitialize( NULL );
3792 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3793 msiobj_release(&view->hdr);
3801 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3803 MSIPACKAGE *package = param;
3808 component = MSI_RecordGetString( row, 4 );
3809 comp = get_loaded_component( package, component );
3811 return ERROR_SUCCESS;
3815 TRACE("component is disabled\n");
3816 return ERROR_SUCCESS;
3819 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3821 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3822 comp->Action = comp->Installed;
3823 return ERROR_SUCCESS;
3825 comp->Action = INSTALLSTATE_ABSENT;
3827 ui_actiondata( package, szRemoveShortcuts, row );
3829 link_file = get_link_file( package, row );
3831 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3832 if (!DeleteFileW( link_file ))
3834 WARN("Failed to remove shortcut file %u\n", GetLastError());
3836 msi_free( link_file );
3838 return ERROR_SUCCESS;
3841 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3845 static const WCHAR query[] =
3846 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3847 '`','S','h','o','r','t','c','u','t','`',0};
3849 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3850 if (rc != ERROR_SUCCESS)
3851 return ERROR_SUCCESS;
3853 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3854 msiobj_release( &view->hdr );
3859 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3861 MSIPACKAGE* package = param;
3869 FileName = MSI_RecordGetString(row,1);
3872 ERR("Unable to get FileName\n");
3873 return ERROR_SUCCESS;
3876 FilePath = build_icon_path(package,FileName);
3878 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3880 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3881 FILE_ATTRIBUTE_NORMAL, NULL);
3883 if (the_file == INVALID_HANDLE_VALUE)
3885 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3887 return ERROR_SUCCESS;
3894 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3895 if (rc != ERROR_SUCCESS)
3897 ERR("Failed to get stream\n");
3898 CloseHandle(the_file);
3899 DeleteFileW(FilePath);
3902 WriteFile(the_file,buffer,sz,&write,NULL);
3903 } while (sz == 1024);
3906 CloseHandle(the_file);
3908 return ERROR_SUCCESS;
3911 static UINT msi_publish_icons(MSIPACKAGE *package)
3916 static const WCHAR query[]= {
3917 'S','E','L','E','C','T',' ','*',' ',
3918 'F','R','O','M',' ','`','I','c','o','n','`',0};
3920 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3921 if (r == ERROR_SUCCESS)
3923 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3924 msiobj_release(&view->hdr);
3927 return ERROR_SUCCESS;
3930 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3936 MSISOURCELISTINFO *info;
3938 r = RegCreateKeyW(hkey, szSourceList, &source);
3939 if (r != ERROR_SUCCESS)
3942 RegCloseKey(source);
3944 buffer = strrchrW(package->PackagePath, '\\') + 1;
3945 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3946 package->Context, MSICODE_PRODUCT,
3947 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3948 if (r != ERROR_SUCCESS)
3951 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3952 package->Context, MSICODE_PRODUCT,
3953 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3954 if (r != ERROR_SUCCESS)
3957 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3958 package->Context, MSICODE_PRODUCT,
3959 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3960 if (r != ERROR_SUCCESS)
3963 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3965 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3966 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3967 info->options, info->value);
3969 MsiSourceListSetInfoW(package->ProductCode, NULL,
3970 info->context, info->options,
3971 info->property, info->value);
3974 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3976 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3977 disk->context, disk->options,
3978 disk->disk_id, disk->volume_label, disk->disk_prompt);
3981 return ERROR_SUCCESS;
3984 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3986 MSIHANDLE hdb, suminfo;
3987 WCHAR guids[MAX_PATH];
3988 WCHAR packcode[SQUISH_GUID_SIZE];
3995 static const WCHAR szProductLanguage[] =
3996 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3997 static const WCHAR szARPProductIcon[] =
3998 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3999 static const WCHAR szProductVersion[] =
4000 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4001 static const WCHAR szAssignment[] =
4002 {'A','s','s','i','g','n','m','e','n','t',0};
4003 static const WCHAR szAdvertiseFlags[] =
4004 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4005 static const WCHAR szClients[] =
4006 {'C','l','i','e','n','t','s',0};
4007 static const WCHAR szColon[] = {':',0};
4009 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4010 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4013 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4014 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4017 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4019 buffer = msi_dup_property(package->db, szARPProductIcon);
4022 LPWSTR path = build_icon_path(package,buffer);
4023 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4028 buffer = msi_dup_property(package->db, szProductVersion);
4031 DWORD verdword = msi_version_str_to_dword(buffer);
4032 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4036 msi_reg_set_val_dword(hkey, szAssignment, 0);
4037 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4038 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4039 msi_reg_set_val_str(hkey, szClients, szColon);
4041 hdb = alloc_msihandle(&package->db->hdr);
4043 return ERROR_NOT_ENOUGH_MEMORY;
4045 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4046 MsiCloseHandle(hdb);
4047 if (r != ERROR_SUCCESS)
4051 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4052 NULL, guids, &size);
4053 if (r != ERROR_SUCCESS)
4056 ptr = strchrW(guids, ';');
4058 squash_guid(guids, packcode);
4059 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4062 MsiCloseHandle(suminfo);
4063 return ERROR_SUCCESS;
4066 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4071 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4073 upgrade = msi_dup_property(package->db, szUpgradeCode);
4075 return ERROR_SUCCESS;
4077 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4079 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4080 if (r != ERROR_SUCCESS)
4085 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4086 if (r != ERROR_SUCCESS)
4090 squash_guid(package->ProductCode, squashed_pc);
4091 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4100 static BOOL msi_check_publish(MSIPACKAGE *package)
4102 MSIFEATURE *feature;
4104 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4106 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4113 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4115 MSIFEATURE *feature;
4117 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4119 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4126 static UINT msi_publish_patches( MSIPACKAGE *package )
4128 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4129 WCHAR patch_squashed[GUID_SIZE];
4130 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4132 MSIPATCHINFO *patch;
4134 WCHAR *p, *all_patches = NULL;
4137 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4138 if (r != ERROR_SUCCESS)
4139 return ERROR_FUNCTION_FAILED;
4141 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4142 if (res != ERROR_SUCCESS)
4144 r = ERROR_FUNCTION_FAILED;
4148 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4149 if (r != ERROR_SUCCESS)
4152 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4154 squash_guid( patch->patchcode, patch_squashed );
4155 len += strlenW( patch_squashed ) + 1;
4158 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4162 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4166 squash_guid( patch->patchcode, p );
4167 p += strlenW( p ) + 1;
4169 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4170 (const BYTE *)patch->transforms,
4171 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4172 if (res != ERROR_SUCCESS)
4175 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4176 if (r != ERROR_SUCCESS)
4179 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4180 (const BYTE *)patch->localfile,
4181 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4182 RegCloseKey( patch_key );
4183 if (res != ERROR_SUCCESS)
4186 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4187 if (res != ERROR_SUCCESS)
4190 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4191 RegCloseKey( patch_key );
4192 if (res != ERROR_SUCCESS)
4196 all_patches[len] = 0;
4197 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4198 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4199 if (res != ERROR_SUCCESS)
4202 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4203 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4204 if (res != ERROR_SUCCESS)
4205 r = ERROR_FUNCTION_FAILED;
4208 RegCloseKey( product_patches_key );
4209 RegCloseKey( patches_key );
4210 RegCloseKey( product_key );
4211 msi_free( all_patches );
4216 * 99% of the work done here is only done for
4217 * advertised installs. However this is where the
4218 * Icon table is processed and written out
4219 * so that is what I am going to do here.
4221 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4224 HKEY hukey = NULL, hudkey = NULL;
4227 if (!list_empty(&package->patches))
4229 rc = msi_publish_patches(package);
4230 if (rc != ERROR_SUCCESS)
4234 /* FIXME: also need to publish if the product is in advertise mode */
4235 if (!msi_check_publish(package))
4236 return ERROR_SUCCESS;
4238 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4240 if (rc != ERROR_SUCCESS)
4243 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4244 NULL, &hudkey, TRUE);
4245 if (rc != ERROR_SUCCESS)
4248 rc = msi_publish_upgrade_code(package);
4249 if (rc != ERROR_SUCCESS)
4252 rc = msi_publish_product_properties(package, hukey);
4253 if (rc != ERROR_SUCCESS)
4256 rc = msi_publish_sourcelist(package, hukey);
4257 if (rc != ERROR_SUCCESS)
4260 rc = msi_publish_icons(package);
4263 uirow = MSI_CreateRecord( 1 );
4264 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4265 ui_actiondata( package, szPublishProduct, uirow );
4266 msiobj_release( &uirow->hdr );
4269 RegCloseKey(hudkey);
4274 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4276 WCHAR *filename, *ptr, *folder, *ret;
4277 const WCHAR *dirprop;
4279 filename = msi_dup_record_field( row, 2 );
4280 if (filename && (ptr = strchrW( filename, '|' )))
4285 dirprop = MSI_RecordGetString( row, 3 );
4288 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4290 folder = msi_dup_property( package->db, dirprop );
4293 folder = msi_dup_property( package->db, szWindowsFolder );
4297 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4298 msi_free( filename );
4302 ret = build_directory_name( 2, folder, ptr );
4304 msi_free( filename );
4309 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4311 MSIPACKAGE *package = param;
4312 LPCWSTR component, section, key, value, identifier;
4313 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4318 component = MSI_RecordGetString(row, 8);
4319 comp = get_loaded_component(package,component);
4321 return ERROR_SUCCESS;
4325 TRACE("component is disabled\n");
4326 return ERROR_SUCCESS;
4329 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4331 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4332 comp->Action = comp->Installed;
4333 return ERROR_SUCCESS;
4335 comp->Action = INSTALLSTATE_LOCAL;
4337 identifier = MSI_RecordGetString(row,1);
4338 section = MSI_RecordGetString(row,4);
4339 key = MSI_RecordGetString(row,5);
4340 value = MSI_RecordGetString(row,6);
4341 action = MSI_RecordGetInteger(row,7);
4343 deformat_string(package,section,&deformated_section);
4344 deformat_string(package,key,&deformated_key);
4345 deformat_string(package,value,&deformated_value);
4347 fullname = get_ini_file_name(package, row);
4351 TRACE("Adding value %s to section %s in %s\n",
4352 debugstr_w(deformated_key), debugstr_w(deformated_section),
4353 debugstr_w(fullname));
4354 WritePrivateProfileStringW(deformated_section, deformated_key,
4355 deformated_value, fullname);
4357 else if (action == 1)
4360 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4361 returned, 10, fullname);
4362 if (returned[0] == 0)
4364 TRACE("Adding value %s to section %s in %s\n",
4365 debugstr_w(deformated_key), debugstr_w(deformated_section),
4366 debugstr_w(fullname));
4368 WritePrivateProfileStringW(deformated_section, deformated_key,
4369 deformated_value, fullname);
4372 else if (action == 3)
4373 FIXME("Append to existing section not yet implemented\n");
4375 uirow = MSI_CreateRecord(4);
4376 MSI_RecordSetStringW(uirow,1,identifier);
4377 MSI_RecordSetStringW(uirow,2,deformated_section);
4378 MSI_RecordSetStringW(uirow,3,deformated_key);
4379 MSI_RecordSetStringW(uirow,4,deformated_value);
4380 ui_actiondata(package,szWriteIniValues,uirow);
4381 msiobj_release( &uirow->hdr );
4384 msi_free(deformated_key);
4385 msi_free(deformated_value);
4386 msi_free(deformated_section);
4387 return ERROR_SUCCESS;
4390 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4394 static const WCHAR ExecSeqQuery[] =
4395 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4396 '`','I','n','i','F','i','l','e','`',0};
4398 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4399 if (rc != ERROR_SUCCESS)
4401 TRACE("no IniFile table\n");
4402 return ERROR_SUCCESS;
4405 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4406 msiobj_release(&view->hdr);
4410 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4412 MSIPACKAGE *package = param;
4413 LPCWSTR component, section, key, value, identifier;
4414 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4419 component = MSI_RecordGetString( row, 8 );
4420 comp = get_loaded_component( package, component );
4422 return ERROR_SUCCESS;
4426 TRACE("component is disabled\n");
4427 return ERROR_SUCCESS;
4430 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4432 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4433 comp->Action = comp->Installed;
4434 return ERROR_SUCCESS;
4436 comp->Action = INSTALLSTATE_ABSENT;
4438 identifier = MSI_RecordGetString( row, 1 );
4439 section = MSI_RecordGetString( row, 4 );
4440 key = MSI_RecordGetString( row, 5 );
4441 value = MSI_RecordGetString( row, 6 );
4442 action = MSI_RecordGetInteger( row, 7 );
4444 deformat_string( package, section, &deformated_section );
4445 deformat_string( package, key, &deformated_key );
4446 deformat_string( package, value, &deformated_value );
4448 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4450 filename = get_ini_file_name( package, row );
4452 TRACE("Removing key %s from section %s in %s\n",
4453 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4455 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4457 WARN("Unable to remove key %u\n", GetLastError());
4459 msi_free( filename );
4462 FIXME("Unsupported action %d\n", action);
4465 uirow = MSI_CreateRecord( 4 );
4466 MSI_RecordSetStringW( uirow, 1, identifier );
4467 MSI_RecordSetStringW( uirow, 2, deformated_section );
4468 MSI_RecordSetStringW( uirow, 3, deformated_key );
4469 MSI_RecordSetStringW( uirow, 4, deformated_value );
4470 ui_actiondata( package, szRemoveIniValues, uirow );
4471 msiobj_release( &uirow->hdr );
4473 msi_free( deformated_key );
4474 msi_free( deformated_value );
4475 msi_free( deformated_section );
4476 return ERROR_SUCCESS;
4479 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4481 MSIPACKAGE *package = param;
4482 LPCWSTR component, section, key, value, identifier;
4483 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4488 component = MSI_RecordGetString( row, 8 );
4489 comp = get_loaded_component( package, component );
4491 return ERROR_SUCCESS;
4495 TRACE("component is disabled\n");
4496 return ERROR_SUCCESS;
4499 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4501 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4502 comp->Action = comp->Installed;
4503 return ERROR_SUCCESS;
4505 comp->Action = INSTALLSTATE_LOCAL;
4507 identifier = MSI_RecordGetString( row, 1 );
4508 section = MSI_RecordGetString( row, 4 );
4509 key = MSI_RecordGetString( row, 5 );
4510 value = MSI_RecordGetString( row, 6 );
4511 action = MSI_RecordGetInteger( row, 7 );
4513 deformat_string( package, section, &deformated_section );
4514 deformat_string( package, key, &deformated_key );
4515 deformat_string( package, value, &deformated_value );
4517 if (action == msidbIniFileActionRemoveLine)
4519 filename = get_ini_file_name( package, row );
4521 TRACE("Removing key %s from section %s in %s\n",
4522 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4524 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4526 WARN("Unable to remove key %u\n", GetLastError());
4528 msi_free( filename );
4531 FIXME("Unsupported action %d\n", action);
4533 uirow = MSI_CreateRecord( 4 );
4534 MSI_RecordSetStringW( uirow, 1, identifier );
4535 MSI_RecordSetStringW( uirow, 2, deformated_section );
4536 MSI_RecordSetStringW( uirow, 3, deformated_key );
4537 MSI_RecordSetStringW( uirow, 4, deformated_value );
4538 ui_actiondata( package, szRemoveIniValues, uirow );
4539 msiobj_release( &uirow->hdr );
4541 msi_free( deformated_key );
4542 msi_free( deformated_value );
4543 msi_free( deformated_section );
4544 return ERROR_SUCCESS;
4547 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4551 static const WCHAR query[] =
4552 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4553 '`','I','n','i','F','i','l','e','`',0};
4554 static const WCHAR remove_query[] =
4555 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4556 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4558 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4559 if (rc == ERROR_SUCCESS)
4561 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4562 msiobj_release( &view->hdr );
4563 if (rc != ERROR_SUCCESS)
4567 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4568 if (rc == ERROR_SUCCESS)
4570 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4571 msiobj_release( &view->hdr );
4572 if (rc != ERROR_SUCCESS)
4576 return ERROR_SUCCESS;
4579 static void register_dll( const WCHAR *dll, BOOL unregister )
4583 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4586 HRESULT (WINAPI *func_ptr)( void );
4587 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4589 func_ptr = (void *)GetProcAddress( hmod, func );
4592 HRESULT hr = func_ptr();
4594 WARN("failed to register dll 0x%08x\n", hr);
4597 WARN("entry point %s not found\n", func);
4598 FreeLibrary( hmod );
4601 WARN("failed to load library %u\n", GetLastError());
4604 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4606 MSIPACKAGE *package = param;
4611 filename = MSI_RecordGetString(row,1);
4612 file = get_loaded_file( package, filename );
4616 ERR("Unable to find file id %s\n",debugstr_w(filename));
4617 return ERROR_SUCCESS;
4620 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4622 register_dll( file->TargetPath, FALSE );
4624 uirow = MSI_CreateRecord( 2 );
4625 MSI_RecordSetStringW( uirow, 1, filename );
4626 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4627 ui_actiondata( package, szSelfRegModules, uirow );
4628 msiobj_release( &uirow->hdr );
4630 return ERROR_SUCCESS;
4633 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4637 static const WCHAR ExecSeqQuery[] =
4638 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4639 '`','S','e','l','f','R','e','g','`',0};
4641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4642 if (rc != ERROR_SUCCESS)
4644 TRACE("no SelfReg table\n");
4645 return ERROR_SUCCESS;
4648 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4649 msiobj_release(&view->hdr);
4651 return ERROR_SUCCESS;
4654 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4656 MSIPACKAGE *package = param;
4661 filename = MSI_RecordGetString( row, 1 );
4662 file = get_loaded_file( package, filename );
4666 ERR("Unable to find file id %s\n", debugstr_w(filename));
4667 return ERROR_SUCCESS;
4670 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4672 register_dll( file->TargetPath, TRUE );
4674 uirow = MSI_CreateRecord( 2 );
4675 MSI_RecordSetStringW( uirow, 1, filename );
4676 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4677 ui_actiondata( package, szSelfUnregModules, uirow );
4678 msiobj_release( &uirow->hdr );
4680 return ERROR_SUCCESS;
4683 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4687 static const WCHAR query[] =
4688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4689 '`','S','e','l','f','R','e','g','`',0};
4691 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4692 if (rc != ERROR_SUCCESS)
4694 TRACE("no SelfReg table\n");
4695 return ERROR_SUCCESS;
4698 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4699 msiobj_release( &view->hdr );
4701 return ERROR_SUCCESS;
4704 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4706 MSIFEATURE *feature;
4708 HKEY hkey = NULL, userdata = NULL;
4710 if (!msi_check_publish(package))
4711 return ERROR_SUCCESS;
4713 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4715 if (rc != ERROR_SUCCESS)
4718 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4720 if (rc != ERROR_SUCCESS)
4723 /* here the guids are base 85 encoded */
4724 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4730 BOOL absent = FALSE;
4733 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4734 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4735 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4738 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4742 if (feature->Feature_Parent)
4743 size += strlenW( feature->Feature_Parent )+2;
4745 data = msi_alloc(size * sizeof(WCHAR));
4748 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4750 MSICOMPONENT* component = cl->component;
4754 if (component->ComponentId)
4756 TRACE("From %s\n",debugstr_w(component->ComponentId));
4757 CLSIDFromString(component->ComponentId, &clsid);
4758 encode_base85_guid(&clsid,buf);
4759 TRACE("to %s\n",debugstr_w(buf));
4764 if (feature->Feature_Parent)
4766 static const WCHAR sep[] = {'\2',0};
4768 strcatW(data,feature->Feature_Parent);
4771 msi_reg_set_val_str( userdata, feature->Feature, data );
4775 if (feature->Feature_Parent)
4776 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4779 size += sizeof(WCHAR);
4780 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4781 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4785 size += 2*sizeof(WCHAR);
4786 data = msi_alloc(size);
4789 if (feature->Feature_Parent)
4790 strcpyW( &data[1], feature->Feature_Parent );
4791 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4797 uirow = MSI_CreateRecord( 1 );
4798 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4799 ui_actiondata( package, szPublishFeatures, uirow);
4800 msiobj_release( &uirow->hdr );
4801 /* FIXME: call ui_progress? */
4806 RegCloseKey(userdata);
4810 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4816 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4818 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4820 if (r == ERROR_SUCCESS)
4822 RegDeleteValueW(hkey, feature->Feature);
4826 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4828 if (r == ERROR_SUCCESS)
4830 RegDeleteValueW(hkey, feature->Feature);
4834 uirow = MSI_CreateRecord( 1 );
4835 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4836 ui_actiondata( package, szUnpublishFeatures, uirow );
4837 msiobj_release( &uirow->hdr );
4839 return ERROR_SUCCESS;
4842 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4844 MSIFEATURE *feature;
4846 if (!msi_check_unpublish(package))
4847 return ERROR_SUCCESS;
4849 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4851 msi_unpublish_feature(package, feature);
4854 return ERROR_SUCCESS;
4857 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4861 WCHAR date[9], *val, *buffer;
4862 const WCHAR *prop, *key;
4864 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4865 static const WCHAR szWindowsInstaller[] =
4866 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4867 static const WCHAR modpath_fmt[] =
4868 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4869 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4870 static const WCHAR szModifyPath[] =
4871 {'M','o','d','i','f','y','P','a','t','h',0};
4872 static const WCHAR szUninstallString[] =
4873 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4874 static const WCHAR szEstimatedSize[] =
4875 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4876 static const WCHAR szProductLanguage[] =
4877 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4878 static const WCHAR szProductVersion[] =
4879 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4880 static const WCHAR szDisplayVersion[] =
4881 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4882 static const WCHAR szInstallSource[] =
4883 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4884 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4885 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4886 static const WCHAR szAuthorizedCDFPrefix[] =
4887 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4888 static const WCHAR szARPCONTACT[] =
4889 {'A','R','P','C','O','N','T','A','C','T',0};
4890 static const WCHAR szContact[] =
4891 {'C','o','n','t','a','c','t',0};
4892 static const WCHAR szARPCOMMENTS[] =
4893 {'A','R','P','C','O','M','M','E','N','T','S',0};
4894 static const WCHAR szComments[] =
4895 {'C','o','m','m','e','n','t','s',0};
4896 static const WCHAR szProductName[] =
4897 {'P','r','o','d','u','c','t','N','a','m','e',0};
4898 static const WCHAR szDisplayName[] =
4899 {'D','i','s','p','l','a','y','N','a','m','e',0};
4900 static const WCHAR szARPHELPLINK[] =
4901 {'A','R','P','H','E','L','P','L','I','N','K',0};
4902 static const WCHAR szHelpLink[] =
4903 {'H','e','l','p','L','i','n','k',0};
4904 static const WCHAR szARPHELPTELEPHONE[] =
4905 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4906 static const WCHAR szHelpTelephone[] =
4907 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4908 static const WCHAR szARPINSTALLLOCATION[] =
4909 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4910 static const WCHAR szInstallLocation[] =
4911 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4912 static const WCHAR szManufacturer[] =
4913 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4914 static const WCHAR szPublisher[] =
4915 {'P','u','b','l','i','s','h','e','r',0};
4916 static const WCHAR szARPREADME[] =
4917 {'A','R','P','R','E','A','D','M','E',0};
4918 static const WCHAR szReadme[] =
4919 {'R','e','a','d','M','e',0};
4920 static const WCHAR szARPSIZE[] =
4921 {'A','R','P','S','I','Z','E',0};
4922 static const WCHAR szSize[] =
4923 {'S','i','z','e',0};
4924 static const WCHAR szARPURLINFOABOUT[] =
4925 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4926 static const WCHAR szURLInfoAbout[] =
4927 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4928 static const WCHAR szARPURLUPDATEINFO[] =
4929 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4930 static const WCHAR szURLUpdateInfo[] =
4931 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4933 static const WCHAR *propval[] = {
4934 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4935 szARPCONTACT, szContact,
4936 szARPCOMMENTS, szComments,
4937 szProductName, szDisplayName,
4938 szARPHELPLINK, szHelpLink,
4939 szARPHELPTELEPHONE, szHelpTelephone,
4940 szARPINSTALLLOCATION, szInstallLocation,
4941 cszSourceDir, szInstallSource,
4942 szManufacturer, szPublisher,
4943 szARPREADME, szReadme,
4945 szARPURLINFOABOUT, szURLInfoAbout,
4946 szARPURLUPDATEINFO, szURLUpdateInfo,
4949 const WCHAR **p = propval;
4955 val = msi_dup_property(package->db, prop);
4956 msi_reg_set_val_str(hkey, key, val);
4960 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4962 size = deformat_string(package, modpath_fmt, &buffer);
4963 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4964 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4967 /* FIXME: Write real Estimated Size when we have it */
4968 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4970 GetLocalTime(&systime);
4971 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4972 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4974 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4975 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4977 buffer = msi_dup_property(package->db, szProductVersion);
4978 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4981 DWORD verdword = msi_version_str_to_dword(buffer);
4983 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4984 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4985 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4989 return ERROR_SUCCESS;
4992 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4994 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4996 LPWSTR upgrade_code;
5001 /* FIXME: also need to publish if the product is in advertise mode */
5002 if (!msi_check_publish(package))
5003 return ERROR_SUCCESS;
5005 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5006 if (rc != ERROR_SUCCESS)
5009 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5010 NULL, &props, TRUE);
5011 if (rc != ERROR_SUCCESS)
5014 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5015 msi_free( package->db->localfile );
5016 package->db->localfile = NULL;
5018 rc = msi_publish_install_properties(package, hkey);
5019 if (rc != ERROR_SUCCESS)
5022 rc = msi_publish_install_properties(package, props);
5023 if (rc != ERROR_SUCCESS)
5026 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5029 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5030 squash_guid(package->ProductCode, squashed_pc);
5031 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5032 RegCloseKey(upgrade);
5033 msi_free(upgrade_code);
5037 uirow = MSI_CreateRecord( 1 );
5038 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5039 ui_actiondata( package, szRegisterProduct, uirow );
5040 msiobj_release( &uirow->hdr );
5043 return ERROR_SUCCESS;
5046 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5048 return execute_script(package,INSTALL_SCRIPT);
5051 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5053 WCHAR *upgrade, **features;
5054 BOOL full_uninstall = TRUE;
5055 MSIFEATURE *feature;
5056 MSIPATCHINFO *patch;
5058 static const WCHAR szUpgradeCode[] =
5059 {'U','p','g','r','a','d','e','C','o','d','e',0};
5061 features = msi_split_string(remove, ',');
5064 ERR("REMOVE feature list is empty!\n");
5065 return ERROR_FUNCTION_FAILED;
5068 if (!strcmpW( features[0], szAll ))
5069 full_uninstall = TRUE;
5072 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5074 if (feature->Action != INSTALLSTATE_ABSENT)
5075 full_uninstall = FALSE;
5080 if (!full_uninstall)
5081 return ERROR_SUCCESS;
5083 MSIREG_DeleteProductKey(package->ProductCode);
5084 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5085 MSIREG_DeleteUninstallKey(package);
5087 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5088 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5089 MSIREG_DeleteUserProductKey(package->ProductCode);
5090 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5092 upgrade = msi_dup_property(package->db, szUpgradeCode);
5095 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5096 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5100 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5102 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5105 return ERROR_SUCCESS;
5108 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5113 /* turn off scheduling */
5114 package->script->CurrentlyScripting= FALSE;
5116 /* first do the same as an InstallExecute */
5117 rc = ACTION_InstallExecute(package);
5118 if (rc != ERROR_SUCCESS)
5121 /* then handle Commit Actions */
5122 rc = execute_script(package,COMMIT_SCRIPT);
5123 if (rc != ERROR_SUCCESS)
5126 remove = msi_dup_property(package->db, szRemove);
5128 rc = msi_unpublish_product(package, remove);
5134 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5136 static const WCHAR RunOnce[] = {
5137 'S','o','f','t','w','a','r','e','\\',
5138 'M','i','c','r','o','s','o','f','t','\\',
5139 'W','i','n','d','o','w','s','\\',
5140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5141 'R','u','n','O','n','c','e',0};
5142 static const WCHAR InstallRunOnce[] = {
5143 'S','o','f','t','w','a','r','e','\\',
5144 'M','i','c','r','o','s','o','f','t','\\',
5145 'W','i','n','d','o','w','s','\\',
5146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5147 'I','n','s','t','a','l','l','e','r','\\',
5148 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5150 static const WCHAR msiexec_fmt[] = {
5152 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5153 '\"','%','s','\"',0};
5154 static const WCHAR install_fmt[] = {
5155 '/','I',' ','\"','%','s','\"',' ',
5156 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5157 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5158 WCHAR buffer[256], sysdir[MAX_PATH];
5160 WCHAR squished_pc[100];
5162 squash_guid(package->ProductCode,squished_pc);
5164 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5165 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5166 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5169 msi_reg_set_val_str( hkey, squished_pc, buffer );
5172 TRACE("Reboot command %s\n",debugstr_w(buffer));
5174 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5175 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5177 msi_reg_set_val_str( hkey, squished_pc, buffer );
5180 return ERROR_INSTALL_SUSPEND;
5183 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5189 * We are currently doing what should be done here in the top level Install
5190 * however for Administrative and uninstalls this step will be needed
5192 if (!package->PackagePath)
5193 return ERROR_SUCCESS;
5195 msi_set_sourcedir_props(package, TRUE);
5197 attrib = GetFileAttributesW(package->db->path);
5198 if (attrib == INVALID_FILE_ATTRIBUTES)
5204 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5205 package->Context, MSICODE_PRODUCT,
5206 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5207 if (rc == ERROR_MORE_DATA)
5209 prompt = msi_alloc(size * sizeof(WCHAR));
5210 MsiSourceListGetInfoW(package->ProductCode, NULL,
5211 package->Context, MSICODE_PRODUCT,
5212 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5215 prompt = strdupW(package->db->path);
5217 msg = generate_error_string(package,1302,1,prompt);
5218 while(attrib == INVALID_FILE_ATTRIBUTES)
5220 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5223 rc = ERROR_INSTALL_USEREXIT;
5226 attrib = GetFileAttributesW(package->db->path);
5232 return ERROR_SUCCESS;
5237 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5240 LPWSTR buffer, productid = NULL;
5241 UINT i, rc = ERROR_SUCCESS;
5244 static const WCHAR szPropKeys[][80] =
5246 {'P','r','o','d','u','c','t','I','D',0},
5247 {'U','S','E','R','N','A','M','E',0},
5248 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5252 static const WCHAR szRegKeys[][80] =
5254 {'P','r','o','d','u','c','t','I','D',0},
5255 {'R','e','g','O','w','n','e','r',0},
5256 {'R','e','g','C','o','m','p','a','n','y',0},
5260 if (msi_check_unpublish(package))
5262 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5266 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5270 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5272 if (rc != ERROR_SUCCESS)
5275 for( i = 0; szPropKeys[i][0]; i++ )
5277 buffer = msi_dup_property( package->db, szPropKeys[i] );
5278 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5283 uirow = MSI_CreateRecord( 1 );
5284 MSI_RecordSetStringW( uirow, 1, productid );
5285 ui_actiondata( package, szRegisterUser, uirow );
5286 msiobj_release( &uirow->hdr );
5288 msi_free(productid);
5294 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5298 package->script->InWhatSequence |= SEQUENCE_EXEC;
5299 rc = ACTION_ProcessExecSequence(package,FALSE);
5304 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5306 MSIPACKAGE *package = param;
5307 LPCWSTR compgroupid, component, feature, qualifier, text;
5308 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5317 feature = MSI_RecordGetString(rec, 5);
5318 feat = get_loaded_feature(package, feature);
5320 return ERROR_SUCCESS;
5322 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5323 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5324 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5326 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5327 feat->Action = feat->Installed;
5328 return ERROR_SUCCESS;
5331 component = MSI_RecordGetString(rec, 3);
5332 comp = get_loaded_component(package, component);
5334 return ERROR_SUCCESS;
5336 compgroupid = MSI_RecordGetString(rec,1);
5337 qualifier = MSI_RecordGetString(rec,2);
5339 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5340 if (rc != ERROR_SUCCESS)
5343 advertise = create_component_advertise_string( package, comp, feature );
5344 text = MSI_RecordGetString( rec, 4 );
5347 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5348 strcpyW( p, advertise );
5350 msi_free( advertise );
5353 existing = msi_reg_get_val_str( hkey, qualifier );
5355 sz = strlenW( advertise ) + 1;
5358 for (p = existing; *p; p += len)
5360 len = strlenW( p ) + 1;
5361 if (strcmpW( advertise, p )) sz += len;
5364 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5366 rc = ERROR_OUTOFMEMORY;
5372 for (p = existing; *p; p += len)
5374 len = strlenW( p ) + 1;
5375 if (strcmpW( advertise, p ))
5377 memcpy( q, p, len * sizeof(WCHAR) );
5382 strcpyW( q, advertise );
5383 q[strlenW( q ) + 1] = 0;
5385 msi_reg_set_val_multi_str( hkey, qualifier, output );
5390 msi_free( advertise );
5391 msi_free( existing );
5394 uirow = MSI_CreateRecord( 2 );
5395 MSI_RecordSetStringW( uirow, 1, compgroupid );
5396 MSI_RecordSetStringW( uirow, 2, qualifier);
5397 ui_actiondata( package, szPublishComponents, uirow);
5398 msiobj_release( &uirow->hdr );
5399 /* FIXME: call ui_progress? */
5405 * At present I am ignorning the advertised components part of this and only
5406 * focusing on the qualified component sets
5408 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5412 static const WCHAR ExecSeqQuery[] =
5413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5414 '`','P','u','b','l','i','s','h',
5415 'C','o','m','p','o','n','e','n','t','`',0};
5417 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5418 if (rc != ERROR_SUCCESS)
5419 return ERROR_SUCCESS;
5421 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5422 msiobj_release(&view->hdr);
5427 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5429 static const WCHAR szInstallerComponents[] = {
5430 'S','o','f','t','w','a','r','e','\\',
5431 'M','i','c','r','o','s','o','f','t','\\',
5432 'I','n','s','t','a','l','l','e','r','\\',
5433 'C','o','m','p','o','n','e','n','t','s','\\',0};
5435 MSIPACKAGE *package = param;
5436 LPCWSTR compgroupid, component, feature, qualifier;
5440 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5443 feature = MSI_RecordGetString( rec, 5 );
5444 feat = get_loaded_feature( package, feature );
5446 return ERROR_SUCCESS;
5448 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5450 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5451 feat->Action = feat->Installed;
5452 return ERROR_SUCCESS;
5455 component = MSI_RecordGetString( rec, 3 );
5456 comp = get_loaded_component( package, component );
5458 return ERROR_SUCCESS;
5460 compgroupid = MSI_RecordGetString( rec, 1 );
5461 qualifier = MSI_RecordGetString( rec, 2 );
5463 squash_guid( compgroupid, squashed );
5464 strcpyW( keypath, szInstallerComponents );
5465 strcatW( keypath, squashed );
5467 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5468 if (res != ERROR_SUCCESS)
5470 WARN("Unable to delete component key %d\n", res);
5473 uirow = MSI_CreateRecord( 2 );
5474 MSI_RecordSetStringW( uirow, 1, compgroupid );
5475 MSI_RecordSetStringW( uirow, 2, qualifier );
5476 ui_actiondata( package, szUnpublishComponents, uirow );
5477 msiobj_release( &uirow->hdr );
5479 return ERROR_SUCCESS;
5482 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5486 static const WCHAR query[] =
5487 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5488 '`','P','u','b','l','i','s','h',
5489 'C','o','m','p','o','n','e','n','t','`',0};
5491 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5492 if (rc != ERROR_SUCCESS)
5493 return ERROR_SUCCESS;
5495 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5496 msiobj_release( &view->hdr );
5501 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5503 MSIPACKAGE *package = param;
5506 SC_HANDLE hscm, service = NULL;
5508 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5509 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5510 DWORD serv_type, start_type, err_control;
5511 SERVICE_DESCRIPTIONW sd = {NULL};
5513 static const WCHAR query[] =
5514 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5515 '`','C','o','m','p','o','n','e','n','t','`',' ',
5516 'W','H','E','R','E',' ',
5517 '`','C','o','m','p','o','n','e','n','t','`',' ',
5518 '=','\'','%','s','\'',0};
5520 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5523 ERR("Failed to open the SC Manager!\n");
5527 comp = MSI_RecordGetString( rec, 12 );
5528 if (!get_loaded_component( package, comp ))
5531 start_type = MSI_RecordGetInteger(rec, 5);
5532 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5535 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5536 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5537 serv_type = MSI_RecordGetInteger(rec, 4);
5538 err_control = MSI_RecordGetInteger(rec, 6);
5539 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5540 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5541 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5542 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5543 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5544 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5546 /* fetch the service path */
5547 row = MSI_QueryGetRecord(package->db, query, comp);
5550 ERR("Control query failed!\n");
5553 key = MSI_RecordGetString(row, 6);
5555 file = get_loaded_file(package, key);
5556 msiobj_release(&row->hdr);
5559 ERR("Failed to load the service file\n");
5563 if (!args || !args[0]) image_path = file->TargetPath;
5566 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5567 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5568 return ERROR_OUTOFMEMORY;
5570 strcpyW(image_path, file->TargetPath);
5571 strcatW(image_path, szSpace);
5572 strcatW(image_path, args);
5574 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5575 start_type, err_control, image_path, load_order,
5576 NULL, depends, serv_name, pass);
5580 if (GetLastError() != ERROR_SERVICE_EXISTS)
5581 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5583 else if (sd.lpDescription)
5585 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5586 WARN("failed to set service description %u\n", GetLastError());
5589 if (image_path != file->TargetPath) msi_free(image_path);
5591 CloseServiceHandle(service);
5592 CloseServiceHandle(hscm);
5595 msi_free(sd.lpDescription);
5596 msi_free(load_order);
5597 msi_free(serv_name);
5602 return ERROR_SUCCESS;
5605 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5609 static const WCHAR ExecSeqQuery[] =
5610 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5611 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5613 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5614 if (rc != ERROR_SUCCESS)
5615 return ERROR_SUCCESS;
5617 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5618 msiobj_release(&view->hdr);
5623 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5624 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5626 LPCWSTR *vector, *temp_vector;
5630 static const WCHAR separator[] = {'[','~',']',0};
5633 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5638 vector = msi_alloc(sizeof(LPWSTR));
5646 vector[*numargs - 1] = p;
5648 if ((q = strstrW(p, separator)))
5652 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5658 vector = temp_vector;
5667 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5669 MSIPACKAGE *package = param;
5672 SC_HANDLE scm = NULL, service = NULL;
5673 LPCWSTR component, *vector = NULL;
5674 LPWSTR name, args, display_name = NULL;
5675 DWORD event, numargs, len;
5676 UINT r = ERROR_FUNCTION_FAILED;
5678 component = MSI_RecordGetString(rec, 6);
5679 comp = get_loaded_component(package, component);
5681 return ERROR_SUCCESS;
5685 TRACE("component is disabled\n");
5686 return ERROR_SUCCESS;
5689 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5691 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5692 comp->Action = comp->Installed;
5693 return ERROR_SUCCESS;
5695 comp->Action = INSTALLSTATE_LOCAL;
5697 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5698 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5699 event = MSI_RecordGetInteger(rec, 3);
5701 if (!(event & msidbServiceControlEventStart))
5707 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5710 ERR("Failed to open the service control manager\n");
5715 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5716 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5718 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5719 GetServiceDisplayNameW( scm, name, display_name, &len );
5722 service = OpenServiceW(scm, name, SERVICE_START);
5725 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5729 vector = msi_service_args_to_vector(args, &numargs);
5731 if (!StartServiceW(service, numargs, vector) &&
5732 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5734 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5741 uirow = MSI_CreateRecord( 2 );
5742 MSI_RecordSetStringW( uirow, 1, display_name );
5743 MSI_RecordSetStringW( uirow, 2, name );
5744 ui_actiondata( package, szStartServices, uirow );
5745 msiobj_release( &uirow->hdr );
5747 CloseServiceHandle(service);
5748 CloseServiceHandle(scm);
5753 msi_free(display_name);
5757 static UINT ACTION_StartServices( MSIPACKAGE *package )
5762 static const WCHAR query[] = {
5763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5764 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5766 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5767 if (rc != ERROR_SUCCESS)
5768 return ERROR_SUCCESS;
5770 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5771 msiobj_release(&view->hdr);
5776 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5778 DWORD i, needed, count;
5779 ENUM_SERVICE_STATUSW *dependencies;
5783 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5784 0, &needed, &count))
5787 if (GetLastError() != ERROR_MORE_DATA)
5790 dependencies = msi_alloc(needed);
5794 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5795 needed, &needed, &count))
5798 for (i = 0; i < count; i++)
5800 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5801 SERVICE_STOP | SERVICE_QUERY_STATUS);
5805 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5812 msi_free(dependencies);
5816 static UINT stop_service( LPCWSTR name )
5818 SC_HANDLE scm = NULL, service = NULL;
5819 SERVICE_STATUS status;
5820 SERVICE_STATUS_PROCESS ssp;
5823 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5826 WARN("Failed to open the SCM: %d\n", GetLastError());
5830 service = OpenServiceW(scm, name,
5832 SERVICE_QUERY_STATUS |
5833 SERVICE_ENUMERATE_DEPENDENTS);
5836 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5840 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5841 sizeof(SERVICE_STATUS_PROCESS), &needed))
5843 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5847 if (ssp.dwCurrentState == SERVICE_STOPPED)
5850 stop_service_dependents(scm, service);
5852 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5853 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5856 CloseServiceHandle(service);
5857 CloseServiceHandle(scm);
5859 return ERROR_SUCCESS;
5862 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5864 MSIPACKAGE *package = param;
5868 LPWSTR name = NULL, display_name = NULL;
5872 event = MSI_RecordGetInteger( rec, 3 );
5873 if (!(event & msidbServiceControlEventStop))
5874 return ERROR_SUCCESS;
5876 component = MSI_RecordGetString( rec, 6 );
5877 comp = get_loaded_component( package, component );
5879 return ERROR_SUCCESS;
5883 TRACE("component is disabled\n");
5884 return ERROR_SUCCESS;
5887 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5889 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5890 comp->Action = comp->Installed;
5891 return ERROR_SUCCESS;
5893 comp->Action = INSTALLSTATE_ABSENT;
5895 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5898 ERR("Failed to open the service control manager\n");
5903 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5904 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5906 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5907 GetServiceDisplayNameW( scm, name, display_name, &len );
5909 CloseServiceHandle( scm );
5911 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5912 stop_service( name );
5915 uirow = MSI_CreateRecord( 2 );
5916 MSI_RecordSetStringW( uirow, 1, display_name );
5917 MSI_RecordSetStringW( uirow, 2, name );
5918 ui_actiondata( package, szStopServices, uirow );
5919 msiobj_release( &uirow->hdr );
5922 msi_free( display_name );
5923 return ERROR_SUCCESS;
5926 static UINT ACTION_StopServices( MSIPACKAGE *package )
5931 static const WCHAR query[] = {
5932 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5933 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5935 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5936 if (rc != ERROR_SUCCESS)
5937 return ERROR_SUCCESS;
5939 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5940 msiobj_release(&view->hdr);
5945 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5947 MSIPACKAGE *package = param;
5951 LPWSTR name = NULL, display_name = NULL;
5953 SC_HANDLE scm = NULL, service = NULL;
5955 event = MSI_RecordGetInteger( rec, 3 );
5956 if (!(event & msidbServiceControlEventDelete))
5957 return ERROR_SUCCESS;
5959 component = MSI_RecordGetString(rec, 6);
5960 comp = get_loaded_component(package, component);
5962 return ERROR_SUCCESS;
5966 TRACE("component is disabled\n");
5967 return ERROR_SUCCESS;
5970 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5972 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5973 comp->Action = comp->Installed;
5974 return ERROR_SUCCESS;
5976 comp->Action = INSTALLSTATE_ABSENT;
5978 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5979 stop_service( name );
5981 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5984 WARN("Failed to open the SCM: %d\n", GetLastError());
5989 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5990 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5992 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5993 GetServiceDisplayNameW( scm, name, display_name, &len );
5996 service = OpenServiceW( scm, name, DELETE );
5999 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6003 if (!DeleteService( service ))
6004 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6007 uirow = MSI_CreateRecord( 2 );
6008 MSI_RecordSetStringW( uirow, 1, display_name );
6009 MSI_RecordSetStringW( uirow, 2, name );
6010 ui_actiondata( package, szDeleteServices, uirow );
6011 msiobj_release( &uirow->hdr );
6013 CloseServiceHandle( service );
6014 CloseServiceHandle( scm );
6016 msi_free( display_name );
6018 return ERROR_SUCCESS;
6021 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6026 static const WCHAR query[] = {
6027 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6028 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6030 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6031 if (rc != ERROR_SUCCESS)
6032 return ERROR_SUCCESS;
6034 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6035 msiobj_release( &view->hdr );
6040 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6042 MSIPACKAGE *package = param;
6043 LPWSTR driver, driver_path, ptr;
6044 WCHAR outpath[MAX_PATH];
6045 MSIFILE *driver_file = NULL, *setup_file = NULL;
6048 LPCWSTR desc, file_key, component;
6050 UINT r = ERROR_SUCCESS;
6052 static const WCHAR driver_fmt[] = {
6053 'D','r','i','v','e','r','=','%','s',0};
6054 static const WCHAR setup_fmt[] = {
6055 'S','e','t','u','p','=','%','s',0};
6056 static const WCHAR usage_fmt[] = {
6057 'F','i','l','e','U','s','a','g','e','=','1',0};
6059 component = MSI_RecordGetString( rec, 2 );
6060 comp = get_loaded_component( package, component );
6062 return ERROR_SUCCESS;
6066 TRACE("component is disabled\n");
6067 return ERROR_SUCCESS;
6070 desc = MSI_RecordGetString(rec, 3);
6072 file_key = MSI_RecordGetString( rec, 4 );
6073 if (file_key) driver_file = get_loaded_file( package, file_key );
6075 file_key = MSI_RecordGetString( rec, 5 );
6076 if (file_key) setup_file = get_loaded_file( package, file_key );
6080 ERR("ODBC Driver entry not found!\n");
6081 return ERROR_FUNCTION_FAILED;
6084 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6086 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6087 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6089 driver = msi_alloc(len * sizeof(WCHAR));
6091 return ERROR_OUTOFMEMORY;
6094 lstrcpyW(ptr, desc);
6095 ptr += lstrlenW(ptr) + 1;
6097 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6102 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6106 lstrcpyW(ptr, usage_fmt);
6107 ptr += lstrlenW(ptr) + 1;
6110 driver_path = strdupW(driver_file->TargetPath);
6111 ptr = strrchrW(driver_path, '\\');
6112 if (ptr) *ptr = '\0';
6114 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6115 NULL, ODBC_INSTALL_COMPLETE, &usage))
6117 ERR("Failed to install SQL driver!\n");
6118 r = ERROR_FUNCTION_FAILED;
6121 uirow = MSI_CreateRecord( 5 );
6122 MSI_RecordSetStringW( uirow, 1, desc );
6123 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6124 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6125 ui_actiondata( package, szInstallODBC, uirow );
6126 msiobj_release( &uirow->hdr );
6129 msi_free(driver_path);
6134 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6136 MSIPACKAGE *package = param;
6137 LPWSTR translator, translator_path, ptr;
6138 WCHAR outpath[MAX_PATH];
6139 MSIFILE *translator_file = NULL, *setup_file = NULL;
6142 LPCWSTR desc, file_key, component;
6144 UINT r = ERROR_SUCCESS;
6146 static const WCHAR translator_fmt[] = {
6147 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6148 static const WCHAR setup_fmt[] = {
6149 'S','e','t','u','p','=','%','s',0};
6151 component = MSI_RecordGetString( rec, 2 );
6152 comp = get_loaded_component( package, component );
6154 return ERROR_SUCCESS;
6158 TRACE("component is disabled\n");
6159 return ERROR_SUCCESS;
6162 desc = MSI_RecordGetString(rec, 3);
6164 file_key = MSI_RecordGetString( rec, 4 );
6165 if (file_key) translator_file = get_loaded_file( package, file_key );
6167 file_key = MSI_RecordGetString( rec, 5 );
6168 if (file_key) setup_file = get_loaded_file( package, file_key );
6170 if (!translator_file)
6172 ERR("ODBC Translator entry not found!\n");
6173 return ERROR_FUNCTION_FAILED;
6176 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6178 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6180 translator = msi_alloc(len * sizeof(WCHAR));
6182 return ERROR_OUTOFMEMORY;
6185 lstrcpyW(ptr, desc);
6186 ptr += lstrlenW(ptr) + 1;
6188 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6193 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6198 translator_path = strdupW(translator_file->TargetPath);
6199 ptr = strrchrW(translator_path, '\\');
6200 if (ptr) *ptr = '\0';
6202 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6203 NULL, ODBC_INSTALL_COMPLETE, &usage))
6205 ERR("Failed to install SQL translator!\n");
6206 r = ERROR_FUNCTION_FAILED;
6209 uirow = MSI_CreateRecord( 5 );
6210 MSI_RecordSetStringW( uirow, 1, desc );
6211 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6212 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6213 ui_actiondata( package, szInstallODBC, uirow );
6214 msiobj_release( &uirow->hdr );
6216 msi_free(translator);
6217 msi_free(translator_path);
6222 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6224 MSIPACKAGE *package = param;
6227 LPCWSTR desc, driver, component;
6228 WORD request = ODBC_ADD_SYS_DSN;
6231 UINT r = ERROR_SUCCESS;
6234 static const WCHAR attrs_fmt[] = {
6235 'D','S','N','=','%','s',0 };
6237 component = MSI_RecordGetString( rec, 2 );
6238 comp = get_loaded_component( package, component );
6240 return ERROR_SUCCESS;
6244 TRACE("component is disabled\n");
6245 return ERROR_SUCCESS;
6248 desc = MSI_RecordGetString(rec, 3);
6249 driver = MSI_RecordGetString(rec, 4);
6250 registration = MSI_RecordGetInteger(rec, 5);
6252 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6253 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6255 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6256 attrs = msi_alloc(len * sizeof(WCHAR));
6258 return ERROR_OUTOFMEMORY;
6260 len = sprintfW(attrs, attrs_fmt, desc);
6263 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6265 ERR("Failed to install SQL data source!\n");
6266 r = ERROR_FUNCTION_FAILED;
6269 uirow = MSI_CreateRecord( 5 );
6270 MSI_RecordSetStringW( uirow, 1, desc );
6271 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6272 MSI_RecordSetInteger( uirow, 3, request );
6273 ui_actiondata( package, szInstallODBC, uirow );
6274 msiobj_release( &uirow->hdr );
6281 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6286 static const WCHAR driver_query[] = {
6287 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6288 'O','D','B','C','D','r','i','v','e','r',0 };
6290 static const WCHAR translator_query[] = {
6291 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6292 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6294 static const WCHAR source_query[] = {
6295 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6296 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6298 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6299 if (rc != ERROR_SUCCESS)
6300 return ERROR_SUCCESS;
6302 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6303 msiobj_release(&view->hdr);
6305 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6306 if (rc != ERROR_SUCCESS)
6307 return ERROR_SUCCESS;
6309 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6310 msiobj_release(&view->hdr);
6312 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6313 if (rc != ERROR_SUCCESS)
6314 return ERROR_SUCCESS;
6316 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6317 msiobj_release(&view->hdr);
6322 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6324 MSIPACKAGE *package = param;
6328 LPCWSTR desc, component;
6330 component = MSI_RecordGetString( rec, 2 );
6331 comp = get_loaded_component( package, component );
6333 return ERROR_SUCCESS;
6337 TRACE("component is disabled\n");
6338 return ERROR_SUCCESS;
6341 desc = MSI_RecordGetString( rec, 3 );
6342 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6344 WARN("Failed to remove ODBC driver\n");
6348 FIXME("Usage count reached 0\n");
6351 uirow = MSI_CreateRecord( 2 );
6352 MSI_RecordSetStringW( uirow, 1, desc );
6353 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6354 ui_actiondata( package, szRemoveODBC, uirow );
6355 msiobj_release( &uirow->hdr );
6357 return ERROR_SUCCESS;
6360 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6362 MSIPACKAGE *package = param;
6366 LPCWSTR desc, component;
6368 component = MSI_RecordGetString( rec, 2 );
6369 comp = get_loaded_component( package, component );
6371 return ERROR_SUCCESS;
6375 TRACE("component is disabled\n");
6376 return ERROR_SUCCESS;
6379 desc = MSI_RecordGetString( rec, 3 );
6380 if (!SQLRemoveTranslatorW( desc, &usage ))
6382 WARN("Failed to remove ODBC translator\n");
6386 FIXME("Usage count reached 0\n");
6389 uirow = MSI_CreateRecord( 2 );
6390 MSI_RecordSetStringW( uirow, 1, desc );
6391 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6392 ui_actiondata( package, szRemoveODBC, uirow );
6393 msiobj_release( &uirow->hdr );
6395 return ERROR_SUCCESS;
6398 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6400 MSIPACKAGE *package = param;
6404 LPCWSTR desc, driver, component;
6405 WORD request = ODBC_REMOVE_SYS_DSN;
6409 static const WCHAR attrs_fmt[] = {
6410 'D','S','N','=','%','s',0 };
6412 component = MSI_RecordGetString( rec, 2 );
6413 comp = get_loaded_component( package, component );
6415 return ERROR_SUCCESS;
6419 TRACE("component is disabled\n");
6420 return ERROR_SUCCESS;
6423 desc = MSI_RecordGetString( rec, 3 );
6424 driver = MSI_RecordGetString( rec, 4 );
6425 registration = MSI_RecordGetInteger( rec, 5 );
6427 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6428 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6430 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6431 attrs = msi_alloc( len * sizeof(WCHAR) );
6433 return ERROR_OUTOFMEMORY;
6435 FIXME("Use ODBCSourceAttribute table\n");
6437 len = sprintfW( attrs, attrs_fmt, desc );
6440 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6442 WARN("Failed to remove ODBC data source\n");
6446 uirow = MSI_CreateRecord( 3 );
6447 MSI_RecordSetStringW( uirow, 1, desc );
6448 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6449 MSI_RecordSetInteger( uirow, 3, request );
6450 ui_actiondata( package, szRemoveODBC, uirow );
6451 msiobj_release( &uirow->hdr );
6453 return ERROR_SUCCESS;
6456 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6461 static const WCHAR driver_query[] = {
6462 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6463 'O','D','B','C','D','r','i','v','e','r',0 };
6465 static const WCHAR translator_query[] = {
6466 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6467 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6469 static const WCHAR source_query[] = {
6470 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6471 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6473 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6474 if (rc != ERROR_SUCCESS)
6475 return ERROR_SUCCESS;
6477 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6478 msiobj_release( &view->hdr );
6480 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6481 if (rc != ERROR_SUCCESS)
6482 return ERROR_SUCCESS;
6484 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6485 msiobj_release( &view->hdr );
6487 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6488 if (rc != ERROR_SUCCESS)
6489 return ERROR_SUCCESS;
6491 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6492 msiobj_release( &view->hdr );
6497 #define ENV_ACT_SETALWAYS 0x1
6498 #define ENV_ACT_SETABSENT 0x2
6499 #define ENV_ACT_REMOVE 0x4
6500 #define ENV_ACT_REMOVEMATCH 0x8
6502 #define ENV_MOD_MACHINE 0x20000000
6503 #define ENV_MOD_APPEND 0x40000000
6504 #define ENV_MOD_PREFIX 0x80000000
6505 #define ENV_MOD_MASK 0xC0000000
6507 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6509 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6511 LPCWSTR cptr = *name;
6513 static const WCHAR prefix[] = {'[','~',']',0};
6514 static const int prefix_len = 3;
6520 *flags |= ENV_ACT_SETALWAYS;
6521 else if (*cptr == '+')
6522 *flags |= ENV_ACT_SETABSENT;
6523 else if (*cptr == '-')
6524 *flags |= ENV_ACT_REMOVE;
6525 else if (*cptr == '!')
6526 *flags |= ENV_ACT_REMOVEMATCH;
6527 else if (*cptr == '*')
6528 *flags |= ENV_MOD_MACHINE;
6538 ERR("Missing environment variable\n");
6539 return ERROR_FUNCTION_FAILED;
6544 LPCWSTR ptr = *value;
6545 if (!strncmpW(ptr, prefix, prefix_len))
6547 if (ptr[prefix_len] == szSemiColon[0])
6549 *flags |= ENV_MOD_APPEND;
6550 *value += lstrlenW(prefix);
6557 else if (lstrlenW(*value) >= prefix_len)
6559 ptr += lstrlenW(ptr) - prefix_len;
6560 if (!strcmpW( ptr, prefix ))
6562 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6564 *flags |= ENV_MOD_PREFIX;
6565 /* the "[~]" will be removed by deformat_string */;
6575 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6576 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6577 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6578 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6580 ERR("Invalid flags: %08x\n", *flags);
6581 return ERROR_FUNCTION_FAILED;
6585 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6587 return ERROR_SUCCESS;
6590 static UINT open_env_key( DWORD flags, HKEY *key )
6592 static const WCHAR user_env[] =
6593 {'E','n','v','i','r','o','n','m','e','n','t',0};
6594 static const WCHAR machine_env[] =
6595 {'S','y','s','t','e','m','\\',
6596 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6597 'C','o','n','t','r','o','l','\\',
6598 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6599 'E','n','v','i','r','o','n','m','e','n','t',0};
6604 if (flags & ENV_MOD_MACHINE)
6607 root = HKEY_LOCAL_MACHINE;
6612 root = HKEY_CURRENT_USER;
6615 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6616 if (res != ERROR_SUCCESS)
6618 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6619 return ERROR_FUNCTION_FAILED;
6622 return ERROR_SUCCESS;
6625 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6627 MSIPACKAGE *package = param;
6628 LPCWSTR name, value, component;
6629 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6630 DWORD flags, type, size;
6637 component = MSI_RecordGetString(rec, 4);
6638 comp = get_loaded_component(package, component);
6640 return ERROR_SUCCESS;
6644 TRACE("component is disabled\n");
6645 return ERROR_SUCCESS;
6648 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6650 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6651 comp->Action = comp->Installed;
6652 return ERROR_SUCCESS;
6654 comp->Action = INSTALLSTATE_LOCAL;
6656 name = MSI_RecordGetString(rec, 2);
6657 value = MSI_RecordGetString(rec, 3);
6659 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6661 res = env_parse_flags(&name, &value, &flags);
6662 if (res != ERROR_SUCCESS || !value)
6665 if (value && !deformat_string(package, value, &deformatted))
6667 res = ERROR_OUTOFMEMORY;
6671 value = deformatted;
6673 res = open_env_key( flags, &env );
6674 if (res != ERROR_SUCCESS)
6677 if (flags & ENV_MOD_MACHINE)
6678 action |= 0x20000000;
6682 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6683 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6684 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6687 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6691 /* Nothing to do. */
6694 res = ERROR_SUCCESS;
6698 /* If we are appending but the string was empty, strip ; */
6699 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6701 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6702 newval = strdupW(value);
6705 res = ERROR_OUTOFMEMORY;
6713 /* Contrary to MSDN, +-variable to [~];path works */
6714 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6716 res = ERROR_SUCCESS;
6720 data = msi_alloc(size);
6724 return ERROR_OUTOFMEMORY;
6727 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6728 if (res != ERROR_SUCCESS)
6731 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6734 res = RegDeleteValueW(env, name);
6735 if (res != ERROR_SUCCESS)
6736 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6740 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6741 if (flags & ENV_MOD_MASK)
6745 if (flags & ENV_MOD_APPEND) multiplier++;
6746 if (flags & ENV_MOD_PREFIX) multiplier++;
6747 mod_size = lstrlenW(value) * multiplier;
6748 size += mod_size * sizeof(WCHAR);
6751 newval = msi_alloc(size);
6755 res = ERROR_OUTOFMEMORY;
6759 if (flags & ENV_MOD_PREFIX)
6761 lstrcpyW(newval, value);
6762 ptr = newval + lstrlenW(value);
6763 action |= 0x80000000;
6766 lstrcpyW(ptr, data);
6768 if (flags & ENV_MOD_APPEND)
6770 lstrcatW(newval, value);
6771 action |= 0x40000000;
6774 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6775 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6778 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6782 uirow = MSI_CreateRecord( 3 );
6783 MSI_RecordSetStringW( uirow, 1, name );
6784 MSI_RecordSetStringW( uirow, 2, newval );
6785 MSI_RecordSetInteger( uirow, 3, action );
6786 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6787 msiobj_release( &uirow->hdr );
6789 if (env) RegCloseKey(env);
6790 msi_free(deformatted);
6796 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6800 static const WCHAR ExecSeqQuery[] =
6801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6802 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6803 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6804 if (rc != ERROR_SUCCESS)
6805 return ERROR_SUCCESS;
6807 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6808 msiobj_release(&view->hdr);
6813 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6815 MSIPACKAGE *package = param;
6816 LPCWSTR name, value, component;
6817 LPWSTR deformatted = NULL;
6826 component = MSI_RecordGetString( rec, 4 );
6827 comp = get_loaded_component( package, component );
6829 return ERROR_SUCCESS;
6833 TRACE("component is disabled\n");
6834 return ERROR_SUCCESS;
6837 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6839 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6840 comp->Action = comp->Installed;
6841 return ERROR_SUCCESS;
6843 comp->Action = INSTALLSTATE_ABSENT;
6845 name = MSI_RecordGetString( rec, 2 );
6846 value = MSI_RecordGetString( rec, 3 );
6848 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6850 r = env_parse_flags( &name, &value, &flags );
6851 if (r != ERROR_SUCCESS)
6854 if (!(flags & ENV_ACT_REMOVE))
6856 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6857 return ERROR_SUCCESS;
6860 if (value && !deformat_string( package, value, &deformatted ))
6861 return ERROR_OUTOFMEMORY;
6863 value = deformatted;
6865 r = open_env_key( flags, &env );
6866 if (r != ERROR_SUCCESS)
6872 if (flags & ENV_MOD_MACHINE)
6873 action |= 0x20000000;
6875 TRACE("Removing %s\n", debugstr_w(name));
6877 res = RegDeleteValueW( env, name );
6878 if (res != ERROR_SUCCESS)
6880 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6885 uirow = MSI_CreateRecord( 3 );
6886 MSI_RecordSetStringW( uirow, 1, name );
6887 MSI_RecordSetStringW( uirow, 2, value );
6888 MSI_RecordSetInteger( uirow, 3, action );
6889 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6890 msiobj_release( &uirow->hdr );
6892 if (env) RegCloseKey( env );
6893 msi_free( deformatted );
6897 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6901 static const WCHAR query[] =
6902 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6903 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6905 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6906 if (rc != ERROR_SUCCESS)
6907 return ERROR_SUCCESS;
6909 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6910 msiobj_release( &view->hdr );
6915 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6917 LPWSTR key, template, id;
6918 UINT r = ERROR_SUCCESS;
6920 id = msi_dup_property( package->db, szProductID );
6924 return ERROR_SUCCESS;
6926 template = msi_dup_property( package->db, szPIDTemplate );
6927 key = msi_dup_property( package->db, szPIDKEY );
6929 if (key && template)
6931 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6932 r = msi_set_property( package->db, szProductID, key );
6934 msi_free( template );
6939 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6942 package->need_reboot = 1;
6943 return ERROR_SUCCESS;
6946 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6948 static const WCHAR szAvailableFreeReg[] =
6949 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6951 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6953 TRACE("%p %d kilobytes\n", package, space);
6955 uirow = MSI_CreateRecord( 1 );
6956 MSI_RecordSetInteger( uirow, 1, space );
6957 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6958 msiobj_release( &uirow->hdr );
6960 return ERROR_SUCCESS;
6963 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6965 FIXME("%p\n", package);
6966 return ERROR_SUCCESS;
6969 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6971 FIXME("%p\n", package);
6972 return ERROR_SUCCESS;
6975 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6980 static const WCHAR driver_query[] = {
6981 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6982 'O','D','B','C','D','r','i','v','e','r',0 };
6984 static const WCHAR translator_query[] = {
6985 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6986 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6988 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6989 if (r == ERROR_SUCCESS)
6992 r = MSI_IterateRecords( view, &count, NULL, package );
6993 msiobj_release( &view->hdr );
6994 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6997 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6998 if (r == ERROR_SUCCESS)
7001 r = MSI_IterateRecords( view, &count, NULL, package );
7002 msiobj_release( &view->hdr );
7003 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7006 return ERROR_SUCCESS;
7009 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7011 MSIPACKAGE *package = param;
7012 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7015 if ((value = msi_dup_property( package->db, property )))
7017 FIXME("remove %s\n", debugstr_w(value));
7020 return ERROR_SUCCESS;
7023 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7028 static const WCHAR query[] =
7029 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7030 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7032 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7033 if (r == ERROR_SUCCESS)
7035 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7036 msiobj_release( &view->hdr );
7038 return ERROR_SUCCESS;
7041 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7043 MSIPACKAGE *package = param;
7044 int attributes = MSI_RecordGetInteger( rec, 5 );
7046 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7048 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7049 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7050 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7051 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7055 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7057 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7058 if (r != ERROR_SUCCESS)
7059 return ERROR_SUCCESS;
7063 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7064 if (r != ERROR_SUCCESS)
7065 return ERROR_SUCCESS;
7067 RegCloseKey( hkey );
7069 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7070 debugstr_w(upgrade_code), debugstr_w(version_min),
7071 debugstr_w(version_max), debugstr_w(language));
7073 return ERROR_SUCCESS;
7076 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7081 static const WCHAR query[] =
7082 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7084 if (msi_get_property_int( package->db, szInstalled, 0 ))
7086 TRACE("product is installed, skipping action\n");
7087 return ERROR_SUCCESS;
7089 if (msi_get_property_int( package->db, szPreselected, 0 ))
7091 TRACE("Preselected property is set, not migrating feature states\n");
7092 return ERROR_SUCCESS;
7095 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7096 if (r == ERROR_SUCCESS)
7098 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7099 msiobj_release( &view->hdr );
7101 return ERROR_SUCCESS;
7104 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7105 LPCSTR action, LPCWSTR table )
7107 static const WCHAR query[] = {
7108 'S','E','L','E','C','T',' ','*',' ',
7109 'F','R','O','M',' ','`','%','s','`',0 };
7110 MSIQUERY *view = NULL;
7114 r = MSI_OpenQuery( package->db, &view, query, table );
7115 if (r == ERROR_SUCCESS)
7117 r = MSI_IterateRecords(view, &count, NULL, package);
7118 msiobj_release(&view->hdr);
7122 FIXME("%s -> %u ignored %s table values\n",
7123 action, count, debugstr_w(table));
7125 return ERROR_SUCCESS;
7128 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7130 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7131 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7134 static UINT ACTION_BindImage( MSIPACKAGE *package )
7136 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7137 return msi_unimplemented_action_stub( package, "BindImage", table );
7140 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7142 static const WCHAR table[] = {
7143 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7144 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7147 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7149 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7150 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7153 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7155 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7156 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7159 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7161 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7162 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7165 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7167 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7168 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7171 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7175 const WCHAR *action;
7176 UINT (*handler)(MSIPACKAGE *);
7180 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7181 { szAppSearch, ACTION_AppSearch },
7182 { szBindImage, ACTION_BindImage },
7183 { szCCPSearch, ACTION_CCPSearch },
7184 { szCostFinalize, ACTION_CostFinalize },
7185 { szCostInitialize, ACTION_CostInitialize },
7186 { szCreateFolders, ACTION_CreateFolders },
7187 { szCreateShortcuts, ACTION_CreateShortcuts },
7188 { szDeleteServices, ACTION_DeleteServices },
7189 { szDisableRollback, ACTION_DisableRollback },
7190 { szDuplicateFiles, ACTION_DuplicateFiles },
7191 { szExecuteAction, ACTION_ExecuteAction },
7192 { szFileCost, ACTION_FileCost },
7193 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7194 { szForceReboot, ACTION_ForceReboot },
7195 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7196 { szInstallExecute, ACTION_InstallExecute },
7197 { szInstallExecuteAgain, ACTION_InstallExecute },
7198 { szInstallFiles, ACTION_InstallFiles},
7199 { szInstallFinalize, ACTION_InstallFinalize },
7200 { szInstallInitialize, ACTION_InstallInitialize },
7201 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7202 { szInstallValidate, ACTION_InstallValidate },
7203 { szIsolateComponents, ACTION_IsolateComponents },
7204 { szLaunchConditions, ACTION_LaunchConditions },
7205 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7206 { szMoveFiles, ACTION_MoveFiles },
7207 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7208 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7209 { szInstallODBC, ACTION_InstallODBC },
7210 { szInstallServices, ACTION_InstallServices },
7211 { szPatchFiles, ACTION_PatchFiles },
7212 { szProcessComponents, ACTION_ProcessComponents },
7213 { szPublishComponents, ACTION_PublishComponents },
7214 { szPublishFeatures, ACTION_PublishFeatures },
7215 { szPublishProduct, ACTION_PublishProduct },
7216 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7217 { szRegisterComPlus, ACTION_RegisterComPlus},
7218 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7219 { szRegisterFonts, ACTION_RegisterFonts },
7220 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7221 { szRegisterProduct, ACTION_RegisterProduct },
7222 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7223 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7224 { szRegisterUser, ACTION_RegisterUser },
7225 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7226 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7227 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7228 { szRemoveFiles, ACTION_RemoveFiles },
7229 { szRemoveFolders, ACTION_RemoveFolders },
7230 { szRemoveIniValues, ACTION_RemoveIniValues },
7231 { szRemoveODBC, ACTION_RemoveODBC },
7232 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7233 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7234 { szResolveSource, ACTION_ResolveSource },
7235 { szRMCCPSearch, ACTION_RMCCPSearch },
7236 { szScheduleReboot, ACTION_ScheduleReboot },
7237 { szSelfRegModules, ACTION_SelfRegModules },
7238 { szSelfUnregModules, ACTION_SelfUnregModules },
7239 { szSetODBCFolders, ACTION_SetODBCFolders },
7240 { szStartServices, ACTION_StartServices },
7241 { szStopServices, ACTION_StopServices },
7242 { szUnpublishComponents, ACTION_UnpublishComponents },
7243 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7244 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7245 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7246 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7247 { szUnregisterFonts, ACTION_UnregisterFonts },
7248 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7249 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7250 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7251 { szValidateProductID, ACTION_ValidateProductID },
7252 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7253 { szWriteIniValues, ACTION_WriteIniValues },
7254 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7258 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7264 while (StandardActions[i].action != NULL)
7266 if (!strcmpW( StandardActions[i].action, action ))
7268 ui_actionstart( package, action );
7269 if (StandardActions[i].handler)
7271 ui_actioninfo( package, action, TRUE, 0 );
7272 *rc = StandardActions[i].handler( package );
7273 ui_actioninfo( package, action, FALSE, *rc );
7277 FIXME("unhandled standard action %s\n", debugstr_w(action));
7278 *rc = ERROR_SUCCESS;
7288 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7290 UINT rc = ERROR_SUCCESS;
7293 TRACE("Performing action (%s)\n", debugstr_w(action));
7295 handled = ACTION_HandleStandardAction(package, action, &rc);
7298 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7302 WARN("unhandled msi action %s\n", debugstr_w(action));
7303 rc = ERROR_FUNCTION_NOT_CALLED;
7309 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7311 UINT rc = ERROR_SUCCESS;
7312 BOOL handled = FALSE;
7314 TRACE("Performing action (%s)\n", debugstr_w(action));
7316 handled = ACTION_HandleStandardAction(package, action, &rc);
7319 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7321 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7326 WARN("unhandled msi action %s\n", debugstr_w(action));
7327 rc = ERROR_FUNCTION_NOT_CALLED;
7333 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7335 UINT rc = ERROR_SUCCESS;
7338 static const WCHAR ExecSeqQuery[] =
7339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7340 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7341 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7342 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7343 static const WCHAR UISeqQuery[] =
7344 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7345 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7346 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7347 ' ', '=',' ','%','i',0};
7349 if (needs_ui_sequence(package))
7350 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7352 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7356 LPCWSTR action, cond;
7358 TRACE("Running the actions\n");
7360 /* check conditions */
7361 cond = MSI_RecordGetString(row, 2);
7363 /* this is a hack to skip errors in the condition code */
7364 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7366 msiobj_release(&row->hdr);
7367 return ERROR_SUCCESS;
7370 action = MSI_RecordGetString(row, 1);
7373 ERR("failed to fetch action\n");
7374 msiobj_release(&row->hdr);
7375 return ERROR_FUNCTION_FAILED;
7378 if (needs_ui_sequence(package))
7379 rc = ACTION_PerformUIAction(package, action, -1);
7381 rc = ACTION_PerformAction(package, action, -1);
7383 msiobj_release(&row->hdr);
7389 /****************************************************
7390 * TOP level entry points
7391 *****************************************************/
7393 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7394 LPCWSTR szCommandLine )
7399 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7400 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7402 msi_set_property( package->db, szAction, szInstall );
7404 package->script->InWhatSequence = SEQUENCE_INSTALL;
7411 dir = strdupW(szPackagePath);
7412 p = strrchrW(dir, '\\');
7416 file = szPackagePath + (p - dir);
7421 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7422 GetCurrentDirectoryW(MAX_PATH, dir);
7423 lstrcatW(dir, szBackSlash);
7424 file = szPackagePath;
7427 msi_free( package->PackagePath );
7428 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7429 if (!package->PackagePath)
7432 return ERROR_OUTOFMEMORY;
7435 lstrcpyW(package->PackagePath, dir);
7436 lstrcatW(package->PackagePath, file);
7439 msi_set_sourcedir_props(package, FALSE);
7442 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7443 if (rc != ERROR_SUCCESS)
7446 msi_apply_transforms( package );
7447 msi_apply_patches( package );
7449 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7451 TRACE("setting reinstall property\n");
7452 msi_set_property( package->db, szReinstall, szAll );
7455 /* properties may have been added by a transform */
7456 msi_clone_properties( package );
7458 msi_parse_command_line( package, szCommandLine, FALSE );
7459 msi_adjust_privilege_properties( package );
7460 msi_set_context( package );
7462 if (needs_ui_sequence( package))
7464 package->script->InWhatSequence |= SEQUENCE_UI;
7465 rc = ACTION_ProcessUISequence(package);
7466 ui_exists = ui_sequence_exists(package);
7467 if (rc == ERROR_SUCCESS || !ui_exists)
7469 package->script->InWhatSequence |= SEQUENCE_EXEC;
7470 rc = ACTION_ProcessExecSequence(package, ui_exists);
7474 rc = ACTION_ProcessExecSequence(package, FALSE);
7476 package->script->CurrentlyScripting = FALSE;
7478 /* process the ending type action */
7479 if (rc == ERROR_SUCCESS)
7480 ACTION_PerformActionSequence(package, -1);
7481 else if (rc == ERROR_INSTALL_USEREXIT)
7482 ACTION_PerformActionSequence(package, -2);
7483 else if (rc == ERROR_INSTALL_SUSPEND)
7484 ACTION_PerformActionSequence(package, -4);
7486 ACTION_PerformActionSequence(package, -3);
7488 /* finish up running custom actions */
7489 ACTION_FinishCustomActions(package);
7491 if (rc == ERROR_SUCCESS && package->need_reboot)
7492 return ERROR_SUCCESS_REBOOT_REQUIRED;