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"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAppSearch[] =
96 {'A','p','p','S','e','a','r','c','h',0};
97 static const WCHAR szAllocateRegistrySpace[] =
98 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
99 static const WCHAR szBindImage[] =
100 {'B','i','n','d','I','m','a','g','e',0};
101 static const WCHAR szCCPSearch[] =
102 {'C','C','P','S','e','a','r','c','h',0};
103 static const WCHAR szDeleteServices[] =
104 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
105 static const WCHAR szDisableRollback[] =
106 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
107 static const WCHAR szExecuteAction[] =
108 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
109 static const WCHAR szInstallAdminPackage[] =
110 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
111 static const WCHAR szInstallSFPCatalogFile[] =
112 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
113 static const WCHAR szIsolateComponents[] =
114 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
115 static const WCHAR szMigrateFeatureStates[] =
116 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
117 static const WCHAR szMoveFiles[] =
118 {'M','o','v','e','F','i','l','e','s',0};
119 static const WCHAR szMsiPublishAssemblies[] =
120 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
121 static const WCHAR szMsiUnpublishAssemblies[] =
122 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
123 static const WCHAR szInstallODBC[] =
124 {'I','n','s','t','a','l','l','O','D','B','C',0};
125 static const WCHAR szInstallServices[] =
126 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szPatchFiles[] =
128 {'P','a','t','c','h','F','i','l','e','s',0};
129 static const WCHAR szPublishComponents[] =
130 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
131 static const WCHAR szRegisterComPlus[] =
132 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
133 static const WCHAR szRegisterFonts[] =
134 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
135 static const WCHAR szRegisterUser[] =
136 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
137 static const WCHAR szRemoveDuplicateFiles[] =
138 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
139 static const WCHAR szRemoveEnvironmentStrings[] =
140 {'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};
141 static const WCHAR szRemoveExistingProducts[] =
142 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
143 static const WCHAR szRemoveFolders[] =
144 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
145 static const WCHAR szRemoveIniValues[] =
146 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
147 static const WCHAR szRemoveODBC[] =
148 {'R','e','m','o','v','e','O','D','B','C',0};
149 static const WCHAR szRemoveRegistryValues[] =
150 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
151 static const WCHAR szRemoveShortcuts[] =
152 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
153 static const WCHAR szRMCCPSearch[] =
154 {'R','M','C','C','P','S','e','a','r','c','h',0};
155 static const WCHAR szScheduleReboot[] =
156 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
157 static const WCHAR szSelfUnregModules[] =
158 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
159 static const WCHAR szSetODBCFolders[] =
160 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
161 static const WCHAR szStartServices[] =
162 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
163 static const WCHAR szStopServices[] =
164 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
165 static const WCHAR szUnpublishComponents[] =
166 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
167 static const WCHAR szUnpublishFeatures[] =
168 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
169 static const WCHAR szUnregisterClassInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
171 static const WCHAR szUnregisterComPlus[] =
172 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
173 static const WCHAR szUnregisterExtensionInfo[] =
174 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
175 static const WCHAR szUnregisterFonts[] =
176 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
177 static const WCHAR szUnregisterMIMEInfo[] =
178 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
179 static const WCHAR szUnregisterProgIdInfo[] =
180 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
181 static const WCHAR szUnregisterTypeLibraries[] =
182 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
183 static const WCHAR szValidateProductID[] =
184 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
185 static const WCHAR szWriteEnvironmentStrings[] =
186 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
188 /********************************************************
190 ********************************************************/
192 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
194 static const WCHAR Query_t[] =
195 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
196 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
197 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
198 ' ','\'','%','s','\'',0};
201 row = MSI_QueryGetRecord( package->db, Query_t, action );
204 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
205 msiobj_release(&row->hdr);
208 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
212 static const WCHAR template_s[]=
213 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
215 static const WCHAR template_e[]=
216 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
217 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
219 static const WCHAR format[] =
220 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
224 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
226 sprintfW(message,template_s,timet,action);
228 sprintfW(message,template_e,timet,action,rc);
230 row = MSI_CreateRecord(1);
231 MSI_RecordSetStringW(row,1,message);
233 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
234 msiobj_release(&row->hdr);
237 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
243 LPWSTR prop = NULL, val = NULL;
246 return ERROR_SUCCESS;
258 TRACE("Looking at %s\n",debugstr_w(ptr));
260 ptr2 = strchrW(ptr,'=');
263 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
270 prop = msi_alloc((len+1)*sizeof(WCHAR));
271 memcpy(prop,ptr,len*sizeof(WCHAR));
281 while (*ptr && (quote || (!quote && *ptr!=' ')))
294 val = msi_alloc((len+1)*sizeof(WCHAR));
295 memcpy(val,ptr2,len*sizeof(WCHAR));
298 if (lstrlenW(prop) > 0)
300 TRACE("Found commandline property (%s) = (%s)\n",
301 debugstr_w(prop), debugstr_w(val));
302 MSI_SetPropertyW(package,prop,val);
308 return ERROR_SUCCESS;
312 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
315 LPWSTR p, *ret = NULL;
321 /* count the number of substrings */
322 for ( pc = str, count = 0; pc; count++ )
324 pc = strchrW( pc, sep );
329 /* allocate space for an array of substring pointers and the substrings */
330 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
331 (lstrlenW(str)+1) * sizeof(WCHAR) );
335 /* copy the string and set the pointers */
336 p = (LPWSTR) &ret[count+1];
338 for( count = 0; (ret[count] = p); count++ )
340 p = strchrW( p, sep );
348 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
350 static const WCHAR szSystemLanguageID[] =
351 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
353 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
354 UINT ret = ERROR_FUNCTION_FAILED;
356 prod_code = msi_dup_property( package, szProductCode );
357 patch_product = msi_get_suminfo_product( patch );
359 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
361 if ( strstrW( patch_product, prod_code ) )
366 si = MSI_GetSummaryInformationW( patch, 0 );
369 ERR("no summary information!\n");
373 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
376 ERR("no template property!\n");
377 msiobj_release( &si->hdr );
384 msiobj_release( &si->hdr );
388 langid = msi_dup_property( package, szSystemLanguageID );
391 msiobj_release( &si->hdr );
395 p = strchrW( template, ';' );
396 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
398 TRACE("applicable transform\n");
402 /* FIXME: check platform */
404 msiobj_release( &si->hdr );
408 msi_free( patch_product );
409 msi_free( prod_code );
410 msi_free( template );
416 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
417 MSIDATABASE *patch_db, LPCWSTR name )
419 UINT ret = ERROR_FUNCTION_FAILED;
420 IStorage *stg = NULL;
423 TRACE("%p %s\n", package, debugstr_w(name) );
427 ERR("expected a colon in %s\n", debugstr_w(name));
428 return ERROR_FUNCTION_FAILED;
431 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
434 ret = msi_check_transform_applicable( package, stg );
435 if (ret == ERROR_SUCCESS)
436 msi_table_apply_transform( package->db, stg );
438 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
439 IStorage_Release( stg );
442 ERR("failed to open substorage %s\n", debugstr_w(name));
444 return ERROR_SUCCESS;
447 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
449 LPWSTR guid_list, *guids, product_code;
450 UINT i, ret = ERROR_FUNCTION_FAILED;
452 product_code = msi_dup_property( package, szProductCode );
455 /* FIXME: the property ProductCode should be written into the DB somewhere */
456 ERR("no product code to check\n");
457 return ERROR_SUCCESS;
460 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
461 guids = msi_split_string( guid_list, ';' );
462 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
464 if (!lstrcmpW( guids[i], product_code ))
468 msi_free( guid_list );
469 msi_free( product_code );
474 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
477 MSIRECORD *rec = NULL;
482 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
483 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
484 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
485 '`','S','o','u','r','c','e','`',' ','I','S',' ',
486 'N','O','T',' ','N','U','L','L',0};
488 r = MSI_DatabaseOpenViewW(package->db, query, &view);
489 if (r != ERROR_SUCCESS)
492 r = MSI_ViewExecute(view, 0);
493 if (r != ERROR_SUCCESS)
496 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
498 prop = MSI_RecordGetString(rec, 1);
499 patch = msi_dup_property(package, szPatch);
500 MSI_SetPropertyW(package, prop, patch);
505 if (rec) msiobj_release(&rec->hdr);
506 msiobj_release(&view->hdr);
511 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
514 LPWSTR str, *substorage;
515 UINT i, r = ERROR_SUCCESS;
517 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
519 return ERROR_FUNCTION_FAILED;
521 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
523 TRACE("Patch not applicable\n");
524 return ERROR_SUCCESS;
527 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
529 return ERROR_OUTOFMEMORY;
531 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
532 if (!package->patch->patchcode)
533 return ERROR_OUTOFMEMORY;
535 /* enumerate the substorage */
536 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
537 package->patch->transforms = str;
539 substorage = msi_split_string( str, ';' );
540 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
541 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
543 msi_free( substorage );
544 msiobj_release( &si->hdr );
546 msi_set_media_source_prop(package);
551 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
553 MSIDATABASE *patch_db = NULL;
556 TRACE("%p %s\n", package, debugstr_w( file ) );
559 * We probably want to make sure we only open a patch collection here.
560 * Patch collections (.msp) and databases (.msi) have different GUIDs
561 * but currently MSI_OpenDatabaseW will accept both.
563 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
564 if ( r != ERROR_SUCCESS )
566 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
570 msi_parse_patch_summary( package, patch_db );
573 * There might be a CAB file in the patch package,
574 * so append it to the list of storage to search for streams.
576 append_storage_to_db( package->db, patch_db->storage );
578 msiobj_release( &patch_db->hdr );
580 return ERROR_SUCCESS;
583 /* get the PATCH property, and apply all the patches it specifies */
584 static UINT msi_apply_patches( MSIPACKAGE *package )
586 LPWSTR patch_list, *patches;
587 UINT i, r = ERROR_SUCCESS;
589 patch_list = msi_dup_property( package, szPatch );
591 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
593 patches = msi_split_string( patch_list, ';' );
594 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
595 r = msi_apply_patch_package( package, patches[i] );
598 msi_free( patch_list );
603 static UINT msi_apply_transforms( MSIPACKAGE *package )
605 static const WCHAR szTransforms[] = {
606 'T','R','A','N','S','F','O','R','M','S',0 };
607 LPWSTR xform_list, *xforms;
608 UINT i, r = ERROR_SUCCESS;
610 xform_list = msi_dup_property( package, szTransforms );
611 xforms = msi_split_string( xform_list, ';' );
613 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
615 if (xforms[i][0] == ':')
616 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
618 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
622 msi_free( xform_list );
627 static BOOL ui_sequence_exists( MSIPACKAGE *package )
632 static const WCHAR ExecSeqQuery [] =
633 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
634 '`','I','n','s','t','a','l','l',
635 'U','I','S','e','q','u','e','n','c','e','`',
636 ' ','W','H','E','R','E',' ',
637 '`','S','e','q','u','e','n','c','e','`',' ',
638 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
639 '`','S','e','q','u','e','n','c','e','`',0};
641 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
642 if (rc == ERROR_SUCCESS)
644 msiobj_release(&view->hdr);
651 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
654 LPWSTR source, check;
657 static const WCHAR szOriginalDatabase[] =
658 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
660 db = msi_dup_property( package, szOriginalDatabase );
662 return ERROR_OUTOFMEMORY;
664 p = strrchrW( db, '\\' );
667 p = strrchrW( db, '/' );
671 return ERROR_SUCCESS;
676 source = msi_alloc( len * sizeof(WCHAR) );
677 lstrcpynW( source, db, len );
679 check = msi_dup_property( package, cszSourceDir );
680 if (!check || replace)
681 MSI_SetPropertyW( package, cszSourceDir, source );
685 check = msi_dup_property( package, cszSOURCEDIR );
686 if (!check || replace)
687 MSI_SetPropertyW( package, cszSOURCEDIR, source );
693 return ERROR_SUCCESS;
696 static BOOL needs_ui_sequence(MSIPACKAGE *package)
698 INT level = msi_get_property_int(package, szUILevel, 0);
699 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
702 static UINT msi_set_context(MSIPACKAGE *package)
709 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
711 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
712 if (r == ERROR_SUCCESS)
715 if (num == 1 || num == 2)
716 package->Context = MSIINSTALLCONTEXT_MACHINE;
719 return ERROR_SUCCESS;
722 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
725 LPCWSTR cond, action;
726 MSIPACKAGE *package = param;
728 action = MSI_RecordGetString(row,1);
731 ERR("Error is retrieving action name\n");
732 return ERROR_FUNCTION_FAILED;
735 /* check conditions */
736 cond = MSI_RecordGetString(row,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
741 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
742 return ERROR_SUCCESS;
745 if (needs_ui_sequence(package))
746 rc = ACTION_PerformUIAction(package, action, -1);
748 rc = ACTION_PerformAction(package, action, -1, FALSE);
750 msi_dialog_check_messages( NULL );
752 if (package->CurrentInstallState != ERROR_SUCCESS)
753 rc = package->CurrentInstallState;
755 if (rc == ERROR_FUNCTION_NOT_CALLED)
758 if (rc != ERROR_SUCCESS)
759 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
764 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
768 static const WCHAR query[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
771 ' ','W','H','E','R','E',' ',
772 '`','S','e','q','u','e','n','c','e','`',' ',
773 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
774 '`','S','e','q','u','e','n','c','e','`',0};
776 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
778 r = MSI_OpenQuery( package->db, &view, query, szTable );
779 if (r == ERROR_SUCCESS)
781 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
782 msiobj_release(&view->hdr);
788 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
792 static const WCHAR ExecSeqQuery[] =
793 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
794 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
795 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
796 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
797 'O','R','D','E','R',' ', 'B','Y',' ',
798 '`','S','e','q','u','e','n','c','e','`',0 };
799 static const WCHAR IVQuery[] =
800 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
801 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
802 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
803 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
804 ' ','\'', 'I','n','s','t','a','l','l',
805 'V','a','l','i','d','a','t','e','\'', 0};
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
819 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
832 msiobj_release(&view->hdr);
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
851 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
852 if (rc == ERROR_SUCCESS)
854 TRACE("Running the actions\n");
856 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
857 msiobj_release(&view->hdr);
863 /********************************************************
864 * ACTION helper functions and functions that perform the actions
865 *******************************************************/
866 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
867 UINT* rc, UINT script, BOOL force )
872 arc = ACTION_CustomAction(package, action, script, force);
874 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
883 * Actual Action Handlers
886 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
888 MSIPACKAGE *package = param;
894 dir = MSI_RecordGetString(row,1);
897 ERR("Unable to get folder id\n");
898 return ERROR_SUCCESS;
901 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
904 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
905 return ERROR_SUCCESS;
908 TRACE("Folder is %s\n",debugstr_w(full_path));
911 uirow = MSI_CreateRecord(1);
912 MSI_RecordSetStringW(uirow,1,full_path);
913 ui_actiondata(package,szCreateFolders,uirow);
914 msiobj_release( &uirow->hdr );
916 if (folder->State == 0)
917 create_full_pathW(full_path);
922 return ERROR_SUCCESS;
925 /* FIXME: probably should merge this with the above function */
926 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
928 UINT rc = ERROR_SUCCESS;
932 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
934 return ERROR_FUNCTION_FAILED;
936 /* create the path */
937 if (folder->State == 0)
939 create_full_pathW(install_path);
942 msi_free(install_path);
947 UINT msi_create_component_directories( MSIPACKAGE *package )
951 /* create all the folders required by the components are going to install */
952 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
954 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
956 msi_create_directory( package, comp->Directory );
959 return ERROR_SUCCESS;
963 * Also we cannot enable/disable components either, so for now I am just going
964 * to do all the directories for all the components.
966 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
968 static const WCHAR ExecSeqQuery[] =
969 {'S','E','L','E','C','T',' ',
970 '`','D','i','r','e','c','t','o','r','y','_','`',
971 ' ','F','R','O','M',' ',
972 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
976 /* create all the empty folders specified in the CreateFolder table */
977 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
978 if (rc != ERROR_SUCCESS)
979 return ERROR_SUCCESS;
981 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
982 msiobj_release(&view->hdr);
984 msi_create_component_directories( package );
989 static UINT load_component( MSIRECORD *row, LPVOID param )
991 MSIPACKAGE *package = param;
994 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
996 return ERROR_FUNCTION_FAILED;
998 list_add_tail( &package->components, &comp->entry );
1000 /* fill in the data */
1001 comp->Component = msi_dup_record_field( row, 1 );
1003 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1005 comp->ComponentId = msi_dup_record_field( row, 2 );
1006 comp->Directory = msi_dup_record_field( row, 3 );
1007 comp->Attributes = MSI_RecordGetInteger(row,4);
1008 comp->Condition = msi_dup_record_field( row, 5 );
1009 comp->KeyPath = msi_dup_record_field( row, 6 );
1011 comp->Installed = INSTALLSTATE_UNKNOWN;
1012 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1014 return ERROR_SUCCESS;
1017 static UINT load_all_components( MSIPACKAGE *package )
1019 static const WCHAR query[] = {
1020 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1021 '`','C','o','m','p','o','n','e','n','t','`',0 };
1025 if (!list_empty(&package->components))
1026 return ERROR_SUCCESS;
1028 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1029 if (r != ERROR_SUCCESS)
1032 r = MSI_IterateRecords(view, NULL, load_component, package);
1033 msiobj_release(&view->hdr);
1038 MSIPACKAGE *package;
1039 MSIFEATURE *feature;
1042 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1046 cl = msi_alloc( sizeof (*cl) );
1048 return ERROR_NOT_ENOUGH_MEMORY;
1049 cl->component = comp;
1050 list_add_tail( &feature->Components, &cl->entry );
1052 return ERROR_SUCCESS;
1055 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1059 fl = msi_alloc( sizeof(*fl) );
1061 return ERROR_NOT_ENOUGH_MEMORY;
1062 fl->feature = child;
1063 list_add_tail( &parent->Children, &fl->entry );
1065 return ERROR_SUCCESS;
1068 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1070 _ilfs* ilfs = param;
1074 component = MSI_RecordGetString(row,1);
1076 /* check to see if the component is already loaded */
1077 comp = get_loaded_component( ilfs->package, component );
1080 ERR("unknown component %s\n", debugstr_w(component));
1081 return ERROR_FUNCTION_FAILED;
1084 add_feature_component( ilfs->feature, comp );
1085 comp->Enabled = TRUE;
1087 return ERROR_SUCCESS;
1090 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1092 MSIFEATURE *feature;
1097 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1099 if ( !lstrcmpW( feature->Feature, name ) )
1106 static UINT load_feature(MSIRECORD * row, LPVOID param)
1108 MSIPACKAGE* package = param;
1109 MSIFEATURE* feature;
1110 static const WCHAR Query1[] =
1111 {'S','E','L','E','C','T',' ',
1112 '`','C','o','m','p','o','n','e','n','t','_','`',
1113 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1114 'C','o','m','p','o','n','e','n','t','s','`',' ',
1115 'W','H','E','R','E',' ',
1116 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1121 /* fill in the data */
1123 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1125 return ERROR_NOT_ENOUGH_MEMORY;
1127 list_init( &feature->Children );
1128 list_init( &feature->Components );
1130 feature->Feature = msi_dup_record_field( row, 1 );
1132 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1134 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1135 feature->Title = msi_dup_record_field( row, 3 );
1136 feature->Description = msi_dup_record_field( row, 4 );
1138 if (!MSI_RecordIsNull(row,5))
1139 feature->Display = MSI_RecordGetInteger(row,5);
1141 feature->Level= MSI_RecordGetInteger(row,6);
1142 feature->Directory = msi_dup_record_field( row, 7 );
1143 feature->Attributes = MSI_RecordGetInteger(row,8);
1145 feature->Installed = INSTALLSTATE_UNKNOWN;
1146 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1148 list_add_tail( &package->features, &feature->entry );
1150 /* load feature components */
1152 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1153 if (rc != ERROR_SUCCESS)
1154 return ERROR_SUCCESS;
1156 ilfs.package = package;
1157 ilfs.feature = feature;
1159 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1160 msiobj_release(&view->hdr);
1162 return ERROR_SUCCESS;
1165 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1167 MSIPACKAGE* package = param;
1168 MSIFEATURE *parent, *child;
1170 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1172 return ERROR_FUNCTION_FAILED;
1174 if (!child->Feature_Parent)
1175 return ERROR_SUCCESS;
1177 parent = find_feature_by_name( package, child->Feature_Parent );
1179 return ERROR_FUNCTION_FAILED;
1181 add_feature_child( parent, child );
1182 return ERROR_SUCCESS;
1185 static UINT load_all_features( MSIPACKAGE *package )
1187 static const WCHAR query[] = {
1188 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1189 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1190 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1194 if (!list_empty(&package->features))
1195 return ERROR_SUCCESS;
1197 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1198 if (r != ERROR_SUCCESS)
1201 r = MSI_IterateRecords( view, NULL, load_feature, package );
1202 if (r != ERROR_SUCCESS)
1205 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1206 msiobj_release( &view->hdr );
1211 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1222 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1224 static const WCHAR query[] = {
1225 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1226 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1227 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1228 MSIQUERY *view = NULL;
1229 MSIRECORD *row = NULL;
1232 TRACE("%s\n", debugstr_w(file->File));
1234 r = MSI_OpenQuery(package->db, &view, query, file->File);
1235 if (r != ERROR_SUCCESS)
1238 r = MSI_ViewExecute(view, NULL);
1239 if (r != ERROR_SUCCESS)
1242 r = MSI_ViewFetch(view, &row);
1243 if (r != ERROR_SUCCESS)
1246 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1247 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1248 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1249 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1250 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1253 if (view) msiobj_release(&view->hdr);
1254 if (row) msiobj_release(&row->hdr);
1258 static UINT load_file(MSIRECORD *row, LPVOID param)
1260 MSIPACKAGE* package = param;
1264 /* fill in the data */
1266 file = msi_alloc_zero( sizeof (MSIFILE) );
1268 return ERROR_NOT_ENOUGH_MEMORY;
1270 file->File = msi_dup_record_field( row, 1 );
1272 component = MSI_RecordGetString( row, 2 );
1273 file->Component = get_loaded_component( package, component );
1275 if (!file->Component)
1277 WARN("Component not found: %s\n", debugstr_w(component));
1278 msi_free(file->File);
1280 return ERROR_SUCCESS;
1283 file->FileName = msi_dup_record_field( row, 3 );
1284 reduce_to_longfilename( file->FileName );
1286 file->ShortName = msi_dup_record_field( row, 3 );
1287 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1289 file->FileSize = MSI_RecordGetInteger( row, 4 );
1290 file->Version = msi_dup_record_field( row, 5 );
1291 file->Language = msi_dup_record_field( row, 6 );
1292 file->Attributes = MSI_RecordGetInteger( row, 7 );
1293 file->Sequence = MSI_RecordGetInteger( row, 8 );
1295 file->state = msifs_invalid;
1297 /* if the compressed bits are not set in the file attributes,
1298 * then read the information from the package word count property
1300 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1302 file->IsCompressed = FALSE;
1304 else if (file->Attributes &
1305 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1307 file->IsCompressed = TRUE;
1309 else if (file->Attributes & msidbFileAttributesNoncompressed)
1311 file->IsCompressed = FALSE;
1315 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1318 load_file_hash(package, file);
1320 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1322 list_add_tail( &package->files, &file->entry );
1324 return ERROR_SUCCESS;
1327 static UINT load_all_files(MSIPACKAGE *package)
1331 static const WCHAR Query[] =
1332 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`', 0};
1336 if (!list_empty(&package->files))
1337 return ERROR_SUCCESS;
1339 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1340 if (rc != ERROR_SUCCESS)
1341 return ERROR_SUCCESS;
1343 rc = MSI_IterateRecords(view, NULL, load_file, package);
1344 msiobj_release(&view->hdr);
1346 return ERROR_SUCCESS;
1349 static UINT load_folder( MSIRECORD *row, LPVOID param )
1351 MSIPACKAGE *package = param;
1352 static WCHAR szEmpty[] = { 0 };
1353 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1356 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1358 return ERROR_NOT_ENOUGH_MEMORY;
1360 folder->Directory = msi_dup_record_field( row, 1 );
1362 TRACE("%s\n", debugstr_w(folder->Directory));
1364 p = msi_dup_record_field(row, 3);
1366 /* split src and target dir */
1368 src_short = folder_split_path( p, ':' );
1370 /* split the long and short paths */
1371 tgt_long = folder_split_path( tgt_short, '|' );
1372 src_long = folder_split_path( src_short, '|' );
1374 /* check for no-op dirs */
1375 if (!lstrcmpW(szDot, tgt_short))
1376 tgt_short = szEmpty;
1377 if (!lstrcmpW(szDot, src_short))
1378 src_short = szEmpty;
1381 tgt_long = tgt_short;
1384 src_short = tgt_short;
1385 src_long = tgt_long;
1389 src_long = src_short;
1391 /* FIXME: use the target short path too */
1392 folder->TargetDefault = strdupW(tgt_long);
1393 folder->SourceShortPath = strdupW(src_short);
1394 folder->SourceLongPath = strdupW(src_long);
1397 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1398 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1399 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1401 folder->Parent = msi_dup_record_field( row, 2 );
1403 folder->Property = msi_dup_property( package, folder->Directory );
1405 list_add_tail( &package->folders, &folder->entry );
1407 TRACE("returning %p\n", folder);
1409 return ERROR_SUCCESS;
1412 static UINT load_all_folders( MSIPACKAGE *package )
1414 static const WCHAR query[] = {
1415 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1416 '`','D','i','r','e','c','t','o','r','y','`',0 };
1420 if (!list_empty(&package->folders))
1421 return ERROR_SUCCESS;
1423 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1424 if (r != ERROR_SUCCESS)
1427 r = MSI_IterateRecords(view, NULL, load_folder, package);
1428 msiobj_release(&view->hdr);
1433 * I am not doing any of the costing functionality yet.
1434 * Mostly looking at doing the Component and Feature loading
1436 * The native MSI does A LOT of modification to tables here. Mostly adding
1437 * a lot of temporary columns to the Feature and Component tables.
1439 * note: Native msi also tracks the short filename. But I am only going to
1440 * track the long ones. Also looking at this directory table
1441 * it appears that the directory table does not get the parents
1442 * resolved base on property only based on their entries in the
1445 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1447 static const WCHAR szCosting[] =
1448 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1450 MSI_SetPropertyW(package, szCosting, szZero);
1451 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1453 load_all_folders( package );
1454 load_all_components( package );
1455 load_all_features( package );
1456 load_all_files( package );
1458 return ERROR_SUCCESS;
1461 static UINT execute_script(MSIPACKAGE *package, UINT script )
1464 UINT rc = ERROR_SUCCESS;
1466 TRACE("Executing Script %i\n",script);
1468 if (!package->script)
1470 ERR("no script!\n");
1471 return ERROR_FUNCTION_FAILED;
1474 for (i = 0; i < package->script->ActionCount[script]; i++)
1477 action = package->script->Actions[script][i];
1478 ui_actionstart(package, action);
1479 TRACE("Executing Action (%s)\n",debugstr_w(action));
1480 rc = ACTION_PerformAction(package, action, script, TRUE);
1481 if (rc != ERROR_SUCCESS)
1484 msi_free_action_script(package, script);
1488 static UINT ACTION_FileCost(MSIPACKAGE *package)
1490 return ERROR_SUCCESS;
1493 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1499 state = MsiQueryProductStateW(package->ProductCode);
1501 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1503 if (!comp->ComponentId)
1506 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1507 comp->Installed = INSTALLSTATE_ABSENT;
1510 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1511 package->Context, comp->ComponentId,
1513 if (r != ERROR_SUCCESS)
1514 comp->Installed = INSTALLSTATE_ABSENT;
1519 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1521 MSIFEATURE *feature;
1524 state = MsiQueryProductStateW(package->ProductCode);
1526 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1528 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1529 feature->Installed = INSTALLSTATE_ABSENT;
1532 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1538 static BOOL process_state_property(MSIPACKAGE* package, int level,
1539 LPCWSTR property, INSTALLSTATE state)
1542 MSIFEATURE *feature;
1544 override = msi_dup_property( package, property );
1548 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1550 if (lstrcmpW(property, szRemove) &&
1551 (feature->Level <= 0 || feature->Level > level))
1554 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1556 if (strcmpiW(override, szAll)==0)
1557 msi_feature_set_state(package, feature, state);
1560 LPWSTR ptr = override;
1561 LPWSTR ptr2 = strchrW(override,',');
1565 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1566 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1568 msi_feature_set_state(package, feature, state);
1574 ptr2 = strchrW(ptr,',');
1586 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1589 static const WCHAR szlevel[] =
1590 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1591 static const WCHAR szAddLocal[] =
1592 {'A','D','D','L','O','C','A','L',0};
1593 static const WCHAR szAddSource[] =
1594 {'A','D','D','S','O','U','R','C','E',0};
1595 static const WCHAR szAdvertise[] =
1596 {'A','D','V','E','R','T','I','S','E',0};
1597 BOOL override = FALSE;
1598 MSICOMPONENT* component;
1599 MSIFEATURE *feature;
1602 /* I do not know if this is where it should happen.. but */
1604 TRACE("Checking Install Level\n");
1606 level = msi_get_property_int(package, szlevel, 1);
1608 /* ok here is the _real_ rub
1609 * all these activation/deactivation things happen in order and things
1610 * later on the list override things earlier on the list.
1611 * 0) INSTALLLEVEL processing
1622 * 11) FILEADDDEFAULT
1624 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1625 * REMOVE are the big ones, since we don't handle administrative installs
1628 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1629 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1630 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1631 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1632 override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
1636 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1638 BOOL feature_state = ((feature->Level > 0) &&
1639 (feature->Level <= level));
1641 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1643 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1644 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1645 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1646 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1648 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1652 /* disable child features of unselected parent features */
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1657 if (feature->Level > 0 && feature->Level <= level)
1660 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1661 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1665 MSI_SetPropertyW(package, szPreselected, szOne);
1668 * now we want to enable or disable components base on feature
1671 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1675 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1676 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1678 if (!feature->Level)
1681 /* features with components that have compressed files are made local */
1682 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1684 if (cl->component->Enabled &&
1685 cl->component->ForceLocalState &&
1686 feature->Action == INSTALLSTATE_SOURCE)
1688 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1693 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1695 component = cl->component;
1697 if (!component->Enabled)
1700 switch (feature->Action)
1702 case INSTALLSTATE_ABSENT:
1703 component->anyAbsent = 1;
1705 case INSTALLSTATE_ADVERTISED:
1706 component->hasAdvertiseFeature = 1;
1708 case INSTALLSTATE_SOURCE:
1709 component->hasSourceFeature = 1;
1711 case INSTALLSTATE_LOCAL:
1712 component->hasLocalFeature = 1;
1714 case INSTALLSTATE_DEFAULT:
1715 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1716 component->hasAdvertiseFeature = 1;
1717 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1718 component->hasSourceFeature = 1;
1720 component->hasLocalFeature = 1;
1728 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1730 /* if the component isn't enabled, leave it alone */
1731 if (!component->Enabled)
1734 /* check if it's local or source */
1735 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1736 (component->hasLocalFeature || component->hasSourceFeature))
1738 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1739 !component->ForceLocalState)
1740 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1742 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1746 /* if any feature is local, the component must be local too */
1747 if (component->hasLocalFeature)
1749 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1753 if (component->hasSourceFeature)
1755 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1759 if (component->hasAdvertiseFeature)
1761 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1765 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1766 if (component->anyAbsent)
1767 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1770 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1772 if (component->Action == INSTALLSTATE_DEFAULT)
1774 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1775 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1778 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1779 debugstr_w(component->Component), component->Installed, component->Action);
1783 return ERROR_SUCCESS;
1786 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1788 MSIPACKAGE *package = param;
1793 name = MSI_RecordGetString(row,1);
1795 f = get_loaded_folder(package, name);
1796 if (!f) return ERROR_SUCCESS;
1798 /* reset the ResolvedTarget */
1799 msi_free(f->ResolvedTarget);
1800 f->ResolvedTarget = NULL;
1802 /* This helper function now does ALL the work */
1803 TRACE("Dir %s ...\n",debugstr_w(name));
1804 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1805 TRACE("resolves to %s\n",debugstr_w(path));
1808 return ERROR_SUCCESS;
1811 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1813 MSIPACKAGE *package = param;
1815 MSIFEATURE *feature;
1817 name = MSI_RecordGetString( row, 1 );
1819 feature = get_loaded_feature( package, name );
1821 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1825 Condition = MSI_RecordGetString(row,3);
1827 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1829 int level = MSI_RecordGetInteger(row,2);
1830 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1831 feature->Level = level;
1834 return ERROR_SUCCESS;
1837 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1839 static const WCHAR name_fmt[] =
1840 {'%','u','.','%','u','.','%','u','.','%','u',0};
1841 static const WCHAR name[] = {'\\',0};
1842 VS_FIXEDFILEINFO *lpVer;
1843 WCHAR filever[0x100];
1849 TRACE("%s\n", debugstr_w(filename));
1851 versize = GetFileVersionInfoSizeW( filename, &handle );
1855 version = msi_alloc( versize );
1856 GetFileVersionInfoW( filename, 0, versize, version );
1858 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1860 msi_free( version );
1864 sprintfW( filever, name_fmt,
1865 HIWORD(lpVer->dwFileVersionMS),
1866 LOWORD(lpVer->dwFileVersionMS),
1867 HIWORD(lpVer->dwFileVersionLS),
1868 LOWORD(lpVer->dwFileVersionLS));
1870 msi_free( version );
1872 return strdupW( filever );
1875 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1877 LPWSTR file_version;
1880 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1882 MSICOMPONENT* comp = file->Component;
1888 if (file->IsCompressed)
1889 comp->ForceLocalState = TRUE;
1891 /* calculate target */
1892 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1894 msi_free(file->TargetPath);
1896 TRACE("file %s is named %s\n",
1897 debugstr_w(file->File), debugstr_w(file->FileName));
1899 file->TargetPath = build_directory_name(2, p, file->FileName);
1903 TRACE("file %s resolves to %s\n",
1904 debugstr_w(file->File), debugstr_w(file->TargetPath));
1906 /* don't check files of components that aren't installed */
1907 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1908 comp->Installed == INSTALLSTATE_ABSENT)
1910 file->state = msifs_missing; /* assume files are missing */
1914 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1916 file->state = msifs_missing;
1917 comp->Cost += file->FileSize;
1921 if (file->Version &&
1922 (file_version = msi_get_disk_file_version( file->TargetPath )))
1924 TRACE("new %s old %s\n", debugstr_w(file->Version),
1925 debugstr_w(file_version));
1926 /* FIXME: seems like a bad way to compare version numbers */
1927 if (lstrcmpiW(file_version, file->Version)<0)
1929 file->state = msifs_overwrite;
1930 comp->Cost += file->FileSize;
1933 file->state = msifs_present;
1934 msi_free( file_version );
1937 file->state = msifs_present;
1940 return ERROR_SUCCESS;
1944 * A lot is done in this function aside from just the costing.
1945 * The costing needs to be implemented at some point but for now I am going
1946 * to focus on the directory building
1949 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1951 static const WCHAR ExecSeqQuery[] =
1952 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1953 '`','D','i','r','e','c','t','o','r','y','`',0};
1954 static const WCHAR ConditionQuery[] =
1955 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1956 '`','C','o','n','d','i','t','i','o','n','`',0};
1957 static const WCHAR szCosting[] =
1958 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1959 static const WCHAR szlevel[] =
1960 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1961 static const WCHAR szOutOfDiskSpace[] =
1962 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1968 TRACE("Building Directory properties\n");
1970 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1971 if (rc == ERROR_SUCCESS)
1973 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1975 msiobj_release(&view->hdr);
1978 /* read components states from the registry */
1979 ACTION_GetComponentInstallStates(package);
1980 ACTION_GetFeatureInstallStates(package);
1982 TRACE("File calculations\n");
1983 msi_check_file_install_states( package );
1985 TRACE("Evaluating Condition Table\n");
1987 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1988 if (rc == ERROR_SUCCESS)
1990 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1992 msiobj_release(&view->hdr);
1995 TRACE("Enabling or Disabling Components\n");
1996 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1998 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2000 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2001 comp->Enabled = FALSE;
2004 comp->Enabled = TRUE;
2007 MSI_SetPropertyW(package,szCosting,szOne);
2008 /* set default run level if not set */
2009 level = msi_dup_property( package, szlevel );
2011 MSI_SetPropertyW(package,szlevel, szOne);
2014 /* FIXME: check volume disk space */
2015 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2017 return MSI_SetFeatureStates(package);
2020 /* OK this value is "interpreted" and then formatted based on the
2021 first few characters */
2022 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2027 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2033 LPWSTR deformated = NULL;
2036 deformat_string(package, &value[2], &deformated);
2038 /* binary value type */
2042 *size = (strlenW(ptr)/2)+1;
2044 *size = strlenW(ptr)/2;
2046 data = msi_alloc(*size);
2052 /* if uneven pad with a zero in front */
2058 data[count] = (BYTE)strtol(byte,NULL,0);
2060 TRACE("Uneven byte count\n");
2068 data[count] = (BYTE)strtol(byte,NULL,0);
2071 msi_free(deformated);
2073 TRACE("Data %i bytes(%i)\n",*size,count);
2080 deformat_string(package, &value[1], &deformated);
2083 *size = sizeof(DWORD);
2084 data = msi_alloc(*size);
2090 if ( (*p < '0') || (*p > '9') )
2096 if (deformated[0] == '-')
2099 TRACE("DWORD %i\n",*(LPDWORD)data);
2101 msi_free(deformated);
2106 static const WCHAR szMulti[] = {'[','~',']',0};
2115 *type=REG_EXPAND_SZ;
2123 if (strstrW(value,szMulti))
2124 *type = REG_MULTI_SZ;
2126 /* remove initial delimiter */
2127 if (!strncmpW(value, szMulti, 3))
2130 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2132 /* add double NULL terminator */
2133 if (*type == REG_MULTI_SZ)
2135 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2136 data = msi_realloc_zero(data, *size);
2142 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2144 MSIPACKAGE *package = param;
2145 static const WCHAR szHCR[] =
2146 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2147 'R','O','O','T','\\',0};
2148 static const WCHAR szHCU[] =
2149 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2150 'U','S','E','R','\\',0};
2151 static const WCHAR szHLM[] =
2152 {'H','K','E','Y','_','L','O','C','A','L','_',
2153 'M','A','C','H','I','N','E','\\',0};
2154 static const WCHAR szHU[] =
2155 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2157 LPSTR value_data = NULL;
2158 HKEY root_key, hkey;
2161 LPCWSTR szRoot, component, name, key, value;
2166 BOOL check_first = FALSE;
2169 ui_progress(package,2,0,0,0);
2176 component = MSI_RecordGetString(row, 6);
2177 comp = get_loaded_component(package,component);
2179 return ERROR_SUCCESS;
2181 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2183 TRACE("Skipping write due to disabled component %s\n",
2184 debugstr_w(component));
2186 comp->Action = comp->Installed;
2188 return ERROR_SUCCESS;
2191 comp->Action = INSTALLSTATE_LOCAL;
2193 name = MSI_RecordGetString(row, 4);
2194 if( MSI_RecordIsNull(row,5) && name )
2196 /* null values can have special meanings */
2197 if (name[0]=='-' && name[1] == 0)
2198 return ERROR_SUCCESS;
2199 else if ((name[0]=='+' && name[1] == 0) ||
2200 (name[0] == '*' && name[1] == 0))
2205 root = MSI_RecordGetInteger(row,2);
2206 key = MSI_RecordGetString(row, 3);
2208 /* get the root key */
2213 LPWSTR all_users = msi_dup_property( package, szAllUsers );
2214 if (all_users && all_users[0] == '1')
2216 root_key = HKEY_LOCAL_MACHINE;
2221 root_key = HKEY_CURRENT_USER;
2224 msi_free(all_users);
2227 case 0: root_key = HKEY_CLASSES_ROOT;
2230 case 1: root_key = HKEY_CURRENT_USER;
2233 case 2: root_key = HKEY_LOCAL_MACHINE;
2236 case 3: root_key = HKEY_USERS;
2240 ERR("Unknown root %i\n",root);
2246 return ERROR_SUCCESS;
2248 deformat_string(package, key , &deformated);
2249 size = strlenW(deformated) + strlenW(szRoot) + 1;
2250 uikey = msi_alloc(size*sizeof(WCHAR));
2251 strcpyW(uikey,szRoot);
2252 strcatW(uikey,deformated);
2254 if (RegCreateKeyW( root_key, deformated, &hkey))
2256 ERR("Could not create key %s\n",debugstr_w(deformated));
2257 msi_free(deformated);
2259 return ERROR_SUCCESS;
2261 msi_free(deformated);
2263 value = MSI_RecordGetString(row,5);
2265 value_data = parse_value(package, value, &type, &size);
2268 value_data = (LPSTR)strdupW(szEmpty);
2269 size = sizeof(szEmpty);
2273 deformat_string(package, name, &deformated);
2277 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2279 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2284 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2285 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2287 TRACE("value %s of %s checked already exists\n",
2288 debugstr_w(deformated), debugstr_w(uikey));
2292 TRACE("Checked and setting value %s of %s\n",
2293 debugstr_w(deformated), debugstr_w(uikey));
2294 if (deformated || size)
2295 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2300 uirow = MSI_CreateRecord(3);
2301 MSI_RecordSetStringW(uirow,2,deformated);
2302 MSI_RecordSetStringW(uirow,1,uikey);
2305 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2307 MSI_RecordSetStringW(uirow,3,value);
2309 ui_actiondata(package,szWriteRegistryValues,uirow);
2310 msiobj_release( &uirow->hdr );
2312 msi_free(value_data);
2313 msi_free(deformated);
2316 return ERROR_SUCCESS;
2319 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2323 static const WCHAR ExecSeqQuery[] =
2324 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2325 '`','R','e','g','i','s','t','r','y','`',0 };
2327 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2328 if (rc != ERROR_SUCCESS)
2329 return ERROR_SUCCESS;
2331 /* increment progress bar each time action data is sent */
2332 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2334 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2336 msiobj_release(&view->hdr);
2340 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2342 package->script->CurrentlyScripting = TRUE;
2344 return ERROR_SUCCESS;
2348 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2353 static const WCHAR q1[]=
2354 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2355 '`','R','e','g','i','s','t','r','y','`',0};
2358 MSIFEATURE *feature;
2361 TRACE("InstallValidate\n");
2363 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2364 if (rc == ERROR_SUCCESS)
2366 MSI_IterateRecords( view, &progress, NULL, package );
2367 msiobj_release( &view->hdr );
2368 total += progress * REG_PROGRESS_VALUE;
2371 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2372 total += COMPONENT_PROGRESS_VALUE;
2374 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2375 total += file->FileSize;
2377 ui_progress(package,0,total,0,0);
2379 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2381 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2382 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2383 feature->ActionRequest);
2386 return ERROR_SUCCESS;
2389 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2391 MSIPACKAGE* package = param;
2392 LPCWSTR cond = NULL;
2393 LPCWSTR message = NULL;
2396 static const WCHAR title[]=
2397 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2399 cond = MSI_RecordGetString(row,1);
2401 r = MSI_EvaluateConditionW(package,cond);
2402 if (r == MSICONDITION_FALSE)
2404 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2407 message = MSI_RecordGetString(row,2);
2408 deformat_string(package,message,&deformated);
2409 MessageBoxW(NULL,deformated,title,MB_OK);
2410 msi_free(deformated);
2413 return ERROR_INSTALL_FAILURE;
2416 return ERROR_SUCCESS;
2419 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2422 MSIQUERY * view = NULL;
2423 static const WCHAR ExecSeqQuery[] =
2424 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2425 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2427 TRACE("Checking launch conditions\n");
2429 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2430 if (rc != ERROR_SUCCESS)
2431 return ERROR_SUCCESS;
2433 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2434 msiobj_release(&view->hdr);
2439 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2443 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2445 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2447 MSIRECORD * row = 0;
2449 LPWSTR deformated,buffer,deformated_name;
2451 static const WCHAR ExecSeqQuery[] =
2452 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2453 '`','R','e','g','i','s','t','r','y','`',' ',
2454 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2455 ' ','=',' ' ,'\'','%','s','\'',0 };
2456 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2457 static const WCHAR fmt2[]=
2458 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2460 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2464 root = MSI_RecordGetInteger(row,2);
2465 key = MSI_RecordGetString(row, 3);
2466 name = MSI_RecordGetString(row, 4);
2467 deformat_string(package, key , &deformated);
2468 deformat_string(package, name, &deformated_name);
2470 len = strlenW(deformated) + 6;
2471 if (deformated_name)
2472 len+=strlenW(deformated_name);
2474 buffer = msi_alloc( len *sizeof(WCHAR));
2476 if (deformated_name)
2477 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2479 sprintfW(buffer,fmt,root,deformated);
2481 msi_free(deformated);
2482 msi_free(deformated_name);
2483 msiobj_release(&row->hdr);
2487 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2489 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2494 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2497 return strdupW( file->TargetPath );
2502 static HKEY openSharedDLLsKey(void)
2505 static const WCHAR path[] =
2506 {'S','o','f','t','w','a','r','e','\\',
2507 'M','i','c','r','o','s','o','f','t','\\',
2508 'W','i','n','d','o','w','s','\\',
2509 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2510 'S','h','a','r','e','d','D','L','L','s',0};
2512 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2516 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2521 DWORD sz = sizeof(count);
2524 hkey = openSharedDLLsKey();
2525 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2526 if (rc != ERROR_SUCCESS)
2532 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2536 hkey = openSharedDLLsKey();
2538 msi_reg_set_val_dword( hkey, path, count );
2540 RegDeleteValueW(hkey,path);
2546 * Return TRUE if the count should be written out and FALSE if not
2548 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2550 MSIFEATURE *feature;
2554 /* only refcount DLLs */
2555 if (comp->KeyPath == NULL ||
2556 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2557 comp->Attributes & msidbComponentAttributesODBCDataSource)
2561 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2562 write = (count > 0);
2564 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2568 /* increment counts */
2569 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2573 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2576 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2578 if ( cl->component == comp )
2583 /* decrement counts */
2584 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2588 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2591 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2593 if ( cl->component == comp )
2598 /* ref count all the files in the component */
2603 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2605 if (file->Component == comp)
2606 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2610 /* add a count for permanent */
2611 if (comp->Attributes & msidbComponentAttributesPermanent)
2614 comp->RefCount = count;
2617 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2620 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2622 WCHAR squished_pc[GUID_SIZE];
2623 WCHAR squished_cc[GUID_SIZE];
2630 squash_guid(package->ProductCode,squished_pc);
2631 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2637 ui_progress(package,2,0,0,0);
2638 if (!comp->ComponentId)
2641 squash_guid(comp->ComponentId,squished_cc);
2643 msi_free(comp->FullKeypath);
2644 comp->FullKeypath = resolve_keypath( package, comp );
2646 ACTION_RefCountComponent( package, comp );
2648 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2649 debugstr_w(comp->Component),
2650 debugstr_w(squished_cc),
2651 debugstr_w(comp->FullKeypath),
2654 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2655 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2657 if (!comp->FullKeypath)
2660 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2661 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2664 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2667 if (rc != ERROR_SUCCESS)
2670 if (comp->Attributes & msidbComponentAttributesPermanent)
2672 static const WCHAR szPermKey[] =
2673 { '0','0','0','0','0','0','0','0','0','0','0','0',
2674 '0','0','0','0','0','0','0','0','0','0','0','0',
2675 '0','0','0','0','0','0','0','0',0 };
2677 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2680 if (comp->Action == INSTALLSTATE_LOCAL)
2681 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2687 WCHAR source[MAX_PATH];
2688 WCHAR base[MAX_PATH];
2691 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2692 static const WCHAR query[] = {
2693 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2694 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2695 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2696 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2697 '`','D','i','s','k','I','d','`',0};
2699 file = get_loaded_file(package, comp->KeyPath);
2703 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2704 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2705 ptr2 = strrchrW(source, '\\') + 1;
2706 msiobj_release(&row->hdr);
2708 lstrcpyW(base, package->PackagePath);
2709 ptr = strrchrW(base, '\\');
2712 sourcepath = resolve_file_source(package, file);
2713 ptr = sourcepath + lstrlenW(base);
2714 lstrcpyW(ptr2, ptr);
2715 msi_free(sourcepath);
2717 msi_reg_set_val_str(hkey, squished_pc, source);
2721 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2723 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2724 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2726 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2730 uirow = MSI_CreateRecord(3);
2731 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2732 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2733 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2734 ui_actiondata(package,szProcessComponents,uirow);
2735 msiobj_release( &uirow->hdr );
2738 return ERROR_SUCCESS;
2749 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2750 LPWSTR lpszName, LONG_PTR lParam)
2753 typelib_struct *tl_struct = (typelib_struct*) lParam;
2754 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2758 if (!IS_INTRESOURCE(lpszName))
2760 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2764 sz = strlenW(tl_struct->source)+4;
2765 sz *= sizeof(WCHAR);
2767 if ((INT_PTR)lpszName == 1)
2768 tl_struct->path = strdupW(tl_struct->source);
2771 tl_struct->path = msi_alloc(sz);
2772 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2775 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2776 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2779 msi_free(tl_struct->path);
2780 tl_struct->path = NULL;
2785 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2786 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2788 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2792 msi_free(tl_struct->path);
2793 tl_struct->path = NULL;
2795 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2796 ITypeLib_Release(tl_struct->ptLib);
2801 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2803 MSIPACKAGE* package = param;
2807 typelib_struct tl_struct;
2812 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2814 component = MSI_RecordGetString(row,3);
2815 comp = get_loaded_component(package,component);
2817 return ERROR_SUCCESS;
2819 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2821 TRACE("Skipping typelib reg due to disabled component\n");
2823 comp->Action = comp->Installed;
2825 return ERROR_SUCCESS;
2828 comp->Action = INSTALLSTATE_LOCAL;
2830 file = get_loaded_file( package, comp->KeyPath );
2832 return ERROR_SUCCESS;
2834 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2838 guid = MSI_RecordGetString(row,1);
2839 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2840 tl_struct.source = strdupW( file->TargetPath );
2841 tl_struct.path = NULL;
2843 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2844 (LONG_PTR)&tl_struct);
2852 helpid = MSI_RecordGetString(row,6);
2855 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2856 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2860 ERR("Failed to register type library %s\n",
2861 debugstr_w(tl_struct.path));
2864 ui_actiondata(package,szRegisterTypeLibraries,row);
2866 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2869 ITypeLib_Release(tl_struct.ptLib);
2870 msi_free(tl_struct.path);
2873 ERR("Failed to load type library %s\n",
2874 debugstr_w(tl_struct.source));
2876 FreeLibrary(module);
2877 msi_free(tl_struct.source);
2881 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
2884 ERR("Failed to load type library: %08x\n", hr);
2885 return ERROR_FUNCTION_FAILED;
2888 ITypeLib_Release(tlib);
2891 return ERROR_SUCCESS;
2894 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2897 * OK this is a bit confusing.. I am given a _Component key and I believe
2898 * that the file that is being registered as a type library is the "key file
2899 * of that component" which I interpret to mean "The file in the KeyPath of
2904 static const WCHAR Query[] =
2905 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2906 '`','T','y','p','e','L','i','b','`',0};
2908 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2909 if (rc != ERROR_SUCCESS)
2910 return ERROR_SUCCESS;
2912 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2913 msiobj_release(&view->hdr);
2917 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2919 MSIPACKAGE *package = param;
2920 LPWSTR target_file, target_folder, filename;
2921 LPCWSTR buffer, extension;
2923 static const WCHAR szlnk[]={'.','l','n','k',0};
2924 IShellLinkW *sl = NULL;
2925 IPersistFile *pf = NULL;
2928 buffer = MSI_RecordGetString(row,4);
2929 comp = get_loaded_component(package,buffer);
2931 return ERROR_SUCCESS;
2933 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2935 TRACE("Skipping shortcut creation due to disabled component\n");
2937 comp->Action = comp->Installed;
2939 return ERROR_SUCCESS;
2942 comp->Action = INSTALLSTATE_LOCAL;
2944 ui_actiondata(package,szCreateShortcuts,row);
2946 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2947 &IID_IShellLinkW, (LPVOID *) &sl );
2951 ERR("CLSID_ShellLink not available\n");
2955 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2958 ERR("QueryInterface(IID_IPersistFile) failed\n");
2962 buffer = MSI_RecordGetString(row,2);
2963 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2965 /* may be needed because of a bug somewhere else */
2966 create_full_pathW(target_folder);
2968 filename = msi_dup_record_field( row, 3 );
2969 reduce_to_longfilename(filename);
2971 extension = strchrW(filename,'.');
2972 if (!extension || strcmpiW(extension,szlnk))
2974 int len = strlenW(filename);
2975 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2976 memcpy(filename + len, szlnk, sizeof(szlnk));
2978 target_file = build_directory_name(2, target_folder, filename);
2979 msi_free(target_folder);
2982 buffer = MSI_RecordGetString(row,5);
2983 if (strchrW(buffer,'['))
2986 deformat_string(package,buffer,&deformated);
2987 IShellLinkW_SetPath(sl,deformated);
2988 msi_free(deformated);
2992 FIXME("poorly handled shortcut format, advertised shortcut\n");
2993 IShellLinkW_SetPath(sl,comp->FullKeypath);
2996 if (!MSI_RecordIsNull(row,6))
2999 buffer = MSI_RecordGetString(row,6);
3000 deformat_string(package,buffer,&deformated);
3001 IShellLinkW_SetArguments(sl,deformated);
3002 msi_free(deformated);
3005 if (!MSI_RecordIsNull(row,7))
3007 buffer = MSI_RecordGetString(row,7);
3008 IShellLinkW_SetDescription(sl,buffer);
3011 if (!MSI_RecordIsNull(row,8))
3012 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3014 if (!MSI_RecordIsNull(row,9))
3019 buffer = MSI_RecordGetString(row,9);
3021 Path = build_icon_path(package,buffer);
3022 index = MSI_RecordGetInteger(row,10);
3024 /* no value means 0 */
3025 if (index == MSI_NULL_INTEGER)
3028 IShellLinkW_SetIconLocation(sl,Path,index);
3032 if (!MSI_RecordIsNull(row,11))
3033 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3035 if (!MSI_RecordIsNull(row,12))
3038 buffer = MSI_RecordGetString(row,12);
3039 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3041 IShellLinkW_SetWorkingDirectory(sl,Path);
3045 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3046 IPersistFile_Save(pf,target_file,FALSE);
3048 msi_free(target_file);
3052 IPersistFile_Release( pf );
3054 IShellLinkW_Release( sl );
3056 return ERROR_SUCCESS;
3059 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3064 static const WCHAR Query[] =
3065 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3066 '`','S','h','o','r','t','c','u','t','`',0};
3068 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3069 if (rc != ERROR_SUCCESS)
3070 return ERROR_SUCCESS;
3072 res = CoInitialize( NULL );
3074 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3075 msiobj_release(&view->hdr);
3083 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3085 MSIPACKAGE* package = param;
3094 FileName = MSI_RecordGetString(row,1);
3097 ERR("Unable to get FileName\n");
3098 return ERROR_SUCCESS;
3101 FilePath = build_icon_path(package,FileName);
3103 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3105 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3106 FILE_ATTRIBUTE_NORMAL, NULL);
3108 if (the_file == INVALID_HANDLE_VALUE)
3110 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3112 return ERROR_SUCCESS;
3119 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3120 if (rc != ERROR_SUCCESS)
3122 ERR("Failed to get stream\n");
3123 CloseHandle(the_file);
3124 DeleteFileW(FilePath);
3127 WriteFile(the_file,buffer,sz,&write,NULL);
3128 } while (sz == 1024);
3132 CloseHandle(the_file);
3134 uirow = MSI_CreateRecord(1);
3135 MSI_RecordSetStringW(uirow,1,FileName);
3136 ui_actiondata(package,szPublishProduct,uirow);
3137 msiobj_release( &uirow->hdr );
3139 return ERROR_SUCCESS;
3142 static UINT msi_publish_icons(MSIPACKAGE *package)
3147 static const WCHAR query[]= {
3148 'S','E','L','E','C','T',' ','*',' ',
3149 'F','R','O','M',' ','`','I','c','o','n','`',0};
3151 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3152 if (r == ERROR_SUCCESS)
3154 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3155 msiobj_release(&view->hdr);
3158 return ERROR_SUCCESS;
3161 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3167 MSISOURCELISTINFO *info;
3169 r = RegCreateKeyW(hkey, szSourceList, &source);
3170 if (r != ERROR_SUCCESS)
3173 RegCloseKey(source);
3175 buffer = strrchrW(package->PackagePath, '\\') + 1;
3176 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3177 package->Context, MSICODE_PRODUCT,
3178 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3179 if (r != ERROR_SUCCESS)
3182 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3183 package->Context, MSICODE_PRODUCT,
3184 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3185 if (r != ERROR_SUCCESS)
3188 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3189 package->Context, MSICODE_PRODUCT,
3190 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3191 if (r != ERROR_SUCCESS)
3194 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3196 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3197 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3198 info->options, info->value);
3200 MsiSourceListSetInfoW(package->ProductCode, NULL,
3201 info->context, info->options,
3202 info->property, info->value);
3205 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3207 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3208 disk->context, disk->options,
3209 disk->disk_id, disk->volume_label, disk->disk_prompt);
3212 return ERROR_SUCCESS;
3215 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3217 MSIHANDLE hdb, suminfo;
3218 WCHAR guids[MAX_PATH];
3219 WCHAR packcode[SQUISH_GUID_SIZE];
3226 static const WCHAR szProductLanguage[] =
3227 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3228 static const WCHAR szARPProductIcon[] =
3229 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3230 static const WCHAR szProductVersion[] =
3231 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3232 static const WCHAR szAssignment[] =
3233 {'A','s','s','i','g','n','m','e','n','t',0};
3234 static const WCHAR szAdvertiseFlags[] =
3235 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3236 static const WCHAR szClients[] =
3237 {'C','l','i','e','n','t','s',0};
3238 static const WCHAR szColon[] = {':',0};
3240 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3241 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3244 langid = msi_get_property_int(package, szProductLanguage, 0);
3245 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3248 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3250 buffer = msi_dup_property(package, szARPProductIcon);
3253 LPWSTR path = build_icon_path(package,buffer);
3254 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3259 buffer = msi_dup_property(package, szProductVersion);
3262 DWORD verdword = msi_version_str_to_dword(buffer);
3263 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3267 msi_reg_set_val_dword(hkey, szAssignment, 0);
3268 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3269 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3270 msi_reg_set_val_str(hkey, szClients, szColon);
3272 hdb = alloc_msihandle(&package->db->hdr);
3274 return ERROR_NOT_ENOUGH_MEMORY;
3276 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3277 MsiCloseHandle(hdb);
3278 if (r != ERROR_SUCCESS)
3282 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3283 NULL, guids, &size);
3284 if (r != ERROR_SUCCESS)
3287 ptr = strchrW(guids, ';');
3289 squash_guid(guids, packcode);
3290 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3293 MsiCloseHandle(suminfo);
3294 return ERROR_SUCCESS;
3297 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3302 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3304 static const WCHAR szUpgradeCode[] =
3305 {'U','p','g','r','a','d','e','C','o','d','e',0};
3307 upgrade = msi_dup_property(package, szUpgradeCode);
3309 return ERROR_SUCCESS;
3311 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3313 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3314 if (r != ERROR_SUCCESS)
3319 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3320 if (r != ERROR_SUCCESS)
3324 squash_guid(package->ProductCode, squashed_pc);
3325 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3334 static BOOL msi_check_publish(MSIPACKAGE *package)
3336 MSIFEATURE *feature;
3338 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3340 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3347 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3349 MSIFEATURE *feature;
3351 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3353 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3360 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3362 WCHAR patch_squashed[GUID_SIZE];
3365 UINT r = ERROR_FUNCTION_FAILED;
3367 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3369 if (res != ERROR_SUCCESS)
3370 return ERROR_FUNCTION_FAILED;
3372 squash_guid(package->patch->patchcode, patch_squashed);
3374 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3375 (const BYTE *)patch_squashed,
3376 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3377 if (res != ERROR_SUCCESS)
3380 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3381 (const BYTE *)package->patch->transforms,
3382 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3383 if (res == ERROR_SUCCESS)
3387 RegCloseKey(patches);
3392 * 99% of the work done here is only done for
3393 * advertised installs. However this is where the
3394 * Icon table is processed and written out
3395 * so that is what I am going to do here.
3397 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3403 /* FIXME: also need to publish if the product is in advertise mode */
3404 if (!msi_check_publish(package))
3405 return ERROR_SUCCESS;
3407 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3409 if (rc != ERROR_SUCCESS)
3412 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3413 NULL, &hudkey, TRUE);
3414 if (rc != ERROR_SUCCESS)
3417 rc = msi_publish_upgrade_code(package);
3418 if (rc != ERROR_SUCCESS)
3423 rc = msi_publish_patch(package, hukey, hudkey);
3424 if (rc != ERROR_SUCCESS)
3428 rc = msi_publish_product_properties(package, hukey);
3429 if (rc != ERROR_SUCCESS)
3432 rc = msi_publish_sourcelist(package, hukey);
3433 if (rc != ERROR_SUCCESS)
3436 rc = msi_publish_icons(package);
3440 RegCloseKey(hudkey);
3445 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3447 MSIPACKAGE *package = param;
3448 LPCWSTR component, section, key, value, identifier, dirproperty;
3449 LPWSTR deformated_section, deformated_key, deformated_value;
3450 LPWSTR folder, filename, fullname = NULL;
3451 LPCWSTR filenameptr;
3455 static const WCHAR szWindowsFolder[] =
3456 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3458 component = MSI_RecordGetString(row, 8);
3459 comp = get_loaded_component(package,component);
3461 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3463 TRACE("Skipping ini file due to disabled component %s\n",
3464 debugstr_w(component));
3466 comp->Action = comp->Installed;
3468 return ERROR_SUCCESS;
3471 comp->Action = INSTALLSTATE_LOCAL;
3473 identifier = MSI_RecordGetString(row,1);
3474 dirproperty = MSI_RecordGetString(row,3);
3475 section = MSI_RecordGetString(row,4);
3476 key = MSI_RecordGetString(row,5);
3477 value = MSI_RecordGetString(row,6);
3478 action = MSI_RecordGetInteger(row,7);
3480 deformat_string(package,section,&deformated_section);
3481 deformat_string(package,key,&deformated_key);
3482 deformat_string(package,value,&deformated_value);
3484 filename = msi_dup_record_field(row, 2);
3485 if (filename && (filenameptr = strchrW(filename, '|')))
3488 filenameptr = filename;
3492 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3494 folder = msi_dup_property( package, dirproperty );
3497 folder = msi_dup_property( package, szWindowsFolder );
3501 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3505 fullname = build_directory_name(2, folder, filenameptr);
3509 TRACE("Adding value %s to section %s in %s\n",
3510 debugstr_w(deformated_key), debugstr_w(deformated_section),
3511 debugstr_w(fullname));
3512 WritePrivateProfileStringW(deformated_section, deformated_key,
3513 deformated_value, fullname);
3515 else if (action == 1)
3518 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3519 returned, 10, fullname);
3520 if (returned[0] == 0)
3522 TRACE("Adding value %s to section %s in %s\n",
3523 debugstr_w(deformated_key), debugstr_w(deformated_section),
3524 debugstr_w(fullname));
3526 WritePrivateProfileStringW(deformated_section, deformated_key,
3527 deformated_value, fullname);
3530 else if (action == 3)
3531 FIXME("Append to existing section not yet implemented\n");
3533 uirow = MSI_CreateRecord(4);
3534 MSI_RecordSetStringW(uirow,1,identifier);
3535 MSI_RecordSetStringW(uirow,2,deformated_section);
3536 MSI_RecordSetStringW(uirow,3,deformated_key);
3537 MSI_RecordSetStringW(uirow,4,deformated_value);
3538 ui_actiondata(package,szWriteIniValues,uirow);
3539 msiobj_release( &uirow->hdr );
3545 msi_free(deformated_key);
3546 msi_free(deformated_value);
3547 msi_free(deformated_section);
3548 return ERROR_SUCCESS;
3551 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3555 static const WCHAR ExecSeqQuery[] =
3556 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3557 '`','I','n','i','F','i','l','e','`',0};
3559 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3560 if (rc != ERROR_SUCCESS)
3562 TRACE("no IniFile table\n");
3563 return ERROR_SUCCESS;
3566 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3567 msiobj_release(&view->hdr);
3571 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3573 MSIPACKAGE *package = param;
3578 static const WCHAR ExeStr[] =
3579 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3580 static const WCHAR close[] = {'\"',0};
3582 PROCESS_INFORMATION info;
3587 memset(&si,0,sizeof(STARTUPINFOW));
3589 filename = MSI_RecordGetString(row,1);
3590 file = get_loaded_file( package, filename );
3594 ERR("Unable to find file id %s\n",debugstr_w(filename));
3595 return ERROR_SUCCESS;
3598 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3600 FullName = msi_alloc(len*sizeof(WCHAR));
3601 strcpyW(FullName,ExeStr);
3602 strcatW( FullName, file->TargetPath );
3603 strcatW(FullName,close);
3605 TRACE("Registering %s\n",debugstr_w(FullName));
3606 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3611 CloseHandle(info.hThread);
3612 msi_dialog_check_messages(info.hProcess);
3613 CloseHandle(info.hProcess);
3619 uirow = MSI_CreateRecord( 2 );
3620 uipath = strdupW( file->TargetPath );
3621 p = strrchrW(uipath,'\\');
3624 MSI_RecordSetStringW( uirow, 1, &p[1] );
3625 MSI_RecordSetStringW( uirow, 2, uipath);
3626 ui_actiondata( package, szSelfRegModules, uirow);
3627 msiobj_release( &uirow->hdr );
3629 /* FIXME: call ui_progress? */
3631 return ERROR_SUCCESS;
3634 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3638 static const WCHAR ExecSeqQuery[] =
3639 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3640 '`','S','e','l','f','R','e','g','`',0};
3642 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3643 if (rc != ERROR_SUCCESS)
3645 TRACE("no SelfReg table\n");
3646 return ERROR_SUCCESS;
3649 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3650 msiobj_release(&view->hdr);
3652 return ERROR_SUCCESS;
3655 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3657 MSIFEATURE *feature;
3660 HKEY userdata = NULL;
3662 if (!msi_check_publish(package))
3663 return ERROR_SUCCESS;
3665 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3667 if (rc != ERROR_SUCCESS)
3670 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3672 if (rc != ERROR_SUCCESS)
3675 /* here the guids are base 85 encoded */
3676 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3682 BOOL absent = FALSE;
3685 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3686 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3687 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3691 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3695 if (feature->Feature_Parent)
3696 size += strlenW( feature->Feature_Parent )+2;
3698 data = msi_alloc(size * sizeof(WCHAR));
3701 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3703 MSICOMPONENT* component = cl->component;
3707 if (component->ComponentId)
3709 TRACE("From %s\n",debugstr_w(component->ComponentId));
3710 CLSIDFromString(component->ComponentId, &clsid);
3711 encode_base85_guid(&clsid,buf);
3712 TRACE("to %s\n",debugstr_w(buf));
3717 if (feature->Feature_Parent)
3719 static const WCHAR sep[] = {'\2',0};
3721 strcatW(data,feature->Feature_Parent);
3724 msi_reg_set_val_str( userdata, feature->Feature, data );
3728 if (feature->Feature_Parent)
3729 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3732 size += sizeof(WCHAR);
3733 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3734 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
3738 size += 2*sizeof(WCHAR);
3739 data = msi_alloc(size);
3742 if (feature->Feature_Parent)
3743 strcpyW( &data[1], feature->Feature_Parent );
3744 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3750 uirow = MSI_CreateRecord( 1 );
3751 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3752 ui_actiondata( package, szPublishFeatures, uirow);
3753 msiobj_release( &uirow->hdr );
3754 /* FIXME: call ui_progress? */
3759 RegCloseKey(userdata);
3763 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3768 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3770 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3772 if (r == ERROR_SUCCESS)
3774 RegDeleteValueW(hkey, feature->Feature);
3778 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3780 if (r == ERROR_SUCCESS)
3782 RegDeleteValueW(hkey, feature->Feature);
3786 return ERROR_SUCCESS;
3789 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3791 MSIFEATURE *feature;
3793 if (!msi_check_unpublish(package))
3794 return ERROR_SUCCESS;
3796 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3798 msi_unpublish_feature(package, feature);
3801 return ERROR_SUCCESS;
3804 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3806 LPWSTR prop, val, key;
3812 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3813 static const WCHAR szWindowsInstaller[] =
3814 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3815 static const WCHAR modpath_fmt[] =
3816 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3817 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3818 static const WCHAR szModifyPath[] =
3819 {'M','o','d','i','f','y','P','a','t','h',0};
3820 static const WCHAR szUninstallString[] =
3821 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3822 static const WCHAR szEstimatedSize[] =
3823 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3824 static const WCHAR szProductLanguage[] =
3825 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3826 static const WCHAR szProductVersion[] =
3827 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3828 static const WCHAR szProductName[] =
3829 {'P','r','o','d','u','c','t','N','a','m','e',0};
3830 static const WCHAR szDisplayName[] =
3831 {'D','i','s','p','l','a','y','N','a','m','e',0};
3832 static const WCHAR szDisplayVersion[] =
3833 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3834 static const WCHAR szManufacturer[] =
3835 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3837 static const LPCSTR propval[] = {
3838 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3839 "ARPCONTACT", "Contact",
3840 "ARPCOMMENTS", "Comments",
3841 "ProductName", "DisplayName",
3842 "ProductVersion", "DisplayVersion",
3843 "ARPHELPLINK", "HelpLink",
3844 "ARPHELPTELEPHONE", "HelpTelephone",
3845 "ARPINSTALLLOCATION", "InstallLocation",
3846 "SourceDir", "InstallSource",
3847 "Manufacturer", "Publisher",
3848 "ARPREADME", "Readme",
3850 "ARPURLINFOABOUT", "URLInfoAbout",
3851 "ARPURLUPDATEINFO", "URLUpdateInfo",
3854 const LPCSTR *p = propval;
3858 prop = strdupAtoW(*p++);
3859 key = strdupAtoW(*p++);
3860 val = msi_dup_property(package, prop);
3861 msi_reg_set_val_str(hkey, key, val);
3867 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
3869 size = deformat_string(package, modpath_fmt, &buffer);
3870 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3871 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3874 /* FIXME: Write real Estimated Size when we have it */
3875 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
3877 buffer = msi_dup_property(package, szProductName);
3878 msi_reg_set_val_str(hkey, szDisplayName, buffer);
3881 buffer = msi_dup_property(package, cszSourceDir);
3882 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
3885 buffer = msi_dup_property(package, szManufacturer);
3886 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
3889 GetLocalTime(&systime);
3890 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
3891 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
3893 langid = msi_get_property_int(package, szProductLanguage, 0);
3894 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3896 buffer = msi_dup_property(package, szProductVersion);
3897 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
3900 DWORD verdword = msi_version_str_to_dword(buffer);
3902 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3903 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
3904 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
3908 return ERROR_SUCCESS;
3911 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3913 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3914 LPWSTR upgrade_code;
3919 static const WCHAR szUpgradeCode[] = {
3920 'U','p','g','r','a','d','e','C','o','d','e',0};
3922 /* FIXME: also need to publish if the product is in advertise mode */
3923 if (!msi_check_publish(package))
3924 return ERROR_SUCCESS;
3926 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
3927 if (rc != ERROR_SUCCESS)
3930 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
3931 NULL, &props, TRUE);
3932 if (rc != ERROR_SUCCESS)
3935 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
3936 msi_free( package->db->localfile );
3937 package->db->localfile = NULL;
3939 rc = msi_publish_install_properties(package, hkey);
3940 if (rc != ERROR_SUCCESS)
3943 rc = msi_publish_install_properties(package, props);
3944 if (rc != ERROR_SUCCESS)
3947 upgrade_code = msi_dup_property(package, szUpgradeCode);
3950 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
3951 squash_guid(package->ProductCode, squashed_pc);
3952 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
3953 RegCloseKey(upgrade);
3954 msi_free(upgrade_code);
3960 return ERROR_SUCCESS;
3963 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3965 return execute_script(package,INSTALL_SCRIPT);
3968 static UINT msi_unpublish_product(MSIPACKAGE *package)
3971 LPWSTR remove = NULL;
3972 LPWSTR *features = NULL;
3973 BOOL full_uninstall = TRUE;
3974 MSIFEATURE *feature;
3976 static const WCHAR szUpgradeCode[] =
3977 {'U','p','g','r','a','d','e','C','o','d','e',0};
3979 remove = msi_dup_property(package, szRemove);
3981 return ERROR_SUCCESS;
3983 features = msi_split_string(remove, ',');
3987 ERR("REMOVE feature list is empty!\n");
3988 return ERROR_FUNCTION_FAILED;
3991 if (!lstrcmpW(features[0], szAll))
3992 full_uninstall = TRUE;
3995 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3997 if (feature->Action != INSTALLSTATE_ABSENT)
3998 full_uninstall = FALSE;
4002 if (!full_uninstall)
4005 MSIREG_DeleteProductKey(package->ProductCode);
4006 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4007 MSIREG_DeleteUninstallKey(package->ProductCode);
4009 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4011 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4012 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4016 MSIREG_DeleteUserProductKey(package->ProductCode);
4017 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4020 upgrade = msi_dup_property(package, szUpgradeCode);
4023 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4030 return ERROR_SUCCESS;
4033 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4037 rc = msi_unpublish_product(package);
4038 if (rc != ERROR_SUCCESS)
4041 /* turn off scheduling */
4042 package->script->CurrentlyScripting= FALSE;
4044 /* first do the same as an InstallExecute */
4045 rc = ACTION_InstallExecute(package);
4046 if (rc != ERROR_SUCCESS)
4049 /* then handle Commit Actions */
4050 rc = execute_script(package,COMMIT_SCRIPT);
4055 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4057 static const WCHAR RunOnce[] = {
4058 'S','o','f','t','w','a','r','e','\\',
4059 'M','i','c','r','o','s','o','f','t','\\',
4060 'W','i','n','d','o','w','s','\\',
4061 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4062 'R','u','n','O','n','c','e',0};
4063 static const WCHAR InstallRunOnce[] = {
4064 'S','o','f','t','w','a','r','e','\\',
4065 'M','i','c','r','o','s','o','f','t','\\',
4066 'W','i','n','d','o','w','s','\\',
4067 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4068 'I','n','s','t','a','l','l','e','r','\\',
4069 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4071 static const WCHAR msiexec_fmt[] = {
4073 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4074 '\"','%','s','\"',0};
4075 static const WCHAR install_fmt[] = {
4076 '/','I',' ','\"','%','s','\"',' ',
4077 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4078 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4079 WCHAR buffer[256], sysdir[MAX_PATH];
4081 WCHAR squished_pc[100];
4083 squash_guid(package->ProductCode,squished_pc);
4085 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4086 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4087 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4090 msi_reg_set_val_str( hkey, squished_pc, buffer );
4093 TRACE("Reboot command %s\n",debugstr_w(buffer));
4095 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4096 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4098 msi_reg_set_val_str( hkey, squished_pc, buffer );
4101 return ERROR_INSTALL_SUSPEND;
4104 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4110 * We are currently doing what should be done here in the top level Install
4111 * however for Administrative and uninstalls this step will be needed
4113 if (!package->PackagePath)
4114 return ERROR_SUCCESS;
4116 msi_set_sourcedir_props(package, TRUE);
4118 attrib = GetFileAttributesW(package->db->path);
4119 if (attrib == INVALID_FILE_ATTRIBUTES)
4125 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4126 package->Context, MSICODE_PRODUCT,
4127 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4128 if (rc == ERROR_MORE_DATA)
4130 prompt = msi_alloc(size * sizeof(WCHAR));
4131 MsiSourceListGetInfoW(package->ProductCode, NULL,
4132 package->Context, MSICODE_PRODUCT,
4133 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4136 prompt = strdupW(package->db->path);
4138 msg = generate_error_string(package,1302,1,prompt);
4139 while(attrib == INVALID_FILE_ATTRIBUTES)
4141 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4144 rc = ERROR_INSTALL_USEREXIT;
4147 attrib = GetFileAttributesW(package->db->path);
4153 return ERROR_SUCCESS;
4158 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4165 static const WCHAR szPropKeys[][80] =
4167 {'P','r','o','d','u','c','t','I','D',0},
4168 {'U','S','E','R','N','A','M','E',0},
4169 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4173 static const WCHAR szRegKeys[][80] =
4175 {'P','r','o','d','u','c','t','I','D',0},
4176 {'R','e','g','O','w','n','e','r',0},
4177 {'R','e','g','C','o','m','p','a','n','y',0},
4181 if (msi_check_unpublish(package))
4183 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4184 return ERROR_SUCCESS;
4187 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4189 return ERROR_SUCCESS;
4191 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4193 if (rc != ERROR_SUCCESS)
4196 for( i = 0; szPropKeys[i][0]; i++ )
4198 buffer = msi_dup_property( package, szPropKeys[i] );
4199 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4204 msi_free(productid);
4207 /* FIXME: call ui_actiondata */
4213 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4217 package->script->InWhatSequence |= SEQUENCE_EXEC;
4218 rc = ACTION_ProcessExecSequence(package,FALSE);
4223 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4225 MSIPACKAGE *package = param;
4226 LPCWSTR compgroupid=NULL;
4227 LPCWSTR feature=NULL;
4228 LPCWSTR text = NULL;
4229 LPCWSTR qualifier = NULL;
4230 LPCWSTR component = NULL;
4231 LPWSTR advertise = NULL;
4232 LPWSTR output = NULL;
4234 UINT rc = ERROR_SUCCESS;
4239 component = MSI_RecordGetString(rec,3);
4240 comp = get_loaded_component(package,component);
4242 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4243 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4244 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4246 TRACE("Skipping: Component %s not scheduled for install\n",
4247 debugstr_w(component));
4249 return ERROR_SUCCESS;
4252 compgroupid = MSI_RecordGetString(rec,1);
4253 qualifier = MSI_RecordGetString(rec,2);
4255 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4256 if (rc != ERROR_SUCCESS)
4259 text = MSI_RecordGetString(rec,4);
4260 feature = MSI_RecordGetString(rec,5);
4262 advertise = create_component_advertise_string(package, comp, feature);
4264 sz = strlenW(advertise);
4267 sz += lstrlenW(text);
4270 sz *= sizeof(WCHAR);
4272 output = msi_alloc_zero(sz);
4273 strcpyW(output,advertise);
4274 msi_free(advertise);
4277 strcatW(output,text);
4279 msi_reg_set_val_multi_str( hkey, qualifier, output );
4286 uirow = MSI_CreateRecord( 2 );
4287 MSI_RecordSetStringW( uirow, 1, compgroupid );
4288 MSI_RecordSetStringW( uirow, 2, qualifier);
4289 ui_actiondata( package, szPublishComponents, uirow);
4290 msiobj_release( &uirow->hdr );
4291 /* FIXME: call ui_progress? */
4297 * At present I am ignorning the advertised components part of this and only
4298 * focusing on the qualified component sets
4300 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4304 static const WCHAR ExecSeqQuery[] =
4305 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4306 '`','P','u','b','l','i','s','h',
4307 'C','o','m','p','o','n','e','n','t','`',0};
4309 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4310 if (rc != ERROR_SUCCESS)
4311 return ERROR_SUCCESS;
4313 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4314 msiobj_release(&view->hdr);
4319 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4321 MSIPACKAGE *package = param;
4324 SC_HANDLE hscm, service = NULL;
4325 LPCWSTR comp, depends, pass;
4326 LPWSTR name = NULL, disp = NULL;
4327 LPCWSTR load_order, serv_name, key;
4328 DWORD serv_type, start_type;
4331 static const WCHAR query[] =
4332 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4333 '`','C','o','m','p','o','n','e','n','t','`',' ',
4334 'W','H','E','R','E',' ',
4335 '`','C','o','m','p','o','n','e','n','t','`',' ',
4336 '=','\'','%','s','\'',0};
4338 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4341 ERR("Failed to open the SC Manager!\n");
4345 start_type = MSI_RecordGetInteger(rec, 5);
4346 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4349 depends = MSI_RecordGetString(rec, 8);
4350 if (depends && *depends)
4351 FIXME("Dependency list unhandled!\n");
4353 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4354 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4355 serv_type = MSI_RecordGetInteger(rec, 4);
4356 err_control = MSI_RecordGetInteger(rec, 6);
4357 load_order = MSI_RecordGetString(rec, 7);
4358 serv_name = MSI_RecordGetString(rec, 9);
4359 pass = MSI_RecordGetString(rec, 10);
4360 comp = MSI_RecordGetString(rec, 12);
4362 /* fetch the service path */
4363 row = MSI_QueryGetRecord(package->db, query, comp);
4366 ERR("Control query failed!\n");
4370 key = MSI_RecordGetString(row, 6);
4372 file = get_loaded_file(package, key);
4373 msiobj_release(&row->hdr);
4376 ERR("Failed to load the service file\n");
4380 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4381 start_type, err_control, file->TargetPath,
4382 load_order, NULL, NULL, serv_name, pass);
4385 if (GetLastError() != ERROR_SERVICE_EXISTS)
4386 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4390 CloseServiceHandle(service);
4391 CloseServiceHandle(hscm);
4395 return ERROR_SUCCESS;
4398 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4402 static const WCHAR ExecSeqQuery[] =
4403 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4404 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4406 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4407 if (rc != ERROR_SUCCESS)
4408 return ERROR_SUCCESS;
4410 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4411 msiobj_release(&view->hdr);
4416 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4417 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4419 LPCWSTR *vector, *temp_vector;
4423 static const WCHAR separator[] = {'[','~',']',0};
4426 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4431 vector = msi_alloc(sizeof(LPWSTR));
4439 vector[*numargs - 1] = p;
4441 if ((q = strstrW(p, separator)))
4445 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4451 vector = temp_vector;
4460 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4462 MSIPACKAGE *package = param;
4464 SC_HANDLE scm, service = NULL;
4465 LPCWSTR name, *vector = NULL;
4467 DWORD event, numargs;
4468 UINT r = ERROR_FUNCTION_FAILED;
4470 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4471 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4472 return ERROR_SUCCESS;
4474 name = MSI_RecordGetString(rec, 2);
4475 event = MSI_RecordGetInteger(rec, 3);
4476 args = strdupW(MSI_RecordGetString(rec, 4));
4478 if (!(event & msidbServiceControlEventStart))
4479 return ERROR_SUCCESS;
4481 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4484 ERR("Failed to open the service control manager\n");
4488 service = OpenServiceW(scm, name, SERVICE_START);
4491 ERR("Failed to open service %s\n", debugstr_w(name));
4495 vector = msi_service_args_to_vector(args, &numargs);
4497 if (!StartServiceW(service, numargs, vector))
4499 ERR("Failed to start service %s\n", debugstr_w(name));
4506 CloseServiceHandle(service);
4507 CloseServiceHandle(scm);
4514 static UINT ACTION_StartServices( MSIPACKAGE *package )
4519 static const WCHAR query[] = {
4520 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4521 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4523 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4524 if (rc != ERROR_SUCCESS)
4525 return ERROR_SUCCESS;
4527 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4528 msiobj_release(&view->hdr);
4533 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4535 DWORD i, needed, count;
4536 ENUM_SERVICE_STATUSW *dependencies;
4540 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4541 0, &needed, &count))
4544 if (GetLastError() != ERROR_MORE_DATA)
4547 dependencies = msi_alloc(needed);
4551 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4552 needed, &needed, &count))
4555 for (i = 0; i < count; i++)
4557 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4558 SERVICE_STOP | SERVICE_QUERY_STATUS);
4562 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4569 msi_free(dependencies);
4573 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4575 MSIPACKAGE *package = param;
4577 SERVICE_STATUS status;
4578 SERVICE_STATUS_PROCESS ssp;
4579 SC_HANDLE scm = NULL, service = NULL;
4581 DWORD event, needed;
4583 event = MSI_RecordGetInteger(rec, 3);
4584 if (!(event & msidbServiceControlEventStop))
4585 return ERROR_SUCCESS;
4587 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4588 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4589 return ERROR_SUCCESS;
4591 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4592 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4593 args = strdupW(MSI_RecordGetString(rec, 4));
4595 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4598 WARN("Failed to open the SCM: %d\n", GetLastError());
4602 service = OpenServiceW(scm, name,
4604 SERVICE_QUERY_STATUS |
4605 SERVICE_ENUMERATE_DEPENDENTS);
4608 WARN("Failed to open service (%s): %d\n",
4609 debugstr_w(name), GetLastError());
4613 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4614 sizeof(SERVICE_STATUS_PROCESS), &needed))
4616 WARN("Failed to query service status (%s): %d\n",
4617 debugstr_w(name), GetLastError());
4621 if (ssp.dwCurrentState == SERVICE_STOPPED)
4624 stop_service_dependents(scm, service);
4626 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4627 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4630 CloseServiceHandle(service);
4631 CloseServiceHandle(scm);
4635 return ERROR_SUCCESS;
4638 static UINT ACTION_StopServices( MSIPACKAGE *package )
4643 static const WCHAR query[] = {
4644 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4645 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4647 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4648 if (rc != ERROR_SUCCESS)
4649 return ERROR_SUCCESS;
4651 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4652 msiobj_release(&view->hdr);
4657 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4661 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4663 if (!lstrcmpW(file->File, filename))
4670 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4672 MSIPACKAGE *package = param;
4673 LPWSTR driver, driver_path, ptr;
4674 WCHAR outpath[MAX_PATH];
4675 MSIFILE *driver_file, *setup_file;
4678 UINT r = ERROR_SUCCESS;
4680 static const WCHAR driver_fmt[] = {
4681 'D','r','i','v','e','r','=','%','s',0};
4682 static const WCHAR setup_fmt[] = {
4683 'S','e','t','u','p','=','%','s',0};
4684 static const WCHAR usage_fmt[] = {
4685 'F','i','l','e','U','s','a','g','e','=','1',0};
4687 desc = MSI_RecordGetString(rec, 3);
4689 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4690 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4692 if (!driver_file || !setup_file)
4694 ERR("ODBC Driver entry not found!\n");
4695 return ERROR_FUNCTION_FAILED;
4698 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4699 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4700 lstrlenW(usage_fmt) + 1;
4701 driver = msi_alloc(len * sizeof(WCHAR));
4703 return ERROR_OUTOFMEMORY;
4706 lstrcpyW(ptr, desc);
4707 ptr += lstrlenW(ptr) + 1;
4709 sprintfW(ptr, driver_fmt, driver_file->FileName);
4710 ptr += lstrlenW(ptr) + 1;
4712 sprintfW(ptr, setup_fmt, setup_file->FileName);
4713 ptr += lstrlenW(ptr) + 1;
4715 lstrcpyW(ptr, usage_fmt);
4716 ptr += lstrlenW(ptr) + 1;
4719 driver_path = strdupW(driver_file->TargetPath);
4720 ptr = strrchrW(driver_path, '\\');
4721 if (ptr) *ptr = '\0';
4723 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4724 NULL, ODBC_INSTALL_COMPLETE, &usage))
4726 ERR("Failed to install SQL driver!\n");
4727 r = ERROR_FUNCTION_FAILED;
4731 msi_free(driver_path);
4736 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4738 MSIPACKAGE *package = param;
4739 LPWSTR translator, translator_path, ptr;
4740 WCHAR outpath[MAX_PATH];
4741 MSIFILE *translator_file, *setup_file;
4744 UINT r = ERROR_SUCCESS;
4746 static const WCHAR translator_fmt[] = {
4747 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4748 static const WCHAR setup_fmt[] = {
4749 'S','e','t','u','p','=','%','s',0};
4751 desc = MSI_RecordGetString(rec, 3);
4753 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4754 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4756 if (!translator_file || !setup_file)
4758 ERR("ODBC Translator entry not found!\n");
4759 return ERROR_FUNCTION_FAILED;
4762 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4763 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4764 translator = msi_alloc(len * sizeof(WCHAR));
4766 return ERROR_OUTOFMEMORY;
4769 lstrcpyW(ptr, desc);
4770 ptr += lstrlenW(ptr) + 1;
4772 sprintfW(ptr, translator_fmt, translator_file->FileName);
4773 ptr += lstrlenW(ptr) + 1;
4775 sprintfW(ptr, setup_fmt, setup_file->FileName);
4776 ptr += lstrlenW(ptr) + 1;
4779 translator_path = strdupW(translator_file->TargetPath);
4780 ptr = strrchrW(translator_path, '\\');
4781 if (ptr) *ptr = '\0';
4783 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4784 NULL, ODBC_INSTALL_COMPLETE, &usage))
4786 ERR("Failed to install SQL translator!\n");
4787 r = ERROR_FUNCTION_FAILED;
4790 msi_free(translator);
4791 msi_free(translator_path);
4796 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4799 LPCWSTR desc, driver;
4800 WORD request = ODBC_ADD_SYS_DSN;
4803 UINT r = ERROR_SUCCESS;
4805 static const WCHAR attrs_fmt[] = {
4806 'D','S','N','=','%','s',0 };
4808 desc = MSI_RecordGetString(rec, 3);
4809 driver = MSI_RecordGetString(rec, 4);
4810 registration = MSI_RecordGetInteger(rec, 5);
4812 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4813 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4815 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4816 attrs = msi_alloc(len * sizeof(WCHAR));
4818 return ERROR_OUTOFMEMORY;
4820 sprintfW(attrs, attrs_fmt, desc);
4821 attrs[len - 1] = '\0';
4823 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4825 ERR("Failed to install SQL data source!\n");
4826 r = ERROR_FUNCTION_FAILED;
4834 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4839 static const WCHAR driver_query[] = {
4840 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4841 'O','D','B','C','D','r','i','v','e','r',0 };
4843 static const WCHAR translator_query[] = {
4844 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4845 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4847 static const WCHAR source_query[] = {
4848 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4849 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4851 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4852 if (rc != ERROR_SUCCESS)
4853 return ERROR_SUCCESS;
4855 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4856 msiobj_release(&view->hdr);
4858 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4859 if (rc != ERROR_SUCCESS)
4860 return ERROR_SUCCESS;
4862 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4863 msiobj_release(&view->hdr);
4865 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4866 if (rc != ERROR_SUCCESS)
4867 return ERROR_SUCCESS;
4869 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4870 msiobj_release(&view->hdr);
4875 #define ENV_ACT_SETALWAYS 0x1
4876 #define ENV_ACT_SETABSENT 0x2
4877 #define ENV_ACT_REMOVE 0x4
4878 #define ENV_ACT_REMOVEMATCH 0x8
4880 #define ENV_MOD_MACHINE 0x20000000
4881 #define ENV_MOD_APPEND 0x40000000
4882 #define ENV_MOD_PREFIX 0x80000000
4883 #define ENV_MOD_MASK 0xC0000000
4885 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4887 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
4889 LPCWSTR cptr = *name;
4891 static const WCHAR prefix[] = {'[','~',']',0};
4892 static const int prefix_len = 3;
4898 *flags |= ENV_ACT_SETALWAYS;
4899 else if (*cptr == '+')
4900 *flags |= ENV_ACT_SETABSENT;
4901 else if (*cptr == '-')
4902 *flags |= ENV_ACT_REMOVE;
4903 else if (*cptr == '!')
4904 *flags |= ENV_ACT_REMOVEMATCH;
4905 else if (*cptr == '*')
4906 *flags |= ENV_MOD_MACHINE;
4916 ERR("Missing environment variable\n");
4917 return ERROR_FUNCTION_FAILED;
4922 LPCWSTR ptr = *value;
4923 if (!strncmpW(ptr, prefix, prefix_len))
4925 *flags |= ENV_MOD_APPEND;
4926 *value += lstrlenW(prefix);
4928 else if (lstrlenW(*value) >= prefix_len)
4930 ptr += lstrlenW(ptr) - prefix_len;
4931 if (!lstrcmpW(ptr, prefix))
4933 *flags |= ENV_MOD_PREFIX;
4934 /* the "[~]" will be removed by deformat_string */;
4939 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4940 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4941 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4942 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4944 ERR("Invalid flags: %08x\n", *flags);
4945 return ERROR_FUNCTION_FAILED;
4949 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
4951 return ERROR_SUCCESS;
4954 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4956 MSIPACKAGE *package = param;
4957 LPCWSTR name, value;
4958 LPWSTR data = NULL, newval = NULL;
4959 LPWSTR deformatted = NULL, ptr;
4960 DWORD flags, type, size;
4962 HKEY env = NULL, root;
4963 LPCWSTR environment;
4965 static const WCHAR user_env[] =
4966 {'E','n','v','i','r','o','n','m','e','n','t',0};
4967 static const WCHAR machine_env[] =
4968 {'S','y','s','t','e','m','\\',
4969 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4970 'C','o','n','t','r','o','l','\\',
4971 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4972 'E','n','v','i','r','o','n','m','e','n','t',0};
4974 name = MSI_RecordGetString(rec, 2);
4975 value = MSI_RecordGetString(rec, 3);
4977 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
4979 res = env_set_flags(&name, &value, &flags);
4980 if (res != ERROR_SUCCESS)
4983 if (value && !deformat_string(package, value, &deformatted))
4985 res = ERROR_OUTOFMEMORY;
4989 value = deformatted;
4991 if (flags & ENV_MOD_MACHINE)
4993 environment = machine_env;
4994 root = HKEY_LOCAL_MACHINE;
4998 environment = user_env;
4999 root = HKEY_CURRENT_USER;
5002 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5003 KEY_ALL_ACCESS, NULL, &env, NULL);
5004 if (res != ERROR_SUCCESS)
5007 if (flags & ENV_ACT_REMOVE)
5008 FIXME("Not removing environment variable on uninstall!\n");
5011 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5012 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5013 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5016 if (res != ERROR_FILE_NOT_FOUND)
5018 if (flags & ENV_ACT_SETABSENT)
5020 res = ERROR_SUCCESS;
5024 data = msi_alloc(size);
5028 return ERROR_OUTOFMEMORY;
5031 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5032 if (res != ERROR_SUCCESS)
5035 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5037 res = RegDeleteKeyW(env, name);
5041 size += (lstrlenW(value) + 1) * sizeof(WCHAR);
5042 newval = msi_alloc(size);
5046 res = ERROR_OUTOFMEMORY;
5050 if (!(flags & ENV_MOD_MASK))
5051 lstrcpyW(newval, value);
5054 if (flags & ENV_MOD_PREFIX)
5056 lstrcpyW(newval, value);
5057 lstrcatW(newval, szSemiColon);
5058 ptr = newval + lstrlenW(value) + 1;
5061 lstrcpyW(ptr, data);
5063 if (flags & ENV_MOD_APPEND)
5065 lstrcatW(newval, szSemiColon);
5066 lstrcatW(newval, value);
5072 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5073 newval = msi_alloc(size);
5076 res = ERROR_OUTOFMEMORY;
5080 lstrcpyW(newval, value);
5085 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5086 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5089 res = ERROR_SUCCESS;
5092 if (env) RegCloseKey(env);
5093 msi_free(deformatted);
5099 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5103 static const WCHAR ExecSeqQuery[] =
5104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5105 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5106 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5107 if (rc != ERROR_SUCCESS)
5108 return ERROR_SUCCESS;
5110 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5111 msiobj_release(&view->hdr);
5116 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5127 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5131 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5132 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5134 WARN("Source or dest is directory, not moving\n");
5138 if (options == msidbMoveFileOptionsMove)
5140 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5141 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5144 WARN("MoveFile failed: %d\n", GetLastError());
5150 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5151 ret = CopyFileW(source, dest, FALSE);
5154 WARN("CopyFile failed: %d\n", GetLastError());
5162 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5165 DWORD dirlen, pathlen;
5167 ptr = strrchrW(wildcard, '\\');
5168 dirlen = ptr - wildcard + 1;
5170 pathlen = dirlen + lstrlenW(filename) + 1;
5171 path = msi_alloc(pathlen * sizeof(WCHAR));
5173 lstrcpynW(path, wildcard, dirlen + 1);
5174 lstrcatW(path, filename);
5179 static void free_file_entry(FILE_LIST *file)
5181 msi_free(file->source);
5182 msi_free(file->dest);
5186 static void free_list(FILE_LIST *list)
5188 while (!list_empty(&list->entry))
5190 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5192 list_remove(&file->entry);
5193 free_file_entry(file);
5197 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5199 FILE_LIST *new, *file;
5200 LPWSTR ptr, filename;
5203 new = msi_alloc_zero(sizeof(FILE_LIST));
5207 new->source = strdupW(source);
5208 ptr = strrchrW(dest, '\\') + 1;
5209 filename = strrchrW(new->source, '\\') + 1;
5211 new->sourcename = filename;
5214 new->destname = ptr;
5216 new->destname = new->sourcename;
5218 size = (ptr - dest) + lstrlenW(filename) + 1;
5219 new->dest = msi_alloc(size * sizeof(WCHAR));
5222 free_file_entry(new);
5226 lstrcpynW(new->dest, dest, ptr - dest + 1);
5227 lstrcatW(new->dest, filename);
5229 if (list_empty(&files->entry))
5231 list_add_head(&files->entry, &new->entry);
5235 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5237 if (lstrcmpW(source, file->source) < 0)
5239 list_add_before(&file->entry, &new->entry);
5244 list_add_after(&file->entry, &new->entry);
5248 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5250 WIN32_FIND_DATAW wfd;
5254 FILE_LIST files, *file;
5257 hfile = FindFirstFileW(source, &wfd);
5258 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5260 list_init(&files.entry);
5262 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5264 if (is_dot_dir(wfd.cFileName)) continue;
5266 path = wildcard_to_file(source, wfd.cFileName);
5273 add_wildcard(&files, path, dest);
5277 /* no files match the wildcard */
5278 if (list_empty(&files.entry))
5281 /* only the first wildcard match gets renamed to dest */
5282 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5283 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5284 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5291 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5293 while (!list_empty(&files.entry))
5295 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5297 msi_move_file(file->source, file->dest, options);
5299 list_remove(&file->entry);
5300 free_file_entry(file);
5311 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5313 MSIPACKAGE *package = param;
5316 LPWSTR destname = NULL;
5317 LPWSTR sourcedir = NULL, destdir = NULL;
5318 LPWSTR source = NULL, dest = NULL;
5321 BOOL ret, wildcards;
5323 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5324 if (!comp || !comp->Enabled ||
5325 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5327 TRACE("Component not set for install, not moving file\n");
5328 return ERROR_SUCCESS;
5331 sourcename = MSI_RecordGetString(rec, 3);
5332 options = MSI_RecordGetInteger(rec, 7);
5334 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5338 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5344 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5347 source = strdupW(sourcedir);
5353 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5354 source = msi_alloc(size * sizeof(WCHAR));
5358 lstrcpyW(source, sourcedir);
5359 if (source[lstrlenW(source) - 1] != '\\')
5360 lstrcatW(source, szBackSlash);
5361 lstrcatW(source, sourcename);
5364 wildcards = strchrW(source, '*') || strchrW(source, '?');
5366 if (MSI_RecordIsNull(rec, 4))
5370 destname = strdupW(sourcename);
5377 destname = strdupW(MSI_RecordGetString(rec, 4));
5379 reduce_to_longfilename(destname);
5384 size = lstrlenW(destname);
5386 size += lstrlenW(destdir) + 2;
5387 dest = msi_alloc(size * sizeof(WCHAR));
5391 lstrcpyW(dest, destdir);
5392 if (dest[lstrlenW(dest) - 1] != '\\')
5393 lstrcatW(dest, szBackSlash);
5396 lstrcatW(dest, destname);
5398 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5400 ret = CreateDirectoryW(destdir, NULL);
5403 WARN("CreateDirectory failed: %d\n", GetLastError());
5404 return ERROR_SUCCESS;
5409 msi_move_file(source, dest, options);
5411 move_files_wildcard(source, dest, options);
5414 msi_free(sourcedir);
5420 return ERROR_SUCCESS;
5423 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5428 static const WCHAR ExecSeqQuery[] =
5429 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5430 '`','M','o','v','e','F','i','l','e','`',0};
5432 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5433 if (rc != ERROR_SUCCESS)
5434 return ERROR_SUCCESS;
5436 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5437 msiobj_release(&view->hdr);
5442 typedef struct tagMSIASSEMBLY
5445 MSICOMPONENT *component;
5446 MSIFEATURE *feature;
5454 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5456 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5457 LPVOID pvReserved, HMODULE *phModDll);
5459 static BOOL init_functionpointers(void)
5465 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5467 hmscoree = LoadLibraryA("mscoree.dll");
5470 WARN("mscoree.dll not available\n");
5474 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5475 if (!pLoadLibraryShim)
5477 WARN("LoadLibraryShim not available\n");
5478 FreeLibrary(hmscoree);
5482 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5485 WARN("fusion.dll not available\n");
5486 FreeLibrary(hmscoree);
5490 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5492 FreeLibrary(hmscoree);
5496 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5499 IAssemblyCache *cache;
5501 UINT r = ERROR_FUNCTION_FAILED;
5503 TRACE("installing assembly: %s\n", debugstr_w(path));
5505 if (assembly->feature)
5506 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5508 if (assembly->manifest)
5509 FIXME("Manifest unhandled\n");
5511 if (assembly->application)
5513 FIXME("Assembly should be privately installed\n");
5514 return ERROR_SUCCESS;
5517 if (assembly->attributes == msidbAssemblyAttributesWin32)
5519 FIXME("Win32 assemblies not handled\n");
5520 return ERROR_SUCCESS;
5523 hr = pCreateAssemblyCache(&cache, 0);
5527 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5529 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5534 IAssemblyCache_Release(cache);
5538 typedef struct tagASSEMBLY_LIST
5540 MSIPACKAGE *package;
5541 IAssemblyCache *cache;
5542 struct list *assemblies;
5545 typedef struct tagASSEMBLY_NAME
5553 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5555 ASSEMBLY_NAME *asmname = param;
5556 LPCWSTR name = MSI_RecordGetString(rec, 2);
5557 LPWSTR val = msi_dup_record_field(rec, 3);
5559 static const WCHAR Name[] = {'N','a','m','e',0};
5560 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5561 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5562 static const WCHAR PublicKeyToken[] = {
5563 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5565 if (!strcmpiW(name, Name))
5566 asmname->name = val;
5567 else if (!strcmpiW(name, Version))
5568 asmname->version = val;
5569 else if (!strcmpiW(name, Culture))
5570 asmname->culture = val;
5571 else if (!strcmpiW(name, PublicKeyToken))
5572 asmname->pubkeytoken = val;
5576 return ERROR_SUCCESS;
5579 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5583 *size = lstrlenW(append) + 1;
5584 *str = msi_alloc((*size) * sizeof(WCHAR));
5585 lstrcpyW(*str, append);
5589 (*size) += lstrlenW(append);
5590 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5591 lstrcatW(*str, append);
5594 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5597 ASSEMBLY_INFO asminfo;
5605 static const WCHAR separator[] = {',',' ',0};
5606 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5607 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5608 static const WCHAR PublicKeyToken[] = {
5609 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5610 static const WCHAR query[] = {
5611 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5612 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5613 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5614 '=','\'','%','s','\'',0};
5618 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5619 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5621 r = MSI_OpenQuery(db, &view, query, comp->Component);
5622 if (r != ERROR_SUCCESS)
5623 return ERROR_SUCCESS;
5625 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5626 msiobj_release(&view->hdr);
5630 ERR("No assembly name specified!\n");
5634 append_str(&disp, &size, name.name);
5638 append_str(&disp, &size, separator);
5639 append_str(&disp, &size, Version);
5640 append_str(&disp, &size, name.version);
5645 append_str(&disp, &size, separator);
5646 append_str(&disp, &size, Culture);
5647 append_str(&disp, &size, name.culture);
5650 if (name.pubkeytoken)
5652 append_str(&disp, &size, separator);
5653 append_str(&disp, &size, PublicKeyToken);
5654 append_str(&disp, &size, name.pubkeytoken);
5657 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5658 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5660 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5664 msi_free(name.name);
5665 msi_free(name.version);
5666 msi_free(name.culture);
5667 msi_free(name.pubkeytoken);
5672 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5674 ASSEMBLY_LIST *list = param;
5675 MSIASSEMBLY *assembly;
5677 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5679 return ERROR_OUTOFMEMORY;
5681 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5683 if (!assembly->component || !assembly->component->Enabled ||
5684 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5686 TRACE("Component not set for install, not publishing assembly\n");
5688 return ERROR_SUCCESS;
5691 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
5692 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
5694 if (!assembly->file)
5696 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
5697 return ERROR_FUNCTION_FAILED;
5700 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
5701 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
5702 assembly->attributes = MSI_RecordGetInteger(rec, 5);
5704 if (assembly->application)
5707 DWORD size = sizeof(version)/sizeof(WCHAR);
5709 /* FIXME: we should probably check the manifest file here */
5711 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
5712 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
5714 assembly->installed = TRUE;
5718 assembly->installed = check_assembly_installed(list->package->db,
5720 assembly->component);
5722 list_add_head(list->assemblies, &assembly->entry);
5723 return ERROR_SUCCESS;
5726 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
5728 IAssemblyCache *cache = NULL;
5734 static const WCHAR query[] =
5735 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5736 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5738 r = MSI_DatabaseOpenViewW(package->db, query, &view);
5739 if (r != ERROR_SUCCESS)
5740 return ERROR_SUCCESS;
5742 hr = pCreateAssemblyCache(&cache, 0);
5744 return ERROR_FUNCTION_FAILED;
5746 list.package = package;
5748 list.assemblies = assemblies;
5750 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
5751 msiobj_release(&view->hdr);
5753 IAssemblyCache_Release(cache);
5758 static void free_assemblies(struct list *assemblies)
5760 struct list *item, *cursor;
5762 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
5764 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
5766 list_remove(&assembly->entry);
5767 msi_free(assembly->application);
5768 msi_free(assembly->manifest);
5773 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
5775 MSIASSEMBLY *assembly;
5777 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
5779 if (!lstrcmpW(assembly->file->File, file))
5789 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
5790 LPWSTR *path, DWORD *attrs, PVOID user)
5792 MSIASSEMBLY *assembly;
5793 WCHAR temppath[MAX_PATH];
5794 struct list *assemblies = user;
5797 if (!find_assembly(assemblies, file, &assembly))
5800 GetTempPathW(MAX_PATH, temppath);
5801 PathAddBackslashW(temppath);
5802 lstrcatW(temppath, assembly->file->FileName);
5804 if (action == MSICABEXTRACT_BEGINEXTRACT)
5806 if (assembly->installed)
5809 *path = strdupW(temppath);
5810 *attrs = assembly->file->Attributes;
5812 else if (action == MSICABEXTRACT_FILEEXTRACTED)
5814 assembly->installed = TRUE;
5816 r = install_assembly(package, assembly, temppath);
5817 if (r != ERROR_SUCCESS)
5818 ERR("Failed to install assembly\n");
5824 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5827 struct list assemblies = LIST_INIT(assemblies);
5828 MSIASSEMBLY *assembly;
5831 if (!init_functionpointers() || !pCreateAssemblyCache)
5832 return ERROR_FUNCTION_FAILED;
5834 r = load_assemblies(package, &assemblies);
5835 if (r != ERROR_SUCCESS)
5838 if (list_empty(&assemblies))
5841 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
5844 r = ERROR_OUTOFMEMORY;
5848 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
5850 if (assembly->installed && !mi->is_continuous)
5853 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
5854 (assembly->file->IsCompressed && !mi->is_extracted))
5858 r = ready_media(package, assembly->file, mi);
5859 if (r != ERROR_SUCCESS)
5861 ERR("Failed to ready media\n");
5866 data.package = package;
5867 data.cb = installassembly_cb;
5868 data.user = &assemblies;
5870 if (assembly->file->IsCompressed &&
5871 !msi_cabextract(package, mi, &data))
5873 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
5874 r = ERROR_FUNCTION_FAILED;
5879 if (!assembly->file->IsCompressed)
5881 LPWSTR source = resolve_file_source(package, assembly->file);
5883 r = install_assembly(package, assembly, source);
5884 if (r != ERROR_SUCCESS)
5885 ERR("Failed to install assembly\n");
5890 /* FIXME: write Installer assembly reg values */
5894 free_assemblies(&assemblies);
5898 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5899 LPCSTR action, LPCWSTR table )
5901 static const WCHAR query[] = {
5902 'S','E','L','E','C','T',' ','*',' ',
5903 'F','R','O','M',' ','`','%','s','`',0 };
5904 MSIQUERY *view = NULL;
5908 r = MSI_OpenQuery( package->db, &view, query, table );
5909 if (r == ERROR_SUCCESS)
5911 r = MSI_IterateRecords(view, &count, NULL, package);
5912 msiobj_release(&view->hdr);
5916 FIXME("%s -> %u ignored %s table values\n",
5917 action, count, debugstr_w(table));
5919 return ERROR_SUCCESS;
5922 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5924 TRACE("%p\n", package);
5925 return ERROR_SUCCESS;
5928 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5930 static const WCHAR table[] =
5931 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5932 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5935 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5937 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5938 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5941 static UINT ACTION_BindImage( MSIPACKAGE *package )
5943 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5944 return msi_unimplemented_action_stub( package, "BindImage", table );
5947 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5949 static const WCHAR table[] = {
5950 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5951 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5954 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5956 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5957 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5960 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5962 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5963 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5966 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5968 static const WCHAR table[] = {
5969 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5970 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5972 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5974 static const WCHAR table[] = {
5975 'P','r','o','d','u','c','t','I','D',0 };
5976 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5979 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5981 static const WCHAR table[] = {
5982 'E','n','v','i','r','o','n','m','e','n','t',0 };
5983 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5986 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5988 static const WCHAR table[] = {
5989 'M','s','i','A','s','s','e','m','b','l','y',0 };
5990 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5993 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5995 static const WCHAR table[] = { 'F','o','n','t',0 };
5996 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5999 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6001 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6002 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6005 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6007 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6008 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6011 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6013 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6014 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6017 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6019 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6020 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6023 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6025 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6026 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6029 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6031 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6032 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6035 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6037 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6038 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6041 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6043 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6044 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6047 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6049 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6050 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6053 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6055 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6056 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6059 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6061 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6062 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6065 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6067 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6068 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6071 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6073 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6074 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6077 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6079 static const WCHAR table[] = { 'M','I','M','E',0 };
6080 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6083 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6085 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6086 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6089 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6091 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6092 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6095 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6099 const WCHAR *action;
6100 UINT (*handler)(MSIPACKAGE *);
6104 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6105 { szAppSearch, ACTION_AppSearch },
6106 { szBindImage, ACTION_BindImage },
6107 { szCCPSearch, ACTION_CCPSearch },
6108 { szCostFinalize, ACTION_CostFinalize },
6109 { szCostInitialize, ACTION_CostInitialize },
6110 { szCreateFolders, ACTION_CreateFolders },
6111 { szCreateShortcuts, ACTION_CreateShortcuts },
6112 { szDeleteServices, ACTION_DeleteServices },
6113 { szDisableRollback, NULL },
6114 { szDuplicateFiles, ACTION_DuplicateFiles },
6115 { szExecuteAction, ACTION_ExecuteAction },
6116 { szFileCost, ACTION_FileCost },
6117 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6118 { szForceReboot, ACTION_ForceReboot },
6119 { szInstallAdminPackage, NULL },
6120 { szInstallExecute, ACTION_InstallExecute },
6121 { szInstallExecuteAgain, ACTION_InstallExecute },
6122 { szInstallFiles, ACTION_InstallFiles},
6123 { szInstallFinalize, ACTION_InstallFinalize },
6124 { szInstallInitialize, ACTION_InstallInitialize },
6125 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6126 { szInstallValidate, ACTION_InstallValidate },
6127 { szIsolateComponents, ACTION_IsolateComponents },
6128 { szLaunchConditions, ACTION_LaunchConditions },
6129 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6130 { szMoveFiles, ACTION_MoveFiles },
6131 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6132 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6133 { szInstallODBC, ACTION_InstallODBC },
6134 { szInstallServices, ACTION_InstallServices },
6135 { szPatchFiles, ACTION_PatchFiles },
6136 { szProcessComponents, ACTION_ProcessComponents },
6137 { szPublishComponents, ACTION_PublishComponents },
6138 { szPublishFeatures, ACTION_PublishFeatures },
6139 { szPublishProduct, ACTION_PublishProduct },
6140 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6141 { szRegisterComPlus, ACTION_RegisterComPlus},
6142 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6143 { szRegisterFonts, ACTION_RegisterFonts },
6144 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6145 { szRegisterProduct, ACTION_RegisterProduct },
6146 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6147 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6148 { szRegisterUser, ACTION_RegisterUser },
6149 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6150 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6151 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6152 { szRemoveFiles, ACTION_RemoveFiles },
6153 { szRemoveFolders, ACTION_RemoveFolders },
6154 { szRemoveIniValues, ACTION_RemoveIniValues },
6155 { szRemoveODBC, ACTION_RemoveODBC },
6156 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6157 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6158 { szResolveSource, ACTION_ResolveSource },
6159 { szRMCCPSearch, ACTION_RMCCPSearch },
6160 { szScheduleReboot, NULL },
6161 { szSelfRegModules, ACTION_SelfRegModules },
6162 { szSelfUnregModules, ACTION_SelfUnregModules },
6163 { szSetODBCFolders, NULL },
6164 { szStartServices, ACTION_StartServices },
6165 { szStopServices, ACTION_StopServices },
6166 { szUnpublishComponents, ACTION_UnpublishComponents },
6167 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6168 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6169 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6170 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6171 { szUnregisterFonts, ACTION_UnregisterFonts },
6172 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6173 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6174 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6175 { szValidateProductID, ACTION_ValidateProductID },
6176 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6177 { szWriteIniValues, ACTION_WriteIniValues },
6178 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6182 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6183 UINT* rc, BOOL force )
6189 if (!run && !package->script->CurrentlyScripting)
6194 if (strcmpW(action,szInstallFinalize) == 0 ||
6195 strcmpW(action,szInstallExecute) == 0 ||
6196 strcmpW(action,szInstallExecuteAgain) == 0)
6201 while (StandardActions[i].action != NULL)
6203 if (strcmpW(StandardActions[i].action, action)==0)
6207 ui_actioninfo(package, action, TRUE, 0);
6208 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6209 ui_actioninfo(package, action, FALSE, *rc);
6213 ui_actionstart(package, action);
6214 if (StandardActions[i].handler)
6216 *rc = StandardActions[i].handler(package);
6220 FIXME("unhandled standard action %s\n",debugstr_w(action));
6221 *rc = ERROR_SUCCESS;
6232 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
6234 UINT rc = ERROR_SUCCESS;
6237 TRACE("Performing action (%s)\n", debugstr_w(action));
6239 handled = ACTION_HandleStandardAction(package, action, &rc, force);
6242 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
6246 WARN("unhandled msi action %s\n", debugstr_w(action));
6247 rc = ERROR_FUNCTION_NOT_CALLED;
6253 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
6255 UINT rc = ERROR_SUCCESS;
6256 BOOL handled = FALSE;
6258 TRACE("Performing action (%s)\n", debugstr_w(action));
6260 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
6263 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
6265 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
6270 WARN("unhandled msi action %s\n", debugstr_w(action));
6271 rc = ERROR_FUNCTION_NOT_CALLED;
6277 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
6279 UINT rc = ERROR_SUCCESS;
6282 static const WCHAR ExecSeqQuery[] =
6283 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6284 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6285 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6286 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6287 static const WCHAR UISeqQuery[] =
6288 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6289 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6290 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6291 ' ', '=',' ','%','i',0};
6293 if (needs_ui_sequence(package))
6294 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
6296 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
6300 LPCWSTR action, cond;
6302 TRACE("Running the actions\n");
6304 /* check conditions */
6305 cond = MSI_RecordGetString(row, 2);
6307 /* this is a hack to skip errors in the condition code */
6308 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
6310 msiobj_release(&row->hdr);
6311 return ERROR_SUCCESS;
6314 action = MSI_RecordGetString(row, 1);
6317 ERR("failed to fetch action\n");
6318 msiobj_release(&row->hdr);
6319 return ERROR_FUNCTION_FAILED;
6322 if (needs_ui_sequence(package))
6323 rc = ACTION_PerformUIAction(package, action, -1);
6325 rc = ACTION_PerformAction(package, action, -1, FALSE);
6327 msiobj_release(&row->hdr);
6333 /****************************************************
6334 * TOP level entry points
6335 *****************************************************/
6337 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
6338 LPCWSTR szCommandLine )
6343 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
6344 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
6346 MSI_SetPropertyW(package, szAction, szInstall);
6348 package->script->InWhatSequence = SEQUENCE_INSTALL;
6355 dir = strdupW(szPackagePath);
6356 p = strrchrW(dir, '\\');
6360 file = szPackagePath + (p - dir);
6365 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
6366 GetCurrentDirectoryW(MAX_PATH, dir);
6367 lstrcatW(dir, szBackSlash);
6368 file = szPackagePath;
6371 msi_free( package->PackagePath );
6372 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
6373 if (!package->PackagePath)
6376 return ERROR_OUTOFMEMORY;
6379 lstrcpyW(package->PackagePath, dir);
6380 lstrcatW(package->PackagePath, file);
6383 msi_set_sourcedir_props(package, FALSE);
6386 msi_parse_command_line( package, szCommandLine, FALSE );
6388 msi_apply_transforms( package );
6389 msi_apply_patches( package );
6391 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
6393 TRACE("setting reinstall property\n");
6394 MSI_SetPropertyW( package, szReinstall, szAll );
6397 /* properties may have been added by a transform */
6398 msi_clone_properties( package );
6399 msi_set_context( package );
6401 if (needs_ui_sequence( package))
6403 package->script->InWhatSequence |= SEQUENCE_UI;
6404 rc = ACTION_ProcessUISequence(package);
6405 ui_exists = ui_sequence_exists(package);
6406 if (rc == ERROR_SUCCESS || !ui_exists)
6408 package->script->InWhatSequence |= SEQUENCE_EXEC;
6409 rc = ACTION_ProcessExecSequence(package, ui_exists);
6413 rc = ACTION_ProcessExecSequence(package, FALSE);
6415 package->script->CurrentlyScripting = FALSE;
6417 /* process the ending type action */
6418 if (rc == ERROR_SUCCESS)
6419 ACTION_PerformActionSequence(package, -1);
6420 else if (rc == ERROR_INSTALL_USEREXIT)
6421 ACTION_PerformActionSequence(package, -2);
6422 else if (rc == ERROR_INSTALL_SUSPEND)
6423 ACTION_PerformActionSequence(package, -4);
6425 ACTION_PerformActionSequence(package, -3);
6427 /* finish up running custom actions */
6428 ACTION_FinishCustomActions(package);
6430 if (rc == ERROR_SUCCESS && package->need_reboot)
6431 return ERROR_SUCCESS_REBOOT_REQUIRED;