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 struct msi_patch_offset
635 struct msi_patch_offset_list
638 UINT count, min, max;
639 UINT offset_to_apply;
642 static struct msi_patch_offset_list *msi_patch_offset_list_create(void)
644 struct msi_patch_offset_list *pos = msi_alloc(sizeof(struct msi_patch_offset_list));
645 list_init( &pos->files );
646 pos->count = pos->max = 0;
652 static void msi_patch_offset_list_free(struct msi_patch_offset_list *pos)
654 struct msi_patch_offset *po, *po2;
656 LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct msi_patch_offset, entry )
658 msi_free( po->Name );
665 static void msi_patch_offset_get_patches(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
670 static const WCHAR query_patch[] = {
671 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
672 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
673 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
675 r = MSI_DatabaseOpenViewW( db, query_patch, &view );
676 if (r != ERROR_SUCCESS)
679 rec = MSI_CreateRecord( 1 );
680 MSI_RecordSetInteger(rec, 1, last_sequence);
682 r = MSI_ViewExecute( view, rec );
683 msiobj_release( &rec->hdr );
684 if (r != ERROR_SUCCESS)
687 while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
689 UINT sequence = MSI_RecordGetInteger( rec, 2 );
692 * We only use the max/min sequence numbers for now.
695 pos->min = min(pos->min, sequence);
696 pos->max = max(pos->max, sequence);
699 msiobj_release( &rec->hdr );
702 msiobj_release( &view->hdr );
705 static void msi_patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct msi_patch_offset_list *pos)
710 static const WCHAR query_files[] = {
711 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
712 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
713 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
715 r = MSI_DatabaseOpenViewW( db, query_files, &view );
716 if (r != ERROR_SUCCESS)
719 rec = MSI_CreateRecord( 1 );
720 MSI_RecordSetInteger(rec, 1, last_sequence);
722 r = MSI_ViewExecute( view, rec );
723 msiobj_release( &rec->hdr );
724 if (r != ERROR_SUCCESS)
727 while (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
729 UINT attributes = MSI_RecordGetInteger( rec, 7 );
730 if (attributes & msidbFileAttributesPatchAdded)
732 struct msi_patch_offset *po = msi_alloc(sizeof(struct msi_patch_offset));
734 po->Name = msi_dup_record_field( rec, 1 );
735 po->Sequence = MSI_RecordGetInteger( rec, 8 );
737 pos->min = min(pos->min, po->Sequence);
738 pos->max = max(pos->max, po->Sequence);
740 list_add_tail( &pos->files, &po->entry );
743 msiobj_release( &rec->hdr );
746 msiobj_release( &view->hdr );
749 static UINT msi_patch_offset_modify_db(MSIDATABASE *db, struct msi_patch_offset_list *pos)
751 static const WCHAR query_files[] =
752 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
753 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
754 'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
755 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
756 struct msi_patch_offset *po;
761 r = MSI_DatabaseOpenViewW( db, query_files, &view );
762 if (r != ERROR_SUCCESS)
763 return ERROR_SUCCESS;
765 rec = MSI_CreateRecord( 2 );
766 MSI_RecordSetInteger( rec, 1, pos->min );
767 MSI_RecordSetInteger( rec, 2, pos->max );
769 r = MSI_ViewExecute( view, rec );
770 msiobj_release( &rec->hdr );
771 if (r != ERROR_SUCCESS)
774 LIST_FOR_EACH_ENTRY( po, &pos->files, struct msi_patch_offset, entry )
777 while ( (r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS )
779 LPCWSTR file = MSI_RecordGetString( rec, 1 );
782 if (!strcmpiW(file, po->Name))
785 seq = MSI_RecordGetInteger( rec, 8 );
786 MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
787 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
788 if (r != ERROR_SUCCESS)
789 ERR("Failed to update offset for file %s.\n", debugstr_w(file));
791 msiobj_release( &rec->hdr );
795 msiobj_release( &rec->hdr );
798 if (r_fetch != ERROR_SUCCESS)
803 msiobj_release( &view->hdr );
805 return ERROR_SUCCESS;
808 static UINT msi_set_patch_offsets(MSIDATABASE *db)
810 static const WCHAR query_media[] = {
811 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','M','e','d','i','a',' ',
812 'W','H','E','R','E',' ','S','o','u','r','c','e',' ','I','S',' ','N','O','T',' ','N','U','L','L',
813 ' ','A','N','D',' ','C','a','b','i','n','e','t',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
814 'O','R','D','E','R',' ','B','Y',' ','D','i','s','k','I','d',0};
815 MSIQUERY *view = NULL;
816 MSIRECORD *rec = NULL;
819 r = MSI_DatabaseOpenViewW( db, query_media, &view );
820 if (r != ERROR_SUCCESS)
823 r = MSI_ViewExecute( view, 0 );
824 if (r != ERROR_SUCCESS)
827 while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
829 UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
830 struct msi_patch_offset_list *pos;
832 /* FIXME: Set/Check Source field instead? */
833 if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
835 msiobj_release( &rec->hdr );
839 pos = msi_patch_offset_list_create();
841 msi_patch_offset_get_files( db, last_sequence, pos );
842 msi_patch_offset_get_patches( db, last_sequence, pos );
846 UINT offset = db->media_transform_offset - pos->min;
847 last_sequence = offset + pos->max;
850 * This is for the patch table, which is not yet properly transformed.
852 last_sequence += pos->min;
854 pos->offset_to_apply = offset;
855 msi_patch_offset_modify_db( db, pos );
857 MSI_RecordSetInteger( rec, 2, last_sequence );
858 r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
859 if (r != ERROR_SUCCESS)
860 ERR("Failed to update Media table entry, expect breakage (%u).\n", r);
862 db->media_transform_offset = last_sequence + 1;
865 msi_patch_offset_list_free( pos );
866 msiobj_release( &rec->hdr );
870 msiobj_release( &view->hdr );
875 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
877 UINT i, r = ERROR_SUCCESS;
880 /* apply substorage transforms */
881 substorage = msi_split_string( patch->transforms, ';' );
882 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
884 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
885 if (r == ERROR_SUCCESS)
886 msi_set_patch_offsets( package->db );
889 msi_free( substorage );
890 if (r != ERROR_SUCCESS)
893 msi_set_media_source_prop( package );
896 * There might be a CAB file in the patch package,
897 * so append it to the list of storages to search for streams.
899 append_storage_to_db( package->db, patch_db->storage );
901 patch->state = MSIPATCHSTATE_APPLIED;
902 list_add_tail( &package->patches, &patch->entry );
903 return ERROR_SUCCESS;
906 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
908 static const WCHAR dotmsp[] = {'.','m','s','p',0};
909 MSIDATABASE *patch_db = NULL;
910 WCHAR localfile[MAX_PATH];
912 MSIPATCHINFO *patch = NULL;
913 UINT r = ERROR_SUCCESS;
915 TRACE("%p %s\n", package, debugstr_w( file ) );
917 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
918 if ( r != ERROR_SUCCESS )
920 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
924 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
927 msiobj_release( &patch_db->hdr );
928 return ERROR_FUNCTION_FAILED;
931 r = msi_check_patch_applicable( package, si );
932 if (r != ERROR_SUCCESS)
934 TRACE("patch not applicable\n");
939 r = msi_parse_patch_summary( si, &patch );
940 if ( r != ERROR_SUCCESS )
943 r = msi_get_local_package_name( localfile, dotmsp );
944 if ( r != ERROR_SUCCESS )
947 TRACE("copying to local package %s\n", debugstr_w(localfile));
949 if (!CopyFileW( file, localfile, FALSE ))
951 ERR("Unable to copy package (%s -> %s) (error %u)\n",
952 debugstr_w(file), debugstr_w(localfile), GetLastError());
956 patch->localfile = strdupW( localfile );
958 r = msi_apply_patch_db( package, patch_db, patch );
959 if ( r != ERROR_SUCCESS )
960 WARN("patch failed to apply %u\n", r);
963 msiobj_release( &si->hdr );
964 msiobj_release( &patch_db->hdr );
965 if (patch && r != ERROR_SUCCESS)
967 if (patch->localfile)
968 DeleteFileW( patch->localfile );
970 msi_free( patch->patchcode );
971 msi_free( patch->transforms );
972 msi_free( patch->localfile );
978 /* get the PATCH property, and apply all the patches it specifies */
979 static UINT msi_apply_patches( MSIPACKAGE *package )
981 LPWSTR patch_list, *patches;
982 UINT i, r = ERROR_SUCCESS;
984 patch_list = msi_dup_property( package->db, szPatch );
986 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
988 patches = msi_split_string( patch_list, ';' );
989 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
990 r = msi_apply_patch_package( package, patches[i] );
993 msi_free( patch_list );
998 static UINT msi_apply_transforms( MSIPACKAGE *package )
1000 static const WCHAR szTransforms[] = {
1001 'T','R','A','N','S','F','O','R','M','S',0 };
1002 LPWSTR xform_list, *xforms;
1003 UINT i, r = ERROR_SUCCESS;
1005 xform_list = msi_dup_property( package->db, szTransforms );
1006 xforms = msi_split_string( xform_list, ';' );
1008 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
1010 if (xforms[i][0] == ':')
1011 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
1016 if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
1019 WCHAR *p = strrchrW( package->PackagePath, '\\' );
1020 DWORD len = p - package->PackagePath + 1;
1022 if (!(transform = msi_alloc( (len + strlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
1025 msi_free( xform_list );
1026 return ERROR_OUTOFMEMORY;
1028 memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
1029 memcpy( transform + len, xforms[i], (strlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
1031 r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
1032 if (transform != xforms[i]) msi_free( transform );
1037 msi_free( xform_list );
1042 static BOOL ui_sequence_exists( MSIPACKAGE *package )
1047 static const WCHAR ExecSeqQuery [] =
1048 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1049 '`','I','n','s','t','a','l','l',
1050 'U','I','S','e','q','u','e','n','c','e','`',
1051 ' ','W','H','E','R','E',' ',
1052 '`','S','e','q','u','e','n','c','e','`',' ',
1053 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1054 '`','S','e','q','u','e','n','c','e','`',0};
1056 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1057 if (rc == ERROR_SUCCESS)
1059 msiobj_release(&view->hdr);
1066 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
1068 LPWSTR source, check;
1070 if (msi_get_property_int( package->db, szInstalled, 0 ))
1074 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
1075 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
1076 RegCloseKey( hkey );
1083 db = msi_dup_property( package->db, szOriginalDatabase );
1085 return ERROR_OUTOFMEMORY;
1087 p = strrchrW( db, '\\' );
1090 p = strrchrW( db, '/' );
1094 return ERROR_SUCCESS;
1099 source = msi_alloc( len * sizeof(WCHAR) );
1100 lstrcpynW( source, db, len );
1104 check = msi_dup_property( package->db, cszSourceDir );
1105 if (!check || replace)
1107 UINT r = msi_set_property( package->db, cszSourceDir, source );
1108 if (r == ERROR_SUCCESS)
1109 msi_reset_folders( package, TRUE );
1113 check = msi_dup_property( package->db, cszSOURCEDIR );
1114 if (!check || replace)
1115 msi_set_property( package->db, cszSOURCEDIR, source );
1120 return ERROR_SUCCESS;
1123 static BOOL needs_ui_sequence(MSIPACKAGE *package)
1125 INT level = msi_get_property_int(package->db, szUILevel, 0);
1126 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
1129 UINT msi_set_context(MSIPACKAGE *package)
1133 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
1135 num = msi_get_property_int(package->db, szAllUsers, 0);
1136 if (num == 1 || num == 2)
1137 package->Context = MSIINSTALLCONTEXT_MACHINE;
1139 return ERROR_SUCCESS;
1142 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
1145 LPCWSTR cond, action;
1146 MSIPACKAGE *package = param;
1148 action = MSI_RecordGetString(row,1);
1151 ERR("Error is retrieving action name\n");
1152 return ERROR_FUNCTION_FAILED;
1155 /* check conditions */
1156 cond = MSI_RecordGetString(row,2);
1158 /* this is a hack to skip errors in the condition code */
1159 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1161 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
1162 return ERROR_SUCCESS;
1165 if (needs_ui_sequence(package))
1166 rc = ACTION_PerformUIAction(package, action, -1);
1168 rc = ACTION_PerformAction(package, action, -1);
1170 msi_dialog_check_messages( NULL );
1172 if (package->CurrentInstallState != ERROR_SUCCESS)
1173 rc = package->CurrentInstallState;
1175 if (rc == ERROR_FUNCTION_NOT_CALLED)
1178 if (rc != ERROR_SUCCESS)
1179 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
1184 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
1188 static const WCHAR query[] =
1189 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1191 ' ','W','H','E','R','E',' ',
1192 '`','S','e','q','u','e','n','c','e','`',' ',
1193 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1194 '`','S','e','q','u','e','n','c','e','`',0};
1196 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1198 r = MSI_OpenQuery( package->db, &view, query, szTable );
1199 if (r == ERROR_SUCCESS)
1201 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
1202 msiobj_release(&view->hdr);
1208 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1212 static const WCHAR ExecSeqQuery[] =
1213 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1214 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1215 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1216 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1217 'O','R','D','E','R',' ', 'B','Y',' ',
1218 '`','S','e','q','u','e','n','c','e','`',0 };
1219 static const WCHAR IVQuery[] =
1220 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1221 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1222 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1223 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1224 ' ','\'', 'I','n','s','t','a','l','l',
1225 'V','a','l','i','d','a','t','e','\'', 0};
1228 if (package->script->ExecuteSequenceRun)
1230 TRACE("Execute Sequence already Run\n");
1231 return ERROR_SUCCESS;
1234 package->script->ExecuteSequenceRun = TRUE;
1236 /* get the sequence number */
1239 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
1241 return ERROR_FUNCTION_FAILED;
1242 seq = MSI_RecordGetInteger(row,1);
1243 msiobj_release(&row->hdr);
1246 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1247 if (rc == ERROR_SUCCESS)
1249 TRACE("Running the actions\n");
1251 msi_set_property(package->db, cszSourceDir, NULL);
1253 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1254 msiobj_release(&view->hdr);
1260 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1264 static const WCHAR ExecSeqQuery [] =
1265 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1266 '`','I','n','s','t','a','l','l',
1267 'U','I','S','e','q','u','e','n','c','e','`',
1268 ' ','W','H','E','R','E',' ',
1269 '`','S','e','q','u','e','n','c','e','`',' ',
1270 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1271 '`','S','e','q','u','e','n','c','e','`',0};
1273 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1274 if (rc == ERROR_SUCCESS)
1276 TRACE("Running the actions\n");
1278 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
1279 msiobj_release(&view->hdr);
1285 /********************************************************
1286 * ACTION helper functions and functions that perform the actions
1287 *******************************************************/
1288 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1289 UINT* rc, UINT script, BOOL force )
1294 arc = ACTION_CustomAction(package, action, script, force);
1296 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1305 * Actual Action Handlers
1308 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1310 MSIPACKAGE *package = param;
1311 LPCWSTR dir, component;
1317 component = MSI_RecordGetString(row, 2);
1319 return ERROR_SUCCESS;
1321 comp = get_loaded_component(package, component);
1323 return ERROR_SUCCESS;
1327 TRACE("component is disabled\n");
1328 return ERROR_SUCCESS;
1331 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1333 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
1334 comp->Action = comp->Installed;
1335 return ERROR_SUCCESS;
1337 comp->Action = INSTALLSTATE_LOCAL;
1339 dir = MSI_RecordGetString(row,1);
1342 ERR("Unable to get folder id\n");
1343 return ERROR_SUCCESS;
1346 uirow = MSI_CreateRecord(1);
1347 MSI_RecordSetStringW(uirow, 1, dir);
1348 ui_actiondata(package, szCreateFolders, uirow);
1349 msiobj_release(&uirow->hdr);
1351 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1354 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1355 return ERROR_SUCCESS;
1358 TRACE("Folder is %s\n",debugstr_w(full_path));
1360 if (folder->State == 0)
1361 create_full_pathW(full_path);
1365 msi_free(full_path);
1366 return ERROR_SUCCESS;
1369 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1371 static const WCHAR query[] =
1372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1373 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1377 /* create all the empty folders specified in the CreateFolder table */
1378 rc = MSI_DatabaseOpenViewW(package->db, query, &view );
1379 if (rc != ERROR_SUCCESS)
1380 return ERROR_SUCCESS;
1382 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1383 msiobj_release(&view->hdr);
1388 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1390 MSIPACKAGE *package = param;
1391 LPCWSTR dir, component;
1397 component = MSI_RecordGetString(row, 2);
1399 return ERROR_SUCCESS;
1401 comp = get_loaded_component(package, component);
1403 return ERROR_SUCCESS;
1407 TRACE("component is disabled\n");
1408 return ERROR_SUCCESS;
1411 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1413 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1414 comp->Action = comp->Installed;
1415 return ERROR_SUCCESS;
1417 comp->Action = INSTALLSTATE_ABSENT;
1419 dir = MSI_RecordGetString( row, 1 );
1422 ERR("Unable to get folder id\n");
1423 return ERROR_SUCCESS;
1426 full_path = resolve_target_folder( package, dir, FALSE, TRUE, &folder );
1429 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1430 return ERROR_SUCCESS;
1433 TRACE("folder is %s\n", debugstr_w(full_path));
1435 uirow = MSI_CreateRecord( 1 );
1436 MSI_RecordSetStringW( uirow, 1, dir );
1437 ui_actiondata( package, szRemoveFolders, uirow );
1438 msiobj_release( &uirow->hdr );
1440 RemoveDirectoryW( full_path );
1443 msi_free( full_path );
1444 return ERROR_SUCCESS;
1447 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1449 static const WCHAR query[] =
1450 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1451 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1456 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1457 if (rc != ERROR_SUCCESS)
1458 return ERROR_SUCCESS;
1460 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1461 msiobj_release( &view->hdr );
1466 static UINT load_component( MSIRECORD *row, LPVOID param )
1468 MSIPACKAGE *package = param;
1471 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1473 return ERROR_FUNCTION_FAILED;
1475 list_add_tail( &package->components, &comp->entry );
1477 /* fill in the data */
1478 comp->Component = msi_dup_record_field( row, 1 );
1480 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1482 comp->ComponentId = msi_dup_record_field( row, 2 );
1483 comp->Directory = msi_dup_record_field( row, 3 );
1484 comp->Attributes = MSI_RecordGetInteger(row,4);
1485 comp->Condition = msi_dup_record_field( row, 5 );
1486 comp->KeyPath = msi_dup_record_field( row, 6 );
1488 comp->Installed = INSTALLSTATE_UNKNOWN;
1489 comp->Action = INSTALLSTATE_UNKNOWN;
1490 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1492 comp->assembly = load_assembly( package, comp );
1493 return ERROR_SUCCESS;
1496 static UINT load_all_components( MSIPACKAGE *package )
1498 static const WCHAR query[] = {
1499 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1500 '`','C','o','m','p','o','n','e','n','t','`',0 };
1504 if (!list_empty(&package->components))
1505 return ERROR_SUCCESS;
1507 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1508 if (r != ERROR_SUCCESS)
1511 r = MSI_IterateRecords(view, NULL, load_component, package);
1512 msiobj_release(&view->hdr);
1517 MSIPACKAGE *package;
1518 MSIFEATURE *feature;
1521 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1525 cl = msi_alloc( sizeof (*cl) );
1527 return ERROR_NOT_ENOUGH_MEMORY;
1528 cl->component = comp;
1529 list_add_tail( &feature->Components, &cl->entry );
1531 return ERROR_SUCCESS;
1534 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1538 fl = msi_alloc( sizeof(*fl) );
1540 return ERROR_NOT_ENOUGH_MEMORY;
1541 fl->feature = child;
1542 list_add_tail( &parent->Children, &fl->entry );
1544 return ERROR_SUCCESS;
1547 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1549 _ilfs* ilfs = param;
1553 component = MSI_RecordGetString(row,1);
1555 /* check to see if the component is already loaded */
1556 comp = get_loaded_component( ilfs->package, component );
1559 ERR("unknown component %s\n", debugstr_w(component));
1560 return ERROR_FUNCTION_FAILED;
1563 add_feature_component( ilfs->feature, comp );
1564 comp->Enabled = TRUE;
1566 return ERROR_SUCCESS;
1569 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1571 MSIFEATURE *feature;
1576 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1578 if ( !strcmpW( feature->Feature, name ) )
1585 static UINT load_feature(MSIRECORD * row, LPVOID param)
1587 MSIPACKAGE* package = param;
1588 MSIFEATURE* feature;
1589 static const WCHAR Query1[] =
1590 {'S','E','L','E','C','T',' ',
1591 '`','C','o','m','p','o','n','e','n','t','_','`',
1592 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1593 'C','o','m','p','o','n','e','n','t','s','`',' ',
1594 'W','H','E','R','E',' ',
1595 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1600 /* fill in the data */
1602 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1604 return ERROR_NOT_ENOUGH_MEMORY;
1606 list_init( &feature->Children );
1607 list_init( &feature->Components );
1609 feature->Feature = msi_dup_record_field( row, 1 );
1611 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1613 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1614 feature->Title = msi_dup_record_field( row, 3 );
1615 feature->Description = msi_dup_record_field( row, 4 );
1617 if (!MSI_RecordIsNull(row,5))
1618 feature->Display = MSI_RecordGetInteger(row,5);
1620 feature->Level= MSI_RecordGetInteger(row,6);
1621 feature->Directory = msi_dup_record_field( row, 7 );
1622 feature->Attributes = MSI_RecordGetInteger(row,8);
1624 feature->Installed = INSTALLSTATE_UNKNOWN;
1625 feature->Action = INSTALLSTATE_UNKNOWN;
1626 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1628 list_add_tail( &package->features, &feature->entry );
1630 /* load feature components */
1632 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1633 if (rc != ERROR_SUCCESS)
1634 return ERROR_SUCCESS;
1636 ilfs.package = package;
1637 ilfs.feature = feature;
1639 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1640 msiobj_release(&view->hdr);
1642 return ERROR_SUCCESS;
1645 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1647 MSIPACKAGE* package = param;
1648 MSIFEATURE *parent, *child;
1650 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1652 return ERROR_FUNCTION_FAILED;
1654 if (!child->Feature_Parent)
1655 return ERROR_SUCCESS;
1657 parent = find_feature_by_name( package, child->Feature_Parent );
1659 return ERROR_FUNCTION_FAILED;
1661 add_feature_child( parent, child );
1662 return ERROR_SUCCESS;
1665 static UINT load_all_features( MSIPACKAGE *package )
1667 static const WCHAR query[] = {
1668 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1669 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1670 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1674 if (!list_empty(&package->features))
1675 return ERROR_SUCCESS;
1677 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1678 if (r != ERROR_SUCCESS)
1681 r = MSI_IterateRecords( view, NULL, load_feature, package );
1682 if (r != ERROR_SUCCESS)
1685 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1686 msiobj_release( &view->hdr );
1691 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1702 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1704 static const WCHAR query[] = {
1705 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1706 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1707 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1708 MSIQUERY *view = NULL;
1709 MSIRECORD *row = NULL;
1712 TRACE("%s\n", debugstr_w(file->File));
1714 r = MSI_OpenQuery(package->db, &view, query, file->File);
1715 if (r != ERROR_SUCCESS)
1718 r = MSI_ViewExecute(view, NULL);
1719 if (r != ERROR_SUCCESS)
1722 r = MSI_ViewFetch(view, &row);
1723 if (r != ERROR_SUCCESS)
1726 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1727 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1728 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1729 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1730 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1733 if (view) msiobj_release(&view->hdr);
1734 if (row) msiobj_release(&row->hdr);
1738 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1741 static const WCHAR query[] = {
1742 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1743 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1744 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1746 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1749 WARN("query failed\n");
1750 return ERROR_FUNCTION_FAILED;
1753 file->disk_id = MSI_RecordGetInteger( row, 1 );
1754 msiobj_release( &row->hdr );
1755 return ERROR_SUCCESS;
1758 static UINT load_file(MSIRECORD *row, LPVOID param)
1760 MSIPACKAGE* package = param;
1764 /* fill in the data */
1766 file = msi_alloc_zero( sizeof (MSIFILE) );
1768 return ERROR_NOT_ENOUGH_MEMORY;
1770 file->File = msi_dup_record_field( row, 1 );
1772 component = MSI_RecordGetString( row, 2 );
1773 file->Component = get_loaded_component( package, component );
1775 if (!file->Component)
1777 WARN("Component not found: %s\n", debugstr_w(component));
1778 msi_free(file->File);
1780 return ERROR_SUCCESS;
1783 file->FileName = msi_dup_record_field( row, 3 );
1784 reduce_to_longfilename( file->FileName );
1786 file->ShortName = msi_dup_record_field( row, 3 );
1787 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1789 file->FileSize = MSI_RecordGetInteger( row, 4 );
1790 file->Version = msi_dup_record_field( row, 5 );
1791 file->Language = msi_dup_record_field( row, 6 );
1792 file->Attributes = MSI_RecordGetInteger( row, 7 );
1793 file->Sequence = MSI_RecordGetInteger( row, 8 );
1795 file->state = msifs_invalid;
1797 /* if the compressed bits are not set in the file attributes,
1798 * then read the information from the package word count property
1800 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1802 file->IsCompressed = FALSE;
1804 else if (file->Attributes &
1805 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1807 file->IsCompressed = TRUE;
1809 else if (file->Attributes & msidbFileAttributesNoncompressed)
1811 file->IsCompressed = FALSE;
1815 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1818 load_file_hash(package, file);
1819 load_file_disk_id(package, file);
1821 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1823 list_add_tail( &package->files, &file->entry );
1825 return ERROR_SUCCESS;
1828 static UINT load_all_files(MSIPACKAGE *package)
1832 static const WCHAR Query[] =
1833 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1834 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1835 '`','S','e','q','u','e','n','c','e','`', 0};
1837 if (!list_empty(&package->files))
1838 return ERROR_SUCCESS;
1840 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1841 if (rc != ERROR_SUCCESS)
1842 return ERROR_SUCCESS;
1844 rc = MSI_IterateRecords(view, NULL, load_file, package);
1845 msiobj_release(&view->hdr);
1847 return ERROR_SUCCESS;
1850 static UINT load_folder( MSIRECORD *row, LPVOID param )
1852 MSIPACKAGE *package = param;
1853 static WCHAR szEmpty[] = { 0 };
1854 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1857 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1859 return ERROR_NOT_ENOUGH_MEMORY;
1861 folder->Directory = msi_dup_record_field( row, 1 );
1863 TRACE("%s\n", debugstr_w(folder->Directory));
1865 p = msi_dup_record_field(row, 3);
1867 /* split src and target dir */
1869 src_short = folder_split_path( p, ':' );
1871 /* split the long and short paths */
1872 tgt_long = folder_split_path( tgt_short, '|' );
1873 src_long = folder_split_path( src_short, '|' );
1875 /* check for no-op dirs */
1876 if (tgt_short && !strcmpW( szDot, tgt_short ))
1877 tgt_short = szEmpty;
1878 if (src_short && !strcmpW( szDot, src_short ))
1879 src_short = szEmpty;
1882 tgt_long = tgt_short;
1885 src_short = tgt_short;
1886 src_long = tgt_long;
1890 src_long = src_short;
1892 /* FIXME: use the target short path too */
1893 folder->TargetDefault = strdupW(tgt_long);
1894 folder->SourceShortPath = strdupW(src_short);
1895 folder->SourceLongPath = strdupW(src_long);
1898 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1899 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1900 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1902 folder->Parent = msi_dup_record_field( row, 2 );
1904 folder->Property = msi_dup_property( package->db, folder->Directory );
1906 list_add_tail( &package->folders, &folder->entry );
1908 TRACE("returning %p\n", folder);
1910 return ERROR_SUCCESS;
1913 static UINT load_all_folders( MSIPACKAGE *package )
1915 static const WCHAR query[] = {
1916 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1917 '`','D','i','r','e','c','t','o','r','y','`',0 };
1921 if (!list_empty(&package->folders))
1922 return ERROR_SUCCESS;
1924 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1925 if (r != ERROR_SUCCESS)
1928 r = MSI_IterateRecords(view, NULL, load_folder, package);
1929 msiobj_release(&view->hdr);
1934 * I am not doing any of the costing functionality yet.
1935 * Mostly looking at doing the Component and Feature loading
1937 * The native MSI does A LOT of modification to tables here. Mostly adding
1938 * a lot of temporary columns to the Feature and Component tables.
1940 * note: Native msi also tracks the short filename. But I am only going to
1941 * track the long ones. Also looking at this directory table
1942 * it appears that the directory table does not get the parents
1943 * resolved base on property only based on their entries in the
1946 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1948 static const WCHAR szCosting[] =
1949 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1951 msi_set_property( package->db, szCosting, szZero );
1952 msi_set_property( package->db, cszRootDrive, c_colon );
1954 load_all_folders( package );
1955 load_all_components( package );
1956 load_all_features( package );
1957 load_all_files( package );
1959 return ERROR_SUCCESS;
1962 static UINT execute_script(MSIPACKAGE *package, UINT script )
1965 UINT rc = ERROR_SUCCESS;
1967 TRACE("Executing Script %i\n",script);
1969 if (!package->script)
1971 ERR("no script!\n");
1972 return ERROR_FUNCTION_FAILED;
1975 for (i = 0; i < package->script->ActionCount[script]; i++)
1978 action = package->script->Actions[script][i];
1979 ui_actionstart(package, action);
1980 TRACE("Executing Action (%s)\n",debugstr_w(action));
1981 rc = ACTION_PerformAction(package, action, script);
1982 if (rc != ERROR_SUCCESS)
1985 msi_free_action_script(package, script);
1989 static UINT ACTION_FileCost(MSIPACKAGE *package)
1991 return ERROR_SUCCESS;
1994 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1999 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
2001 if (!comp->ComponentId) continue;
2003 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2004 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
2006 if (r != ERROR_SUCCESS)
2007 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2008 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
2010 if (r != ERROR_SUCCESS)
2011 r = MsiQueryComponentStateW( package->ProductCode, NULL,
2012 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
2014 if (r != ERROR_SUCCESS)
2015 comp->Installed = INSTALLSTATE_ABSENT;
2019 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
2021 MSIFEATURE *feature;
2023 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2025 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
2027 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
2028 feature->Installed = INSTALLSTATE_ABSENT;
2030 feature->Installed = state;
2034 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
2036 return (feature->Level > 0 && feature->Level <= level);
2039 static BOOL process_state_property(MSIPACKAGE* package, int level,
2040 LPCWSTR property, INSTALLSTATE state)
2043 MSIFEATURE *feature;
2045 override = msi_dup_property( package->db, property );
2049 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2051 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level ))
2054 if (!strcmpW(property, szReinstall)) state = feature->Installed;
2056 if (!strcmpiW( override, szAll ))
2058 if (feature->Installed != state)
2060 feature->Action = state;
2061 feature->ActionRequest = state;
2066 LPWSTR ptr = override;
2067 LPWSTR ptr2 = strchrW(override,',');
2071 int len = ptr2 - ptr;
2073 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
2074 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
2076 if (feature->Installed != state)
2078 feature->Action = state;
2079 feature->ActionRequest = state;
2086 ptr2 = strchrW(ptr,',');
2097 static BOOL process_overrides( MSIPACKAGE *package, int level )
2099 static const WCHAR szAddLocal[] =
2100 {'A','D','D','L','O','C','A','L',0};
2101 static const WCHAR szAddSource[] =
2102 {'A','D','D','S','O','U','R','C','E',0};
2103 static const WCHAR szAdvertise[] =
2104 {'A','D','V','E','R','T','I','S','E',0};
2107 /* all these activation/deactivation things happen in order and things
2108 * later on the list override things earlier on the list.
2110 * 0 INSTALLLEVEL processing
2123 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
2124 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
2125 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
2126 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
2127 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
2130 msi_set_property( package->db, szPreselected, szOne );
2135 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
2138 static const WCHAR szlevel[] =
2139 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2140 MSICOMPONENT* component;
2141 MSIFEATURE *feature;
2143 TRACE("Checking Install Level\n");
2145 level = msi_get_property_int(package->db, szlevel, 1);
2147 if (!msi_get_property_int( package->db, szPreselected, 0 ))
2149 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2151 if (!is_feature_selected( feature, level )) continue;
2153 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2155 if (feature->Attributes & msidbFeatureAttributesFavorSource)
2157 feature->Action = INSTALLSTATE_SOURCE;
2158 feature->ActionRequest = INSTALLSTATE_SOURCE;
2160 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2162 feature->Action = INSTALLSTATE_ADVERTISED;
2163 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
2167 feature->Action = INSTALLSTATE_LOCAL;
2168 feature->ActionRequest = INSTALLSTATE_LOCAL;
2173 /* disable child features of unselected parent features */
2174 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2178 if (is_feature_selected( feature, level )) continue;
2180 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
2182 fl->feature->Action = INSTALLSTATE_UNKNOWN;
2183 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
2187 else /* preselected */
2189 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2191 if (!is_feature_selected( feature, level )) continue;
2193 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
2195 if (feature->Installed == INSTALLSTATE_ABSENT)
2197 feature->Action = INSTALLSTATE_UNKNOWN;
2198 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
2202 feature->Action = feature->Installed;
2203 feature->ActionRequest = feature->Installed;
2209 /* now we want to set component state based based on feature state */
2210 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2214 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2215 debugstr_w(feature->Feature), feature->Level, feature->Installed,
2216 feature->ActionRequest, feature->Action);
2218 if (!is_feature_selected( feature, level )) continue;
2220 /* features with components that have compressed files are made local */
2221 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2223 if (cl->component->ForceLocalState &&
2224 feature->ActionRequest == INSTALLSTATE_SOURCE)
2226 feature->Action = INSTALLSTATE_LOCAL;
2227 feature->ActionRequest = INSTALLSTATE_LOCAL;
2232 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2234 component = cl->component;
2236 switch (feature->ActionRequest)
2238 case INSTALLSTATE_ABSENT:
2239 component->anyAbsent = 1;
2241 case INSTALLSTATE_ADVERTISED:
2242 component->hasAdvertiseFeature = 1;
2244 case INSTALLSTATE_SOURCE:
2245 component->hasSourceFeature = 1;
2247 case INSTALLSTATE_LOCAL:
2248 component->hasLocalFeature = 1;
2250 case INSTALLSTATE_DEFAULT:
2251 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2252 component->hasAdvertiseFeature = 1;
2253 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2254 component->hasSourceFeature = 1;
2256 component->hasLocalFeature = 1;
2264 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2266 /* check if it's local or source */
2267 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2268 (component->hasLocalFeature || component->hasSourceFeature))
2270 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2271 !component->ForceLocalState)
2273 component->Action = INSTALLSTATE_SOURCE;
2274 component->ActionRequest = INSTALLSTATE_SOURCE;
2278 component->Action = INSTALLSTATE_LOCAL;
2279 component->ActionRequest = INSTALLSTATE_LOCAL;
2284 /* if any feature is local, the component must be local too */
2285 if (component->hasLocalFeature)
2287 component->Action = INSTALLSTATE_LOCAL;
2288 component->ActionRequest = INSTALLSTATE_LOCAL;
2291 if (component->hasSourceFeature)
2293 component->Action = INSTALLSTATE_SOURCE;
2294 component->ActionRequest = INSTALLSTATE_SOURCE;
2297 if (component->hasAdvertiseFeature)
2299 component->Action = INSTALLSTATE_ADVERTISED;
2300 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2303 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2304 if (component->anyAbsent &&
2305 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE))
2307 component->Action = INSTALLSTATE_ABSENT;
2308 component->ActionRequest = INSTALLSTATE_ABSENT;
2312 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2314 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
2316 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2317 component->Action = INSTALLSTATE_LOCAL;
2318 component->ActionRequest = INSTALLSTATE_LOCAL;
2321 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
2322 component->Installed == INSTALLSTATE_SOURCE &&
2323 component->hasSourceFeature)
2325 component->Action = INSTALLSTATE_UNKNOWN;
2326 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2329 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2330 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
2333 return ERROR_SUCCESS;
2336 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2338 MSIPACKAGE *package = param;
2343 name = MSI_RecordGetString(row,1);
2345 f = get_loaded_folder(package, name);
2346 if (!f) return ERROR_SUCCESS;
2348 /* reset the ResolvedTarget */
2349 msi_free(f->ResolvedTarget);
2350 f->ResolvedTarget = NULL;
2352 TRACE("directory %s ...\n", debugstr_w(name));
2353 path = resolve_target_folder( package, name, TRUE, TRUE, NULL );
2354 TRACE("resolves to %s\n", debugstr_w(path));
2357 return ERROR_SUCCESS;
2360 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2362 MSIPACKAGE *package = param;
2364 MSIFEATURE *feature;
2366 name = MSI_RecordGetString( row, 1 );
2368 feature = get_loaded_feature( package, name );
2370 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2374 Condition = MSI_RecordGetString(row,3);
2376 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2378 int level = MSI_RecordGetInteger(row,2);
2379 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2380 feature->Level = level;
2383 return ERROR_SUCCESS;
2386 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
2388 static const WCHAR name[] = {'\\',0};
2389 VS_FIXEDFILEINFO *ptr, *ret;
2391 DWORD versize, handle;
2394 TRACE("%s\n", debugstr_w(filename));
2396 versize = GetFileVersionInfoSizeW( filename, &handle );
2400 version = msi_alloc( versize );
2404 GetFileVersionInfoW( filename, 0, versize, version );
2406 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
2408 msi_free( version );
2412 ret = msi_alloc( sz );
2413 memcpy( ret, ptr, sz );
2415 msi_free( version );
2419 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2423 msi_parse_version_string( version, &ms, &ls );
2425 if (fi->dwFileVersionMS > ms) return 1;
2426 else if (fi->dwFileVersionMS < ms) return -1;
2427 else if (fi->dwFileVersionLS > ls) return 1;
2428 else if (fi->dwFileVersionLS < ls) return -1;
2432 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
2436 msi_parse_version_string( ver1, &ms1, NULL );
2437 msi_parse_version_string( ver2, &ms2, NULL );
2439 if (ms1 > ms2) return 1;
2440 else if (ms1 < ms2) return -1;
2444 DWORD msi_get_disk_file_size( LPCWSTR filename )
2449 TRACE("%s\n", debugstr_w(filename));
2451 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2452 if (file == INVALID_HANDLE_VALUE)
2453 return INVALID_FILE_SIZE;
2455 size = GetFileSize( file, NULL );
2456 CloseHandle( file );
2460 BOOL msi_file_hash_matches( MSIFILE *file )
2463 MSIFILEHASHINFO hash;
2465 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2466 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2467 if (r != ERROR_SUCCESS)
2470 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2473 static WCHAR *get_temp_dir( void )
2476 WCHAR tmp[MAX_PATH], dir[MAX_PATH];
2478 GetTempPathW( MAX_PATH, tmp );
2481 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
2482 if (CreateDirectoryW( dir, NULL )) break;
2484 return strdupW( dir );
2487 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2489 MSIASSEMBLY *assembly = file->Component->assembly;
2491 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2493 msi_free( file->TargetPath );
2494 if (assembly && !assembly->application)
2496 if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
2497 file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
2498 track_tempfile( package, file->TargetPath );
2502 WCHAR *dir = resolve_target_folder( package, file->Component->Directory, FALSE, TRUE, NULL );
2503 file->TargetPath = build_directory_name( 2, dir, file->FileName );
2507 TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
2510 static UINT calculate_file_cost( MSIPACKAGE *package )
2512 VS_FIXEDFILEINFO *file_version;
2513 WCHAR *font_version;
2516 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2518 MSICOMPONENT *comp = file->Component;
2521 if (!comp->Enabled) continue;
2523 if (file->IsCompressed)
2524 comp->ForceLocalState = TRUE;
2526 set_target_path( package, file );
2528 if ((comp->assembly && !comp->assembly->installed) ||
2529 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2531 comp->Cost += file->FileSize;
2534 file_size = msi_get_disk_file_size( file->TargetPath );
2538 if ((file_version = msi_get_disk_file_version( file->TargetPath )))
2540 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2542 comp->Cost += file->FileSize - file_size;
2544 msi_free( file_version );
2547 else if ((font_version = font_version_from_file( file->TargetPath )))
2549 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2551 comp->Cost += file->FileSize - file_size;
2553 msi_free( font_version );
2557 if (file_size != file->FileSize)
2559 comp->Cost += file->FileSize - file_size;
2562 return ERROR_SUCCESS;
2566 * A lot is done in this function aside from just the costing.
2567 * The costing needs to be implemented at some point but for now I am going
2568 * to focus on the directory building
2571 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2573 static const WCHAR ExecSeqQuery[] =
2574 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2575 '`','D','i','r','e','c','t','o','r','y','`',0};
2576 static const WCHAR ConditionQuery[] =
2577 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2578 '`','C','o','n','d','i','t','i','o','n','`',0};
2579 static const WCHAR szCosting[] =
2580 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2581 static const WCHAR szlevel[] =
2582 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2583 static const WCHAR szOutOfDiskSpace[] =
2584 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2586 UINT rc = ERROR_SUCCESS;
2590 TRACE("Building Directory properties\n");
2592 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2593 if (rc == ERROR_SUCCESS)
2595 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2597 msiobj_release(&view->hdr);
2600 TRACE("Evaluating component conditions\n");
2601 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2603 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2605 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2606 comp->Enabled = FALSE;
2609 comp->Enabled = TRUE;
2612 /* read components states from the registry */
2613 ACTION_GetComponentInstallStates(package);
2614 ACTION_GetFeatureInstallStates(package);
2616 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2618 TRACE("Evaluating feature conditions\n");
2620 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2621 if (rc == ERROR_SUCCESS)
2623 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2624 msiobj_release( &view->hdr );
2628 TRACE("Calculating file cost\n");
2629 calculate_file_cost( package );
2631 msi_set_property( package->db, szCosting, szOne );
2632 /* set default run level if not set */
2633 level = msi_dup_property( package->db, szlevel );
2635 msi_set_property( package->db, szlevel, szOne );
2638 /* FIXME: check volume disk space */
2639 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2641 return MSI_SetFeatureStates(package);
2644 /* OK this value is "interpreted" and then formatted based on the
2645 first few characters */
2646 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2651 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2657 LPWSTR deformated = NULL;
2660 deformat_string(package, &value[2], &deformated);
2662 /* binary value type */
2666 *size = (strlenW(ptr)/2)+1;
2668 *size = strlenW(ptr)/2;
2670 data = msi_alloc(*size);
2676 /* if uneven pad with a zero in front */
2682 data[count] = (BYTE)strtol(byte,NULL,0);
2684 TRACE("Uneven byte count\n");
2692 data[count] = (BYTE)strtol(byte,NULL,0);
2695 msi_free(deformated);
2697 TRACE("Data %i bytes(%i)\n",*size,count);
2704 deformat_string(package, &value[1], &deformated);
2707 *size = sizeof(DWORD);
2708 data = msi_alloc(*size);
2714 if ( (*p < '0') || (*p > '9') )
2720 if (deformated[0] == '-')
2723 TRACE("DWORD %i\n",*(LPDWORD)data);
2725 msi_free(deformated);
2730 static const WCHAR szMulti[] = {'[','~',']',0};
2739 *type=REG_EXPAND_SZ;
2747 if (strstrW(value, szMulti))
2748 *type = REG_MULTI_SZ;
2750 /* remove initial delimiter */
2751 if (!strncmpW(value, szMulti, 3))
2754 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2756 /* add double NULL terminator */
2757 if (*type == REG_MULTI_SZ)
2759 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2760 data = msi_realloc_zero(data, *size);
2766 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2773 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2775 *root_key = HKEY_LOCAL_MACHINE;
2780 *root_key = HKEY_CURRENT_USER;
2785 *root_key = HKEY_CLASSES_ROOT;
2789 *root_key = HKEY_CURRENT_USER;
2793 *root_key = HKEY_LOCAL_MACHINE;
2797 *root_key = HKEY_USERS;
2801 ERR("Unknown root %i\n", root);
2808 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2810 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2811 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2813 if (is_64bit && package->platform == PLATFORM_INTEL &&
2814 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2819 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2820 path_32node = msi_alloc( size );
2824 memcpy( path_32node, path, len * sizeof(WCHAR) );
2825 path_32node[len] = 0;
2826 strcatW( path_32node, szWow6432Node );
2827 strcatW( path_32node, szBackSlash );
2828 strcatW( path_32node, path + len );
2832 return strdupW( path );
2835 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2837 MSIPACKAGE *package = param;
2838 LPSTR value_data = NULL;
2839 HKEY root_key, hkey;
2841 LPWSTR deformated, uikey, keypath;
2842 LPCWSTR szRoot, component, name, key, value;
2846 BOOL check_first = FALSE;
2849 ui_progress(package,2,0,0,0);
2851 component = MSI_RecordGetString(row, 6);
2852 comp = get_loaded_component(package,component);
2854 return ERROR_SUCCESS;
2858 TRACE("component is disabled\n");
2859 return ERROR_SUCCESS;
2862 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2864 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2865 comp->Action = comp->Installed;
2866 return ERROR_SUCCESS;
2868 comp->Action = INSTALLSTATE_LOCAL;
2870 name = MSI_RecordGetString(row, 4);
2871 if( MSI_RecordIsNull(row,5) && name )
2873 /* null values can have special meanings */
2874 if (name[0]=='-' && name[1] == 0)
2875 return ERROR_SUCCESS;
2876 else if ((name[0]=='+' && name[1] == 0) ||
2877 (name[0] == '*' && name[1] == 0))
2882 root = MSI_RecordGetInteger(row,2);
2883 key = MSI_RecordGetString(row, 3);
2885 szRoot = get_root_key( package, root, &root_key );
2887 return ERROR_SUCCESS;
2889 deformat_string(package, key , &deformated);
2890 size = strlenW(deformated) + strlenW(szRoot) + 1;
2891 uikey = msi_alloc(size*sizeof(WCHAR));
2892 strcpyW(uikey,szRoot);
2893 strcatW(uikey,deformated);
2895 keypath = get_keypath( package, root_key, deformated );
2896 msi_free( deformated );
2897 if (RegCreateKeyW( root_key, keypath, &hkey ))
2899 ERR("Could not create key %s\n", debugstr_w(keypath));
2902 return ERROR_SUCCESS;
2905 value = MSI_RecordGetString(row,5);
2907 value_data = parse_value(package, value, &type, &size);
2910 value_data = (LPSTR)strdupW(szEmpty);
2911 size = sizeof(szEmpty);
2915 deformat_string(package, name, &deformated);
2919 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2921 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2926 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2927 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2929 TRACE("value %s of %s checked already exists\n",
2930 debugstr_w(deformated), debugstr_w(uikey));
2934 TRACE("Checked and setting value %s of %s\n",
2935 debugstr_w(deformated), debugstr_w(uikey));
2936 if (deformated || size)
2937 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2942 uirow = MSI_CreateRecord(3);
2943 MSI_RecordSetStringW(uirow,2,deformated);
2944 MSI_RecordSetStringW(uirow,1,uikey);
2945 if (type == REG_SZ || type == REG_EXPAND_SZ)
2946 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2947 ui_actiondata(package,szWriteRegistryValues,uirow);
2948 msiobj_release( &uirow->hdr );
2950 msi_free(value_data);
2951 msi_free(deformated);
2955 return ERROR_SUCCESS;
2958 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2962 static const WCHAR ExecSeqQuery[] =
2963 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2964 '`','R','e','g','i','s','t','r','y','`',0 };
2966 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2967 if (rc != ERROR_SUCCESS)
2968 return ERROR_SUCCESS;
2970 /* increment progress bar each time action data is sent */
2971 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2973 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2975 msiobj_release(&view->hdr);
2979 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2983 DWORD num_subkeys, num_values;
2987 if ((res = RegDeleteTreeW( hkey_root, key )))
2989 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2994 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2996 if ((res = RegDeleteValueW( hkey, value )))
2998 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value), res);
3000 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
3001 NULL, NULL, NULL, NULL );
3002 RegCloseKey( hkey );
3003 if (!res && !num_subkeys && !num_values)
3005 TRACE("Removing empty key %s\n", debugstr_w(key));
3006 RegDeleteKeyW( hkey_root, key );
3010 TRACE("Failed to open key %s (%d)\n", debugstr_w(key), res);
3014 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
3016 MSIPACKAGE *package = param;
3017 LPCWSTR component, name, key_str, root_key_str;
3018 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3021 BOOL delete_key = FALSE;
3026 ui_progress( package, 2, 0, 0, 0 );
3028 component = MSI_RecordGetString( row, 6 );
3029 comp = get_loaded_component( package, component );
3031 return ERROR_SUCCESS;
3035 TRACE("component is disabled\n");
3036 return ERROR_SUCCESS;
3039 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3041 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
3042 comp->Action = comp->Installed;
3043 return ERROR_SUCCESS;
3045 comp->Action = INSTALLSTATE_ABSENT;
3047 name = MSI_RecordGetString( row, 4 );
3048 if (MSI_RecordIsNull( row, 5 ) && name )
3050 if (name[0] == '+' && !name[1])
3051 return ERROR_SUCCESS;
3052 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
3059 root = MSI_RecordGetInteger( row, 2 );
3060 key_str = MSI_RecordGetString( row, 3 );
3062 root_key_str = get_root_key( package, root, &hkey_root );
3064 return ERROR_SUCCESS;
3066 deformat_string( package, key_str, &deformated_key );
3067 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3068 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3069 strcpyW( ui_key_str, root_key_str );
3070 strcatW( ui_key_str, deformated_key );
3072 deformat_string( package, name, &deformated_name );
3074 keypath = get_keypath( package, hkey_root, deformated_key );
3075 msi_free( deformated_key );
3076 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
3077 msi_free( keypath );
3079 uirow = MSI_CreateRecord( 2 );
3080 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3081 MSI_RecordSetStringW( uirow, 2, deformated_name );
3083 ui_actiondata( package, szRemoveRegistryValues, uirow );
3084 msiobj_release( &uirow->hdr );
3086 msi_free( ui_key_str );
3087 msi_free( deformated_name );
3088 return ERROR_SUCCESS;
3091 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
3093 MSIPACKAGE *package = param;
3094 LPCWSTR component, name, key_str, root_key_str;
3095 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
3098 BOOL delete_key = FALSE;
3103 ui_progress( package, 2, 0, 0, 0 );
3105 component = MSI_RecordGetString( row, 5 );
3106 comp = get_loaded_component( package, component );
3108 return ERROR_SUCCESS;
3112 TRACE("component is disabled\n");
3113 return ERROR_SUCCESS;
3116 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3118 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3119 comp->Action = comp->Installed;
3120 return ERROR_SUCCESS;
3122 comp->Action = INSTALLSTATE_LOCAL;
3124 if ((name = MSI_RecordGetString( row, 4 )))
3126 if (name[0] == '-' && !name[1])
3133 root = MSI_RecordGetInteger( row, 2 );
3134 key_str = MSI_RecordGetString( row, 3 );
3136 root_key_str = get_root_key( package, root, &hkey_root );
3138 return ERROR_SUCCESS;
3140 deformat_string( package, key_str, &deformated_key );
3141 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
3142 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
3143 strcpyW( ui_key_str, root_key_str );
3144 strcatW( ui_key_str, deformated_key );
3146 deformat_string( package, name, &deformated_name );
3148 keypath = get_keypath( package, hkey_root, deformated_key );
3149 msi_free( deformated_key );
3150 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
3151 msi_free( keypath );
3153 uirow = MSI_CreateRecord( 2 );
3154 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3155 MSI_RecordSetStringW( uirow, 2, deformated_name );
3157 ui_actiondata( package, szRemoveRegistryValues, uirow );
3158 msiobj_release( &uirow->hdr );
3160 msi_free( ui_key_str );
3161 msi_free( deformated_name );
3162 return ERROR_SUCCESS;
3165 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3169 static const WCHAR registry_query[] =
3170 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3171 '`','R','e','g','i','s','t','r','y','`',0 };
3172 static const WCHAR remove_registry_query[] =
3173 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3174 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
3176 /* increment progress bar each time action data is sent */
3177 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
3179 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
3180 if (rc == ERROR_SUCCESS)
3182 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3183 msiobj_release( &view->hdr );
3184 if (rc != ERROR_SUCCESS)
3188 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
3189 if (rc == ERROR_SUCCESS)
3191 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3192 msiobj_release( &view->hdr );
3193 if (rc != ERROR_SUCCESS)
3197 return ERROR_SUCCESS;
3200 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3202 package->script->CurrentlyScripting = TRUE;
3204 return ERROR_SUCCESS;
3208 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3213 static const WCHAR q1[]=
3214 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3215 '`','R','e','g','i','s','t','r','y','`',0};
3218 MSIFEATURE *feature;
3221 TRACE("InstallValidate\n");
3223 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3224 if (rc == ERROR_SUCCESS)
3226 MSI_IterateRecords( view, &progress, NULL, package );
3227 msiobj_release( &view->hdr );
3228 total += progress * REG_PROGRESS_VALUE;
3231 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3232 total += COMPONENT_PROGRESS_VALUE;
3234 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3235 total += file->FileSize;
3237 ui_progress(package,0,total,0,0);
3239 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3241 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3242 debugstr_w(feature->Feature), feature->Installed,
3243 feature->ActionRequest, feature->Action);
3246 return ERROR_SUCCESS;
3249 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3251 MSIPACKAGE* package = param;
3252 LPCWSTR cond = NULL;
3253 LPCWSTR message = NULL;
3256 static const WCHAR title[]=
3257 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3259 cond = MSI_RecordGetString(row,1);
3261 r = MSI_EvaluateConditionW(package,cond);
3262 if (r == MSICONDITION_FALSE)
3264 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3267 message = MSI_RecordGetString(row,2);
3268 deformat_string(package,message,&deformated);
3269 MessageBoxW(NULL,deformated,title,MB_OK);
3270 msi_free(deformated);
3273 return ERROR_INSTALL_FAILURE;
3276 return ERROR_SUCCESS;
3279 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3282 MSIQUERY * view = NULL;
3283 static const WCHAR ExecSeqQuery[] =
3284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3285 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3287 TRACE("Checking launch conditions\n");
3289 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3290 if (rc != ERROR_SUCCESS)
3291 return ERROR_SUCCESS;
3293 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3294 msiobj_release(&view->hdr);
3299 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3303 return resolve_target_folder( package, cmp->Directory, FALSE, TRUE, NULL );
3305 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3307 MSIRECORD * row = 0;
3309 LPWSTR deformated,buffer,deformated_name;
3311 static const WCHAR ExecSeqQuery[] =
3312 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3313 '`','R','e','g','i','s','t','r','y','`',' ',
3314 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3315 ' ','=',' ' ,'\'','%','s','\'',0 };
3316 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3317 static const WCHAR fmt2[]=
3318 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3320 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3324 root = MSI_RecordGetInteger(row,2);
3325 key = MSI_RecordGetString(row, 3);
3326 name = MSI_RecordGetString(row, 4);
3327 deformat_string(package, key , &deformated);
3328 deformat_string(package, name, &deformated_name);
3330 len = strlenW(deformated) + 6;
3331 if (deformated_name)
3332 len+=strlenW(deformated_name);
3334 buffer = msi_alloc( len *sizeof(WCHAR));
3336 if (deformated_name)
3337 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3339 sprintfW(buffer,fmt,root,deformated);
3341 msi_free(deformated);
3342 msi_free(deformated_name);
3343 msiobj_release(&row->hdr);
3347 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3349 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3354 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
3357 return strdupW( file->TargetPath );
3362 static HKEY openSharedDLLsKey(void)
3365 static const WCHAR path[] =
3366 {'S','o','f','t','w','a','r','e','\\',
3367 'M','i','c','r','o','s','o','f','t','\\',
3368 'W','i','n','d','o','w','s','\\',
3369 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3370 'S','h','a','r','e','d','D','L','L','s',0};
3372 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3376 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3381 DWORD sz = sizeof(count);
3384 hkey = openSharedDLLsKey();
3385 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3386 if (rc != ERROR_SUCCESS)
3392 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3396 hkey = openSharedDLLsKey();
3398 msi_reg_set_val_dword( hkey, path, count );
3400 RegDeleteValueW(hkey,path);
3405 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
3407 MSIFEATURE *feature;
3411 /* only refcount DLLs */
3412 if (comp->KeyPath == NULL ||
3414 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3415 comp->Attributes & msidbComponentAttributesODBCDataSource)
3419 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
3420 write = (count > 0);
3422 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3426 /* increment counts */
3427 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3431 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3434 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3436 if ( cl->component == comp )
3441 /* decrement counts */
3442 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3446 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3449 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3451 if ( cl->component == comp )
3456 /* ref count all the files in the component */
3461 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3463 if (file->Component == comp)
3464 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3468 /* add a count for permanent */
3469 if (comp->Attributes & msidbComponentAttributesPermanent)
3472 comp->RefCount = count;
3475 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3478 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3480 WCHAR squished_pc[GUID_SIZE];
3481 WCHAR squished_cc[GUID_SIZE];
3488 squash_guid(package->ProductCode,squished_pc);
3489 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3491 msi_set_sourcedir_props(package, FALSE);
3493 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3497 ui_progress(package,2,0,0,0);
3498 if (!comp->ComponentId)
3501 squash_guid(comp->ComponentId,squished_cc);
3503 msi_free(comp->FullKeypath);
3506 const WCHAR prefixW[] = {'<','\\',0};
3507 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
3509 comp->FullKeypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
3510 if (comp->FullKeypath)
3512 strcpyW( comp->FullKeypath, prefixW );
3513 strcatW( comp->FullKeypath, comp->assembly->display_name );
3516 else comp->FullKeypath = resolve_keypath( package, comp );
3518 ACTION_RefCountComponent( package, comp );
3520 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3521 debugstr_w(comp->Component),
3522 debugstr_w(squished_cc),
3523 debugstr_w(comp->FullKeypath),
3525 comp->ActionRequest);
3527 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3528 comp->ActionRequest == INSTALLSTATE_SOURCE)
3530 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3531 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
3533 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3535 if (rc != ERROR_SUCCESS)
3538 if (comp->Attributes & msidbComponentAttributesPermanent)
3540 static const WCHAR szPermKey[] =
3541 { '0','0','0','0','0','0','0','0','0','0','0','0',
3542 '0','0','0','0','0','0','0','0','0','0','0','0',
3543 '0','0','0','0','0','0','0','0',0 };
3545 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3548 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3549 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3555 WCHAR source[MAX_PATH];
3556 WCHAR base[MAX_PATH];
3559 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3560 static const WCHAR query[] = {
3561 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3562 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3563 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3564 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3565 '`','D','i','s','k','I','d','`',0};
3567 if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
3570 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3571 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3572 ptr2 = strrchrW(source, '\\') + 1;
3573 msiobj_release(&row->hdr);
3575 lstrcpyW(base, package->PackagePath);
3576 ptr = strrchrW(base, '\\');
3579 sourcepath = resolve_file_source(package, file);
3580 ptr = sourcepath + lstrlenW(base);
3581 lstrcpyW(ptr2, ptr);
3582 msi_free(sourcepath);
3584 msi_reg_set_val_str(hkey, squished_pc, source);
3588 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3590 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3591 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3593 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3595 comp->Action = comp->ActionRequest;
3598 uirow = MSI_CreateRecord(3);
3599 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3600 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3601 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3602 ui_actiondata(package,szProcessComponents,uirow);
3603 msiobj_release( &uirow->hdr );
3606 return ERROR_SUCCESS;
3617 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3618 LPWSTR lpszName, LONG_PTR lParam)
3621 typelib_struct *tl_struct = (typelib_struct*) lParam;
3622 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3626 if (!IS_INTRESOURCE(lpszName))
3628 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3632 sz = strlenW(tl_struct->source)+4;
3633 sz *= sizeof(WCHAR);
3635 if ((INT_PTR)lpszName == 1)
3636 tl_struct->path = strdupW(tl_struct->source);
3639 tl_struct->path = msi_alloc(sz);
3640 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3643 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3644 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3647 msi_free(tl_struct->path);
3648 tl_struct->path = NULL;
3653 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3654 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3656 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3660 msi_free(tl_struct->path);
3661 tl_struct->path = NULL;
3663 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3664 ITypeLib_Release(tl_struct->ptLib);
3669 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3671 MSIPACKAGE* package = param;
3675 typelib_struct tl_struct;
3680 component = MSI_RecordGetString(row,3);
3681 comp = get_loaded_component(package,component);
3683 return ERROR_SUCCESS;
3687 TRACE("component is disabled\n");
3688 return ERROR_SUCCESS;
3691 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3693 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3694 comp->Action = comp->Installed;
3695 return ERROR_SUCCESS;
3697 comp->Action = INSTALLSTATE_LOCAL;
3699 if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3701 TRACE("component has no key path\n");
3702 return ERROR_SUCCESS;
3704 ui_actiondata( package, szRegisterTypeLibraries, row );
3706 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3710 guid = MSI_RecordGetString(row,1);
3711 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3712 tl_struct.source = strdupW( file->TargetPath );
3713 tl_struct.path = NULL;
3715 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3716 (LONG_PTR)&tl_struct);
3724 helpid = MSI_RecordGetString(row,6);
3726 if (helpid) help = resolve_target_folder( package, helpid, FALSE, TRUE, NULL );
3727 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3731 ERR("Failed to register type library %s\n",
3732 debugstr_w(tl_struct.path));
3734 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3736 ITypeLib_Release(tl_struct.ptLib);
3737 msi_free(tl_struct.path);
3740 ERR("Failed to load type library %s\n",
3741 debugstr_w(tl_struct.source));
3743 FreeLibrary(module);
3744 msi_free(tl_struct.source);
3748 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3751 ERR("Failed to load type library: %08x\n", hr);
3752 return ERROR_INSTALL_FAILURE;
3755 ITypeLib_Release(tlib);
3758 return ERROR_SUCCESS;
3761 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3764 * OK this is a bit confusing.. I am given a _Component key and I believe
3765 * that the file that is being registered as a type library is the "key file
3766 * of that component" which I interpret to mean "The file in the KeyPath of
3771 static const WCHAR Query[] =
3772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3773 '`','T','y','p','e','L','i','b','`',0};
3775 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3776 if (rc != ERROR_SUCCESS)
3777 return ERROR_SUCCESS;
3779 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3780 msiobj_release(&view->hdr);
3784 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3786 MSIPACKAGE *package = param;
3787 LPCWSTR component, guid;
3795 component = MSI_RecordGetString( row, 3 );
3796 comp = get_loaded_component( package, component );
3798 return ERROR_SUCCESS;
3802 TRACE("component is disabled\n");
3803 return ERROR_SUCCESS;
3806 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3808 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3809 comp->Action = comp->Installed;
3810 return ERROR_SUCCESS;
3812 comp->Action = INSTALLSTATE_ABSENT;
3814 ui_actiondata( package, szUnregisterTypeLibraries, row );
3816 guid = MSI_RecordGetString( row, 1 );
3817 CLSIDFromString( (LPCWSTR)guid, &libid );
3818 version = MSI_RecordGetInteger( row, 4 );
3819 language = MSI_RecordGetInteger( row, 2 );
3822 syskind = SYS_WIN64;
3824 syskind = SYS_WIN32;
3827 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3830 WARN("Failed to unregister typelib: %08x\n", hr);
3833 return ERROR_SUCCESS;
3836 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3840 static const WCHAR query[] =
3841 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3842 '`','T','y','p','e','L','i','b','`',0};
3844 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3845 if (rc != ERROR_SUCCESS)
3846 return ERROR_SUCCESS;
3848 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3849 msiobj_release( &view->hdr );
3853 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3855 static const WCHAR szlnk[] = {'.','l','n','k',0};
3856 LPCWSTR directory, extension;
3857 LPWSTR link_folder, link_file, filename;
3859 directory = MSI_RecordGetString( row, 2 );
3860 link_folder = resolve_target_folder( package, directory, FALSE, TRUE, NULL );
3862 /* may be needed because of a bug somewhere else */
3863 create_full_pathW( link_folder );
3865 filename = msi_dup_record_field( row, 3 );
3866 reduce_to_longfilename( filename );
3868 extension = strchrW( filename, '.' );
3869 if (!extension || strcmpiW( extension, szlnk ))
3871 int len = strlenW( filename );
3872 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3873 memcpy( filename + len, szlnk, sizeof(szlnk) );
3875 link_file = build_directory_name( 2, link_folder, filename );
3876 msi_free( link_folder );
3877 msi_free( filename );
3882 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3884 MSIPACKAGE *package = param;
3885 LPWSTR link_file, deformated, path;
3886 LPCWSTR component, target;
3888 IShellLinkW *sl = NULL;
3889 IPersistFile *pf = NULL;
3892 component = MSI_RecordGetString(row, 4);
3893 comp = get_loaded_component(package, component);
3895 return ERROR_SUCCESS;
3899 TRACE("component is disabled\n");
3900 return ERROR_SUCCESS;
3903 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3905 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3906 comp->Action = comp->Installed;
3907 return ERROR_SUCCESS;
3909 comp->Action = INSTALLSTATE_LOCAL;
3911 ui_actiondata(package,szCreateShortcuts,row);
3913 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3914 &IID_IShellLinkW, (LPVOID *) &sl );
3918 ERR("CLSID_ShellLink not available\n");
3922 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3925 ERR("QueryInterface(IID_IPersistFile) failed\n");
3929 target = MSI_RecordGetString(row, 5);
3930 if (strchrW(target, '['))
3932 deformat_string(package, target, &deformated);
3933 IShellLinkW_SetPath(sl,deformated);
3934 msi_free(deformated);
3938 FIXME("poorly handled shortcut format, advertised shortcut\n");
3939 IShellLinkW_SetPath(sl,comp->FullKeypath);
3942 if (!MSI_RecordIsNull(row,6))
3944 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3945 deformat_string(package, arguments, &deformated);
3946 IShellLinkW_SetArguments(sl,deformated);
3947 msi_free(deformated);
3950 if (!MSI_RecordIsNull(row,7))
3952 LPCWSTR description = MSI_RecordGetString(row, 7);
3953 IShellLinkW_SetDescription(sl, description);
3956 if (!MSI_RecordIsNull(row,8))
3957 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3959 if (!MSI_RecordIsNull(row,9))
3962 LPCWSTR icon = MSI_RecordGetString(row, 9);
3964 path = build_icon_path(package, icon);
3965 index = MSI_RecordGetInteger(row,10);
3967 /* no value means 0 */
3968 if (index == MSI_NULL_INTEGER)
3971 IShellLinkW_SetIconLocation(sl, path, index);
3975 if (!MSI_RecordIsNull(row,11))
3976 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3978 if (!MSI_RecordIsNull(row,12))
3980 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3981 path = resolve_target_folder( package, wkdir, FALSE, TRUE, NULL );
3983 IShellLinkW_SetWorkingDirectory(sl, path);
3987 link_file = get_link_file(package, row);
3989 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3990 IPersistFile_Save(pf, link_file, FALSE);
3992 msi_free(link_file);
3996 IPersistFile_Release( pf );
3998 IShellLinkW_Release( sl );
4000 return ERROR_SUCCESS;
4003 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
4008 static const WCHAR Query[] =
4009 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4010 '`','S','h','o','r','t','c','u','t','`',0};
4012 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4013 if (rc != ERROR_SUCCESS)
4014 return ERROR_SUCCESS;
4016 res = CoInitialize( NULL );
4018 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
4019 msiobj_release(&view->hdr);
4027 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
4029 MSIPACKAGE *package = param;
4034 component = MSI_RecordGetString( row, 4 );
4035 comp = get_loaded_component( package, component );
4037 return ERROR_SUCCESS;
4041 TRACE("component is disabled\n");
4042 return ERROR_SUCCESS;
4045 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4047 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4048 comp->Action = comp->Installed;
4049 return ERROR_SUCCESS;
4051 comp->Action = INSTALLSTATE_ABSENT;
4053 ui_actiondata( package, szRemoveShortcuts, row );
4055 link_file = get_link_file( package, row );
4057 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
4058 if (!DeleteFileW( link_file ))
4060 WARN("Failed to remove shortcut file %u\n", GetLastError());
4062 msi_free( link_file );
4064 return ERROR_SUCCESS;
4067 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4071 static const WCHAR query[] =
4072 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4073 '`','S','h','o','r','t','c','u','t','`',0};
4075 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4076 if (rc != ERROR_SUCCESS)
4077 return ERROR_SUCCESS;
4079 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
4080 msiobj_release( &view->hdr );
4085 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
4087 MSIPACKAGE* package = param;
4095 FileName = MSI_RecordGetString(row,1);
4098 ERR("Unable to get FileName\n");
4099 return ERROR_SUCCESS;
4102 FilePath = build_icon_path(package,FileName);
4104 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4106 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4107 FILE_ATTRIBUTE_NORMAL, NULL);
4109 if (the_file == INVALID_HANDLE_VALUE)
4111 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4113 return ERROR_SUCCESS;
4120 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4121 if (rc != ERROR_SUCCESS)
4123 ERR("Failed to get stream\n");
4124 CloseHandle(the_file);
4125 DeleteFileW(FilePath);
4128 WriteFile(the_file,buffer,sz,&write,NULL);
4129 } while (sz == 1024);
4132 CloseHandle(the_file);
4134 return ERROR_SUCCESS;
4137 static UINT msi_publish_icons(MSIPACKAGE *package)
4142 static const WCHAR query[]= {
4143 'S','E','L','E','C','T',' ','*',' ',
4144 'F','R','O','M',' ','`','I','c','o','n','`',0};
4146 r = MSI_DatabaseOpenViewW(package->db, query, &view);
4147 if (r == ERROR_SUCCESS)
4149 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
4150 msiobj_release(&view->hdr);
4153 return ERROR_SUCCESS;
4156 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
4162 MSISOURCELISTINFO *info;
4164 r = RegCreateKeyW(hkey, szSourceList, &source);
4165 if (r != ERROR_SUCCESS)
4168 RegCloseKey(source);
4170 buffer = strrchrW(package->PackagePath, '\\') + 1;
4171 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4172 package->Context, MSICODE_PRODUCT,
4173 INSTALLPROPERTY_PACKAGENAMEW, buffer);
4174 if (r != ERROR_SUCCESS)
4177 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4178 package->Context, MSICODE_PRODUCT,
4179 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
4180 if (r != ERROR_SUCCESS)
4183 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4184 package->Context, MSICODE_PRODUCT,
4185 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
4186 if (r != ERROR_SUCCESS)
4189 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4191 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4192 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4193 info->options, info->value);
4195 MsiSourceListSetInfoW(package->ProductCode, NULL,
4196 info->context, info->options,
4197 info->property, info->value);
4200 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4202 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4203 disk->context, disk->options,
4204 disk->disk_id, disk->volume_label, disk->disk_prompt);
4207 return ERROR_SUCCESS;
4210 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4212 MSIHANDLE hdb, suminfo;
4213 WCHAR guids[MAX_PATH];
4214 WCHAR packcode[SQUISH_GUID_SIZE];
4221 static const WCHAR szProductLanguage[] =
4222 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4223 static const WCHAR szARPProductIcon[] =
4224 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4225 static const WCHAR szProductVersion[] =
4226 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4227 static const WCHAR szAssignment[] =
4228 {'A','s','s','i','g','n','m','e','n','t',0};
4229 static const WCHAR szAdvertiseFlags[] =
4230 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4231 static const WCHAR szClients[] =
4232 {'C','l','i','e','n','t','s',0};
4233 static const WCHAR szColon[] = {':',0};
4235 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4236 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4239 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4240 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4243 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4245 buffer = msi_dup_property(package->db, szARPProductIcon);
4248 LPWSTR path = build_icon_path(package,buffer);
4249 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4254 buffer = msi_dup_property(package->db, szProductVersion);
4257 DWORD verdword = msi_version_str_to_dword(buffer);
4258 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4262 msi_reg_set_val_dword(hkey, szAssignment, 0);
4263 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
4264 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4265 msi_reg_set_val_str(hkey, szClients, szColon);
4267 hdb = alloc_msihandle(&package->db->hdr);
4269 return ERROR_NOT_ENOUGH_MEMORY;
4271 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
4272 MsiCloseHandle(hdb);
4273 if (r != ERROR_SUCCESS)
4277 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
4278 NULL, guids, &size);
4279 if (r != ERROR_SUCCESS)
4282 ptr = strchrW(guids, ';');
4284 squash_guid(guids, packcode);
4285 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4288 MsiCloseHandle(suminfo);
4289 return ERROR_SUCCESS;
4292 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
4297 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4299 upgrade = msi_dup_property(package->db, szUpgradeCode);
4301 return ERROR_SUCCESS;
4303 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4305 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4306 if (r != ERROR_SUCCESS)
4311 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4312 if (r != ERROR_SUCCESS)
4316 squash_guid(package->ProductCode, squashed_pc);
4317 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4326 static BOOL msi_check_publish(MSIPACKAGE *package)
4328 MSIFEATURE *feature;
4330 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4332 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4339 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4341 MSIFEATURE *feature;
4343 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4345 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4352 static UINT msi_publish_patches( MSIPACKAGE *package )
4354 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4355 WCHAR patch_squashed[GUID_SIZE];
4356 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4358 MSIPATCHINFO *patch;
4360 WCHAR *p, *all_patches = NULL;
4363 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4364 if (r != ERROR_SUCCESS)
4365 return ERROR_FUNCTION_FAILED;
4367 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4368 if (res != ERROR_SUCCESS)
4370 r = ERROR_FUNCTION_FAILED;
4374 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4375 if (r != ERROR_SUCCESS)
4378 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4380 squash_guid( patch->patchcode, patch_squashed );
4381 len += strlenW( patch_squashed ) + 1;
4384 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4388 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4392 squash_guid( patch->patchcode, p );
4393 p += strlenW( p ) + 1;
4395 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4396 (const BYTE *)patch->transforms,
4397 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4398 if (res != ERROR_SUCCESS)
4401 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4402 if (r != ERROR_SUCCESS)
4405 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4406 (const BYTE *)patch->localfile,
4407 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4408 RegCloseKey( patch_key );
4409 if (res != ERROR_SUCCESS)
4412 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4413 if (res != ERROR_SUCCESS)
4416 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4417 RegCloseKey( patch_key );
4418 if (res != ERROR_SUCCESS)
4422 all_patches[len] = 0;
4423 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4424 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4425 if (res != ERROR_SUCCESS)
4428 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4429 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4430 if (res != ERROR_SUCCESS)
4431 r = ERROR_FUNCTION_FAILED;
4434 RegCloseKey( product_patches_key );
4435 RegCloseKey( patches_key );
4436 RegCloseKey( product_key );
4437 msi_free( all_patches );
4442 * 99% of the work done here is only done for
4443 * advertised installs. However this is where the
4444 * Icon table is processed and written out
4445 * so that is what I am going to do here.
4447 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4450 HKEY hukey = NULL, hudkey = NULL;
4453 if (!list_empty(&package->patches))
4455 rc = msi_publish_patches(package);
4456 if (rc != ERROR_SUCCESS)
4460 /* FIXME: also need to publish if the product is in advertise mode */
4461 if (!msi_check_publish(package))
4462 return ERROR_SUCCESS;
4464 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4466 if (rc != ERROR_SUCCESS)
4469 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4470 NULL, &hudkey, TRUE);
4471 if (rc != ERROR_SUCCESS)
4474 rc = msi_publish_upgrade_code(package);
4475 if (rc != ERROR_SUCCESS)
4478 rc = msi_publish_product_properties(package, hukey);
4479 if (rc != ERROR_SUCCESS)
4482 rc = msi_publish_sourcelist(package, hukey);
4483 if (rc != ERROR_SUCCESS)
4486 rc = msi_publish_icons(package);
4489 uirow = MSI_CreateRecord( 1 );
4490 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4491 ui_actiondata( package, szPublishProduct, uirow );
4492 msiobj_release( &uirow->hdr );
4495 RegCloseKey(hudkey);
4500 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4502 WCHAR *filename, *ptr, *folder, *ret;
4503 const WCHAR *dirprop;
4505 filename = msi_dup_record_field( row, 2 );
4506 if (filename && (ptr = strchrW( filename, '|' )))
4511 dirprop = MSI_RecordGetString( row, 3 );
4514 folder = resolve_target_folder( package, dirprop, FALSE, TRUE, NULL );
4516 folder = msi_dup_property( package->db, dirprop );
4519 folder = msi_dup_property( package->db, szWindowsFolder );
4523 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4524 msi_free( filename );
4528 ret = build_directory_name( 2, folder, ptr );
4530 msi_free( filename );
4535 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4537 MSIPACKAGE *package = param;
4538 LPCWSTR component, section, key, value, identifier;
4539 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4544 component = MSI_RecordGetString(row, 8);
4545 comp = get_loaded_component(package,component);
4547 return ERROR_SUCCESS;
4551 TRACE("component is disabled\n");
4552 return ERROR_SUCCESS;
4555 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4557 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4558 comp->Action = comp->Installed;
4559 return ERROR_SUCCESS;
4561 comp->Action = INSTALLSTATE_LOCAL;
4563 identifier = MSI_RecordGetString(row,1);
4564 section = MSI_RecordGetString(row,4);
4565 key = MSI_RecordGetString(row,5);
4566 value = MSI_RecordGetString(row,6);
4567 action = MSI_RecordGetInteger(row,7);
4569 deformat_string(package,section,&deformated_section);
4570 deformat_string(package,key,&deformated_key);
4571 deformat_string(package,value,&deformated_value);
4573 fullname = get_ini_file_name(package, row);
4577 TRACE("Adding value %s to section %s in %s\n",
4578 debugstr_w(deformated_key), debugstr_w(deformated_section),
4579 debugstr_w(fullname));
4580 WritePrivateProfileStringW(deformated_section, deformated_key,
4581 deformated_value, fullname);
4583 else if (action == 1)
4586 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4587 returned, 10, fullname);
4588 if (returned[0] == 0)
4590 TRACE("Adding value %s to section %s in %s\n",
4591 debugstr_w(deformated_key), debugstr_w(deformated_section),
4592 debugstr_w(fullname));
4594 WritePrivateProfileStringW(deformated_section, deformated_key,
4595 deformated_value, fullname);
4598 else if (action == 3)
4599 FIXME("Append to existing section not yet implemented\n");
4601 uirow = MSI_CreateRecord(4);
4602 MSI_RecordSetStringW(uirow,1,identifier);
4603 MSI_RecordSetStringW(uirow,2,deformated_section);
4604 MSI_RecordSetStringW(uirow,3,deformated_key);
4605 MSI_RecordSetStringW(uirow,4,deformated_value);
4606 ui_actiondata(package,szWriteIniValues,uirow);
4607 msiobj_release( &uirow->hdr );
4610 msi_free(deformated_key);
4611 msi_free(deformated_value);
4612 msi_free(deformated_section);
4613 return ERROR_SUCCESS;
4616 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4620 static const WCHAR ExecSeqQuery[] =
4621 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4622 '`','I','n','i','F','i','l','e','`',0};
4624 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4625 if (rc != ERROR_SUCCESS)
4627 TRACE("no IniFile table\n");
4628 return ERROR_SUCCESS;
4631 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4632 msiobj_release(&view->hdr);
4636 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4638 MSIPACKAGE *package = param;
4639 LPCWSTR component, section, key, value, identifier;
4640 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4645 component = MSI_RecordGetString( row, 8 );
4646 comp = get_loaded_component( package, component );
4648 return ERROR_SUCCESS;
4652 TRACE("component is disabled\n");
4653 return ERROR_SUCCESS;
4656 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4658 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4659 comp->Action = comp->Installed;
4660 return ERROR_SUCCESS;
4662 comp->Action = INSTALLSTATE_ABSENT;
4664 identifier = MSI_RecordGetString( row, 1 );
4665 section = MSI_RecordGetString( row, 4 );
4666 key = MSI_RecordGetString( row, 5 );
4667 value = MSI_RecordGetString( row, 6 );
4668 action = MSI_RecordGetInteger( row, 7 );
4670 deformat_string( package, section, &deformated_section );
4671 deformat_string( package, key, &deformated_key );
4672 deformat_string( package, value, &deformated_value );
4674 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4676 filename = get_ini_file_name( package, row );
4678 TRACE("Removing key %s from section %s in %s\n",
4679 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4681 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4683 WARN("Unable to remove key %u\n", GetLastError());
4685 msi_free( filename );
4688 FIXME("Unsupported action %d\n", action);
4691 uirow = MSI_CreateRecord( 4 );
4692 MSI_RecordSetStringW( uirow, 1, identifier );
4693 MSI_RecordSetStringW( uirow, 2, deformated_section );
4694 MSI_RecordSetStringW( uirow, 3, deformated_key );
4695 MSI_RecordSetStringW( uirow, 4, deformated_value );
4696 ui_actiondata( package, szRemoveIniValues, uirow );
4697 msiobj_release( &uirow->hdr );
4699 msi_free( deformated_key );
4700 msi_free( deformated_value );
4701 msi_free( deformated_section );
4702 return ERROR_SUCCESS;
4705 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4707 MSIPACKAGE *package = param;
4708 LPCWSTR component, section, key, value, identifier;
4709 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4714 component = MSI_RecordGetString( row, 8 );
4715 comp = get_loaded_component( package, component );
4717 return ERROR_SUCCESS;
4721 TRACE("component is disabled\n");
4722 return ERROR_SUCCESS;
4725 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4727 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4728 comp->Action = comp->Installed;
4729 return ERROR_SUCCESS;
4731 comp->Action = INSTALLSTATE_LOCAL;
4733 identifier = MSI_RecordGetString( row, 1 );
4734 section = MSI_RecordGetString( row, 4 );
4735 key = MSI_RecordGetString( row, 5 );
4736 value = MSI_RecordGetString( row, 6 );
4737 action = MSI_RecordGetInteger( row, 7 );
4739 deformat_string( package, section, &deformated_section );
4740 deformat_string( package, key, &deformated_key );
4741 deformat_string( package, value, &deformated_value );
4743 if (action == msidbIniFileActionRemoveLine)
4745 filename = get_ini_file_name( package, row );
4747 TRACE("Removing key %s from section %s in %s\n",
4748 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4750 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4752 WARN("Unable to remove key %u\n", GetLastError());
4754 msi_free( filename );
4757 FIXME("Unsupported action %d\n", action);
4759 uirow = MSI_CreateRecord( 4 );
4760 MSI_RecordSetStringW( uirow, 1, identifier );
4761 MSI_RecordSetStringW( uirow, 2, deformated_section );
4762 MSI_RecordSetStringW( uirow, 3, deformated_key );
4763 MSI_RecordSetStringW( uirow, 4, deformated_value );
4764 ui_actiondata( package, szRemoveIniValues, uirow );
4765 msiobj_release( &uirow->hdr );
4767 msi_free( deformated_key );
4768 msi_free( deformated_value );
4769 msi_free( deformated_section );
4770 return ERROR_SUCCESS;
4773 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4777 static const WCHAR query[] =
4778 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4779 '`','I','n','i','F','i','l','e','`',0};
4780 static const WCHAR remove_query[] =
4781 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4782 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4784 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4785 if (rc == ERROR_SUCCESS)
4787 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4788 msiobj_release( &view->hdr );
4789 if (rc != ERROR_SUCCESS)
4793 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4794 if (rc == ERROR_SUCCESS)
4796 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4797 msiobj_release( &view->hdr );
4798 if (rc != ERROR_SUCCESS)
4802 return ERROR_SUCCESS;
4805 static void register_dll( const WCHAR *dll, BOOL unregister )
4809 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4812 HRESULT (WINAPI *func_ptr)( void );
4813 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4815 func_ptr = (void *)GetProcAddress( hmod, func );
4818 HRESULT hr = func_ptr();
4820 WARN("failed to register dll 0x%08x\n", hr);
4823 WARN("entry point %s not found\n", func);
4824 FreeLibrary( hmod );
4827 WARN("failed to load library %u\n", GetLastError());
4830 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4832 MSIPACKAGE *package = param;
4837 filename = MSI_RecordGetString(row,1);
4838 file = get_loaded_file( package, filename );
4842 ERR("Unable to find file id %s\n",debugstr_w(filename));
4843 return ERROR_SUCCESS;
4846 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4848 register_dll( file->TargetPath, FALSE );
4850 uirow = MSI_CreateRecord( 2 );
4851 MSI_RecordSetStringW( uirow, 1, filename );
4852 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4853 ui_actiondata( package, szSelfRegModules, uirow );
4854 msiobj_release( &uirow->hdr );
4856 return ERROR_SUCCESS;
4859 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4863 static const WCHAR ExecSeqQuery[] =
4864 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4865 '`','S','e','l','f','R','e','g','`',0};
4867 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4868 if (rc != ERROR_SUCCESS)
4870 TRACE("no SelfReg table\n");
4871 return ERROR_SUCCESS;
4874 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4875 msiobj_release(&view->hdr);
4877 return ERROR_SUCCESS;
4880 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4882 MSIPACKAGE *package = param;
4887 filename = MSI_RecordGetString( row, 1 );
4888 file = get_loaded_file( package, filename );
4892 ERR("Unable to find file id %s\n", debugstr_w(filename));
4893 return ERROR_SUCCESS;
4896 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4898 register_dll( file->TargetPath, TRUE );
4900 uirow = MSI_CreateRecord( 2 );
4901 MSI_RecordSetStringW( uirow, 1, filename );
4902 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4903 ui_actiondata( package, szSelfUnregModules, uirow );
4904 msiobj_release( &uirow->hdr );
4906 return ERROR_SUCCESS;
4909 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4913 static const WCHAR query[] =
4914 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4915 '`','S','e','l','f','R','e','g','`',0};
4917 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4918 if (rc != ERROR_SUCCESS)
4920 TRACE("no SelfReg table\n");
4921 return ERROR_SUCCESS;
4924 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4925 msiobj_release( &view->hdr );
4927 return ERROR_SUCCESS;
4930 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4932 MSIFEATURE *feature;
4934 HKEY hkey = NULL, userdata = NULL;
4936 if (!msi_check_publish(package))
4937 return ERROR_SUCCESS;
4939 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4941 if (rc != ERROR_SUCCESS)
4944 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4946 if (rc != ERROR_SUCCESS)
4949 /* here the guids are base 85 encoded */
4950 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4956 BOOL absent = FALSE;
4959 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4960 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4961 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4964 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4968 if (feature->Feature_Parent)
4969 size += strlenW( feature->Feature_Parent )+2;
4971 data = msi_alloc(size * sizeof(WCHAR));
4974 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4976 MSICOMPONENT* component = cl->component;
4980 if (component->ComponentId)
4982 TRACE("From %s\n",debugstr_w(component->ComponentId));
4983 CLSIDFromString(component->ComponentId, &clsid);
4984 encode_base85_guid(&clsid,buf);
4985 TRACE("to %s\n",debugstr_w(buf));
4990 if (feature->Feature_Parent)
4992 static const WCHAR sep[] = {'\2',0};
4994 strcatW(data,feature->Feature_Parent);
4997 msi_reg_set_val_str( userdata, feature->Feature, data );
5001 if (feature->Feature_Parent)
5002 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
5005 size += sizeof(WCHAR);
5006 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
5007 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
5011 size += 2*sizeof(WCHAR);
5012 data = msi_alloc(size);
5015 if (feature->Feature_Parent)
5016 strcpyW( &data[1], feature->Feature_Parent );
5017 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
5023 uirow = MSI_CreateRecord( 1 );
5024 MSI_RecordSetStringW( uirow, 1, feature->Feature );
5025 ui_actiondata( package, szPublishFeatures, uirow);
5026 msiobj_release( &uirow->hdr );
5027 /* FIXME: call ui_progress? */
5032 RegCloseKey(userdata);
5036 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
5042 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
5044 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
5046 if (r == ERROR_SUCCESS)
5048 RegDeleteValueW(hkey, feature->Feature);
5052 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
5054 if (r == ERROR_SUCCESS)
5056 RegDeleteValueW(hkey, feature->Feature);
5060 uirow = MSI_CreateRecord( 1 );
5061 MSI_RecordSetStringW( uirow, 1, feature->Feature );
5062 ui_actiondata( package, szUnpublishFeatures, uirow );
5063 msiobj_release( &uirow->hdr );
5065 return ERROR_SUCCESS;
5068 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
5070 MSIFEATURE *feature;
5072 if (!msi_check_unpublish(package))
5073 return ERROR_SUCCESS;
5075 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5077 msi_unpublish_feature(package, feature);
5080 return ERROR_SUCCESS;
5083 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
5087 WCHAR date[9], *val, *buffer;
5088 const WCHAR *prop, *key;
5090 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
5091 static const WCHAR szWindowsInstaller[] =
5092 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5093 static const WCHAR modpath_fmt[] =
5094 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5095 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5096 static const WCHAR szModifyPath[] =
5097 {'M','o','d','i','f','y','P','a','t','h',0};
5098 static const WCHAR szUninstallString[] =
5099 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5100 static const WCHAR szEstimatedSize[] =
5101 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5102 static const WCHAR szProductLanguage[] =
5103 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
5104 static const WCHAR szProductVersion[] =
5105 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
5106 static const WCHAR szDisplayVersion[] =
5107 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5108 static const WCHAR szInstallSource[] =
5109 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5110 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
5111 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5112 static const WCHAR szAuthorizedCDFPrefix[] =
5113 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5114 static const WCHAR szARPCONTACT[] =
5115 {'A','R','P','C','O','N','T','A','C','T',0};
5116 static const WCHAR szContact[] =
5117 {'C','o','n','t','a','c','t',0};
5118 static const WCHAR szARPCOMMENTS[] =
5119 {'A','R','P','C','O','M','M','E','N','T','S',0};
5120 static const WCHAR szComments[] =
5121 {'C','o','m','m','e','n','t','s',0};
5122 static const WCHAR szProductName[] =
5123 {'P','r','o','d','u','c','t','N','a','m','e',0};
5124 static const WCHAR szDisplayName[] =
5125 {'D','i','s','p','l','a','y','N','a','m','e',0};
5126 static const WCHAR szARPHELPLINK[] =
5127 {'A','R','P','H','E','L','P','L','I','N','K',0};
5128 static const WCHAR szHelpLink[] =
5129 {'H','e','l','p','L','i','n','k',0};
5130 static const WCHAR szARPHELPTELEPHONE[] =
5131 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5132 static const WCHAR szHelpTelephone[] =
5133 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5134 static const WCHAR szARPINSTALLLOCATION[] =
5135 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5136 static const WCHAR szInstallLocation[] =
5137 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
5138 static const WCHAR szManufacturer[] =
5139 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5140 static const WCHAR szPublisher[] =
5141 {'P','u','b','l','i','s','h','e','r',0};
5142 static const WCHAR szARPREADME[] =
5143 {'A','R','P','R','E','A','D','M','E',0};
5144 static const WCHAR szReadme[] =
5145 {'R','e','a','d','M','e',0};
5146 static const WCHAR szARPSIZE[] =
5147 {'A','R','P','S','I','Z','E',0};
5148 static const WCHAR szSize[] =
5149 {'S','i','z','e',0};
5150 static const WCHAR szARPURLINFOABOUT[] =
5151 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5152 static const WCHAR szURLInfoAbout[] =
5153 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5154 static const WCHAR szARPURLUPDATEINFO[] =
5155 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5156 static const WCHAR szURLUpdateInfo[] =
5157 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5159 static const WCHAR *propval[] = {
5160 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
5161 szARPCONTACT, szContact,
5162 szARPCOMMENTS, szComments,
5163 szProductName, szDisplayName,
5164 szARPHELPLINK, szHelpLink,
5165 szARPHELPTELEPHONE, szHelpTelephone,
5166 szARPINSTALLLOCATION, szInstallLocation,
5167 cszSourceDir, szInstallSource,
5168 szManufacturer, szPublisher,
5169 szARPREADME, szReadme,
5171 szARPURLINFOABOUT, szURLInfoAbout,
5172 szARPURLUPDATEINFO, szURLUpdateInfo,
5175 const WCHAR **p = propval;
5181 val = msi_dup_property(package->db, prop);
5182 msi_reg_set_val_str(hkey, key, val);
5186 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
5188 size = deformat_string(package, modpath_fmt, &buffer);
5189 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5190 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
5193 /* FIXME: Write real Estimated Size when we have it */
5194 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
5196 GetLocalTime(&systime);
5197 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
5198 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
5200 langid = msi_get_property_int(package->db, szProductLanguage, 0);
5201 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
5203 buffer = msi_dup_property(package->db, szProductVersion);
5204 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
5207 DWORD verdword = msi_version_str_to_dword(buffer);
5209 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
5210 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
5211 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
5215 return ERROR_SUCCESS;
5218 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5220 WCHAR squashed_pc[SQUISH_GUID_SIZE];
5222 LPWSTR upgrade_code;
5227 /* FIXME: also need to publish if the product is in advertise mode */
5228 if (!msi_check_publish(package))
5229 return ERROR_SUCCESS;
5231 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
5232 if (rc != ERROR_SUCCESS)
5235 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5236 NULL, &props, TRUE);
5237 if (rc != ERROR_SUCCESS)
5240 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
5241 msi_free( package->db->localfile );
5242 package->db->localfile = NULL;
5244 rc = msi_publish_install_properties(package, hkey);
5245 if (rc != ERROR_SUCCESS)
5248 rc = msi_publish_install_properties(package, props);
5249 if (rc != ERROR_SUCCESS)
5252 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
5255 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
5256 squash_guid(package->ProductCode, squashed_pc);
5257 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
5258 RegCloseKey(upgrade);
5259 msi_free(upgrade_code);
5263 uirow = MSI_CreateRecord( 1 );
5264 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5265 ui_actiondata( package, szRegisterProduct, uirow );
5266 msiobj_release( &uirow->hdr );
5269 return ERROR_SUCCESS;
5272 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5274 return execute_script(package,INSTALL_SCRIPT);
5277 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
5279 WCHAR *upgrade, **features;
5280 BOOL full_uninstall = TRUE;
5281 MSIFEATURE *feature;
5282 MSIPATCHINFO *patch;
5284 static const WCHAR szUpgradeCode[] =
5285 {'U','p','g','r','a','d','e','C','o','d','e',0};
5287 features = msi_split_string(remove, ',');
5290 ERR("REMOVE feature list is empty!\n");
5291 return ERROR_FUNCTION_FAILED;
5294 if (!strcmpW( features[0], szAll ))
5295 full_uninstall = TRUE;
5298 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
5300 if (feature->Action != INSTALLSTATE_ABSENT)
5301 full_uninstall = FALSE;
5306 if (!full_uninstall)
5307 return ERROR_SUCCESS;
5309 MSIREG_DeleteProductKey(package->ProductCode);
5310 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5311 MSIREG_DeleteUninstallKey(package);
5313 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5314 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5315 MSIREG_DeleteUserProductKey(package->ProductCode);
5316 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5318 upgrade = msi_dup_property(package->db, szUpgradeCode);
5321 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5322 MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
5326 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5328 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5331 return ERROR_SUCCESS;
5334 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5339 /* turn off scheduling */
5340 package->script->CurrentlyScripting= FALSE;
5342 /* first do the same as an InstallExecute */
5343 rc = ACTION_InstallExecute(package);
5344 if (rc != ERROR_SUCCESS)
5347 /* then handle Commit Actions */
5348 rc = execute_script(package,COMMIT_SCRIPT);
5349 if (rc != ERROR_SUCCESS)
5352 remove = msi_dup_property(package->db, szRemove);
5354 rc = msi_unpublish_product(package, remove);
5360 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5362 static const WCHAR RunOnce[] = {
5363 'S','o','f','t','w','a','r','e','\\',
5364 'M','i','c','r','o','s','o','f','t','\\',
5365 'W','i','n','d','o','w','s','\\',
5366 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5367 'R','u','n','O','n','c','e',0};
5368 static const WCHAR InstallRunOnce[] = {
5369 'S','o','f','t','w','a','r','e','\\',
5370 'M','i','c','r','o','s','o','f','t','\\',
5371 'W','i','n','d','o','w','s','\\',
5372 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5373 'I','n','s','t','a','l','l','e','r','\\',
5374 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5376 static const WCHAR msiexec_fmt[] = {
5378 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5379 '\"','%','s','\"',0};
5380 static const WCHAR install_fmt[] = {
5381 '/','I',' ','\"','%','s','\"',' ',
5382 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5383 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5384 WCHAR buffer[256], sysdir[MAX_PATH];
5386 WCHAR squished_pc[100];
5388 squash_guid(package->ProductCode,squished_pc);
5390 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5391 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5392 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5395 msi_reg_set_val_str( hkey, squished_pc, buffer );
5398 TRACE("Reboot command %s\n",debugstr_w(buffer));
5400 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5401 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5403 msi_reg_set_val_str( hkey, squished_pc, buffer );
5406 return ERROR_INSTALL_SUSPEND;
5409 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5415 * We are currently doing what should be done here in the top level Install
5416 * however for Administrative and uninstalls this step will be needed
5418 if (!package->PackagePath)
5419 return ERROR_SUCCESS;
5421 msi_set_sourcedir_props(package, TRUE);
5423 attrib = GetFileAttributesW(package->db->path);
5424 if (attrib == INVALID_FILE_ATTRIBUTES)
5430 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5431 package->Context, MSICODE_PRODUCT,
5432 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5433 if (rc == ERROR_MORE_DATA)
5435 prompt = msi_alloc(size * sizeof(WCHAR));
5436 MsiSourceListGetInfoW(package->ProductCode, NULL,
5437 package->Context, MSICODE_PRODUCT,
5438 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5441 prompt = strdupW(package->db->path);
5443 msg = generate_error_string(package,1302,1,prompt);
5444 while(attrib == INVALID_FILE_ATTRIBUTES)
5446 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5449 rc = ERROR_INSTALL_USEREXIT;
5452 attrib = GetFileAttributesW(package->db->path);
5458 return ERROR_SUCCESS;
5463 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5466 LPWSTR buffer, productid = NULL;
5467 UINT i, rc = ERROR_SUCCESS;
5470 static const WCHAR szPropKeys[][80] =
5472 {'P','r','o','d','u','c','t','I','D',0},
5473 {'U','S','E','R','N','A','M','E',0},
5474 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5478 static const WCHAR szRegKeys[][80] =
5480 {'P','r','o','d','u','c','t','I','D',0},
5481 {'R','e','g','O','w','n','e','r',0},
5482 {'R','e','g','C','o','m','p','a','n','y',0},
5486 if (msi_check_unpublish(package))
5488 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5492 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5496 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5498 if (rc != ERROR_SUCCESS)
5501 for( i = 0; szPropKeys[i][0]; i++ )
5503 buffer = msi_dup_property( package->db, szPropKeys[i] );
5504 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5509 uirow = MSI_CreateRecord( 1 );
5510 MSI_RecordSetStringW( uirow, 1, productid );
5511 ui_actiondata( package, szRegisterUser, uirow );
5512 msiobj_release( &uirow->hdr );
5514 msi_free(productid);
5520 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5524 package->script->InWhatSequence |= SEQUENCE_EXEC;
5525 rc = ACTION_ProcessExecSequence(package,FALSE);
5530 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5532 MSIPACKAGE *package = param;
5533 LPCWSTR compgroupid, component, feature, qualifier, text;
5534 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5543 feature = MSI_RecordGetString(rec, 5);
5544 feat = get_loaded_feature(package, feature);
5546 return ERROR_SUCCESS;
5548 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5549 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5550 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5552 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5553 feat->Action = feat->Installed;
5554 return ERROR_SUCCESS;
5557 component = MSI_RecordGetString(rec, 3);
5558 comp = get_loaded_component(package, component);
5560 return ERROR_SUCCESS;
5562 compgroupid = MSI_RecordGetString(rec,1);
5563 qualifier = MSI_RecordGetString(rec,2);
5565 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5566 if (rc != ERROR_SUCCESS)
5569 advertise = create_component_advertise_string( package, comp, feature );
5570 text = MSI_RecordGetString( rec, 4 );
5573 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5574 strcpyW( p, advertise );
5576 msi_free( advertise );
5579 existing = msi_reg_get_val_str( hkey, qualifier );
5581 sz = strlenW( advertise ) + 1;
5584 for (p = existing; *p; p += len)
5586 len = strlenW( p ) + 1;
5587 if (strcmpW( advertise, p )) sz += len;
5590 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5592 rc = ERROR_OUTOFMEMORY;
5598 for (p = existing; *p; p += len)
5600 len = strlenW( p ) + 1;
5601 if (strcmpW( advertise, p ))
5603 memcpy( q, p, len * sizeof(WCHAR) );
5608 strcpyW( q, advertise );
5609 q[strlenW( q ) + 1] = 0;
5611 msi_reg_set_val_multi_str( hkey, qualifier, output );
5616 msi_free( advertise );
5617 msi_free( existing );
5620 uirow = MSI_CreateRecord( 2 );
5621 MSI_RecordSetStringW( uirow, 1, compgroupid );
5622 MSI_RecordSetStringW( uirow, 2, qualifier);
5623 ui_actiondata( package, szPublishComponents, uirow);
5624 msiobj_release( &uirow->hdr );
5625 /* FIXME: call ui_progress? */
5631 * At present I am ignorning the advertised components part of this and only
5632 * focusing on the qualified component sets
5634 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5638 static const WCHAR ExecSeqQuery[] =
5639 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5640 '`','P','u','b','l','i','s','h',
5641 'C','o','m','p','o','n','e','n','t','`',0};
5643 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5644 if (rc != ERROR_SUCCESS)
5645 return ERROR_SUCCESS;
5647 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5648 msiobj_release(&view->hdr);
5653 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5655 static const WCHAR szInstallerComponents[] = {
5656 'S','o','f','t','w','a','r','e','\\',
5657 'M','i','c','r','o','s','o','f','t','\\',
5658 'I','n','s','t','a','l','l','e','r','\\',
5659 'C','o','m','p','o','n','e','n','t','s','\\',0};
5661 MSIPACKAGE *package = param;
5662 LPCWSTR compgroupid, component, feature, qualifier;
5666 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5669 feature = MSI_RecordGetString( rec, 5 );
5670 feat = get_loaded_feature( package, feature );
5672 return ERROR_SUCCESS;
5674 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5676 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5677 feat->Action = feat->Installed;
5678 return ERROR_SUCCESS;
5681 component = MSI_RecordGetString( rec, 3 );
5682 comp = get_loaded_component( package, component );
5684 return ERROR_SUCCESS;
5686 compgroupid = MSI_RecordGetString( rec, 1 );
5687 qualifier = MSI_RecordGetString( rec, 2 );
5689 squash_guid( compgroupid, squashed );
5690 strcpyW( keypath, szInstallerComponents );
5691 strcatW( keypath, squashed );
5693 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5694 if (res != ERROR_SUCCESS)
5696 WARN("Unable to delete component key %d\n", res);
5699 uirow = MSI_CreateRecord( 2 );
5700 MSI_RecordSetStringW( uirow, 1, compgroupid );
5701 MSI_RecordSetStringW( uirow, 2, qualifier );
5702 ui_actiondata( package, szUnpublishComponents, uirow );
5703 msiobj_release( &uirow->hdr );
5705 return ERROR_SUCCESS;
5708 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5712 static const WCHAR query[] =
5713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 '`','P','u','b','l','i','s','h',
5715 'C','o','m','p','o','n','e','n','t','`',0};
5717 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5718 if (rc != ERROR_SUCCESS)
5719 return ERROR_SUCCESS;
5721 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5722 msiobj_release( &view->hdr );
5727 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5729 MSIPACKAGE *package = param;
5732 SC_HANDLE hscm, service = NULL;
5734 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5735 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5736 DWORD serv_type, start_type, err_control;
5737 SERVICE_DESCRIPTIONW sd = {NULL};
5739 static const WCHAR query[] =
5740 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5741 '`','C','o','m','p','o','n','e','n','t','`',' ',
5742 'W','H','E','R','E',' ',
5743 '`','C','o','m','p','o','n','e','n','t','`',' ',
5744 '=','\'','%','s','\'',0};
5746 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5749 ERR("Failed to open the SC Manager!\n");
5753 comp = MSI_RecordGetString( rec, 12 );
5754 if (!get_loaded_component( package, comp ))
5757 start_type = MSI_RecordGetInteger(rec, 5);
5758 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5761 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5762 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5763 serv_type = MSI_RecordGetInteger(rec, 4);
5764 err_control = MSI_RecordGetInteger(rec, 6);
5765 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5766 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5767 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5768 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5769 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5770 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5772 /* fetch the service path */
5773 row = MSI_QueryGetRecord(package->db, query, comp);
5776 ERR("Control query failed!\n");
5779 key = MSI_RecordGetString(row, 6);
5781 file = get_loaded_file(package, key);
5782 msiobj_release(&row->hdr);
5785 ERR("Failed to load the service file\n");
5789 if (!args || !args[0]) image_path = file->TargetPath;
5792 int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5793 if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5794 return ERROR_OUTOFMEMORY;
5796 strcpyW(image_path, file->TargetPath);
5797 strcatW(image_path, szSpace);
5798 strcatW(image_path, args);
5800 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5801 start_type, err_control, image_path, load_order,
5802 NULL, depends, serv_name, pass);
5806 if (GetLastError() != ERROR_SERVICE_EXISTS)
5807 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5809 else if (sd.lpDescription)
5811 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5812 WARN("failed to set service description %u\n", GetLastError());
5815 if (image_path != file->TargetPath) msi_free(image_path);
5817 CloseServiceHandle(service);
5818 CloseServiceHandle(hscm);
5821 msi_free(sd.lpDescription);
5822 msi_free(load_order);
5823 msi_free(serv_name);
5828 return ERROR_SUCCESS;
5831 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5835 static const WCHAR ExecSeqQuery[] =
5836 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5837 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5839 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5840 if (rc != ERROR_SUCCESS)
5841 return ERROR_SUCCESS;
5843 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5844 msiobj_release(&view->hdr);
5849 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5850 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5852 LPCWSTR *vector, *temp_vector;
5856 static const WCHAR separator[] = {'[','~',']',0};
5859 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5864 vector = msi_alloc(sizeof(LPWSTR));
5872 vector[*numargs - 1] = p;
5874 if ((q = strstrW(p, separator)))
5878 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5884 vector = temp_vector;
5893 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5895 MSIPACKAGE *package = param;
5898 SC_HANDLE scm = NULL, service = NULL;
5899 LPCWSTR component, *vector = NULL;
5900 LPWSTR name, args, display_name = NULL;
5901 DWORD event, numargs, len;
5902 UINT r = ERROR_FUNCTION_FAILED;
5904 component = MSI_RecordGetString(rec, 6);
5905 comp = get_loaded_component(package, component);
5907 return ERROR_SUCCESS;
5911 TRACE("component is disabled\n");
5912 return ERROR_SUCCESS;
5915 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5917 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5918 comp->Action = comp->Installed;
5919 return ERROR_SUCCESS;
5921 comp->Action = INSTALLSTATE_LOCAL;
5923 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5924 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5925 event = MSI_RecordGetInteger(rec, 3);
5927 if (!(event & msidbServiceControlEventStart))
5933 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5936 ERR("Failed to open the service control manager\n");
5941 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5942 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5944 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5945 GetServiceDisplayNameW( scm, name, display_name, &len );
5948 service = OpenServiceW(scm, name, SERVICE_START);
5951 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5955 vector = msi_service_args_to_vector(args, &numargs);
5957 if (!StartServiceW(service, numargs, vector) &&
5958 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5960 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5967 uirow = MSI_CreateRecord( 2 );
5968 MSI_RecordSetStringW( uirow, 1, display_name );
5969 MSI_RecordSetStringW( uirow, 2, name );
5970 ui_actiondata( package, szStartServices, uirow );
5971 msiobj_release( &uirow->hdr );
5973 CloseServiceHandle(service);
5974 CloseServiceHandle(scm);
5979 msi_free(display_name);
5983 static UINT ACTION_StartServices( MSIPACKAGE *package )
5988 static const WCHAR query[] = {
5989 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5990 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5992 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5993 if (rc != ERROR_SUCCESS)
5994 return ERROR_SUCCESS;
5996 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5997 msiobj_release(&view->hdr);
6002 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6004 DWORD i, needed, count;
6005 ENUM_SERVICE_STATUSW *dependencies;
6009 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6010 0, &needed, &count))
6013 if (GetLastError() != ERROR_MORE_DATA)
6016 dependencies = msi_alloc(needed);
6020 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6021 needed, &needed, &count))
6024 for (i = 0; i < count; i++)
6026 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6027 SERVICE_STOP | SERVICE_QUERY_STATUS);
6031 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
6038 msi_free(dependencies);
6042 static UINT stop_service( LPCWSTR name )
6044 SC_HANDLE scm = NULL, service = NULL;
6045 SERVICE_STATUS status;
6046 SERVICE_STATUS_PROCESS ssp;
6049 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6052 WARN("Failed to open the SCM: %d\n", GetLastError());
6056 service = OpenServiceW(scm, name,
6058 SERVICE_QUERY_STATUS |
6059 SERVICE_ENUMERATE_DEPENDENTS);
6062 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
6066 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
6067 sizeof(SERVICE_STATUS_PROCESS), &needed))
6069 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
6073 if (ssp.dwCurrentState == SERVICE_STOPPED)
6076 stop_service_dependents(scm, service);
6078 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6079 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
6082 CloseServiceHandle(service);
6083 CloseServiceHandle(scm);
6085 return ERROR_SUCCESS;
6088 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6090 MSIPACKAGE *package = param;
6094 LPWSTR name = NULL, display_name = NULL;
6098 event = MSI_RecordGetInteger( rec, 3 );
6099 if (!(event & msidbServiceControlEventStop))
6100 return ERROR_SUCCESS;
6102 component = MSI_RecordGetString( rec, 6 );
6103 comp = get_loaded_component( package, component );
6105 return ERROR_SUCCESS;
6109 TRACE("component is disabled\n");
6110 return ERROR_SUCCESS;
6113 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6115 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6116 comp->Action = comp->Installed;
6117 return ERROR_SUCCESS;
6119 comp->Action = INSTALLSTATE_ABSENT;
6121 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6124 ERR("Failed to open the service control manager\n");
6129 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6130 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6132 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6133 GetServiceDisplayNameW( scm, name, display_name, &len );
6135 CloseServiceHandle( scm );
6137 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6138 stop_service( name );
6141 uirow = MSI_CreateRecord( 2 );
6142 MSI_RecordSetStringW( uirow, 1, display_name );
6143 MSI_RecordSetStringW( uirow, 2, name );
6144 ui_actiondata( package, szStopServices, uirow );
6145 msiobj_release( &uirow->hdr );
6148 msi_free( display_name );
6149 return ERROR_SUCCESS;
6152 static UINT ACTION_StopServices( MSIPACKAGE *package )
6157 static const WCHAR query[] = {
6158 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6159 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6161 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6162 if (rc != ERROR_SUCCESS)
6163 return ERROR_SUCCESS;
6165 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6166 msiobj_release(&view->hdr);
6171 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6173 MSIPACKAGE *package = param;
6177 LPWSTR name = NULL, display_name = NULL;
6179 SC_HANDLE scm = NULL, service = NULL;
6181 event = MSI_RecordGetInteger( rec, 3 );
6182 if (!(event & msidbServiceControlEventDelete))
6183 return ERROR_SUCCESS;
6185 component = MSI_RecordGetString(rec, 6);
6186 comp = get_loaded_component(package, component);
6188 return ERROR_SUCCESS;
6192 TRACE("component is disabled\n");
6193 return ERROR_SUCCESS;
6196 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6198 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6199 comp->Action = comp->Installed;
6200 return ERROR_SUCCESS;
6202 comp->Action = INSTALLSTATE_ABSENT;
6204 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6205 stop_service( name );
6207 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6210 WARN("Failed to open the SCM: %d\n", GetLastError());
6215 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6216 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6218 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
6219 GetServiceDisplayNameW( scm, name, display_name, &len );
6222 service = OpenServiceW( scm, name, DELETE );
6225 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
6229 if (!DeleteService( service ))
6230 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
6233 uirow = MSI_CreateRecord( 2 );
6234 MSI_RecordSetStringW( uirow, 1, display_name );
6235 MSI_RecordSetStringW( uirow, 2, name );
6236 ui_actiondata( package, szDeleteServices, uirow );
6237 msiobj_release( &uirow->hdr );
6239 CloseServiceHandle( service );
6240 CloseServiceHandle( scm );
6242 msi_free( display_name );
6244 return ERROR_SUCCESS;
6247 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6252 static const WCHAR query[] = {
6253 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6254 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6256 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6257 if (rc != ERROR_SUCCESS)
6258 return ERROR_SUCCESS;
6260 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6261 msiobj_release( &view->hdr );
6266 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6268 MSIPACKAGE *package = param;
6269 LPWSTR driver, driver_path, ptr;
6270 WCHAR outpath[MAX_PATH];
6271 MSIFILE *driver_file = NULL, *setup_file = NULL;
6274 LPCWSTR desc, file_key, component;
6276 UINT r = ERROR_SUCCESS;
6278 static const WCHAR driver_fmt[] = {
6279 'D','r','i','v','e','r','=','%','s',0};
6280 static const WCHAR setup_fmt[] = {
6281 'S','e','t','u','p','=','%','s',0};
6282 static const WCHAR usage_fmt[] = {
6283 'F','i','l','e','U','s','a','g','e','=','1',0};
6285 component = MSI_RecordGetString( rec, 2 );
6286 comp = get_loaded_component( package, component );
6288 return ERROR_SUCCESS;
6292 TRACE("component is disabled\n");
6293 return ERROR_SUCCESS;
6296 desc = MSI_RecordGetString(rec, 3);
6298 file_key = MSI_RecordGetString( rec, 4 );
6299 if (file_key) driver_file = get_loaded_file( package, file_key );
6301 file_key = MSI_RecordGetString( rec, 5 );
6302 if (file_key) setup_file = get_loaded_file( package, file_key );
6306 ERR("ODBC Driver entry not found!\n");
6307 return ERROR_FUNCTION_FAILED;
6310 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
6312 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6313 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
6315 driver = msi_alloc(len * sizeof(WCHAR));
6317 return ERROR_OUTOFMEMORY;
6320 lstrcpyW(ptr, desc);
6321 ptr += lstrlenW(ptr) + 1;
6323 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
6328 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6332 lstrcpyW(ptr, usage_fmt);
6333 ptr += lstrlenW(ptr) + 1;
6336 driver_path = strdupW(driver_file->TargetPath);
6337 ptr = strrchrW(driver_path, '\\');
6338 if (ptr) *ptr = '\0';
6340 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6341 NULL, ODBC_INSTALL_COMPLETE, &usage))
6343 ERR("Failed to install SQL driver!\n");
6344 r = ERROR_FUNCTION_FAILED;
6347 uirow = MSI_CreateRecord( 5 );
6348 MSI_RecordSetStringW( uirow, 1, desc );
6349 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6350 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6351 ui_actiondata( package, szInstallODBC, uirow );
6352 msiobj_release( &uirow->hdr );
6355 msi_free(driver_path);
6360 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6362 MSIPACKAGE *package = param;
6363 LPWSTR translator, translator_path, ptr;
6364 WCHAR outpath[MAX_PATH];
6365 MSIFILE *translator_file = NULL, *setup_file = NULL;
6368 LPCWSTR desc, file_key, component;
6370 UINT r = ERROR_SUCCESS;
6372 static const WCHAR translator_fmt[] = {
6373 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6374 static const WCHAR setup_fmt[] = {
6375 'S','e','t','u','p','=','%','s',0};
6377 component = MSI_RecordGetString( rec, 2 );
6378 comp = get_loaded_component( package, component );
6380 return ERROR_SUCCESS;
6384 TRACE("component is disabled\n");
6385 return ERROR_SUCCESS;
6388 desc = MSI_RecordGetString(rec, 3);
6390 file_key = MSI_RecordGetString( rec, 4 );
6391 if (file_key) translator_file = get_loaded_file( package, file_key );
6393 file_key = MSI_RecordGetString( rec, 5 );
6394 if (file_key) setup_file = get_loaded_file( package, file_key );
6396 if (!translator_file)
6398 ERR("ODBC Translator entry not found!\n");
6399 return ERROR_FUNCTION_FAILED;
6402 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6404 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6406 translator = msi_alloc(len * sizeof(WCHAR));
6408 return ERROR_OUTOFMEMORY;
6411 lstrcpyW(ptr, desc);
6412 ptr += lstrlenW(ptr) + 1;
6414 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6419 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6424 translator_path = strdupW(translator_file->TargetPath);
6425 ptr = strrchrW(translator_path, '\\');
6426 if (ptr) *ptr = '\0';
6428 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6429 NULL, ODBC_INSTALL_COMPLETE, &usage))
6431 ERR("Failed to install SQL translator!\n");
6432 r = ERROR_FUNCTION_FAILED;
6435 uirow = MSI_CreateRecord( 5 );
6436 MSI_RecordSetStringW( uirow, 1, desc );
6437 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6438 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6439 ui_actiondata( package, szInstallODBC, uirow );
6440 msiobj_release( &uirow->hdr );
6442 msi_free(translator);
6443 msi_free(translator_path);
6448 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6450 MSIPACKAGE *package = param;
6453 LPCWSTR desc, driver, component;
6454 WORD request = ODBC_ADD_SYS_DSN;
6457 UINT r = ERROR_SUCCESS;
6460 static const WCHAR attrs_fmt[] = {
6461 'D','S','N','=','%','s',0 };
6463 component = MSI_RecordGetString( rec, 2 );
6464 comp = get_loaded_component( package, component );
6466 return ERROR_SUCCESS;
6470 TRACE("component is disabled\n");
6471 return ERROR_SUCCESS;
6474 desc = MSI_RecordGetString(rec, 3);
6475 driver = MSI_RecordGetString(rec, 4);
6476 registration = MSI_RecordGetInteger(rec, 5);
6478 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6479 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6481 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6482 attrs = msi_alloc(len * sizeof(WCHAR));
6484 return ERROR_OUTOFMEMORY;
6486 len = sprintfW(attrs, attrs_fmt, desc);
6489 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6491 ERR("Failed to install SQL data source!\n");
6492 r = ERROR_FUNCTION_FAILED;
6495 uirow = MSI_CreateRecord( 5 );
6496 MSI_RecordSetStringW( uirow, 1, desc );
6497 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6498 MSI_RecordSetInteger( uirow, 3, request );
6499 ui_actiondata( package, szInstallODBC, uirow );
6500 msiobj_release( &uirow->hdr );
6507 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6512 static const WCHAR driver_query[] = {
6513 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6514 'O','D','B','C','D','r','i','v','e','r',0 };
6516 static const WCHAR translator_query[] = {
6517 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6518 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6520 static const WCHAR source_query[] = {
6521 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6522 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6524 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6525 if (rc != ERROR_SUCCESS)
6526 return ERROR_SUCCESS;
6528 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6529 msiobj_release(&view->hdr);
6531 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6532 if (rc != ERROR_SUCCESS)
6533 return ERROR_SUCCESS;
6535 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6536 msiobj_release(&view->hdr);
6538 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6539 if (rc != ERROR_SUCCESS)
6540 return ERROR_SUCCESS;
6542 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6543 msiobj_release(&view->hdr);
6548 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6550 MSIPACKAGE *package = param;
6554 LPCWSTR desc, component;
6556 component = MSI_RecordGetString( rec, 2 );
6557 comp = get_loaded_component( package, component );
6559 return ERROR_SUCCESS;
6563 TRACE("component is disabled\n");
6564 return ERROR_SUCCESS;
6567 desc = MSI_RecordGetString( rec, 3 );
6568 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6570 WARN("Failed to remove ODBC driver\n");
6574 FIXME("Usage count reached 0\n");
6577 uirow = MSI_CreateRecord( 2 );
6578 MSI_RecordSetStringW( uirow, 1, desc );
6579 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6580 ui_actiondata( package, szRemoveODBC, uirow );
6581 msiobj_release( &uirow->hdr );
6583 return ERROR_SUCCESS;
6586 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6588 MSIPACKAGE *package = param;
6592 LPCWSTR desc, component;
6594 component = MSI_RecordGetString( rec, 2 );
6595 comp = get_loaded_component( package, component );
6597 return ERROR_SUCCESS;
6601 TRACE("component is disabled\n");
6602 return ERROR_SUCCESS;
6605 desc = MSI_RecordGetString( rec, 3 );
6606 if (!SQLRemoveTranslatorW( desc, &usage ))
6608 WARN("Failed to remove ODBC translator\n");
6612 FIXME("Usage count reached 0\n");
6615 uirow = MSI_CreateRecord( 2 );
6616 MSI_RecordSetStringW( uirow, 1, desc );
6617 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6618 ui_actiondata( package, szRemoveODBC, uirow );
6619 msiobj_release( &uirow->hdr );
6621 return ERROR_SUCCESS;
6624 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6626 MSIPACKAGE *package = param;
6630 LPCWSTR desc, driver, component;
6631 WORD request = ODBC_REMOVE_SYS_DSN;
6635 static const WCHAR attrs_fmt[] = {
6636 'D','S','N','=','%','s',0 };
6638 component = MSI_RecordGetString( rec, 2 );
6639 comp = get_loaded_component( package, component );
6641 return ERROR_SUCCESS;
6645 TRACE("component is disabled\n");
6646 return ERROR_SUCCESS;
6649 desc = MSI_RecordGetString( rec, 3 );
6650 driver = MSI_RecordGetString( rec, 4 );
6651 registration = MSI_RecordGetInteger( rec, 5 );
6653 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6654 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6656 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6657 attrs = msi_alloc( len * sizeof(WCHAR) );
6659 return ERROR_OUTOFMEMORY;
6661 FIXME("Use ODBCSourceAttribute table\n");
6663 len = sprintfW( attrs, attrs_fmt, desc );
6666 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6668 WARN("Failed to remove ODBC data source\n");
6672 uirow = MSI_CreateRecord( 3 );
6673 MSI_RecordSetStringW( uirow, 1, desc );
6674 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6675 MSI_RecordSetInteger( uirow, 3, request );
6676 ui_actiondata( package, szRemoveODBC, uirow );
6677 msiobj_release( &uirow->hdr );
6679 return ERROR_SUCCESS;
6682 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6687 static const WCHAR driver_query[] = {
6688 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6689 'O','D','B','C','D','r','i','v','e','r',0 };
6691 static const WCHAR translator_query[] = {
6692 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6693 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6695 static const WCHAR source_query[] = {
6696 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6697 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6699 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6700 if (rc != ERROR_SUCCESS)
6701 return ERROR_SUCCESS;
6703 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6704 msiobj_release( &view->hdr );
6706 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6707 if (rc != ERROR_SUCCESS)
6708 return ERROR_SUCCESS;
6710 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6711 msiobj_release( &view->hdr );
6713 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6714 if (rc != ERROR_SUCCESS)
6715 return ERROR_SUCCESS;
6717 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6718 msiobj_release( &view->hdr );
6723 #define ENV_ACT_SETALWAYS 0x1
6724 #define ENV_ACT_SETABSENT 0x2
6725 #define ENV_ACT_REMOVE 0x4
6726 #define ENV_ACT_REMOVEMATCH 0x8
6728 #define ENV_MOD_MACHINE 0x20000000
6729 #define ENV_MOD_APPEND 0x40000000
6730 #define ENV_MOD_PREFIX 0x80000000
6731 #define ENV_MOD_MASK 0xC0000000
6733 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6735 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6737 LPCWSTR cptr = *name;
6739 static const WCHAR prefix[] = {'[','~',']',0};
6740 static const int prefix_len = 3;
6746 *flags |= ENV_ACT_SETALWAYS;
6747 else if (*cptr == '+')
6748 *flags |= ENV_ACT_SETABSENT;
6749 else if (*cptr == '-')
6750 *flags |= ENV_ACT_REMOVE;
6751 else if (*cptr == '!')
6752 *flags |= ENV_ACT_REMOVEMATCH;
6753 else if (*cptr == '*')
6754 *flags |= ENV_MOD_MACHINE;
6764 ERR("Missing environment variable\n");
6765 return ERROR_FUNCTION_FAILED;
6770 LPCWSTR ptr = *value;
6771 if (!strncmpW(ptr, prefix, prefix_len))
6773 if (ptr[prefix_len] == szSemiColon[0])
6775 *flags |= ENV_MOD_APPEND;
6776 *value += lstrlenW(prefix);
6783 else if (lstrlenW(*value) >= prefix_len)
6785 ptr += lstrlenW(ptr) - prefix_len;
6786 if (!strcmpW( ptr, prefix ))
6788 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6790 *flags |= ENV_MOD_PREFIX;
6791 /* the "[~]" will be removed by deformat_string */;
6801 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6802 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6803 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6804 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6806 ERR("Invalid flags: %08x\n", *flags);
6807 return ERROR_FUNCTION_FAILED;
6811 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6813 return ERROR_SUCCESS;
6816 static UINT open_env_key( DWORD flags, HKEY *key )
6818 static const WCHAR user_env[] =
6819 {'E','n','v','i','r','o','n','m','e','n','t',0};
6820 static const WCHAR machine_env[] =
6821 {'S','y','s','t','e','m','\\',
6822 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6823 'C','o','n','t','r','o','l','\\',
6824 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6825 'E','n','v','i','r','o','n','m','e','n','t',0};
6830 if (flags & ENV_MOD_MACHINE)
6833 root = HKEY_LOCAL_MACHINE;
6838 root = HKEY_CURRENT_USER;
6841 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6842 if (res != ERROR_SUCCESS)
6844 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6845 return ERROR_FUNCTION_FAILED;
6848 return ERROR_SUCCESS;
6851 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6853 MSIPACKAGE *package = param;
6854 LPCWSTR name, value, component;
6855 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6856 DWORD flags, type, size;
6863 component = MSI_RecordGetString(rec, 4);
6864 comp = get_loaded_component(package, component);
6866 return ERROR_SUCCESS;
6870 TRACE("component is disabled\n");
6871 return ERROR_SUCCESS;
6874 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6876 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6877 comp->Action = comp->Installed;
6878 return ERROR_SUCCESS;
6880 comp->Action = INSTALLSTATE_LOCAL;
6882 name = MSI_RecordGetString(rec, 2);
6883 value = MSI_RecordGetString(rec, 3);
6885 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6887 res = env_parse_flags(&name, &value, &flags);
6888 if (res != ERROR_SUCCESS || !value)
6891 if (value && !deformat_string(package, value, &deformatted))
6893 res = ERROR_OUTOFMEMORY;
6897 value = deformatted;
6899 res = open_env_key( flags, &env );
6900 if (res != ERROR_SUCCESS)
6903 if (flags & ENV_MOD_MACHINE)
6904 action |= 0x20000000;
6908 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6909 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6910 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6913 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6917 /* Nothing to do. */
6920 res = ERROR_SUCCESS;
6924 /* If we are appending but the string was empty, strip ; */
6925 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6927 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6928 newval = strdupW(value);
6931 res = ERROR_OUTOFMEMORY;
6939 /* Contrary to MSDN, +-variable to [~];path works */
6940 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6942 res = ERROR_SUCCESS;
6946 data = msi_alloc(size);
6950 return ERROR_OUTOFMEMORY;
6953 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6954 if (res != ERROR_SUCCESS)
6957 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6960 res = RegDeleteValueW(env, name);
6961 if (res != ERROR_SUCCESS)
6962 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6966 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6967 if (flags & ENV_MOD_MASK)
6971 if (flags & ENV_MOD_APPEND) multiplier++;
6972 if (flags & ENV_MOD_PREFIX) multiplier++;
6973 mod_size = lstrlenW(value) * multiplier;
6974 size += mod_size * sizeof(WCHAR);
6977 newval = msi_alloc(size);
6981 res = ERROR_OUTOFMEMORY;
6985 if (flags & ENV_MOD_PREFIX)
6987 lstrcpyW(newval, value);
6988 ptr = newval + lstrlenW(value);
6989 action |= 0x80000000;
6992 lstrcpyW(ptr, data);
6994 if (flags & ENV_MOD_APPEND)
6996 lstrcatW(newval, value);
6997 action |= 0x40000000;
7000 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
7001 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
7004 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7008 uirow = MSI_CreateRecord( 3 );
7009 MSI_RecordSetStringW( uirow, 1, name );
7010 MSI_RecordSetStringW( uirow, 2, newval );
7011 MSI_RecordSetInteger( uirow, 3, action );
7012 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
7013 msiobj_release( &uirow->hdr );
7015 if (env) RegCloseKey(env);
7016 msi_free(deformatted);
7022 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7026 static const WCHAR ExecSeqQuery[] =
7027 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7028 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7029 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7030 if (rc != ERROR_SUCCESS)
7031 return ERROR_SUCCESS;
7033 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7034 msiobj_release(&view->hdr);
7039 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7041 MSIPACKAGE *package = param;
7042 LPCWSTR name, value, component;
7043 LPWSTR deformatted = NULL;
7052 component = MSI_RecordGetString( rec, 4 );
7053 comp = get_loaded_component( package, component );
7055 return ERROR_SUCCESS;
7059 TRACE("component is disabled\n");
7060 return ERROR_SUCCESS;
7063 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
7065 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
7066 comp->Action = comp->Installed;
7067 return ERROR_SUCCESS;
7069 comp->Action = INSTALLSTATE_ABSENT;
7071 name = MSI_RecordGetString( rec, 2 );
7072 value = MSI_RecordGetString( rec, 3 );
7074 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7076 r = env_parse_flags( &name, &value, &flags );
7077 if (r != ERROR_SUCCESS)
7080 if (!(flags & ENV_ACT_REMOVE))
7082 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7083 return ERROR_SUCCESS;
7086 if (value && !deformat_string( package, value, &deformatted ))
7087 return ERROR_OUTOFMEMORY;
7089 value = deformatted;
7091 r = open_env_key( flags, &env );
7092 if (r != ERROR_SUCCESS)
7098 if (flags & ENV_MOD_MACHINE)
7099 action |= 0x20000000;
7101 TRACE("Removing %s\n", debugstr_w(name));
7103 res = RegDeleteValueW( env, name );
7104 if (res != ERROR_SUCCESS)
7106 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
7111 uirow = MSI_CreateRecord( 3 );
7112 MSI_RecordSetStringW( uirow, 1, name );
7113 MSI_RecordSetStringW( uirow, 2, value );
7114 MSI_RecordSetInteger( uirow, 3, action );
7115 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
7116 msiobj_release( &uirow->hdr );
7118 if (env) RegCloseKey( env );
7119 msi_free( deformatted );
7123 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7127 static const WCHAR query[] =
7128 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7129 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7131 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
7132 if (rc != ERROR_SUCCESS)
7133 return ERROR_SUCCESS;
7135 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7136 msiobj_release( &view->hdr );
7141 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7143 LPWSTR key, template, id;
7144 UINT r = ERROR_SUCCESS;
7146 id = msi_dup_property( package->db, szProductID );
7150 return ERROR_SUCCESS;
7152 template = msi_dup_property( package->db, szPIDTemplate );
7153 key = msi_dup_property( package->db, szPIDKEY );
7155 if (key && template)
7157 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7158 r = msi_set_property( package->db, szProductID, key );
7160 msi_free( template );
7165 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7168 package->need_reboot = 1;
7169 return ERROR_SUCCESS;
7172 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7174 static const WCHAR szAvailableFreeReg[] =
7175 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7177 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7179 TRACE("%p %d kilobytes\n", package, space);
7181 uirow = MSI_CreateRecord( 1 );
7182 MSI_RecordSetInteger( uirow, 1, space );
7183 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7184 msiobj_release( &uirow->hdr );
7186 return ERROR_SUCCESS;
7189 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7191 FIXME("%p\n", package);
7192 return ERROR_SUCCESS;
7195 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7197 FIXME("%p\n", package);
7198 return ERROR_SUCCESS;
7201 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7206 static const WCHAR driver_query[] = {
7207 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7208 'O','D','B','C','D','r','i','v','e','r',0 };
7210 static const WCHAR translator_query[] = {
7211 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7212 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7214 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7215 if (r == ERROR_SUCCESS)
7218 r = MSI_IterateRecords( view, &count, NULL, package );
7219 msiobj_release( &view->hdr );
7220 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7223 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7224 if (r == ERROR_SUCCESS)
7227 r = MSI_IterateRecords( view, &count, NULL, package );
7228 msiobj_release( &view->hdr );
7229 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7232 return ERROR_SUCCESS;
7235 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7237 MSIPACKAGE *package = param;
7238 const WCHAR *property = MSI_RecordGetString( rec, 1 );
7241 if ((value = msi_dup_property( package->db, property )))
7243 FIXME("remove %s\n", debugstr_w(value));
7246 return ERROR_SUCCESS;
7249 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7254 static const WCHAR query[] =
7255 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7256 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7258 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7259 if (r == ERROR_SUCCESS)
7261 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7262 msiobj_release( &view->hdr );
7264 return ERROR_SUCCESS;
7267 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7269 MSIPACKAGE *package = param;
7270 int attributes = MSI_RecordGetInteger( rec, 5 );
7272 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7274 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7275 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7276 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7277 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7281 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7283 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7284 if (r != ERROR_SUCCESS)
7285 return ERROR_SUCCESS;
7289 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7290 if (r != ERROR_SUCCESS)
7291 return ERROR_SUCCESS;
7293 RegCloseKey( hkey );
7295 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7296 debugstr_w(upgrade_code), debugstr_w(version_min),
7297 debugstr_w(version_max), debugstr_w(language));
7299 return ERROR_SUCCESS;
7302 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7307 static const WCHAR query[] =
7308 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7310 if (msi_get_property_int( package->db, szInstalled, 0 ))
7312 TRACE("product is installed, skipping action\n");
7313 return ERROR_SUCCESS;
7315 if (msi_get_property_int( package->db, szPreselected, 0 ))
7317 TRACE("Preselected property is set, not migrating feature states\n");
7318 return ERROR_SUCCESS;
7321 r = MSI_DatabaseOpenViewW( package->db, query, &view );
7322 if (r == ERROR_SUCCESS)
7324 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7325 msiobj_release( &view->hdr );
7327 return ERROR_SUCCESS;
7330 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7331 LPCSTR action, LPCWSTR table )
7333 static const WCHAR query[] = {
7334 'S','E','L','E','C','T',' ','*',' ',
7335 'F','R','O','M',' ','`','%','s','`',0 };
7336 MSIQUERY *view = NULL;
7340 r = MSI_OpenQuery( package->db, &view, query, table );
7341 if (r == ERROR_SUCCESS)
7343 r = MSI_IterateRecords(view, &count, NULL, package);
7344 msiobj_release(&view->hdr);
7348 FIXME("%s -> %u ignored %s table values\n",
7349 action, count, debugstr_w(table));
7351 return ERROR_SUCCESS;
7354 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7356 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7357 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7360 static UINT ACTION_BindImage( MSIPACKAGE *package )
7362 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7363 return msi_unimplemented_action_stub( package, "BindImage", table );
7366 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7368 static const WCHAR table[] = {
7369 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7370 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7373 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7375 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7376 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7379 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7381 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7382 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7385 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7387 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7388 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7391 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7393 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7394 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7397 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7401 const WCHAR *action;
7402 UINT (*handler)(MSIPACKAGE *);
7406 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7407 { szAppSearch, ACTION_AppSearch },
7408 { szBindImage, ACTION_BindImage },
7409 { szCCPSearch, ACTION_CCPSearch },
7410 { szCostFinalize, ACTION_CostFinalize },
7411 { szCostInitialize, ACTION_CostInitialize },
7412 { szCreateFolders, ACTION_CreateFolders },
7413 { szCreateShortcuts, ACTION_CreateShortcuts },
7414 { szDeleteServices, ACTION_DeleteServices },
7415 { szDisableRollback, ACTION_DisableRollback },
7416 { szDuplicateFiles, ACTION_DuplicateFiles },
7417 { szExecuteAction, ACTION_ExecuteAction },
7418 { szFileCost, ACTION_FileCost },
7419 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7420 { szForceReboot, ACTION_ForceReboot },
7421 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7422 { szInstallExecute, ACTION_InstallExecute },
7423 { szInstallExecuteAgain, ACTION_InstallExecute },
7424 { szInstallFiles, ACTION_InstallFiles},
7425 { szInstallFinalize, ACTION_InstallFinalize },
7426 { szInstallInitialize, ACTION_InstallInitialize },
7427 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7428 { szInstallValidate, ACTION_InstallValidate },
7429 { szIsolateComponents, ACTION_IsolateComponents },
7430 { szLaunchConditions, ACTION_LaunchConditions },
7431 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7432 { szMoveFiles, ACTION_MoveFiles },
7433 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7434 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7435 { szInstallODBC, ACTION_InstallODBC },
7436 { szInstallServices, ACTION_InstallServices },
7437 { szPatchFiles, ACTION_PatchFiles },
7438 { szProcessComponents, ACTION_ProcessComponents },
7439 { szPublishComponents, ACTION_PublishComponents },
7440 { szPublishFeatures, ACTION_PublishFeatures },
7441 { szPublishProduct, ACTION_PublishProduct },
7442 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7443 { szRegisterComPlus, ACTION_RegisterComPlus},
7444 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7445 { szRegisterFonts, ACTION_RegisterFonts },
7446 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7447 { szRegisterProduct, ACTION_RegisterProduct },
7448 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7449 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7450 { szRegisterUser, ACTION_RegisterUser },
7451 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7452 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7453 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7454 { szRemoveFiles, ACTION_RemoveFiles },
7455 { szRemoveFolders, ACTION_RemoveFolders },
7456 { szRemoveIniValues, ACTION_RemoveIniValues },
7457 { szRemoveODBC, ACTION_RemoveODBC },
7458 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7459 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7460 { szResolveSource, ACTION_ResolveSource },
7461 { szRMCCPSearch, ACTION_RMCCPSearch },
7462 { szScheduleReboot, ACTION_ScheduleReboot },
7463 { szSelfRegModules, ACTION_SelfRegModules },
7464 { szSelfUnregModules, ACTION_SelfUnregModules },
7465 { szSetODBCFolders, ACTION_SetODBCFolders },
7466 { szStartServices, ACTION_StartServices },
7467 { szStopServices, ACTION_StopServices },
7468 { szUnpublishComponents, ACTION_UnpublishComponents },
7469 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7470 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7471 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7472 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7473 { szUnregisterFonts, ACTION_UnregisterFonts },
7474 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7475 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7476 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7477 { szValidateProductID, ACTION_ValidateProductID },
7478 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7479 { szWriteIniValues, ACTION_WriteIniValues },
7480 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7484 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7490 while (StandardActions[i].action != NULL)
7492 if (!strcmpW( StandardActions[i].action, action ))
7494 ui_actionstart( package, action );
7495 if (StandardActions[i].handler)
7497 ui_actioninfo( package, action, TRUE, 0 );
7498 *rc = StandardActions[i].handler( package );
7499 ui_actioninfo( package, action, FALSE, *rc );
7503 FIXME("unhandled standard action %s\n", debugstr_w(action));
7504 *rc = ERROR_SUCCESS;
7514 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7516 UINT rc = ERROR_SUCCESS;
7519 TRACE("Performing action (%s)\n", debugstr_w(action));
7521 handled = ACTION_HandleStandardAction(package, action, &rc);
7524 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7528 WARN("unhandled msi action %s\n", debugstr_w(action));
7529 rc = ERROR_FUNCTION_NOT_CALLED;
7535 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7537 UINT rc = ERROR_SUCCESS;
7538 BOOL handled = FALSE;
7540 TRACE("Performing action (%s)\n", debugstr_w(action));
7542 handled = ACTION_HandleStandardAction(package, action, &rc);
7545 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7547 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7552 WARN("unhandled msi action %s\n", debugstr_w(action));
7553 rc = ERROR_FUNCTION_NOT_CALLED;
7559 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7561 UINT rc = ERROR_SUCCESS;
7564 static const WCHAR ExecSeqQuery[] =
7565 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7566 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7567 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7568 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7569 static const WCHAR UISeqQuery[] =
7570 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7571 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7572 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7573 ' ', '=',' ','%','i',0};
7575 if (needs_ui_sequence(package))
7576 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7578 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7582 LPCWSTR action, cond;
7584 TRACE("Running the actions\n");
7586 /* check conditions */
7587 cond = MSI_RecordGetString(row, 2);
7589 /* this is a hack to skip errors in the condition code */
7590 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7592 msiobj_release(&row->hdr);
7593 return ERROR_SUCCESS;
7596 action = MSI_RecordGetString(row, 1);
7599 ERR("failed to fetch action\n");
7600 msiobj_release(&row->hdr);
7601 return ERROR_FUNCTION_FAILED;
7604 if (needs_ui_sequence(package))
7605 rc = ACTION_PerformUIAction(package, action, -1);
7607 rc = ACTION_PerformAction(package, action, -1);
7609 msiobj_release(&row->hdr);
7615 /****************************************************
7616 * TOP level entry points
7617 *****************************************************/
7619 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7620 LPCWSTR szCommandLine )
7625 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7626 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7628 msi_set_property( package->db, szAction, szInstall );
7630 package->script->InWhatSequence = SEQUENCE_INSTALL;
7637 dir = strdupW(szPackagePath);
7638 p = strrchrW(dir, '\\');
7642 file = szPackagePath + (p - dir);
7647 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7648 GetCurrentDirectoryW(MAX_PATH, dir);
7649 lstrcatW(dir, szBackSlash);
7650 file = szPackagePath;
7653 msi_free( package->PackagePath );
7654 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7655 if (!package->PackagePath)
7658 return ERROR_OUTOFMEMORY;
7661 lstrcpyW(package->PackagePath, dir);
7662 lstrcatW(package->PackagePath, file);
7665 msi_set_sourcedir_props(package, FALSE);
7668 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7669 if (rc != ERROR_SUCCESS)
7672 msi_apply_transforms( package );
7673 msi_apply_patches( package );
7675 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7677 TRACE("setting reinstall property\n");
7678 msi_set_property( package->db, szReinstall, szAll );
7681 /* properties may have been added by a transform */
7682 msi_clone_properties( package );
7684 msi_parse_command_line( package, szCommandLine, FALSE );
7685 msi_adjust_privilege_properties( package );
7686 msi_set_context( package );
7688 if (needs_ui_sequence( package))
7690 package->script->InWhatSequence |= SEQUENCE_UI;
7691 rc = ACTION_ProcessUISequence(package);
7692 ui_exists = ui_sequence_exists(package);
7693 if (rc == ERROR_SUCCESS || !ui_exists)
7695 package->script->InWhatSequence |= SEQUENCE_EXEC;
7696 rc = ACTION_ProcessExecSequence(package, ui_exists);
7700 rc = ACTION_ProcessExecSequence(package, FALSE);
7702 package->script->CurrentlyScripting = FALSE;
7704 /* process the ending type action */
7705 if (rc == ERROR_SUCCESS)
7706 ACTION_PerformActionSequence(package, -1);
7707 else if (rc == ERROR_INSTALL_USEREXIT)
7708 ACTION_PerformActionSequence(package, -2);
7709 else if (rc == ERROR_INSTALL_SUSPEND)
7710 ACTION_PerformActionSequence(package, -4);
7712 ACTION_PerformActionSequence(package, -3);
7714 /* finish up running custom actions */
7715 ACTION_FinishCustomActions(package);
7717 if (rc == ERROR_SUCCESS && package->need_reboot)
7718 return ERROR_SUCCESS_REBOOT_REQUIRED;