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 szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterFonts[] =
128 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
129 static const WCHAR szRegisterUser[] =
130 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
131 static const WCHAR szRemoveEnvironmentStrings[] =
132 {'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};
133 static const WCHAR szRemoveExistingProducts[] =
134 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
135 static const WCHAR szRemoveFolders[] =
136 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
137 static const WCHAR szRemoveIniValues[] =
138 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
139 static const WCHAR szRemoveODBC[] =
140 {'R','e','m','o','v','e','O','D','B','C',0};
141 static const WCHAR szRemoveRegistryValues[] =
142 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
143 static const WCHAR szRemoveShortcuts[] =
144 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
145 static const WCHAR szRMCCPSearch[] =
146 {'R','M','C','C','P','S','e','a','r','c','h',0};
147 static const WCHAR szScheduleReboot[] =
148 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
149 static const WCHAR szSelfUnregModules[] =
150 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
151 static const WCHAR szSetODBCFolders[] =
152 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
153 static const WCHAR szStartServices[] =
154 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szStopServices[] =
156 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szUnpublishComponents[] =
158 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szUnpublishFeatures[] =
160 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
161 static const WCHAR szUnregisterClassInfo[] =
162 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
163 static const WCHAR szUnregisterComPlus[] =
164 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
165 static const WCHAR szUnregisterExtensionInfo[] =
166 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
167 static const WCHAR szUnregisterFonts[] =
168 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 static const WCHAR szUnregisterMIMEInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szUnregisterProgIdInfo[] =
172 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
173 static const WCHAR szUnregisterTypeLibraries[] =
174 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
175 static const WCHAR szValidateProductID[] =
176 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
177 static const WCHAR szWriteEnvironmentStrings[] =
178 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
180 /********************************************************
182 ********************************************************/
184 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
186 static const WCHAR Query_t[] =
187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
188 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
189 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
190 ' ','\'','%','s','\'',0};
193 row = MSI_QueryGetRecord( package->db, Query_t, action );
196 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
197 msiobj_release(&row->hdr);
200 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
204 static const WCHAR template_s[]=
205 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
207 static const WCHAR template_e[]=
208 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
209 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
211 static const WCHAR format[] =
212 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
216 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
218 sprintfW(message,template_s,timet,action);
220 sprintfW(message,template_e,timet,action,rc);
222 row = MSI_CreateRecord(1);
223 MSI_RecordSetStringW(row,1,message);
225 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
226 msiobj_release(&row->hdr);
229 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
235 LPWSTR prop = NULL, val = NULL;
238 return ERROR_SUCCESS;
250 TRACE("Looking at %s\n",debugstr_w(ptr));
252 ptr2 = strchrW(ptr,'=');
255 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
262 prop = msi_alloc((len+1)*sizeof(WCHAR));
263 memcpy(prop,ptr,len*sizeof(WCHAR));
273 while (*ptr && (quote || (!quote && *ptr!=' ')))
286 val = msi_alloc((len+1)*sizeof(WCHAR));
287 memcpy(val,ptr2,len*sizeof(WCHAR));
290 if (lstrlenW(prop) > 0)
292 TRACE("Found commandline property (%s) = (%s)\n",
293 debugstr_w(prop), debugstr_w(val));
294 MSI_SetPropertyW(package,prop,val);
300 return ERROR_SUCCESS;
304 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
307 LPWSTR p, *ret = NULL;
313 /* count the number of substrings */
314 for ( pc = str, count = 0; pc; count++ )
316 pc = strchrW( pc, sep );
321 /* allocate space for an array of substring pointers and the substrings */
322 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
323 (lstrlenW(str)+1) * sizeof(WCHAR) );
327 /* copy the string and set the pointers */
328 p = (LPWSTR) &ret[count+1];
330 for( count = 0; (ret[count] = p); count++ )
332 p = strchrW( p, sep );
340 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
342 static const WCHAR szSystemLanguageID[] =
343 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
345 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
346 UINT ret = ERROR_FUNCTION_FAILED;
348 prod_code = msi_dup_property( package, szProductCode );
349 patch_product = msi_get_suminfo_product( patch );
351 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
353 if ( strstrW( patch_product, prod_code ) )
358 si = MSI_GetSummaryInformationW( patch, 0 );
361 ERR("no summary information!\n");
365 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
368 ERR("no template property!\n");
369 msiobj_release( &si->hdr );
376 msiobj_release( &si->hdr );
380 langid = msi_dup_property( package, szSystemLanguageID );
383 msiobj_release( &si->hdr );
387 p = strchrW( template, ';' );
388 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
390 TRACE("applicable transform\n");
394 /* FIXME: check platform */
396 msiobj_release( &si->hdr );
400 msi_free( patch_product );
401 msi_free( prod_code );
402 msi_free( template );
408 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
415 TRACE("%p %s\n", package, debugstr_w(name) );
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
426 ret = msi_check_transform_applicable( package, stg );
427 if (ret == ERROR_SUCCESS)
428 msi_table_apply_transform( package->db, stg );
430 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
431 IStorage_Release( stg );
434 ERR("failed to open substorage %s\n", debugstr_w(name));
436 return ERROR_SUCCESS;
439 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
441 LPWSTR guid_list, *guids, product_code;
442 UINT i, ret = ERROR_FUNCTION_FAILED;
444 product_code = msi_dup_property( package, szProductCode );
447 /* FIXME: the property ProductCode should be written into the DB somewhere */
448 ERR("no product code to check\n");
449 return ERROR_SUCCESS;
452 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
453 guids = msi_split_string( guid_list, ';' );
454 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
456 if (!lstrcmpW( guids[i], product_code ))
460 msi_free( guid_list );
461 msi_free( product_code );
466 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
469 MSIRECORD *rec = NULL;
474 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
475 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
476 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
477 '`','S','o','u','r','c','e','`',' ','I','S',' ',
478 'N','O','T',' ','N','U','L','L',0};
480 r = MSI_DatabaseOpenViewW(package->db, query, &view);
481 if (r != ERROR_SUCCESS)
484 r = MSI_ViewExecute(view, 0);
485 if (r != ERROR_SUCCESS)
488 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
490 prop = MSI_RecordGetString(rec, 1);
491 patch = msi_dup_property(package, szPatch);
492 MSI_SetPropertyW(package, prop, patch);
497 if (rec) msiobj_release(&rec->hdr);
498 msiobj_release(&view->hdr);
503 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
506 LPWSTR str, *substorage;
507 UINT i, r = ERROR_SUCCESS;
509 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
511 return ERROR_FUNCTION_FAILED;
513 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
515 TRACE("Patch not applicable\n");
516 return ERROR_SUCCESS;
519 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
521 return ERROR_OUTOFMEMORY;
523 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
524 if (!package->patch->patchcode)
525 return ERROR_OUTOFMEMORY;
527 /* enumerate the substorage */
528 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
529 package->patch->transforms = str;
531 substorage = msi_split_string( str, ';' );
532 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
533 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
535 msi_free( substorage );
536 msiobj_release( &si->hdr );
538 msi_set_media_source_prop(package);
543 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
545 MSIDATABASE *patch_db = NULL;
548 TRACE("%p %s\n", package, debugstr_w( file ) );
551 * We probably want to make sure we only open a patch collection here.
552 * Patch collections (.msp) and databases (.msi) have different GUIDs
553 * but currently MSI_OpenDatabaseW will accept both.
555 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
556 if ( r != ERROR_SUCCESS )
558 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
562 msi_parse_patch_summary( package, patch_db );
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storage to search for streams.
568 append_storage_to_db( package->db, patch_db->storage );
570 msiobj_release( &patch_db->hdr );
572 return ERROR_SUCCESS;
575 /* get the PATCH property, and apply all the patches it specifies */
576 static UINT msi_apply_patches( MSIPACKAGE *package )
578 LPWSTR patch_list, *patches;
579 UINT i, r = ERROR_SUCCESS;
581 patch_list = msi_dup_property( package, szPatch );
583 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
585 patches = msi_split_string( patch_list, ';' );
586 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
587 r = msi_apply_patch_package( package, patches[i] );
590 msi_free( patch_list );
595 static UINT msi_apply_transforms( MSIPACKAGE *package )
597 static const WCHAR szTransforms[] = {
598 'T','R','A','N','S','F','O','R','M','S',0 };
599 LPWSTR xform_list, *xforms;
600 UINT i, r = ERROR_SUCCESS;
602 xform_list = msi_dup_property( package, szTransforms );
603 xforms = msi_split_string( xform_list, ';' );
605 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
607 if (xforms[i][0] == ':')
608 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
610 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
614 msi_free( xform_list );
619 static BOOL ui_sequence_exists( MSIPACKAGE *package )
624 static const WCHAR ExecSeqQuery [] =
625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
626 '`','I','n','s','t','a','l','l',
627 'U','I','S','e','q','u','e','n','c','e','`',
628 ' ','W','H','E','R','E',' ',
629 '`','S','e','q','u','e','n','c','e','`',' ',
630 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
631 '`','S','e','q','u','e','n','c','e','`',0};
633 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
634 if (rc == ERROR_SUCCESS)
636 msiobj_release(&view->hdr);
643 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
646 LPWSTR source, check;
649 static const WCHAR szOriginalDatabase[] =
650 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
652 db = msi_dup_property( package, szOriginalDatabase );
654 return ERROR_OUTOFMEMORY;
656 p = strrchrW( db, '\\' );
659 p = strrchrW( db, '/' );
663 return ERROR_SUCCESS;
668 source = msi_alloc( len * sizeof(WCHAR) );
669 lstrcpynW( source, db, len );
671 check = msi_dup_property( package, cszSourceDir );
672 if (!check || replace)
673 MSI_SetPropertyW( package, cszSourceDir, source );
677 check = msi_dup_property( package, cszSOURCEDIR );
678 if (!check || replace)
679 MSI_SetPropertyW( package, cszSOURCEDIR, source );
685 return ERROR_SUCCESS;
688 static BOOL needs_ui_sequence(MSIPACKAGE *package)
690 INT level = msi_get_property_int(package, szUILevel, 0);
691 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
694 static UINT msi_set_context(MSIPACKAGE *package)
701 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
703 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
704 if (r == ERROR_SUCCESS)
707 if (num == 1 || num == 2)
708 package->Context = MSIINSTALLCONTEXT_MACHINE;
711 return ERROR_SUCCESS;
714 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
717 LPCWSTR cond, action;
718 MSIPACKAGE *package = param;
720 action = MSI_RecordGetString(row,1);
723 ERR("Error is retrieving action name\n");
724 return ERROR_FUNCTION_FAILED;
727 /* check conditions */
728 cond = MSI_RecordGetString(row,2);
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
733 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
734 return ERROR_SUCCESS;
737 if (needs_ui_sequence(package))
738 rc = ACTION_PerformUIAction(package, action, -1);
740 rc = ACTION_PerformAction(package, action, -1, FALSE);
742 msi_dialog_check_messages( NULL );
744 if (package->CurrentInstallState != ERROR_SUCCESS)
745 rc = package->CurrentInstallState;
747 if (rc == ERROR_FUNCTION_NOT_CALLED)
750 if (rc != ERROR_SUCCESS)
751 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
756 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
760 static const WCHAR query[] =
761 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
763 ' ','W','H','E','R','E',' ',
764 '`','S','e','q','u','e','n','c','e','`',' ',
765 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
766 '`','S','e','q','u','e','n','c','e','`',0};
768 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
770 r = MSI_OpenQuery( package->db, &view, query, szTable );
771 if (r == ERROR_SUCCESS)
773 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
774 msiobj_release(&view->hdr);
780 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
784 static const WCHAR ExecSeqQuery[] =
785 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
786 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
787 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
788 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
789 'O','R','D','E','R',' ', 'B','Y',' ',
790 '`','S','e','q','u','e','n','c','e','`',0 };
791 static const WCHAR IVQuery[] =
792 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
793 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
794 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
795 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
796 ' ','\'', 'I','n','s','t','a','l','l',
797 'V','a','l','i','d','a','t','e','\'', 0};
800 if (package->script->ExecuteSequenceRun)
802 TRACE("Execute Sequence already Run\n");
803 return ERROR_SUCCESS;
806 package->script->ExecuteSequenceRun = TRUE;
808 /* get the sequence number */
811 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
813 return ERROR_FUNCTION_FAILED;
814 seq = MSI_RecordGetInteger(row,1);
815 msiobj_release(&row->hdr);
818 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
819 if (rc == ERROR_SUCCESS)
821 TRACE("Running the actions\n");
823 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
824 msiobj_release(&view->hdr);
830 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
834 static const WCHAR ExecSeqQuery [] =
835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
836 '`','I','n','s','t','a','l','l',
837 'U','I','S','e','q','u','e','n','c','e','`',
838 ' ','W','H','E','R','E',' ',
839 '`','S','e','q','u','e','n','c','e','`',' ',
840 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
841 '`','S','e','q','u','e','n','c','e','`',0};
843 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
844 if (rc == ERROR_SUCCESS)
846 TRACE("Running the actions\n");
848 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
849 msiobj_release(&view->hdr);
855 /********************************************************
856 * ACTION helper functions and functions that perform the actions
857 *******************************************************/
858 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
859 UINT* rc, UINT script, BOOL force )
864 arc = ACTION_CustomAction(package, action, script, force);
866 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
875 * Actual Action Handlers
878 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
880 MSIPACKAGE *package = param;
881 LPCWSTR dir, component;
887 component = MSI_RecordGetString(row, 2);
888 comp = get_loaded_component(package, component);
890 return ERROR_SUCCESS;
892 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
894 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
895 comp->Action = comp->Installed;
896 return ERROR_SUCCESS;
898 comp->Action = INSTALLSTATE_LOCAL;
900 dir = MSI_RecordGetString(row,1);
903 ERR("Unable to get folder id\n");
904 return ERROR_SUCCESS;
907 uirow = MSI_CreateRecord(1);
908 MSI_RecordSetStringW(uirow, 1, dir);
909 ui_actiondata(package, szCreateFolders, uirow);
910 msiobj_release(&uirow->hdr);
912 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
915 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
916 return ERROR_SUCCESS;
919 TRACE("Folder is %s\n",debugstr_w(full_path));
921 if (folder->State == 0)
922 create_full_pathW(full_path);
927 return ERROR_SUCCESS;
930 /* FIXME: probably should merge this with the above function */
931 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
933 UINT rc = ERROR_SUCCESS;
937 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
939 return ERROR_FUNCTION_FAILED;
941 /* create the path */
942 if (folder->State == 0)
944 create_full_pathW(install_path);
947 msi_free(install_path);
952 UINT msi_create_component_directories( MSIPACKAGE *package )
956 /* create all the folders required by the components are going to install */
957 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
959 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
961 msi_create_directory( package, comp->Directory );
964 return ERROR_SUCCESS;
967 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
969 static const WCHAR ExecSeqQuery[] =
970 {'S','E','L','E','C','T',' ',
971 '`','D','i','r','e','c','t','o','r','y','_','`',
972 ' ','F','R','O','M',' ',
973 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
977 /* create all the empty folders specified in the CreateFolder table */
978 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
979 if (rc != ERROR_SUCCESS)
980 return ERROR_SUCCESS;
982 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
983 msiobj_release(&view->hdr);
988 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
990 MSIPACKAGE *package = param;
991 LPCWSTR dir, component;
997 component = MSI_RecordGetString(row, 2);
998 comp = get_loaded_component(package, component);
1000 return ERROR_SUCCESS;
1002 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1004 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1005 comp->Action = comp->Installed;
1006 return ERROR_SUCCESS;
1008 comp->Action = INSTALLSTATE_ABSENT;
1010 dir = MSI_RecordGetString( row, 1 );
1013 ERR("Unable to get folder id\n");
1014 return ERROR_SUCCESS;
1017 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1020 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1021 return ERROR_SUCCESS;
1024 TRACE("folder is %s\n", debugstr_w(full_path));
1026 uirow = MSI_CreateRecord( 1 );
1027 MSI_RecordSetStringW( uirow, 1, full_path );
1028 ui_actiondata( package, szRemoveFolders, uirow );
1029 msiobj_release( &uirow->hdr );
1031 RemoveDirectoryW( full_path );
1034 msi_free( full_path );
1035 return ERROR_SUCCESS;
1038 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1040 static const WCHAR query[] =
1041 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1042 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1047 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1048 if (rc != ERROR_SUCCESS)
1049 return ERROR_SUCCESS;
1051 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1052 msiobj_release( &view->hdr );
1057 static UINT load_component( MSIRECORD *row, LPVOID param )
1059 MSIPACKAGE *package = param;
1062 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1064 return ERROR_FUNCTION_FAILED;
1066 list_add_tail( &package->components, &comp->entry );
1068 /* fill in the data */
1069 comp->Component = msi_dup_record_field( row, 1 );
1071 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1073 comp->ComponentId = msi_dup_record_field( row, 2 );
1074 comp->Directory = msi_dup_record_field( row, 3 );
1075 comp->Attributes = MSI_RecordGetInteger(row,4);
1076 comp->Condition = msi_dup_record_field( row, 5 );
1077 comp->KeyPath = msi_dup_record_field( row, 6 );
1079 comp->Installed = INSTALLSTATE_UNKNOWN;
1080 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1082 return ERROR_SUCCESS;
1085 static UINT load_all_components( MSIPACKAGE *package )
1087 static const WCHAR query[] = {
1088 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1089 '`','C','o','m','p','o','n','e','n','t','`',0 };
1093 if (!list_empty(&package->components))
1094 return ERROR_SUCCESS;
1096 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1097 if (r != ERROR_SUCCESS)
1100 r = MSI_IterateRecords(view, NULL, load_component, package);
1101 msiobj_release(&view->hdr);
1106 MSIPACKAGE *package;
1107 MSIFEATURE *feature;
1110 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1114 cl = msi_alloc( sizeof (*cl) );
1116 return ERROR_NOT_ENOUGH_MEMORY;
1117 cl->component = comp;
1118 list_add_tail( &feature->Components, &cl->entry );
1120 return ERROR_SUCCESS;
1123 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1127 fl = msi_alloc( sizeof(*fl) );
1129 return ERROR_NOT_ENOUGH_MEMORY;
1130 fl->feature = child;
1131 list_add_tail( &parent->Children, &fl->entry );
1133 return ERROR_SUCCESS;
1136 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1138 _ilfs* ilfs = param;
1142 component = MSI_RecordGetString(row,1);
1144 /* check to see if the component is already loaded */
1145 comp = get_loaded_component( ilfs->package, component );
1148 ERR("unknown component %s\n", debugstr_w(component));
1149 return ERROR_FUNCTION_FAILED;
1152 add_feature_component( ilfs->feature, comp );
1153 comp->Enabled = TRUE;
1155 return ERROR_SUCCESS;
1158 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1160 MSIFEATURE *feature;
1165 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1167 if ( !lstrcmpW( feature->Feature, name ) )
1174 static UINT load_feature(MSIRECORD * row, LPVOID param)
1176 MSIPACKAGE* package = param;
1177 MSIFEATURE* feature;
1178 static const WCHAR Query1[] =
1179 {'S','E','L','E','C','T',' ',
1180 '`','C','o','m','p','o','n','e','n','t','_','`',
1181 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1182 'C','o','m','p','o','n','e','n','t','s','`',' ',
1183 'W','H','E','R','E',' ',
1184 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1189 /* fill in the data */
1191 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1193 return ERROR_NOT_ENOUGH_MEMORY;
1195 list_init( &feature->Children );
1196 list_init( &feature->Components );
1198 feature->Feature = msi_dup_record_field( row, 1 );
1200 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1202 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1203 feature->Title = msi_dup_record_field( row, 3 );
1204 feature->Description = msi_dup_record_field( row, 4 );
1206 if (!MSI_RecordIsNull(row,5))
1207 feature->Display = MSI_RecordGetInteger(row,5);
1209 feature->Level= MSI_RecordGetInteger(row,6);
1210 feature->Directory = msi_dup_record_field( row, 7 );
1211 feature->Attributes = MSI_RecordGetInteger(row,8);
1213 feature->Installed = INSTALLSTATE_UNKNOWN;
1214 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1216 list_add_tail( &package->features, &feature->entry );
1218 /* load feature components */
1220 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1221 if (rc != ERROR_SUCCESS)
1222 return ERROR_SUCCESS;
1224 ilfs.package = package;
1225 ilfs.feature = feature;
1227 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1228 msiobj_release(&view->hdr);
1230 return ERROR_SUCCESS;
1233 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1235 MSIPACKAGE* package = param;
1236 MSIFEATURE *parent, *child;
1238 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1240 return ERROR_FUNCTION_FAILED;
1242 if (!child->Feature_Parent)
1243 return ERROR_SUCCESS;
1245 parent = find_feature_by_name( package, child->Feature_Parent );
1247 return ERROR_FUNCTION_FAILED;
1249 add_feature_child( parent, child );
1250 return ERROR_SUCCESS;
1253 static UINT load_all_features( MSIPACKAGE *package )
1255 static const WCHAR query[] = {
1256 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1257 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1258 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1262 if (!list_empty(&package->features))
1263 return ERROR_SUCCESS;
1265 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1266 if (r != ERROR_SUCCESS)
1269 r = MSI_IterateRecords( view, NULL, load_feature, package );
1270 if (r != ERROR_SUCCESS)
1273 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1274 msiobj_release( &view->hdr );
1279 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1290 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1292 static const WCHAR query[] = {
1293 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1294 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1295 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1296 MSIQUERY *view = NULL;
1297 MSIRECORD *row = NULL;
1300 TRACE("%s\n", debugstr_w(file->File));
1302 r = MSI_OpenQuery(package->db, &view, query, file->File);
1303 if (r != ERROR_SUCCESS)
1306 r = MSI_ViewExecute(view, NULL);
1307 if (r != ERROR_SUCCESS)
1310 r = MSI_ViewFetch(view, &row);
1311 if (r != ERROR_SUCCESS)
1314 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1315 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1316 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1317 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1318 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1321 if (view) msiobj_release(&view->hdr);
1322 if (row) msiobj_release(&row->hdr);
1326 static UINT load_file(MSIRECORD *row, LPVOID param)
1328 MSIPACKAGE* package = param;
1332 /* fill in the data */
1334 file = msi_alloc_zero( sizeof (MSIFILE) );
1336 return ERROR_NOT_ENOUGH_MEMORY;
1338 file->File = msi_dup_record_field( row, 1 );
1340 component = MSI_RecordGetString( row, 2 );
1341 file->Component = get_loaded_component( package, component );
1343 if (!file->Component)
1345 WARN("Component not found: %s\n", debugstr_w(component));
1346 msi_free(file->File);
1348 return ERROR_SUCCESS;
1351 file->FileName = msi_dup_record_field( row, 3 );
1352 reduce_to_longfilename( file->FileName );
1354 file->ShortName = msi_dup_record_field( row, 3 );
1355 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1357 file->FileSize = MSI_RecordGetInteger( row, 4 );
1358 file->Version = msi_dup_record_field( row, 5 );
1359 file->Language = msi_dup_record_field( row, 6 );
1360 file->Attributes = MSI_RecordGetInteger( row, 7 );
1361 file->Sequence = MSI_RecordGetInteger( row, 8 );
1363 file->state = msifs_invalid;
1365 /* if the compressed bits are not set in the file attributes,
1366 * then read the information from the package word count property
1368 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1370 file->IsCompressed = FALSE;
1372 else if (file->Attributes &
1373 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1375 file->IsCompressed = TRUE;
1377 else if (file->Attributes & msidbFileAttributesNoncompressed)
1379 file->IsCompressed = FALSE;
1383 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1386 load_file_hash(package, file);
1388 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1390 list_add_tail( &package->files, &file->entry );
1392 return ERROR_SUCCESS;
1395 static UINT load_all_files(MSIPACKAGE *package)
1399 static const WCHAR Query[] =
1400 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1401 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1402 '`','S','e','q','u','e','n','c','e','`', 0};
1404 if (!list_empty(&package->files))
1405 return ERROR_SUCCESS;
1407 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1408 if (rc != ERROR_SUCCESS)
1409 return ERROR_SUCCESS;
1411 rc = MSI_IterateRecords(view, NULL, load_file, package);
1412 msiobj_release(&view->hdr);
1414 return ERROR_SUCCESS;
1417 static UINT load_folder( MSIRECORD *row, LPVOID param )
1419 MSIPACKAGE *package = param;
1420 static WCHAR szEmpty[] = { 0 };
1421 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1424 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1426 return ERROR_NOT_ENOUGH_MEMORY;
1428 folder->Directory = msi_dup_record_field( row, 1 );
1430 TRACE("%s\n", debugstr_w(folder->Directory));
1432 p = msi_dup_record_field(row, 3);
1434 /* split src and target dir */
1436 src_short = folder_split_path( p, ':' );
1438 /* split the long and short paths */
1439 tgt_long = folder_split_path( tgt_short, '|' );
1440 src_long = folder_split_path( src_short, '|' );
1442 /* check for no-op dirs */
1443 if (!lstrcmpW(szDot, tgt_short))
1444 tgt_short = szEmpty;
1445 if (!lstrcmpW(szDot, src_short))
1446 src_short = szEmpty;
1449 tgt_long = tgt_short;
1452 src_short = tgt_short;
1453 src_long = tgt_long;
1457 src_long = src_short;
1459 /* FIXME: use the target short path too */
1460 folder->TargetDefault = strdupW(tgt_long);
1461 folder->SourceShortPath = strdupW(src_short);
1462 folder->SourceLongPath = strdupW(src_long);
1465 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1466 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1467 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1469 folder->Parent = msi_dup_record_field( row, 2 );
1471 folder->Property = msi_dup_property( package, folder->Directory );
1473 list_add_tail( &package->folders, &folder->entry );
1475 TRACE("returning %p\n", folder);
1477 return ERROR_SUCCESS;
1480 static UINT load_all_folders( MSIPACKAGE *package )
1482 static const WCHAR query[] = {
1483 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1484 '`','D','i','r','e','c','t','o','r','y','`',0 };
1488 if (!list_empty(&package->folders))
1489 return ERROR_SUCCESS;
1491 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1492 if (r != ERROR_SUCCESS)
1495 r = MSI_IterateRecords(view, NULL, load_folder, package);
1496 msiobj_release(&view->hdr);
1501 * I am not doing any of the costing functionality yet.
1502 * Mostly looking at doing the Component and Feature loading
1504 * The native MSI does A LOT of modification to tables here. Mostly adding
1505 * a lot of temporary columns to the Feature and Component tables.
1507 * note: Native msi also tracks the short filename. But I am only going to
1508 * track the long ones. Also looking at this directory table
1509 * it appears that the directory table does not get the parents
1510 * resolved base on property only based on their entries in the
1513 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1515 static const WCHAR szCosting[] =
1516 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1518 MSI_SetPropertyW(package, szCosting, szZero);
1519 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1521 load_all_folders( package );
1522 load_all_components( package );
1523 load_all_features( package );
1524 load_all_files( package );
1526 return ERROR_SUCCESS;
1529 static UINT execute_script(MSIPACKAGE *package, UINT script )
1532 UINT rc = ERROR_SUCCESS;
1534 TRACE("Executing Script %i\n",script);
1536 if (!package->script)
1538 ERR("no script!\n");
1539 return ERROR_FUNCTION_FAILED;
1542 for (i = 0; i < package->script->ActionCount[script]; i++)
1545 action = package->script->Actions[script][i];
1546 ui_actionstart(package, action);
1547 TRACE("Executing Action (%s)\n",debugstr_w(action));
1548 rc = ACTION_PerformAction(package, action, script, TRUE);
1549 if (rc != ERROR_SUCCESS)
1552 msi_free_action_script(package, script);
1556 static UINT ACTION_FileCost(MSIPACKAGE *package)
1558 return ERROR_SUCCESS;
1561 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1567 state = MsiQueryProductStateW(package->ProductCode);
1569 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1571 if (!comp->ComponentId)
1574 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1575 comp->Installed = INSTALLSTATE_ABSENT;
1578 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1579 package->Context, comp->ComponentId,
1581 if (r != ERROR_SUCCESS)
1582 comp->Installed = INSTALLSTATE_ABSENT;
1587 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1589 MSIFEATURE *feature;
1592 state = MsiQueryProductStateW(package->ProductCode);
1594 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1596 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1597 feature->Installed = INSTALLSTATE_ABSENT;
1600 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1606 static BOOL process_state_property(MSIPACKAGE* package, int level,
1607 LPCWSTR property, INSTALLSTATE state)
1610 MSIFEATURE *feature;
1612 override = msi_dup_property( package, property );
1616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1618 if (lstrcmpW(property, szRemove) &&
1619 (feature->Level <= 0 || feature->Level > level))
1622 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1624 if (strcmpiW(override, szAll)==0)
1625 msi_feature_set_state(package, feature, state);
1628 LPWSTR ptr = override;
1629 LPWSTR ptr2 = strchrW(override,',');
1633 int len = ptr2 - ptr;
1635 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1636 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1638 msi_feature_set_state(package, feature, state);
1644 ptr2 = strchrW(ptr,',');
1656 static BOOL process_overrides( MSIPACKAGE *package, int level )
1658 static const WCHAR szAddLocal[] =
1659 {'A','D','D','L','O','C','A','L',0};
1660 static const WCHAR szAddSource[] =
1661 {'A','D','D','S','O','U','R','C','E',0};
1662 static const WCHAR szAdvertise[] =
1663 {'A','D','V','E','R','T','I','S','E',0};
1666 /* all these activation/deactivation things happen in order and things
1667 * later on the list override things earlier on the list.
1669 * 0 INSTALLLEVEL processing
1682 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1683 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1684 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1685 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1686 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1689 MSI_SetPropertyW( package, szPreselected, szOne );
1694 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1697 static const WCHAR szlevel[] =
1698 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1699 MSICOMPONENT* component;
1700 MSIFEATURE *feature;
1702 TRACE("Checking Install Level\n");
1704 level = msi_get_property_int(package, szlevel, 1);
1706 if (!msi_get_property_int( package, szPreselected, 0 ))
1708 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1710 BOOL feature_state = ((feature->Level > 0) &&
1711 (feature->Level <= level));
1713 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1715 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1716 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1717 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1718 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1720 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1724 /* disable child features of unselected parent features */
1725 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1729 if (feature->Level > 0 && feature->Level <= level)
1732 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1733 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1738 * now we want to enable or disable components base on feature
1741 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1745 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1746 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1748 if (!feature->Level)
1751 /* features with components that have compressed files are made local */
1752 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1754 if (cl->component->Enabled &&
1755 cl->component->ForceLocalState &&
1756 feature->Action == INSTALLSTATE_SOURCE)
1758 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1763 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1765 component = cl->component;
1767 if (!component->Enabled)
1770 switch (feature->Action)
1772 case INSTALLSTATE_ABSENT:
1773 component->anyAbsent = 1;
1775 case INSTALLSTATE_ADVERTISED:
1776 component->hasAdvertiseFeature = 1;
1778 case INSTALLSTATE_SOURCE:
1779 component->hasSourceFeature = 1;
1781 case INSTALLSTATE_LOCAL:
1782 component->hasLocalFeature = 1;
1784 case INSTALLSTATE_DEFAULT:
1785 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1786 component->hasAdvertiseFeature = 1;
1787 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 component->hasSourceFeature = 1;
1790 component->hasLocalFeature = 1;
1798 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1800 /* if the component isn't enabled, leave it alone */
1801 if (!component->Enabled)
1804 /* check if it's local or source */
1805 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1806 (component->hasLocalFeature || component->hasSourceFeature))
1808 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1809 !component->ForceLocalState)
1810 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1812 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1816 /* if any feature is local, the component must be local too */
1817 if (component->hasLocalFeature)
1819 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1823 if (component->hasSourceFeature)
1825 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1829 if (component->hasAdvertiseFeature)
1831 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1835 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1836 if (component->anyAbsent)
1837 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1840 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1842 if (component->Action == INSTALLSTATE_DEFAULT)
1844 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1845 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1848 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1849 debugstr_w(component->Component), component->Installed, component->Action);
1853 return ERROR_SUCCESS;
1856 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1858 MSIPACKAGE *package = param;
1863 name = MSI_RecordGetString(row,1);
1865 f = get_loaded_folder(package, name);
1866 if (!f) return ERROR_SUCCESS;
1868 /* reset the ResolvedTarget */
1869 msi_free(f->ResolvedTarget);
1870 f->ResolvedTarget = NULL;
1872 /* This helper function now does ALL the work */
1873 TRACE("Dir %s ...\n",debugstr_w(name));
1874 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1875 TRACE("resolves to %s\n",debugstr_w(path));
1878 return ERROR_SUCCESS;
1881 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1883 MSIPACKAGE *package = param;
1885 MSIFEATURE *feature;
1887 name = MSI_RecordGetString( row, 1 );
1889 feature = get_loaded_feature( package, name );
1891 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1895 Condition = MSI_RecordGetString(row,3);
1897 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1899 int level = MSI_RecordGetInteger(row,2);
1900 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1901 feature->Level = level;
1904 return ERROR_SUCCESS;
1907 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1909 static const WCHAR name_fmt[] =
1910 {'%','u','.','%','u','.','%','u','.','%','u',0};
1911 static const WCHAR name[] = {'\\',0};
1912 VS_FIXEDFILEINFO *lpVer;
1913 WCHAR filever[0x100];
1919 TRACE("%s\n", debugstr_w(filename));
1921 versize = GetFileVersionInfoSizeW( filename, &handle );
1925 version = msi_alloc( versize );
1926 GetFileVersionInfoW( filename, 0, versize, version );
1928 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1930 msi_free( version );
1934 sprintfW( filever, name_fmt,
1935 HIWORD(lpVer->dwFileVersionMS),
1936 LOWORD(lpVer->dwFileVersionMS),
1937 HIWORD(lpVer->dwFileVersionLS),
1938 LOWORD(lpVer->dwFileVersionLS));
1940 msi_free( version );
1942 return strdupW( filever );
1945 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1947 LPWSTR file_version;
1950 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1952 MSICOMPONENT* comp = file->Component;
1958 if (file->IsCompressed)
1959 comp->ForceLocalState = TRUE;
1961 /* calculate target */
1962 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1964 msi_free(file->TargetPath);
1966 TRACE("file %s is named %s\n",
1967 debugstr_w(file->File), debugstr_w(file->FileName));
1969 file->TargetPath = build_directory_name(2, p, file->FileName);
1973 TRACE("file %s resolves to %s\n",
1974 debugstr_w(file->File), debugstr_w(file->TargetPath));
1976 /* don't check files of components that aren't installed */
1977 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1978 comp->Installed == INSTALLSTATE_ABSENT)
1980 file->state = msifs_missing; /* assume files are missing */
1984 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1986 file->state = msifs_missing;
1987 comp->Cost += file->FileSize;
1991 if (file->Version &&
1992 (file_version = msi_get_disk_file_version( file->TargetPath )))
1994 TRACE("new %s old %s\n", debugstr_w(file->Version),
1995 debugstr_w(file_version));
1996 /* FIXME: seems like a bad way to compare version numbers */
1997 if (lstrcmpiW(file_version, file->Version)<0)
1999 file->state = msifs_overwrite;
2000 comp->Cost += file->FileSize;
2003 file->state = msifs_present;
2004 msi_free( file_version );
2007 file->state = msifs_present;
2010 return ERROR_SUCCESS;
2014 * A lot is done in this function aside from just the costing.
2015 * The costing needs to be implemented at some point but for now I am going
2016 * to focus on the directory building
2019 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2021 static const WCHAR ExecSeqQuery[] =
2022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023 '`','D','i','r','e','c','t','o','r','y','`',0};
2024 static const WCHAR ConditionQuery[] =
2025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026 '`','C','o','n','d','i','t','i','o','n','`',0};
2027 static const WCHAR szCosting[] =
2028 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029 static const WCHAR szlevel[] =
2030 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2031 static const WCHAR szOutOfDiskSpace[] =
2032 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2034 UINT rc = ERROR_SUCCESS;
2038 TRACE("Building Directory properties\n");
2040 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2041 if (rc == ERROR_SUCCESS)
2043 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2045 msiobj_release(&view->hdr);
2048 /* read components states from the registry */
2049 ACTION_GetComponentInstallStates(package);
2050 ACTION_GetFeatureInstallStates(package);
2052 TRACE("File calculations\n");
2053 msi_check_file_install_states( package );
2055 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2057 TRACE("Evaluating Condition Table\n");
2059 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2060 if (rc == ERROR_SUCCESS)
2062 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2063 msiobj_release( &view->hdr );
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2069 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2071 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2072 comp->Enabled = FALSE;
2075 comp->Enabled = TRUE;
2079 MSI_SetPropertyW(package,szCosting,szOne);
2080 /* set default run level if not set */
2081 level = msi_dup_property( package, szlevel );
2083 MSI_SetPropertyW(package,szlevel, szOne);
2086 /* FIXME: check volume disk space */
2087 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2089 return MSI_SetFeatureStates(package);
2092 /* OK this value is "interpreted" and then formatted based on the
2093 first few characters */
2094 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2099 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2105 LPWSTR deformated = NULL;
2108 deformat_string(package, &value[2], &deformated);
2110 /* binary value type */
2114 *size = (strlenW(ptr)/2)+1;
2116 *size = strlenW(ptr)/2;
2118 data = msi_alloc(*size);
2124 /* if uneven pad with a zero in front */
2130 data[count] = (BYTE)strtol(byte,NULL,0);
2132 TRACE("Uneven byte count\n");
2140 data[count] = (BYTE)strtol(byte,NULL,0);
2143 msi_free(deformated);
2145 TRACE("Data %i bytes(%i)\n",*size,count);
2152 deformat_string(package, &value[1], &deformated);
2155 *size = sizeof(DWORD);
2156 data = msi_alloc(*size);
2162 if ( (*p < '0') || (*p > '9') )
2168 if (deformated[0] == '-')
2171 TRACE("DWORD %i\n",*(LPDWORD)data);
2173 msi_free(deformated);
2178 static const WCHAR szMulti[] = {'[','~',']',0};
2187 *type=REG_EXPAND_SZ;
2195 if (strstrW(value,szMulti))
2196 *type = REG_MULTI_SZ;
2198 /* remove initial delimiter */
2199 if (!strncmpW(value, szMulti, 3))
2202 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2204 /* add double NULL terminator */
2205 if (*type == REG_MULTI_SZ)
2207 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2208 data = msi_realloc_zero(data, *size);
2214 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2221 if (msi_get_property_int( package, szAllUsers, 0 ))
2223 *root_key = HKEY_LOCAL_MACHINE;
2228 *root_key = HKEY_CURRENT_USER;
2233 *root_key = HKEY_CLASSES_ROOT;
2237 *root_key = HKEY_CURRENT_USER;
2241 *root_key = HKEY_LOCAL_MACHINE;
2245 *root_key = HKEY_USERS;
2249 ERR("Unknown root %i\n", root);
2256 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2258 MSIPACKAGE *package = param;
2259 LPSTR value_data = NULL;
2260 HKEY root_key, hkey;
2263 LPCWSTR szRoot, component, name, key, value;
2268 BOOL check_first = FALSE;
2271 ui_progress(package,2,0,0,0);
2278 component = MSI_RecordGetString(row, 6);
2279 comp = get_loaded_component(package,component);
2281 return ERROR_SUCCESS;
2283 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2285 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2286 comp->Action = comp->Installed;
2287 return ERROR_SUCCESS;
2289 comp->Action = INSTALLSTATE_LOCAL;
2291 name = MSI_RecordGetString(row, 4);
2292 if( MSI_RecordIsNull(row,5) && name )
2294 /* null values can have special meanings */
2295 if (name[0]=='-' && name[1] == 0)
2296 return ERROR_SUCCESS;
2297 else if ((name[0]=='+' && name[1] == 0) ||
2298 (name[0] == '*' && name[1] == 0))
2303 root = MSI_RecordGetInteger(row,2);
2304 key = MSI_RecordGetString(row, 3);
2306 szRoot = get_root_key( package, root, &root_key );
2308 return ERROR_SUCCESS;
2310 deformat_string(package, key , &deformated);
2311 size = strlenW(deformated) + strlenW(szRoot) + 1;
2312 uikey = msi_alloc(size*sizeof(WCHAR));
2313 strcpyW(uikey,szRoot);
2314 strcatW(uikey,deformated);
2316 if (RegCreateKeyW( root_key, deformated, &hkey))
2318 ERR("Could not create key %s\n",debugstr_w(deformated));
2319 msi_free(deformated);
2321 return ERROR_SUCCESS;
2323 msi_free(deformated);
2325 value = MSI_RecordGetString(row,5);
2327 value_data = parse_value(package, value, &type, &size);
2330 value_data = (LPSTR)strdupW(szEmpty);
2331 size = sizeof(szEmpty);
2335 deformat_string(package, name, &deformated);
2339 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2341 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2346 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2347 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2349 TRACE("value %s of %s checked already exists\n",
2350 debugstr_w(deformated), debugstr_w(uikey));
2354 TRACE("Checked and setting value %s of %s\n",
2355 debugstr_w(deformated), debugstr_w(uikey));
2356 if (deformated || size)
2357 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2362 uirow = MSI_CreateRecord(3);
2363 MSI_RecordSetStringW(uirow,2,deformated);
2364 MSI_RecordSetStringW(uirow,1,uikey);
2367 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2369 MSI_RecordSetStringW(uirow,3,value);
2371 ui_actiondata(package,szWriteRegistryValues,uirow);
2372 msiobj_release( &uirow->hdr );
2374 msi_free(value_data);
2375 msi_free(deformated);
2378 return ERROR_SUCCESS;
2381 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2385 static const WCHAR ExecSeqQuery[] =
2386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2387 '`','R','e','g','i','s','t','r','y','`',0 };
2389 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2390 if (rc != ERROR_SUCCESS)
2391 return ERROR_SUCCESS;
2393 /* increment progress bar each time action data is sent */
2394 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2396 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2398 msiobj_release(&view->hdr);
2402 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2406 DWORD num_subkeys, num_values;
2410 if ((res = RegDeleteTreeW( hkey_root, key )))
2412 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2417 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2419 if ((res = RegDeleteValueW( hkey, value )))
2421 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2423 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2424 NULL, NULL, NULL, NULL );
2425 RegCloseKey( hkey );
2427 if (!res && !num_subkeys && !num_values)
2429 TRACE("Removing empty key %s\n", debugstr_w(key));
2430 RegDeleteKeyW( hkey_root, key );
2434 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2438 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2440 MSIPACKAGE *package = param;
2441 LPCWSTR component, name, key_str, root_key_str;
2442 LPWSTR deformated_key, deformated_name, ui_key_str;
2445 BOOL delete_key = FALSE;
2450 ui_progress( package, 2, 0, 0, 0 );
2452 component = MSI_RecordGetString( row, 6 );
2453 comp = get_loaded_component( package, component );
2455 return ERROR_SUCCESS;
2457 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2459 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2460 comp->Action = comp->Installed;
2461 return ERROR_SUCCESS;
2463 comp->Action = INSTALLSTATE_ABSENT;
2465 name = MSI_RecordGetString( row, 4 );
2466 if (MSI_RecordIsNull( row, 5 ) && name )
2468 if (name[0] == '+' && !name[1])
2469 return ERROR_SUCCESS;
2470 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2477 root = MSI_RecordGetInteger( row, 2 );
2478 key_str = MSI_RecordGetString( row, 3 );
2480 root_key_str = get_root_key( package, root, &hkey_root );
2482 return ERROR_SUCCESS;
2484 deformat_string( package, key_str, &deformated_key );
2485 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2486 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2487 strcpyW( ui_key_str, root_key_str );
2488 strcatW( ui_key_str, deformated_key );
2490 deformat_string( package, name, &deformated_name );
2492 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2493 msi_free( deformated_key );
2495 uirow = MSI_CreateRecord( 2 );
2496 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2497 MSI_RecordSetStringW( uirow, 2, deformated_name );
2499 ui_actiondata( package, szRemoveRegistryValues, uirow );
2500 msiobj_release( &uirow->hdr );
2502 msi_free( ui_key_str );
2503 msi_free( deformated_name );
2504 return ERROR_SUCCESS;
2507 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2509 MSIPACKAGE *package = param;
2510 LPCWSTR component, name, key_str, root_key_str;
2511 LPWSTR deformated_key, deformated_name, ui_key_str;
2514 BOOL delete_key = FALSE;
2519 ui_progress( package, 2, 0, 0, 0 );
2521 component = MSI_RecordGetString( row, 5 );
2522 comp = get_loaded_component( package, component );
2524 return ERROR_SUCCESS;
2526 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2528 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2529 comp->Action = comp->Installed;
2530 return ERROR_SUCCESS;
2532 comp->Action = INSTALLSTATE_LOCAL;
2534 if ((name = MSI_RecordGetString( row, 4 )))
2536 if (name[0] == '-' && !name[1])
2543 root = MSI_RecordGetInteger( row, 2 );
2544 key_str = MSI_RecordGetString( row, 3 );
2546 root_key_str = get_root_key( package, root, &hkey_root );
2548 return ERROR_SUCCESS;
2550 deformat_string( package, key_str, &deformated_key );
2551 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2552 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2553 strcpyW( ui_key_str, root_key_str );
2554 strcatW( ui_key_str, deformated_key );
2556 deformat_string( package, name, &deformated_name );
2558 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2559 msi_free( deformated_key );
2561 uirow = MSI_CreateRecord( 2 );
2562 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2563 MSI_RecordSetStringW( uirow, 2, deformated_name );
2565 ui_actiondata( package, szRemoveRegistryValues, uirow );
2566 msiobj_release( &uirow->hdr );
2568 msi_free( ui_key_str );
2569 msi_free( deformated_name );
2570 return ERROR_SUCCESS;
2573 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2577 static const WCHAR registry_query[] =
2578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2579 '`','R','e','g','i','s','t','r','y','`',0 };
2580 static const WCHAR remove_registry_query[] =
2581 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2582 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2584 /* increment progress bar each time action data is sent */
2585 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2587 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2588 if (rc == ERROR_SUCCESS)
2590 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2591 msiobj_release( &view->hdr );
2592 if (rc != ERROR_SUCCESS)
2596 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2597 if (rc == ERROR_SUCCESS)
2599 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2600 msiobj_release( &view->hdr );
2601 if (rc != ERROR_SUCCESS)
2605 return ERROR_SUCCESS;
2608 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2610 package->script->CurrentlyScripting = TRUE;
2612 return ERROR_SUCCESS;
2616 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2621 static const WCHAR q1[]=
2622 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2623 '`','R','e','g','i','s','t','r','y','`',0};
2626 MSIFEATURE *feature;
2629 TRACE("InstallValidate\n");
2631 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2632 if (rc == ERROR_SUCCESS)
2634 MSI_IterateRecords( view, &progress, NULL, package );
2635 msiobj_release( &view->hdr );
2636 total += progress * REG_PROGRESS_VALUE;
2639 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2640 total += COMPONENT_PROGRESS_VALUE;
2642 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2643 total += file->FileSize;
2645 ui_progress(package,0,total,0,0);
2647 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2649 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2650 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2651 feature->ActionRequest);
2654 return ERROR_SUCCESS;
2657 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2659 MSIPACKAGE* package = param;
2660 LPCWSTR cond = NULL;
2661 LPCWSTR message = NULL;
2664 static const WCHAR title[]=
2665 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2667 cond = MSI_RecordGetString(row,1);
2669 r = MSI_EvaluateConditionW(package,cond);
2670 if (r == MSICONDITION_FALSE)
2672 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2675 message = MSI_RecordGetString(row,2);
2676 deformat_string(package,message,&deformated);
2677 MessageBoxW(NULL,deformated,title,MB_OK);
2678 msi_free(deformated);
2681 return ERROR_INSTALL_FAILURE;
2684 return ERROR_SUCCESS;
2687 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2690 MSIQUERY * view = NULL;
2691 static const WCHAR ExecSeqQuery[] =
2692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2693 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2695 TRACE("Checking launch conditions\n");
2697 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2698 if (rc != ERROR_SUCCESS)
2699 return ERROR_SUCCESS;
2701 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2702 msiobj_release(&view->hdr);
2707 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2711 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2713 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2715 MSIRECORD * row = 0;
2717 LPWSTR deformated,buffer,deformated_name;
2719 static const WCHAR ExecSeqQuery[] =
2720 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2721 '`','R','e','g','i','s','t','r','y','`',' ',
2722 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2723 ' ','=',' ' ,'\'','%','s','\'',0 };
2724 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2725 static const WCHAR fmt2[]=
2726 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2728 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2732 root = MSI_RecordGetInteger(row,2);
2733 key = MSI_RecordGetString(row, 3);
2734 name = MSI_RecordGetString(row, 4);
2735 deformat_string(package, key , &deformated);
2736 deformat_string(package, name, &deformated_name);
2738 len = strlenW(deformated) + 6;
2739 if (deformated_name)
2740 len+=strlenW(deformated_name);
2742 buffer = msi_alloc( len *sizeof(WCHAR));
2744 if (deformated_name)
2745 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2747 sprintfW(buffer,fmt,root,deformated);
2749 msi_free(deformated);
2750 msi_free(deformated_name);
2751 msiobj_release(&row->hdr);
2755 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2757 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2762 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2765 return strdupW( file->TargetPath );
2770 static HKEY openSharedDLLsKey(void)
2773 static const WCHAR path[] =
2774 {'S','o','f','t','w','a','r','e','\\',
2775 'M','i','c','r','o','s','o','f','t','\\',
2776 'W','i','n','d','o','w','s','\\',
2777 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2778 'S','h','a','r','e','d','D','L','L','s',0};
2780 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2784 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2789 DWORD sz = sizeof(count);
2792 hkey = openSharedDLLsKey();
2793 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2794 if (rc != ERROR_SUCCESS)
2800 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2804 hkey = openSharedDLLsKey();
2806 msi_reg_set_val_dword( hkey, path, count );
2808 RegDeleteValueW(hkey,path);
2814 * Return TRUE if the count should be written out and FALSE if not
2816 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2818 MSIFEATURE *feature;
2822 /* only refcount DLLs */
2823 if (comp->KeyPath == NULL ||
2824 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2825 comp->Attributes & msidbComponentAttributesODBCDataSource)
2829 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2830 write = (count > 0);
2832 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2836 /* increment counts */
2837 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2841 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2844 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2846 if ( cl->component == comp )
2851 /* decrement counts */
2852 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2856 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2859 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2861 if ( cl->component == comp )
2866 /* ref count all the files in the component */
2871 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2873 if (file->Component == comp)
2874 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2878 /* add a count for permanent */
2879 if (comp->Attributes & msidbComponentAttributesPermanent)
2882 comp->RefCount = count;
2885 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2888 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2890 WCHAR squished_pc[GUID_SIZE];
2891 WCHAR squished_cc[GUID_SIZE];
2898 squash_guid(package->ProductCode,squished_pc);
2899 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2901 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2905 ui_progress(package,2,0,0,0);
2906 if (!comp->ComponentId)
2909 squash_guid(comp->ComponentId,squished_cc);
2911 msi_free(comp->FullKeypath);
2912 comp->FullKeypath = resolve_keypath( package, comp );
2914 ACTION_RefCountComponent( package, comp );
2916 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2917 debugstr_w(comp->Component),
2918 debugstr_w(squished_cc),
2919 debugstr_w(comp->FullKeypath),
2922 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2923 comp->ActionRequest == INSTALLSTATE_SOURCE)
2925 if (!comp->FullKeypath)
2928 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2929 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2932 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2935 if (rc != ERROR_SUCCESS)
2938 if (comp->Attributes & msidbComponentAttributesPermanent)
2940 static const WCHAR szPermKey[] =
2941 { '0','0','0','0','0','0','0','0','0','0','0','0',
2942 '0','0','0','0','0','0','0','0','0','0','0','0',
2943 '0','0','0','0','0','0','0','0',0 };
2945 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2948 if (comp->Action == INSTALLSTATE_LOCAL)
2949 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2955 WCHAR source[MAX_PATH];
2956 WCHAR base[MAX_PATH];
2959 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2960 static const WCHAR query[] = {
2961 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2962 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2963 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2964 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2965 '`','D','i','s','k','I','d','`',0};
2967 file = get_loaded_file(package, comp->KeyPath);
2971 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2972 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2973 ptr2 = strrchrW(source, '\\') + 1;
2974 msiobj_release(&row->hdr);
2976 lstrcpyW(base, package->PackagePath);
2977 ptr = strrchrW(base, '\\');
2980 sourcepath = resolve_file_source(package, file);
2981 ptr = sourcepath + lstrlenW(base);
2982 lstrcpyW(ptr2, ptr);
2983 msi_free(sourcepath);
2985 msi_reg_set_val_str(hkey, squished_pc, source);
2989 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2991 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2992 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2994 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2996 comp->Action = comp->ActionRequest;
2999 uirow = MSI_CreateRecord(3);
3000 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3001 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3002 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3003 ui_actiondata(package,szProcessComponents,uirow);
3004 msiobj_release( &uirow->hdr );
3007 return ERROR_SUCCESS;
3018 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3019 LPWSTR lpszName, LONG_PTR lParam)
3022 typelib_struct *tl_struct = (typelib_struct*) lParam;
3023 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3027 if (!IS_INTRESOURCE(lpszName))
3029 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3033 sz = strlenW(tl_struct->source)+4;
3034 sz *= sizeof(WCHAR);
3036 if ((INT_PTR)lpszName == 1)
3037 tl_struct->path = strdupW(tl_struct->source);
3040 tl_struct->path = msi_alloc(sz);
3041 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3044 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3045 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3048 msi_free(tl_struct->path);
3049 tl_struct->path = NULL;
3054 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3055 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3057 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3061 msi_free(tl_struct->path);
3062 tl_struct->path = NULL;
3064 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3065 ITypeLib_Release(tl_struct->ptLib);
3070 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3072 MSIPACKAGE* package = param;
3076 typelib_struct tl_struct;
3081 component = MSI_RecordGetString(row,3);
3082 comp = get_loaded_component(package,component);
3084 return ERROR_SUCCESS;
3086 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3088 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3089 comp->Action = comp->Installed;
3090 return ERROR_SUCCESS;
3092 comp->Action = INSTALLSTATE_LOCAL;
3094 file = get_loaded_file( package, comp->KeyPath );
3096 return ERROR_SUCCESS;
3098 ui_actiondata( package, szRegisterTypeLibraries, row );
3100 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3104 guid = MSI_RecordGetString(row,1);
3105 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3106 tl_struct.source = strdupW( file->TargetPath );
3107 tl_struct.path = NULL;
3109 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3110 (LONG_PTR)&tl_struct);
3118 helpid = MSI_RecordGetString(row,6);
3121 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3122 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3126 ERR("Failed to register type library %s\n",
3127 debugstr_w(tl_struct.path));
3129 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3131 ITypeLib_Release(tl_struct.ptLib);
3132 msi_free(tl_struct.path);
3135 ERR("Failed to load type library %s\n",
3136 debugstr_w(tl_struct.source));
3138 FreeLibrary(module);
3139 msi_free(tl_struct.source);
3143 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3146 ERR("Failed to load type library: %08x\n", hr);
3147 return ERROR_INSTALL_FAILURE;
3150 ITypeLib_Release(tlib);
3153 return ERROR_SUCCESS;
3156 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3159 * OK this is a bit confusing.. I am given a _Component key and I believe
3160 * that the file that is being registered as a type library is the "key file
3161 * of that component" which I interpret to mean "The file in the KeyPath of
3166 static const WCHAR Query[] =
3167 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3168 '`','T','y','p','e','L','i','b','`',0};
3170 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3171 if (rc != ERROR_SUCCESS)
3172 return ERROR_SUCCESS;
3174 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3175 msiobj_release(&view->hdr);
3179 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3181 MSIPACKAGE *package = param;
3182 LPCWSTR component, guid;
3190 component = MSI_RecordGetString( row, 3 );
3191 comp = get_loaded_component( package, component );
3193 return ERROR_SUCCESS;
3195 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3197 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3198 comp->Action = comp->Installed;
3199 return ERROR_SUCCESS;
3201 comp->Action = INSTALLSTATE_ABSENT;
3203 ui_actiondata( package, szUnregisterTypeLibraries, row );
3205 guid = MSI_RecordGetString( row, 1 );
3206 CLSIDFromString( (LPWSTR)guid, &libid );
3207 version = MSI_RecordGetInteger( row, 4 );
3208 language = MSI_RecordGetInteger( row, 2 );
3211 syskind = SYS_WIN64;
3213 syskind = SYS_WIN32;
3216 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3219 WARN("Failed to unregister typelib: %08x\n", hr);
3222 return ERROR_SUCCESS;
3225 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3229 static const WCHAR query[] =
3230 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3231 '`','T','y','p','e','L','i','b','`',0};
3233 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3234 if (rc != ERROR_SUCCESS)
3235 return ERROR_SUCCESS;
3237 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3238 msiobj_release( &view->hdr );
3242 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3244 static const WCHAR szlnk[] = {'.','l','n','k',0};
3245 LPCWSTR directory, extension;
3246 LPWSTR link_folder, link_file, filename;
3248 directory = MSI_RecordGetString( row, 2 );
3249 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3251 /* may be needed because of a bug somewhere else */
3252 create_full_pathW( link_folder );
3254 filename = msi_dup_record_field( row, 3 );
3255 reduce_to_longfilename( filename );
3257 extension = strchrW( filename, '.' );
3258 if (!extension || strcmpiW( extension, szlnk ))
3260 int len = strlenW( filename );
3261 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3262 memcpy( filename + len, szlnk, sizeof(szlnk) );
3264 link_file = build_directory_name( 2, link_folder, filename );
3265 msi_free( link_folder );
3266 msi_free( filename );
3271 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3273 MSIPACKAGE *package = param;
3274 LPWSTR link_file, deformated, path;
3275 LPCWSTR component, target;
3277 IShellLinkW *sl = NULL;
3278 IPersistFile *pf = NULL;
3281 component = MSI_RecordGetString(row, 4);
3282 comp = get_loaded_component(package, component);
3284 return ERROR_SUCCESS;
3286 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3288 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3289 comp->Action = comp->Installed;
3290 return ERROR_SUCCESS;
3292 comp->Action = INSTALLSTATE_LOCAL;
3294 ui_actiondata(package,szCreateShortcuts,row);
3296 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3297 &IID_IShellLinkW, (LPVOID *) &sl );
3301 ERR("CLSID_ShellLink not available\n");
3305 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3308 ERR("QueryInterface(IID_IPersistFile) failed\n");
3312 target = MSI_RecordGetString(row, 5);
3313 if (strchrW(target, '['))
3315 deformat_string(package, target, &deformated);
3316 IShellLinkW_SetPath(sl,deformated);
3317 msi_free(deformated);
3321 FIXME("poorly handled shortcut format, advertised shortcut\n");
3322 IShellLinkW_SetPath(sl,comp->FullKeypath);
3325 if (!MSI_RecordIsNull(row,6))
3327 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3328 deformat_string(package, arguments, &deformated);
3329 IShellLinkW_SetArguments(sl,deformated);
3330 msi_free(deformated);
3333 if (!MSI_RecordIsNull(row,7))
3335 LPCWSTR description = MSI_RecordGetString(row, 7);
3336 IShellLinkW_SetDescription(sl, description);
3339 if (!MSI_RecordIsNull(row,8))
3340 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3342 if (!MSI_RecordIsNull(row,9))
3345 LPCWSTR icon = MSI_RecordGetString(row, 9);
3347 path = build_icon_path(package, icon);
3348 index = MSI_RecordGetInteger(row,10);
3350 /* no value means 0 */
3351 if (index == MSI_NULL_INTEGER)
3354 IShellLinkW_SetIconLocation(sl, path, index);
3358 if (!MSI_RecordIsNull(row,11))
3359 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3361 if (!MSI_RecordIsNull(row,12))
3363 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3364 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3366 IShellLinkW_SetWorkingDirectory(sl, path);
3370 link_file = get_link_file(package, row);
3372 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3373 IPersistFile_Save(pf, link_file, FALSE);
3375 msi_free(link_file);
3379 IPersistFile_Release( pf );
3381 IShellLinkW_Release( sl );
3383 return ERROR_SUCCESS;
3386 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3391 static const WCHAR Query[] =
3392 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3393 '`','S','h','o','r','t','c','u','t','`',0};
3395 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3396 if (rc != ERROR_SUCCESS)
3397 return ERROR_SUCCESS;
3399 res = CoInitialize( NULL );
3401 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3402 msiobj_release(&view->hdr);
3410 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3412 MSIPACKAGE *package = param;
3417 component = MSI_RecordGetString( row, 4 );
3418 comp = get_loaded_component( package, component );
3420 return ERROR_SUCCESS;
3422 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3424 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3425 comp->Action = comp->Installed;
3426 return ERROR_SUCCESS;
3428 comp->Action = INSTALLSTATE_ABSENT;
3430 ui_actiondata( package, szRemoveShortcuts, row );
3432 link_file = get_link_file( package, row );
3434 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3435 if (!DeleteFileW( link_file ))
3437 WARN("Failed to remove shortcut file %u\n", GetLastError());
3439 msi_free( link_file );
3441 return ERROR_SUCCESS;
3444 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3448 static const WCHAR query[] =
3449 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3450 '`','S','h','o','r','t','c','u','t','`',0};
3452 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3453 if (rc != ERROR_SUCCESS)
3454 return ERROR_SUCCESS;
3456 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3457 msiobj_release( &view->hdr );
3462 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3464 MSIPACKAGE* package = param;
3472 FileName = MSI_RecordGetString(row,1);
3475 ERR("Unable to get FileName\n");
3476 return ERROR_SUCCESS;
3479 FilePath = build_icon_path(package,FileName);
3481 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3483 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3484 FILE_ATTRIBUTE_NORMAL, NULL);
3486 if (the_file == INVALID_HANDLE_VALUE)
3488 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3490 return ERROR_SUCCESS;
3497 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3498 if (rc != ERROR_SUCCESS)
3500 ERR("Failed to get stream\n");
3501 CloseHandle(the_file);
3502 DeleteFileW(FilePath);
3505 WriteFile(the_file,buffer,sz,&write,NULL);
3506 } while (sz == 1024);
3509 CloseHandle(the_file);
3511 return ERROR_SUCCESS;
3514 static UINT msi_publish_icons(MSIPACKAGE *package)
3519 static const WCHAR query[]= {
3520 'S','E','L','E','C','T',' ','*',' ',
3521 'F','R','O','M',' ','`','I','c','o','n','`',0};
3523 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3524 if (r == ERROR_SUCCESS)
3526 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3527 msiobj_release(&view->hdr);
3530 return ERROR_SUCCESS;
3533 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3539 MSISOURCELISTINFO *info;
3541 r = RegCreateKeyW(hkey, szSourceList, &source);
3542 if (r != ERROR_SUCCESS)
3545 RegCloseKey(source);
3547 buffer = strrchrW(package->PackagePath, '\\') + 1;
3548 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3549 package->Context, MSICODE_PRODUCT,
3550 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3551 if (r != ERROR_SUCCESS)
3554 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3555 package->Context, MSICODE_PRODUCT,
3556 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3557 if (r != ERROR_SUCCESS)
3560 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3561 package->Context, MSICODE_PRODUCT,
3562 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3563 if (r != ERROR_SUCCESS)
3566 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3568 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3569 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3570 info->options, info->value);
3572 MsiSourceListSetInfoW(package->ProductCode, NULL,
3573 info->context, info->options,
3574 info->property, info->value);
3577 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3579 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3580 disk->context, disk->options,
3581 disk->disk_id, disk->volume_label, disk->disk_prompt);
3584 return ERROR_SUCCESS;
3587 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3589 MSIHANDLE hdb, suminfo;
3590 WCHAR guids[MAX_PATH];
3591 WCHAR packcode[SQUISH_GUID_SIZE];
3598 static const WCHAR szProductLanguage[] =
3599 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3600 static const WCHAR szARPProductIcon[] =
3601 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3602 static const WCHAR szProductVersion[] =
3603 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3604 static const WCHAR szAssignment[] =
3605 {'A','s','s','i','g','n','m','e','n','t',0};
3606 static const WCHAR szAdvertiseFlags[] =
3607 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3608 static const WCHAR szClients[] =
3609 {'C','l','i','e','n','t','s',0};
3610 static const WCHAR szColon[] = {':',0};
3612 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3613 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3616 langid = msi_get_property_int(package, szProductLanguage, 0);
3617 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3620 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3622 buffer = msi_dup_property(package, szARPProductIcon);
3625 LPWSTR path = build_icon_path(package,buffer);
3626 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3631 buffer = msi_dup_property(package, szProductVersion);
3634 DWORD verdword = msi_version_str_to_dword(buffer);
3635 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3639 msi_reg_set_val_dword(hkey, szAssignment, 0);
3640 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3641 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3642 msi_reg_set_val_str(hkey, szClients, szColon);
3644 hdb = alloc_msihandle(&package->db->hdr);
3646 return ERROR_NOT_ENOUGH_MEMORY;
3648 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3649 MsiCloseHandle(hdb);
3650 if (r != ERROR_SUCCESS)
3654 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3655 NULL, guids, &size);
3656 if (r != ERROR_SUCCESS)
3659 ptr = strchrW(guids, ';');
3661 squash_guid(guids, packcode);
3662 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3665 MsiCloseHandle(suminfo);
3666 return ERROR_SUCCESS;
3669 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3674 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3676 static const WCHAR szUpgradeCode[] =
3677 {'U','p','g','r','a','d','e','C','o','d','e',0};
3679 upgrade = msi_dup_property(package, szUpgradeCode);
3681 return ERROR_SUCCESS;
3683 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3685 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3686 if (r != ERROR_SUCCESS)
3691 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3692 if (r != ERROR_SUCCESS)
3696 squash_guid(package->ProductCode, squashed_pc);
3697 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3706 static BOOL msi_check_publish(MSIPACKAGE *package)
3708 MSIFEATURE *feature;
3710 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3712 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3719 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3721 MSIFEATURE *feature;
3723 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3725 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3732 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3734 WCHAR patch_squashed[GUID_SIZE];
3737 UINT r = ERROR_FUNCTION_FAILED;
3739 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3741 if (res != ERROR_SUCCESS)
3742 return ERROR_FUNCTION_FAILED;
3744 squash_guid(package->patch->patchcode, patch_squashed);
3746 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3747 (const BYTE *)patch_squashed,
3748 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3749 if (res != ERROR_SUCCESS)
3752 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3753 (const BYTE *)package->patch->transforms,
3754 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3755 if (res == ERROR_SUCCESS)
3759 RegCloseKey(patches);
3764 * 99% of the work done here is only done for
3765 * advertised installs. However this is where the
3766 * Icon table is processed and written out
3767 * so that is what I am going to do here.
3769 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3772 HKEY hukey = NULL, hudkey = NULL;
3775 /* FIXME: also need to publish if the product is in advertise mode */
3776 if (!msi_check_publish(package))
3777 return ERROR_SUCCESS;
3779 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3781 if (rc != ERROR_SUCCESS)
3784 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3785 NULL, &hudkey, TRUE);
3786 if (rc != ERROR_SUCCESS)
3789 rc = msi_publish_upgrade_code(package);
3790 if (rc != ERROR_SUCCESS)
3795 rc = msi_publish_patch(package, hukey, hudkey);
3796 if (rc != ERROR_SUCCESS)
3800 rc = msi_publish_product_properties(package, hukey);
3801 if (rc != ERROR_SUCCESS)
3804 rc = msi_publish_sourcelist(package, hukey);
3805 if (rc != ERROR_SUCCESS)
3808 rc = msi_publish_icons(package);
3811 uirow = MSI_CreateRecord( 1 );
3812 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3813 ui_actiondata( package, szPublishProduct, uirow );
3814 msiobj_release( &uirow->hdr );
3817 RegCloseKey(hudkey);
3822 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3824 WCHAR *filename, *ptr, *folder, *ret;
3825 const WCHAR *dirprop;
3827 filename = msi_dup_record_field( row, 2 );
3828 if (filename && (ptr = strchrW( filename, '|' )))
3833 dirprop = MSI_RecordGetString( row, 3 );
3836 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3838 folder = msi_dup_property( package, dirprop );
3841 folder = msi_dup_property( package, szWindowsFolder );
3845 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3846 msi_free( filename );
3850 ret = build_directory_name( 2, folder, ptr );
3852 msi_free( filename );
3857 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3859 MSIPACKAGE *package = param;
3860 LPCWSTR component, section, key, value, identifier;
3861 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3866 component = MSI_RecordGetString(row, 8);
3867 comp = get_loaded_component(package,component);
3869 return ERROR_SUCCESS;
3871 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3873 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3874 comp->Action = comp->Installed;
3875 return ERROR_SUCCESS;
3877 comp->Action = INSTALLSTATE_LOCAL;
3879 identifier = MSI_RecordGetString(row,1);
3880 section = MSI_RecordGetString(row,4);
3881 key = MSI_RecordGetString(row,5);
3882 value = MSI_RecordGetString(row,6);
3883 action = MSI_RecordGetInteger(row,7);
3885 deformat_string(package,section,&deformated_section);
3886 deformat_string(package,key,&deformated_key);
3887 deformat_string(package,value,&deformated_value);
3889 fullname = get_ini_file_name(package, row);
3893 TRACE("Adding value %s to section %s in %s\n",
3894 debugstr_w(deformated_key), debugstr_w(deformated_section),
3895 debugstr_w(fullname));
3896 WritePrivateProfileStringW(deformated_section, deformated_key,
3897 deformated_value, fullname);
3899 else if (action == 1)
3902 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3903 returned, 10, fullname);
3904 if (returned[0] == 0)
3906 TRACE("Adding value %s to section %s in %s\n",
3907 debugstr_w(deformated_key), debugstr_w(deformated_section),
3908 debugstr_w(fullname));
3910 WritePrivateProfileStringW(deformated_section, deformated_key,
3911 deformated_value, fullname);
3914 else if (action == 3)
3915 FIXME("Append to existing section not yet implemented\n");
3917 uirow = MSI_CreateRecord(4);
3918 MSI_RecordSetStringW(uirow,1,identifier);
3919 MSI_RecordSetStringW(uirow,2,deformated_section);
3920 MSI_RecordSetStringW(uirow,3,deformated_key);
3921 MSI_RecordSetStringW(uirow,4,deformated_value);
3922 ui_actiondata(package,szWriteIniValues,uirow);
3923 msiobj_release( &uirow->hdr );
3926 msi_free(deformated_key);
3927 msi_free(deformated_value);
3928 msi_free(deformated_section);
3929 return ERROR_SUCCESS;
3932 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3936 static const WCHAR ExecSeqQuery[] =
3937 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3938 '`','I','n','i','F','i','l','e','`',0};
3940 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3941 if (rc != ERROR_SUCCESS)
3943 TRACE("no IniFile table\n");
3944 return ERROR_SUCCESS;
3947 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3948 msiobj_release(&view->hdr);
3952 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3954 MSIPACKAGE *package = param;
3955 LPCWSTR component, section, key, value, identifier;
3956 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3961 component = MSI_RecordGetString( row, 8 );
3962 comp = get_loaded_component( package, component );
3964 return ERROR_SUCCESS;
3966 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3968 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3969 comp->Action = comp->Installed;
3970 return ERROR_SUCCESS;
3972 comp->Action = INSTALLSTATE_ABSENT;
3974 identifier = MSI_RecordGetString( row, 1 );
3975 section = MSI_RecordGetString( row, 4 );
3976 key = MSI_RecordGetString( row, 5 );
3977 value = MSI_RecordGetString( row, 6 );
3978 action = MSI_RecordGetInteger( row, 7 );
3980 deformat_string( package, section, &deformated_section );
3981 deformat_string( package, key, &deformated_key );
3982 deformat_string( package, value, &deformated_value );
3984 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3986 filename = get_ini_file_name( package, row );
3988 TRACE("Removing key %s from section %s in %s\n",
3989 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3991 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3993 WARN("Unable to remove key %u\n", GetLastError());
3995 msi_free( filename );
3998 FIXME("Unsupported action %d\n", action);
4001 uirow = MSI_CreateRecord( 4 );
4002 MSI_RecordSetStringW( uirow, 1, identifier );
4003 MSI_RecordSetStringW( uirow, 2, deformated_section );
4004 MSI_RecordSetStringW( uirow, 3, deformated_key );
4005 MSI_RecordSetStringW( uirow, 4, deformated_value );
4006 ui_actiondata( package, szRemoveIniValues, uirow );
4007 msiobj_release( &uirow->hdr );
4009 msi_free( deformated_key );
4010 msi_free( deformated_value );
4011 msi_free( deformated_section );
4012 return ERROR_SUCCESS;
4015 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4017 MSIPACKAGE *package = param;
4018 LPCWSTR component, section, key, value, identifier;
4019 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4024 component = MSI_RecordGetString( row, 8 );
4025 comp = get_loaded_component( package, component );
4027 return ERROR_SUCCESS;
4029 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4031 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4032 comp->Action = comp->Installed;
4033 return ERROR_SUCCESS;
4035 comp->Action = INSTALLSTATE_LOCAL;
4037 identifier = MSI_RecordGetString( row, 1 );
4038 section = MSI_RecordGetString( row, 4 );
4039 key = MSI_RecordGetString( row, 5 );
4040 value = MSI_RecordGetString( row, 6 );
4041 action = MSI_RecordGetInteger( row, 7 );
4043 deformat_string( package, section, &deformated_section );
4044 deformat_string( package, key, &deformated_key );
4045 deformat_string( package, value, &deformated_value );
4047 if (action == msidbIniFileActionRemoveLine)
4049 filename = get_ini_file_name( package, row );
4051 TRACE("Removing key %s from section %s in %s\n",
4052 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4054 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4056 WARN("Unable to remove key %u\n", GetLastError());
4058 msi_free( filename );
4061 FIXME("Unsupported action %d\n", action);
4063 uirow = MSI_CreateRecord( 4 );
4064 MSI_RecordSetStringW( uirow, 1, identifier );
4065 MSI_RecordSetStringW( uirow, 2, deformated_section );
4066 MSI_RecordSetStringW( uirow, 3, deformated_key );
4067 MSI_RecordSetStringW( uirow, 4, deformated_value );
4068 ui_actiondata( package, szRemoveIniValues, uirow );
4069 msiobj_release( &uirow->hdr );
4071 msi_free( deformated_key );
4072 msi_free( deformated_value );
4073 msi_free( deformated_section );
4074 return ERROR_SUCCESS;
4077 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4081 static const WCHAR query[] =
4082 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4083 '`','I','n','i','F','i','l','e','`',0};
4084 static const WCHAR remove_query[] =
4085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4086 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4088 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4089 if (rc == ERROR_SUCCESS)
4091 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4092 msiobj_release( &view->hdr );
4093 if (rc != ERROR_SUCCESS)
4097 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4098 if (rc == ERROR_SUCCESS)
4100 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4101 msiobj_release( &view->hdr );
4102 if (rc != ERROR_SUCCESS)
4106 return ERROR_SUCCESS;
4109 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4111 MSIPACKAGE *package = param;
4116 static const WCHAR ExeStr[] =
4117 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4118 static const WCHAR close[] = {'\"',0};
4120 PROCESS_INFORMATION info;
4125 memset(&si,0,sizeof(STARTUPINFOW));
4127 filename = MSI_RecordGetString(row,1);
4128 file = get_loaded_file( package, filename );
4132 ERR("Unable to find file id %s\n",debugstr_w(filename));
4133 return ERROR_SUCCESS;
4136 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4138 FullName = msi_alloc(len*sizeof(WCHAR));
4139 strcpyW(FullName,ExeStr);
4140 strcatW( FullName, file->TargetPath );
4141 strcatW(FullName,close);
4143 TRACE("Registering %s\n",debugstr_w(FullName));
4144 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4149 CloseHandle(info.hThread);
4150 msi_dialog_check_messages(info.hProcess);
4151 CloseHandle(info.hProcess);
4154 uirow = MSI_CreateRecord( 2 );
4155 MSI_RecordSetStringW( uirow, 1, filename );
4156 uipath = strdupW( file->TargetPath );
4157 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4158 MSI_RecordSetStringW( uirow, 2, uipath );
4159 ui_actiondata( package, szSelfRegModules, uirow );
4160 msiobj_release( &uirow->hdr );
4162 msi_free( FullName );
4164 return ERROR_SUCCESS;
4167 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4171 static const WCHAR ExecSeqQuery[] =
4172 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4173 '`','S','e','l','f','R','e','g','`',0};
4175 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4176 if (rc != ERROR_SUCCESS)
4178 TRACE("no SelfReg table\n");
4179 return ERROR_SUCCESS;
4182 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4183 msiobj_release(&view->hdr);
4185 return ERROR_SUCCESS;
4188 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4190 static const WCHAR regsvr32[] =
4191 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4192 static const WCHAR close[] = {'\"',0};
4193 MSIPACKAGE *package = param;
4199 PROCESS_INFORMATION pi;
4204 memset( &si, 0, sizeof(STARTUPINFOW) );
4206 filename = MSI_RecordGetString( row, 1 );
4207 file = get_loaded_file( package, filename );
4211 ERR("Unable to find file id %s\n", debugstr_w(filename));
4212 return ERROR_SUCCESS;
4215 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4217 cmdline = msi_alloc( len * sizeof(WCHAR) );
4218 strcpyW( cmdline, regsvr32 );
4219 strcatW( cmdline, file->TargetPath );
4220 strcatW( cmdline, close );
4222 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4224 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4227 CloseHandle( pi.hThread );
4228 msi_dialog_check_messages( pi.hProcess );
4229 CloseHandle( pi.hProcess );
4232 uirow = MSI_CreateRecord( 2 );
4233 MSI_RecordSetStringW( uirow, 1, filename );
4234 uipath = strdupW( file->TargetPath );
4235 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4236 MSI_RecordSetStringW( uirow, 2, uipath );
4237 ui_actiondata( package, szSelfUnregModules, uirow );
4238 msiobj_release( &uirow->hdr );
4240 msi_free( cmdline );
4242 return ERROR_SUCCESS;
4245 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4249 static const WCHAR query[] =
4250 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4251 '`','S','e','l','f','R','e','g','`',0};
4253 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4254 if (rc != ERROR_SUCCESS)
4256 TRACE("no SelfReg table\n");
4257 return ERROR_SUCCESS;
4260 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4261 msiobj_release( &view->hdr );
4263 return ERROR_SUCCESS;
4266 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4268 MSIFEATURE *feature;
4270 HKEY hkey = NULL, userdata = NULL;
4272 if (!msi_check_publish(package))
4273 return ERROR_SUCCESS;
4275 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4277 if (rc != ERROR_SUCCESS)
4280 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4282 if (rc != ERROR_SUCCESS)
4285 /* here the guids are base 85 encoded */
4286 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4292 BOOL absent = FALSE;
4295 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4296 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4297 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4300 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4304 if (feature->Feature_Parent)
4305 size += strlenW( feature->Feature_Parent )+2;
4307 data = msi_alloc(size * sizeof(WCHAR));
4310 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4312 MSICOMPONENT* component = cl->component;
4316 if (component->ComponentId)
4318 TRACE("From %s\n",debugstr_w(component->ComponentId));
4319 CLSIDFromString(component->ComponentId, &clsid);
4320 encode_base85_guid(&clsid,buf);
4321 TRACE("to %s\n",debugstr_w(buf));
4326 if (feature->Feature_Parent)
4328 static const WCHAR sep[] = {'\2',0};
4330 strcatW(data,feature->Feature_Parent);
4333 msi_reg_set_val_str( userdata, feature->Feature, data );
4337 if (feature->Feature_Parent)
4338 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4341 size += sizeof(WCHAR);
4342 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4343 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4347 size += 2*sizeof(WCHAR);
4348 data = msi_alloc(size);
4351 if (feature->Feature_Parent)
4352 strcpyW( &data[1], feature->Feature_Parent );
4353 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4359 uirow = MSI_CreateRecord( 1 );
4360 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4361 ui_actiondata( package, szPublishFeatures, uirow);
4362 msiobj_release( &uirow->hdr );
4363 /* FIXME: call ui_progress? */
4368 RegCloseKey(userdata);
4372 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4377 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4379 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4381 if (r == ERROR_SUCCESS)
4383 RegDeleteValueW(hkey, feature->Feature);
4387 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4389 if (r == ERROR_SUCCESS)
4391 RegDeleteValueW(hkey, feature->Feature);
4395 return ERROR_SUCCESS;
4398 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4400 MSIFEATURE *feature;
4402 if (!msi_check_unpublish(package))
4403 return ERROR_SUCCESS;
4405 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4407 msi_unpublish_feature(package, feature);
4410 return ERROR_SUCCESS;
4413 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4415 LPWSTR prop, val, key;
4421 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4422 static const WCHAR szWindowsInstaller[] =
4423 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4424 static const WCHAR modpath_fmt[] =
4425 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4426 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4427 static const WCHAR szModifyPath[] =
4428 {'M','o','d','i','f','y','P','a','t','h',0};
4429 static const WCHAR szUninstallString[] =
4430 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4431 static const WCHAR szEstimatedSize[] =
4432 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4433 static const WCHAR szProductLanguage[] =
4434 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4435 static const WCHAR szProductVersion[] =
4436 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4437 static const WCHAR szProductName[] =
4438 {'P','r','o','d','u','c','t','N','a','m','e',0};
4439 static const WCHAR szDisplayName[] =
4440 {'D','i','s','p','l','a','y','N','a','m','e',0};
4441 static const WCHAR szDisplayVersion[] =
4442 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4443 static const WCHAR szManufacturer[] =
4444 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4446 static const LPCSTR propval[] = {
4447 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4448 "ARPCONTACT", "Contact",
4449 "ARPCOMMENTS", "Comments",
4450 "ProductName", "DisplayName",
4451 "ProductVersion", "DisplayVersion",
4452 "ARPHELPLINK", "HelpLink",
4453 "ARPHELPTELEPHONE", "HelpTelephone",
4454 "ARPINSTALLLOCATION", "InstallLocation",
4455 "SourceDir", "InstallSource",
4456 "Manufacturer", "Publisher",
4457 "ARPREADME", "Readme",
4459 "ARPURLINFOABOUT", "URLInfoAbout",
4460 "ARPURLUPDATEINFO", "URLUpdateInfo",
4463 const LPCSTR *p = propval;
4467 prop = strdupAtoW(*p++);
4468 key = strdupAtoW(*p++);
4469 val = msi_dup_property(package, prop);
4470 msi_reg_set_val_str(hkey, key, val);
4476 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4478 size = deformat_string(package, modpath_fmt, &buffer);
4479 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4480 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4483 /* FIXME: Write real Estimated Size when we have it */
4484 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4486 buffer = msi_dup_property(package, szProductName);
4487 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4490 buffer = msi_dup_property(package, cszSourceDir);
4491 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4494 buffer = msi_dup_property(package, szManufacturer);
4495 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4498 GetLocalTime(&systime);
4499 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4500 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4502 langid = msi_get_property_int(package, szProductLanguage, 0);
4503 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4505 buffer = msi_dup_property(package, szProductVersion);
4506 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4509 DWORD verdword = msi_version_str_to_dword(buffer);
4511 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4512 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4517 return ERROR_SUCCESS;
4520 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4522 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4524 LPWSTR upgrade_code;
4529 static const WCHAR szUpgradeCode[] = {
4530 'U','p','g','r','a','d','e','C','o','d','e',0};
4532 /* FIXME: also need to publish if the product is in advertise mode */
4533 if (!msi_check_publish(package))
4534 return ERROR_SUCCESS;
4536 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4537 if (rc != ERROR_SUCCESS)
4540 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4541 NULL, &props, TRUE);
4542 if (rc != ERROR_SUCCESS)
4545 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4546 msi_free( package->db->localfile );
4547 package->db->localfile = NULL;
4549 rc = msi_publish_install_properties(package, hkey);
4550 if (rc != ERROR_SUCCESS)
4553 rc = msi_publish_install_properties(package, props);
4554 if (rc != ERROR_SUCCESS)
4557 upgrade_code = msi_dup_property(package, szUpgradeCode);
4560 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4561 squash_guid(package->ProductCode, squashed_pc);
4562 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4563 RegCloseKey(upgrade);
4564 msi_free(upgrade_code);
4568 uirow = MSI_CreateRecord( 1 );
4569 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4570 ui_actiondata( package, szRegisterProduct, uirow );
4571 msiobj_release( &uirow->hdr );
4574 return ERROR_SUCCESS;
4577 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4579 return execute_script(package,INSTALL_SCRIPT);
4582 static UINT msi_unpublish_product(MSIPACKAGE *package)
4585 LPWSTR remove = NULL;
4586 LPWSTR *features = NULL;
4587 BOOL full_uninstall = TRUE;
4588 MSIFEATURE *feature;
4590 static const WCHAR szUpgradeCode[] =
4591 {'U','p','g','r','a','d','e','C','o','d','e',0};
4593 remove = msi_dup_property(package, szRemove);
4595 return ERROR_SUCCESS;
4597 features = msi_split_string(remove, ',');
4601 ERR("REMOVE feature list is empty!\n");
4602 return ERROR_FUNCTION_FAILED;
4605 if (!lstrcmpW(features[0], szAll))
4606 full_uninstall = TRUE;
4609 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4611 if (feature->Action != INSTALLSTATE_ABSENT)
4612 full_uninstall = FALSE;
4616 if (!full_uninstall)
4619 MSIREG_DeleteProductKey(package->ProductCode);
4620 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4621 MSIREG_DeleteUninstallKey(package->ProductCode);
4623 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4625 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4626 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4630 MSIREG_DeleteUserProductKey(package->ProductCode);
4631 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4634 upgrade = msi_dup_property(package, szUpgradeCode);
4637 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4644 return ERROR_SUCCESS;
4647 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4651 rc = msi_unpublish_product(package);
4652 if (rc != ERROR_SUCCESS)
4655 /* turn off scheduling */
4656 package->script->CurrentlyScripting= FALSE;
4658 /* first do the same as an InstallExecute */
4659 rc = ACTION_InstallExecute(package);
4660 if (rc != ERROR_SUCCESS)
4663 /* then handle Commit Actions */
4664 rc = execute_script(package,COMMIT_SCRIPT);
4669 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4671 static const WCHAR RunOnce[] = {
4672 'S','o','f','t','w','a','r','e','\\',
4673 'M','i','c','r','o','s','o','f','t','\\',
4674 'W','i','n','d','o','w','s','\\',
4675 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4676 'R','u','n','O','n','c','e',0};
4677 static const WCHAR InstallRunOnce[] = {
4678 'S','o','f','t','w','a','r','e','\\',
4679 'M','i','c','r','o','s','o','f','t','\\',
4680 'W','i','n','d','o','w','s','\\',
4681 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4682 'I','n','s','t','a','l','l','e','r','\\',
4683 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4685 static const WCHAR msiexec_fmt[] = {
4687 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4688 '\"','%','s','\"',0};
4689 static const WCHAR install_fmt[] = {
4690 '/','I',' ','\"','%','s','\"',' ',
4691 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4692 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4693 WCHAR buffer[256], sysdir[MAX_PATH];
4695 WCHAR squished_pc[100];
4697 squash_guid(package->ProductCode,squished_pc);
4699 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4700 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4701 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4704 msi_reg_set_val_str( hkey, squished_pc, buffer );
4707 TRACE("Reboot command %s\n",debugstr_w(buffer));
4709 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4710 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4712 msi_reg_set_val_str( hkey, squished_pc, buffer );
4715 return ERROR_INSTALL_SUSPEND;
4718 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4724 * We are currently doing what should be done here in the top level Install
4725 * however for Administrative and uninstalls this step will be needed
4727 if (!package->PackagePath)
4728 return ERROR_SUCCESS;
4730 msi_set_sourcedir_props(package, TRUE);
4732 attrib = GetFileAttributesW(package->db->path);
4733 if (attrib == INVALID_FILE_ATTRIBUTES)
4739 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4740 package->Context, MSICODE_PRODUCT,
4741 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4742 if (rc == ERROR_MORE_DATA)
4744 prompt = msi_alloc(size * sizeof(WCHAR));
4745 MsiSourceListGetInfoW(package->ProductCode, NULL,
4746 package->Context, MSICODE_PRODUCT,
4747 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4750 prompt = strdupW(package->db->path);
4752 msg = generate_error_string(package,1302,1,prompt);
4753 while(attrib == INVALID_FILE_ATTRIBUTES)
4755 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4758 rc = ERROR_INSTALL_USEREXIT;
4761 attrib = GetFileAttributesW(package->db->path);
4767 return ERROR_SUCCESS;
4772 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4775 LPWSTR buffer, productid = NULL;
4776 UINT i, rc = ERROR_SUCCESS;
4779 static const WCHAR szPropKeys[][80] =
4781 {'P','r','o','d','u','c','t','I','D',0},
4782 {'U','S','E','R','N','A','M','E',0},
4783 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4787 static const WCHAR szRegKeys[][80] =
4789 {'P','r','o','d','u','c','t','I','D',0},
4790 {'R','e','g','O','w','n','e','r',0},
4791 {'R','e','g','C','o','m','p','a','n','y',0},
4795 if (msi_check_unpublish(package))
4797 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4801 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4805 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4807 if (rc != ERROR_SUCCESS)
4810 for( i = 0; szPropKeys[i][0]; i++ )
4812 buffer = msi_dup_property( package, szPropKeys[i] );
4813 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4818 uirow = MSI_CreateRecord( 1 );
4819 MSI_RecordSetStringW( uirow, 1, productid );
4820 ui_actiondata( package, szRegisterUser, uirow );
4821 msiobj_release( &uirow->hdr );
4823 msi_free(productid);
4829 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4833 package->script->InWhatSequence |= SEQUENCE_EXEC;
4834 rc = ACTION_ProcessExecSequence(package,FALSE);
4839 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4841 MSIPACKAGE *package = param;
4842 LPCWSTR compgroupid, component, feature, qualifier, text;
4843 LPWSTR advertise = NULL, output = NULL;
4851 feature = MSI_RecordGetString(rec, 5);
4852 feat = get_loaded_feature(package, feature);
4854 return ERROR_SUCCESS;
4856 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4857 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4858 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4860 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4861 feat->Action = feat->Installed;
4862 return ERROR_SUCCESS;
4865 component = MSI_RecordGetString(rec, 3);
4866 comp = get_loaded_component(package, component);
4868 return ERROR_SUCCESS;
4870 compgroupid = MSI_RecordGetString(rec,1);
4871 qualifier = MSI_RecordGetString(rec,2);
4873 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4874 if (rc != ERROR_SUCCESS)
4877 text = MSI_RecordGetString(rec,4);
4878 advertise = create_component_advertise_string(package, comp, feature);
4880 sz = strlenW(advertise);
4883 sz += lstrlenW(text);
4886 sz *= sizeof(WCHAR);
4888 output = msi_alloc_zero(sz);
4889 strcpyW(output,advertise);
4890 msi_free(advertise);
4893 strcatW(output,text);
4895 msi_reg_set_val_multi_str( hkey, qualifier, output );
4902 uirow = MSI_CreateRecord( 2 );
4903 MSI_RecordSetStringW( uirow, 1, compgroupid );
4904 MSI_RecordSetStringW( uirow, 2, qualifier);
4905 ui_actiondata( package, szPublishComponents, uirow);
4906 msiobj_release( &uirow->hdr );
4907 /* FIXME: call ui_progress? */
4913 * At present I am ignorning the advertised components part of this and only
4914 * focusing on the qualified component sets
4916 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4920 static const WCHAR ExecSeqQuery[] =
4921 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4922 '`','P','u','b','l','i','s','h',
4923 'C','o','m','p','o','n','e','n','t','`',0};
4925 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4926 if (rc != ERROR_SUCCESS)
4927 return ERROR_SUCCESS;
4929 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4930 msiobj_release(&view->hdr);
4935 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4937 static const WCHAR szInstallerComponents[] = {
4938 'S','o','f','t','w','a','r','e','\\',
4939 'M','i','c','r','o','s','o','f','t','\\',
4940 'I','n','s','t','a','l','l','e','r','\\',
4941 'C','o','m','p','o','n','e','n','t','s','\\',0};
4943 MSIPACKAGE *package = param;
4944 LPCWSTR compgroupid, component, feature, qualifier;
4948 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4951 feature = MSI_RecordGetString( rec, 5 );
4952 feat = get_loaded_feature( package, feature );
4954 return ERROR_SUCCESS;
4956 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4958 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4959 feat->Action = feat->Installed;
4960 return ERROR_SUCCESS;
4963 component = MSI_RecordGetString( rec, 3 );
4964 comp = get_loaded_component( package, component );
4966 return ERROR_SUCCESS;
4968 compgroupid = MSI_RecordGetString( rec, 1 );
4969 qualifier = MSI_RecordGetString( rec, 2 );
4971 squash_guid( compgroupid, squashed );
4972 strcpyW( keypath, szInstallerComponents );
4973 strcatW( keypath, squashed );
4975 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4976 if (res != ERROR_SUCCESS)
4978 WARN("Unable to delete component key %d\n", res);
4981 uirow = MSI_CreateRecord( 2 );
4982 MSI_RecordSetStringW( uirow, 1, compgroupid );
4983 MSI_RecordSetStringW( uirow, 2, qualifier );
4984 ui_actiondata( package, szUnpublishComponents, uirow );
4985 msiobj_release( &uirow->hdr );
4987 return ERROR_SUCCESS;
4990 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4994 static const WCHAR query[] =
4995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4996 '`','P','u','b','l','i','s','h',
4997 'C','o','m','p','o','n','e','n','t','`',0};
4999 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5000 if (rc != ERROR_SUCCESS)
5001 return ERROR_SUCCESS;
5003 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5004 msiobj_release( &view->hdr );
5009 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5011 MSIPACKAGE *package = param;
5014 SC_HANDLE hscm, service = NULL;
5015 LPCWSTR comp, depends, pass;
5016 LPWSTR name = NULL, disp = NULL;
5017 LPCWSTR load_order, serv_name, key;
5018 DWORD serv_type, start_type;
5021 static const WCHAR query[] =
5022 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5023 '`','C','o','m','p','o','n','e','n','t','`',' ',
5024 'W','H','E','R','E',' ',
5025 '`','C','o','m','p','o','n','e','n','t','`',' ',
5026 '=','\'','%','s','\'',0};
5028 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5031 ERR("Failed to open the SC Manager!\n");
5035 start_type = MSI_RecordGetInteger(rec, 5);
5036 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5039 depends = MSI_RecordGetString(rec, 8);
5040 if (depends && *depends)
5041 FIXME("Dependency list unhandled!\n");
5043 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5044 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5045 serv_type = MSI_RecordGetInteger(rec, 4);
5046 err_control = MSI_RecordGetInteger(rec, 6);
5047 load_order = MSI_RecordGetString(rec, 7);
5048 serv_name = MSI_RecordGetString(rec, 9);
5049 pass = MSI_RecordGetString(rec, 10);
5050 comp = MSI_RecordGetString(rec, 12);
5052 /* fetch the service path */
5053 row = MSI_QueryGetRecord(package->db, query, comp);
5056 ERR("Control query failed!\n");
5060 key = MSI_RecordGetString(row, 6);
5062 file = get_loaded_file(package, key);
5063 msiobj_release(&row->hdr);
5066 ERR("Failed to load the service file\n");
5070 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5071 start_type, err_control, file->TargetPath,
5072 load_order, NULL, NULL, serv_name, pass);
5075 if (GetLastError() != ERROR_SERVICE_EXISTS)
5076 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5080 CloseServiceHandle(service);
5081 CloseServiceHandle(hscm);
5085 return ERROR_SUCCESS;
5088 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5092 static const WCHAR ExecSeqQuery[] =
5093 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5094 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5096 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5097 if (rc != ERROR_SUCCESS)
5098 return ERROR_SUCCESS;
5100 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5101 msiobj_release(&view->hdr);
5106 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5107 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5109 LPCWSTR *vector, *temp_vector;
5113 static const WCHAR separator[] = {'[','~',']',0};
5116 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5121 vector = msi_alloc(sizeof(LPWSTR));
5129 vector[*numargs - 1] = p;
5131 if ((q = strstrW(p, separator)))
5135 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5141 vector = temp_vector;
5150 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5152 MSIPACKAGE *package = param;
5154 SC_HANDLE scm = NULL, service = NULL;
5155 LPCWSTR component, *vector = NULL;
5157 DWORD event, numargs;
5158 UINT r = ERROR_FUNCTION_FAILED;
5160 component = MSI_RecordGetString(rec, 6);
5161 comp = get_loaded_component(package, component);
5163 return ERROR_SUCCESS;
5165 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5167 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5168 comp->Action = comp->Installed;
5169 return ERROR_SUCCESS;
5171 comp->Action = INSTALLSTATE_LOCAL;
5173 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5174 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5175 event = MSI_RecordGetInteger(rec, 3);
5177 if (!(event & msidbServiceControlEventStart))
5183 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5186 ERR("Failed to open the service control manager\n");
5190 service = OpenServiceW(scm, name, SERVICE_START);
5193 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5197 vector = msi_service_args_to_vector(args, &numargs);
5199 if (!StartServiceW(service, numargs, vector) &&
5200 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5202 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5209 CloseServiceHandle(service);
5210 CloseServiceHandle(scm);
5218 static UINT ACTION_StartServices( MSIPACKAGE *package )
5223 static const WCHAR query[] = {
5224 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5225 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5227 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5228 if (rc != ERROR_SUCCESS)
5229 return ERROR_SUCCESS;
5231 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5232 msiobj_release(&view->hdr);
5237 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5239 DWORD i, needed, count;
5240 ENUM_SERVICE_STATUSW *dependencies;
5244 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5245 0, &needed, &count))
5248 if (GetLastError() != ERROR_MORE_DATA)
5251 dependencies = msi_alloc(needed);
5255 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5256 needed, &needed, &count))
5259 for (i = 0; i < count; i++)
5261 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5262 SERVICE_STOP | SERVICE_QUERY_STATUS);
5266 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5273 msi_free(dependencies);
5277 static UINT stop_service( LPCWSTR name )
5279 SC_HANDLE scm = NULL, service = NULL;
5280 SERVICE_STATUS status;
5281 SERVICE_STATUS_PROCESS ssp;
5284 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5287 WARN("Failed to open the SCM: %d\n", GetLastError());
5291 service = OpenServiceW(scm, name,
5293 SERVICE_QUERY_STATUS |
5294 SERVICE_ENUMERATE_DEPENDENTS);
5297 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5301 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5302 sizeof(SERVICE_STATUS_PROCESS), &needed))
5304 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5308 if (ssp.dwCurrentState == SERVICE_STOPPED)
5311 stop_service_dependents(scm, service);
5313 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5314 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5317 CloseServiceHandle(service);
5318 CloseServiceHandle(scm);
5320 return ERROR_SUCCESS;
5323 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5325 MSIPACKAGE *package = param;
5331 event = MSI_RecordGetInteger( rec, 3 );
5332 if (!(event & msidbServiceControlEventStop))
5333 return ERROR_SUCCESS;
5335 component = MSI_RecordGetString( rec, 6 );
5336 comp = get_loaded_component( package, component );
5338 return ERROR_SUCCESS;
5340 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5342 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5343 comp->Action = comp->Installed;
5344 return ERROR_SUCCESS;
5346 comp->Action = INSTALLSTATE_ABSENT;
5348 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5349 stop_service( name );
5352 return ERROR_SUCCESS;
5355 static UINT ACTION_StopServices( MSIPACKAGE *package )
5360 static const WCHAR query[] = {
5361 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5362 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5364 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5365 if (rc != ERROR_SUCCESS)
5366 return ERROR_SUCCESS;
5368 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5369 msiobj_release(&view->hdr);
5374 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5376 MSIPACKAGE *package = param;
5380 LPWSTR name = NULL, display_name = NULL;
5382 SC_HANDLE scm = NULL, service = NULL;
5384 event = MSI_RecordGetInteger( rec, 3 );
5385 if (!(event & msidbServiceControlEventDelete))
5386 return ERROR_SUCCESS;
5388 component = MSI_RecordGetString(rec, 6);
5389 comp = get_loaded_component(package, component);
5391 return ERROR_SUCCESS;
5393 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5395 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5396 comp->Action = comp->Installed;
5397 return ERROR_SUCCESS;
5399 comp->Action = INSTALLSTATE_ABSENT;
5401 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5402 stop_service( name );
5404 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5407 WARN("Failed to open the SCM: %d\n", GetLastError());
5412 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5413 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5415 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5416 GetServiceDisplayNameW( scm, name, display_name, &len );
5419 service = OpenServiceW( scm, name, DELETE );
5422 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5426 if (!DeleteService( service ))
5427 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5430 uirow = MSI_CreateRecord( 2 );
5431 MSI_RecordSetStringW( uirow, 1, display_name );
5432 MSI_RecordSetStringW( uirow, 2, name );
5433 ui_actiondata( package, szDeleteServices, uirow );
5434 msiobj_release( &uirow->hdr );
5436 CloseServiceHandle( service );
5437 CloseServiceHandle( scm );
5439 msi_free( display_name );
5441 return ERROR_SUCCESS;
5444 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5449 static const WCHAR query[] = {
5450 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5451 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5453 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5454 if (rc != ERROR_SUCCESS)
5455 return ERROR_SUCCESS;
5457 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5458 msiobj_release( &view->hdr );
5463 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5467 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5469 if (!lstrcmpW(file->File, filename))
5476 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5478 MSIPACKAGE *package = param;
5479 LPWSTR driver, driver_path, ptr;
5480 WCHAR outpath[MAX_PATH];
5481 MSIFILE *driver_file, *setup_file;
5485 UINT r = ERROR_SUCCESS;
5487 static const WCHAR driver_fmt[] = {
5488 'D','r','i','v','e','r','=','%','s',0};
5489 static const WCHAR setup_fmt[] = {
5490 'S','e','t','u','p','=','%','s',0};
5491 static const WCHAR usage_fmt[] = {
5492 'F','i','l','e','U','s','a','g','e','=','1',0};
5494 desc = MSI_RecordGetString(rec, 3);
5496 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5497 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5501 ERR("ODBC Driver entry not found!\n");
5502 return ERROR_FUNCTION_FAILED;
5505 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5507 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5508 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5510 driver = msi_alloc(len * sizeof(WCHAR));
5512 return ERROR_OUTOFMEMORY;
5515 lstrcpyW(ptr, desc);
5516 ptr += lstrlenW(ptr) + 1;
5518 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5523 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5527 lstrcpyW(ptr, usage_fmt);
5528 ptr += lstrlenW(ptr) + 1;
5531 driver_path = strdupW(driver_file->TargetPath);
5532 ptr = strrchrW(driver_path, '\\');
5533 if (ptr) *ptr = '\0';
5535 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5536 NULL, ODBC_INSTALL_COMPLETE, &usage))
5538 ERR("Failed to install SQL driver!\n");
5539 r = ERROR_FUNCTION_FAILED;
5542 uirow = MSI_CreateRecord( 5 );
5543 MSI_RecordSetStringW( uirow, 1, desc );
5544 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5545 MSI_RecordSetStringW( uirow, 3, driver_path );
5546 ui_actiondata( package, szInstallODBC, uirow );
5547 msiobj_release( &uirow->hdr );
5550 msi_free(driver_path);
5555 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5557 MSIPACKAGE *package = param;
5558 LPWSTR translator, translator_path, ptr;
5559 WCHAR outpath[MAX_PATH];
5560 MSIFILE *translator_file, *setup_file;
5564 UINT r = ERROR_SUCCESS;
5566 static const WCHAR translator_fmt[] = {
5567 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5568 static const WCHAR setup_fmt[] = {
5569 'S','e','t','u','p','=','%','s',0};
5571 desc = MSI_RecordGetString(rec, 3);
5573 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5574 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5576 if (!translator_file)
5578 ERR("ODBC Translator entry not found!\n");
5579 return ERROR_FUNCTION_FAILED;
5582 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5584 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5586 translator = msi_alloc(len * sizeof(WCHAR));
5588 return ERROR_OUTOFMEMORY;
5591 lstrcpyW(ptr, desc);
5592 ptr += lstrlenW(ptr) + 1;
5594 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5599 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5604 translator_path = strdupW(translator_file->TargetPath);
5605 ptr = strrchrW(translator_path, '\\');
5606 if (ptr) *ptr = '\0';
5608 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5609 NULL, ODBC_INSTALL_COMPLETE, &usage))
5611 ERR("Failed to install SQL translator!\n");
5612 r = ERROR_FUNCTION_FAILED;
5615 uirow = MSI_CreateRecord( 5 );
5616 MSI_RecordSetStringW( uirow, 1, desc );
5617 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5618 MSI_RecordSetStringW( uirow, 3, translator_path );
5619 ui_actiondata( package, szInstallODBC, uirow );
5620 msiobj_release( &uirow->hdr );
5622 msi_free(translator);
5623 msi_free(translator_path);
5628 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5630 MSIPACKAGE *package = param;
5632 LPCWSTR desc, driver;
5633 WORD request = ODBC_ADD_SYS_DSN;
5636 UINT r = ERROR_SUCCESS;
5639 static const WCHAR attrs_fmt[] = {
5640 'D','S','N','=','%','s',0 };
5642 desc = MSI_RecordGetString(rec, 3);
5643 driver = MSI_RecordGetString(rec, 4);
5644 registration = MSI_RecordGetInteger(rec, 5);
5646 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5647 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5649 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5650 attrs = msi_alloc(len * sizeof(WCHAR));
5652 return ERROR_OUTOFMEMORY;
5654 len = sprintfW(attrs, attrs_fmt, desc);
5657 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5659 ERR("Failed to install SQL data source!\n");
5660 r = ERROR_FUNCTION_FAILED;
5663 uirow = MSI_CreateRecord( 5 );
5664 MSI_RecordSetStringW( uirow, 1, desc );
5665 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5666 MSI_RecordSetInteger( uirow, 3, request );
5667 ui_actiondata( package, szInstallODBC, uirow );
5668 msiobj_release( &uirow->hdr );
5675 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5680 static const WCHAR driver_query[] = {
5681 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5682 'O','D','B','C','D','r','i','v','e','r',0 };
5684 static const WCHAR translator_query[] = {
5685 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5686 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5688 static const WCHAR source_query[] = {
5689 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5690 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5692 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5693 if (rc != ERROR_SUCCESS)
5694 return ERROR_SUCCESS;
5696 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5697 msiobj_release(&view->hdr);
5699 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5700 if (rc != ERROR_SUCCESS)
5701 return ERROR_SUCCESS;
5703 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5704 msiobj_release(&view->hdr);
5706 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5707 if (rc != ERROR_SUCCESS)
5708 return ERROR_SUCCESS;
5710 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5711 msiobj_release(&view->hdr);
5716 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5718 MSIPACKAGE *package = param;
5723 desc = MSI_RecordGetString( rec, 3 );
5724 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5726 WARN("Failed to remove ODBC driver\n");
5730 FIXME("Usage count reached 0\n");
5733 uirow = MSI_CreateRecord( 2 );
5734 MSI_RecordSetStringW( uirow, 1, desc );
5735 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5736 ui_actiondata( package, szRemoveODBC, uirow );
5737 msiobj_release( &uirow->hdr );
5739 return ERROR_SUCCESS;
5742 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5744 MSIPACKAGE *package = param;
5749 desc = MSI_RecordGetString( rec, 3 );
5750 if (!SQLRemoveTranslatorW( desc, &usage ))
5752 WARN("Failed to remove ODBC translator\n");
5756 FIXME("Usage count reached 0\n");
5759 uirow = MSI_CreateRecord( 2 );
5760 MSI_RecordSetStringW( uirow, 1, desc );
5761 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5762 ui_actiondata( package, szRemoveODBC, uirow );
5763 msiobj_release( &uirow->hdr );
5765 return ERROR_SUCCESS;
5768 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5770 MSIPACKAGE *package = param;
5773 LPCWSTR desc, driver;
5774 WORD request = ODBC_REMOVE_SYS_DSN;
5778 static const WCHAR attrs_fmt[] = {
5779 'D','S','N','=','%','s',0 };
5781 desc = MSI_RecordGetString( rec, 3 );
5782 driver = MSI_RecordGetString( rec, 4 );
5783 registration = MSI_RecordGetInteger( rec, 5 );
5785 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5786 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5788 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5789 attrs = msi_alloc( len * sizeof(WCHAR) );
5791 return ERROR_OUTOFMEMORY;
5793 FIXME("Use ODBCSourceAttribute table\n");
5795 len = sprintfW( attrs, attrs_fmt, desc );
5798 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5800 WARN("Failed to remove ODBC data source\n");
5804 uirow = MSI_CreateRecord( 3 );
5805 MSI_RecordSetStringW( uirow, 1, desc );
5806 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5807 MSI_RecordSetInteger( uirow, 3, request );
5808 ui_actiondata( package, szRemoveODBC, uirow );
5809 msiobj_release( &uirow->hdr );
5811 return ERROR_SUCCESS;
5814 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5819 static const WCHAR driver_query[] = {
5820 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5821 'O','D','B','C','D','r','i','v','e','r',0 };
5823 static const WCHAR translator_query[] = {
5824 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5825 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5827 static const WCHAR source_query[] = {
5828 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5829 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5831 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5832 if (rc != ERROR_SUCCESS)
5833 return ERROR_SUCCESS;
5835 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5836 msiobj_release( &view->hdr );
5838 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5839 if (rc != ERROR_SUCCESS)
5840 return ERROR_SUCCESS;
5842 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5843 msiobj_release( &view->hdr );
5845 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5846 if (rc != ERROR_SUCCESS)
5847 return ERROR_SUCCESS;
5849 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5850 msiobj_release( &view->hdr );
5855 #define ENV_ACT_SETALWAYS 0x1
5856 #define ENV_ACT_SETABSENT 0x2
5857 #define ENV_ACT_REMOVE 0x4
5858 #define ENV_ACT_REMOVEMATCH 0x8
5860 #define ENV_MOD_MACHINE 0x20000000
5861 #define ENV_MOD_APPEND 0x40000000
5862 #define ENV_MOD_PREFIX 0x80000000
5863 #define ENV_MOD_MASK 0xC0000000
5865 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5867 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5869 LPCWSTR cptr = *name;
5871 static const WCHAR prefix[] = {'[','~',']',0};
5872 static const int prefix_len = 3;
5878 *flags |= ENV_ACT_SETALWAYS;
5879 else if (*cptr == '+')
5880 *flags |= ENV_ACT_SETABSENT;
5881 else if (*cptr == '-')
5882 *flags |= ENV_ACT_REMOVE;
5883 else if (*cptr == '!')
5884 *flags |= ENV_ACT_REMOVEMATCH;
5885 else if (*cptr == '*')
5886 *flags |= ENV_MOD_MACHINE;
5896 ERR("Missing environment variable\n");
5897 return ERROR_FUNCTION_FAILED;
5902 LPCWSTR ptr = *value;
5903 if (!strncmpW(ptr, prefix, prefix_len))
5905 if (ptr[prefix_len] == szSemiColon[0])
5907 *flags |= ENV_MOD_APPEND;
5908 *value += lstrlenW(prefix);
5915 else if (lstrlenW(*value) >= prefix_len)
5917 ptr += lstrlenW(ptr) - prefix_len;
5918 if (!lstrcmpW(ptr, prefix))
5920 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5922 *flags |= ENV_MOD_PREFIX;
5923 /* the "[~]" will be removed by deformat_string */;
5933 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5934 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5935 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5936 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5938 ERR("Invalid flags: %08x\n", *flags);
5939 return ERROR_FUNCTION_FAILED;
5943 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5945 return ERROR_SUCCESS;
5948 static UINT open_env_key( DWORD flags, HKEY *key )
5950 static const WCHAR user_env[] =
5951 {'E','n','v','i','r','o','n','m','e','n','t',0};
5952 static const WCHAR machine_env[] =
5953 {'S','y','s','t','e','m','\\',
5954 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5955 'C','o','n','t','r','o','l','\\',
5956 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5957 'E','n','v','i','r','o','n','m','e','n','t',0};
5962 if (flags & ENV_MOD_MACHINE)
5965 root = HKEY_LOCAL_MACHINE;
5970 root = HKEY_CURRENT_USER;
5973 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
5974 if (res != ERROR_SUCCESS)
5976 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
5977 return ERROR_FUNCTION_FAILED;
5980 return ERROR_SUCCESS;
5983 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5985 MSIPACKAGE *package = param;
5986 LPCWSTR name, value, component;
5987 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
5988 DWORD flags, type, size;
5995 component = MSI_RecordGetString(rec, 4);
5996 comp = get_loaded_component(package, component);
5998 return ERROR_SUCCESS;
6000 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6002 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6003 comp->Action = comp->Installed;
6004 return ERROR_SUCCESS;
6006 comp->Action = INSTALLSTATE_LOCAL;
6008 name = MSI_RecordGetString(rec, 2);
6009 value = MSI_RecordGetString(rec, 3);
6011 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6013 res = env_parse_flags(&name, &value, &flags);
6014 if (res != ERROR_SUCCESS || !value)
6017 if (value && !deformat_string(package, value, &deformatted))
6019 res = ERROR_OUTOFMEMORY;
6023 value = deformatted;
6025 res = open_env_key( flags, &env );
6026 if (res != ERROR_SUCCESS)
6029 if (flags & ENV_MOD_MACHINE)
6030 action |= 0x20000000;
6034 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6035 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6036 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6039 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6043 /* Nothing to do. */
6046 res = ERROR_SUCCESS;
6050 /* If we are appending but the string was empty, strip ; */
6051 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6053 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6054 newval = strdupW(value);
6057 res = ERROR_OUTOFMEMORY;
6065 /* Contrary to MSDN, +-variable to [~];path works */
6066 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6068 res = ERROR_SUCCESS;
6072 data = msi_alloc(size);
6076 return ERROR_OUTOFMEMORY;
6079 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6080 if (res != ERROR_SUCCESS)
6083 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6086 res = RegDeleteValueW(env, name);
6087 if (res != ERROR_SUCCESS)
6088 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6092 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6093 if (flags & ENV_MOD_MASK)
6097 if (flags & ENV_MOD_APPEND) multiplier++;
6098 if (flags & ENV_MOD_PREFIX) multiplier++;
6099 mod_size = lstrlenW(value) * multiplier;
6100 size += mod_size * sizeof(WCHAR);
6103 newval = msi_alloc(size);
6107 res = ERROR_OUTOFMEMORY;
6111 if (flags & ENV_MOD_PREFIX)
6113 lstrcpyW(newval, value);
6114 ptr = newval + lstrlenW(value);
6115 action |= 0x80000000;
6118 lstrcpyW(ptr, data);
6120 if (flags & ENV_MOD_APPEND)
6122 lstrcatW(newval, value);
6123 action |= 0x40000000;
6126 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6127 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6130 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6134 uirow = MSI_CreateRecord( 3 );
6135 MSI_RecordSetStringW( uirow, 1, name );
6136 MSI_RecordSetStringW( uirow, 2, newval );
6137 MSI_RecordSetInteger( uirow, 3, action );
6138 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6139 msiobj_release( &uirow->hdr );
6141 if (env) RegCloseKey(env);
6142 msi_free(deformatted);
6148 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6152 static const WCHAR ExecSeqQuery[] =
6153 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6154 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6155 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6156 if (rc != ERROR_SUCCESS)
6157 return ERROR_SUCCESS;
6159 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6160 msiobj_release(&view->hdr);
6165 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6167 MSIPACKAGE *package = param;
6168 LPCWSTR name, value, component;
6169 LPWSTR deformatted = NULL;
6178 component = MSI_RecordGetString( rec, 4 );
6179 comp = get_loaded_component( package, component );
6181 return ERROR_SUCCESS;
6183 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6185 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6186 comp->Action = comp->Installed;
6187 return ERROR_SUCCESS;
6189 comp->Action = INSTALLSTATE_ABSENT;
6191 name = MSI_RecordGetString( rec, 2 );
6192 value = MSI_RecordGetString( rec, 3 );
6194 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6196 r = env_parse_flags( &name, &value, &flags );
6197 if (r != ERROR_SUCCESS)
6200 if (!(flags & ENV_ACT_REMOVE))
6202 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6203 return ERROR_SUCCESS;
6206 if (value && !deformat_string( package, value, &deformatted ))
6207 return ERROR_OUTOFMEMORY;
6209 value = deformatted;
6211 r = open_env_key( flags, &env );
6212 if (r != ERROR_SUCCESS)
6218 if (flags & ENV_MOD_MACHINE)
6219 action |= 0x20000000;
6221 TRACE("Removing %s\n", debugstr_w(name));
6223 res = RegDeleteValueW( env, name );
6224 if (res != ERROR_SUCCESS)
6226 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6231 uirow = MSI_CreateRecord( 3 );
6232 MSI_RecordSetStringW( uirow, 1, name );
6233 MSI_RecordSetStringW( uirow, 2, value );
6234 MSI_RecordSetInteger( uirow, 3, action );
6235 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6236 msiobj_release( &uirow->hdr );
6238 if (env) RegCloseKey( env );
6239 msi_free( deformatted );
6243 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6247 static const WCHAR query[] =
6248 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6249 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6251 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6252 if (rc != ERROR_SUCCESS)
6253 return ERROR_SUCCESS;
6255 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6256 msiobj_release( &view->hdr );
6261 typedef struct tagMSIASSEMBLY
6264 MSICOMPONENT *component;
6265 MSIFEATURE *feature;
6269 LPWSTR display_name;
6274 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6276 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6277 LPVOID pvReserved, HMODULE *phModDll);
6279 static BOOL init_functionpointers(void)
6285 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6287 hmscoree = LoadLibraryA("mscoree.dll");
6290 WARN("mscoree.dll not available\n");
6294 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6295 if (!pLoadLibraryShim)
6297 WARN("LoadLibraryShim not available\n");
6298 FreeLibrary(hmscoree);
6302 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6305 WARN("fusion.dll not available\n");
6306 FreeLibrary(hmscoree);
6310 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6312 FreeLibrary(hmscoree);
6316 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6319 IAssemblyCache *cache;
6322 UINT r = ERROR_FUNCTION_FAILED;
6324 TRACE("installing assembly: %s\n", debugstr_w(path));
6326 uirow = MSI_CreateRecord( 2 );
6327 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6328 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6329 msiobj_release( &uirow->hdr );
6331 if (assembly->feature)
6332 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6334 if (assembly->manifest)
6335 FIXME("Manifest unhandled\n");
6337 if (assembly->application)
6339 FIXME("Assembly should be privately installed\n");
6340 return ERROR_SUCCESS;
6343 if (assembly->attributes == msidbAssemblyAttributesWin32)
6345 FIXME("Win32 assemblies not handled\n");
6346 return ERROR_SUCCESS;
6349 hr = pCreateAssemblyCache(&cache, 0);
6353 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6355 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6360 IAssemblyCache_Release(cache);
6364 typedef struct tagASSEMBLY_LIST
6366 MSIPACKAGE *package;
6367 IAssemblyCache *cache;
6368 struct list *assemblies;
6371 typedef struct tagASSEMBLY_NAME
6379 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6381 ASSEMBLY_NAME *asmname = param;
6382 LPCWSTR name = MSI_RecordGetString(rec, 2);
6383 LPWSTR val = msi_dup_record_field(rec, 3);
6385 static const WCHAR Name[] = {'N','a','m','e',0};
6386 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6387 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6388 static const WCHAR PublicKeyToken[] = {
6389 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6391 if (!strcmpiW(name, Name))
6392 asmname->name = val;
6393 else if (!strcmpiW(name, Version))
6394 asmname->version = val;
6395 else if (!strcmpiW(name, Culture))
6396 asmname->culture = val;
6397 else if (!strcmpiW(name, PublicKeyToken))
6398 asmname->pubkeytoken = val;
6402 return ERROR_SUCCESS;
6405 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6409 *size = lstrlenW(append) + 1;
6410 *str = msi_alloc((*size) * sizeof(WCHAR));
6411 lstrcpyW(*str, append);
6415 (*size) += lstrlenW(append);
6416 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6417 lstrcatW(*str, append);
6420 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6422 static const WCHAR separator[] = {',',' ',0};
6423 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6424 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6425 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6426 static const WCHAR query[] = {
6427 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6428 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6429 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6430 '=','\'','%','s','\'',0};
6433 LPWSTR display_name;
6437 display_name = NULL;
6438 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6440 r = MSI_OpenQuery( db, &view, query, comp->Component );
6441 if (r != ERROR_SUCCESS)
6444 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6445 msiobj_release( &view->hdr );
6449 ERR("No assembly name specified!\n");
6453 append_str( &display_name, &size, name.name );
6457 append_str( &display_name, &size, separator );
6458 append_str( &display_name, &size, Version );
6459 append_str( &display_name, &size, name.version );
6463 append_str( &display_name, &size, separator );
6464 append_str( &display_name, &size, Culture );
6465 append_str( &display_name, &size, name.culture );
6467 if (name.pubkeytoken)
6469 append_str( &display_name, &size, separator );
6470 append_str( &display_name, &size, PublicKeyToken );
6471 append_str( &display_name, &size, name.pubkeytoken );
6474 msi_free( name.name );
6475 msi_free( name.version );
6476 msi_free( name.culture );
6477 msi_free( name.pubkeytoken );
6479 return display_name;
6482 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6484 ASSEMBLY_INFO asminfo;
6489 disp = get_assembly_display_name( db, comp );
6493 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6494 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6496 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6498 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6504 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6506 ASSEMBLY_LIST *list = param;
6507 MSIASSEMBLY *assembly;
6510 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6512 return ERROR_OUTOFMEMORY;
6514 component = MSI_RecordGetString(rec, 1);
6515 assembly->component = get_loaded_component(list->package, component);
6516 if (!assembly->component)
6517 return ERROR_SUCCESS;
6519 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6520 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6522 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6523 assembly->component->Action = assembly->component->Installed;
6524 return ERROR_SUCCESS;
6526 assembly->component->Action = assembly->component->ActionRequest;
6528 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6529 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6531 if (!assembly->file)
6533 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6534 return ERROR_FUNCTION_FAILED;
6537 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6538 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6539 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6541 if (assembly->application)
6544 DWORD size = sizeof(version)/sizeof(WCHAR);
6546 /* FIXME: we should probably check the manifest file here */
6548 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6549 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6551 assembly->installed = TRUE;
6555 assembly->installed = check_assembly_installed(list->package->db,
6557 assembly->component);
6559 list_add_head(list->assemblies, &assembly->entry);
6560 return ERROR_SUCCESS;
6563 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6565 IAssemblyCache *cache = NULL;
6571 static const WCHAR query[] =
6572 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6573 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6575 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6576 if (r != ERROR_SUCCESS)
6577 return ERROR_SUCCESS;
6579 hr = pCreateAssemblyCache(&cache, 0);
6581 return ERROR_FUNCTION_FAILED;
6583 list.package = package;
6585 list.assemblies = assemblies;
6587 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6588 msiobj_release(&view->hdr);
6590 IAssemblyCache_Release(cache);
6595 static void free_assemblies(struct list *assemblies)
6597 struct list *item, *cursor;
6599 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6601 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6603 list_remove(&assembly->entry);
6604 msi_free(assembly->application);
6605 msi_free(assembly->manifest);
6606 msi_free(assembly->display_name);
6611 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6613 MSIASSEMBLY *assembly;
6615 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6617 if (!lstrcmpW(assembly->file->File, file))
6627 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6628 LPWSTR *path, DWORD *attrs, PVOID user)
6630 MSIASSEMBLY *assembly;
6631 WCHAR temppath[MAX_PATH];
6632 struct list *assemblies = user;
6635 if (!find_assembly(assemblies, file, &assembly))
6638 GetTempPathW(MAX_PATH, temppath);
6639 PathAddBackslashW(temppath);
6640 lstrcatW(temppath, assembly->file->FileName);
6642 if (action == MSICABEXTRACT_BEGINEXTRACT)
6644 if (assembly->installed)
6647 *path = strdupW(temppath);
6648 *attrs = assembly->file->Attributes;
6650 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6652 assembly->installed = TRUE;
6654 r = install_assembly(package, assembly, temppath);
6655 if (r != ERROR_SUCCESS)
6656 ERR("Failed to install assembly\n");
6662 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6665 struct list assemblies = LIST_INIT(assemblies);
6666 MSIASSEMBLY *assembly;
6669 if (!init_functionpointers() || !pCreateAssemblyCache)
6670 return ERROR_FUNCTION_FAILED;
6672 r = load_assemblies(package, &assemblies);
6673 if (r != ERROR_SUCCESS)
6676 if (list_empty(&assemblies))
6679 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6682 r = ERROR_OUTOFMEMORY;
6686 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6688 if (assembly->installed && !mi->is_continuous)
6691 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6692 (assembly->file->IsCompressed && !mi->is_extracted))
6696 r = ready_media(package, assembly->file, mi);
6697 if (r != ERROR_SUCCESS)
6699 ERR("Failed to ready media\n");
6704 data.package = package;
6705 data.cb = installassembly_cb;
6706 data.user = &assemblies;
6708 if (assembly->file->IsCompressed &&
6709 !msi_cabextract(package, mi, &data))
6711 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6712 r = ERROR_FUNCTION_FAILED;
6717 if (!assembly->file->IsCompressed)
6719 LPWSTR source = resolve_file_source(package, assembly->file);
6721 r = install_assembly(package, assembly, source);
6722 if (r != ERROR_SUCCESS)
6723 ERR("Failed to install assembly\n");
6728 /* FIXME: write Installer assembly reg values */
6732 free_assemblies(&assemblies);
6736 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6738 LPWSTR key, template, id;
6739 UINT r = ERROR_SUCCESS;
6741 id = msi_dup_property( package, szProductID );
6745 return ERROR_SUCCESS;
6747 template = msi_dup_property( package, szPIDTemplate );
6748 key = msi_dup_property( package, szPIDKEY );
6750 if (key && template)
6752 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6753 r = MSI_SetPropertyW( package, szProductID, key );
6755 msi_free( template );
6760 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6763 package->need_reboot = 1;
6764 return ERROR_SUCCESS;
6767 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6769 static const WCHAR szAvailableFreeReg[] =
6770 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6772 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6774 TRACE("%p %d kilobytes\n", package, space);
6776 uirow = MSI_CreateRecord( 1 );
6777 MSI_RecordSetInteger( uirow, 1, space );
6778 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6779 msiobj_release( &uirow->hdr );
6781 return ERROR_SUCCESS;
6784 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6786 FIXME("%p\n", package);
6787 return ERROR_SUCCESS;
6790 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6792 FIXME("%p\n", package);
6793 return ERROR_SUCCESS;
6796 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6797 LPCSTR action, LPCWSTR table )
6799 static const WCHAR query[] = {
6800 'S','E','L','E','C','T',' ','*',' ',
6801 'F','R','O','M',' ','`','%','s','`',0 };
6802 MSIQUERY *view = NULL;
6806 r = MSI_OpenQuery( package->db, &view, query, table );
6807 if (r == ERROR_SUCCESS)
6809 r = MSI_IterateRecords(view, &count, NULL, package);
6810 msiobj_release(&view->hdr);
6814 FIXME("%s -> %u ignored %s table values\n",
6815 action, count, debugstr_w(table));
6817 return ERROR_SUCCESS;
6820 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6822 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6823 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6826 static UINT ACTION_BindImage( MSIPACKAGE *package )
6828 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6829 return msi_unimplemented_action_stub( package, "BindImage", table );
6832 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6834 static const WCHAR table[] = {
6835 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6836 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6839 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6841 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6842 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6845 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6847 static const WCHAR table[] = {
6848 'M','s','i','A','s','s','e','m','b','l','y',0 };
6849 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6852 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6854 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6855 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6858 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6860 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6861 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6864 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6866 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6867 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6870 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6872 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6873 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6876 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6878 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6879 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6882 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6884 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6885 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6888 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6890 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6891 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6894 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6896 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6897 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6900 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6902 static const WCHAR table[] = { 'M','I','M','E',0 };
6903 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6906 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6908 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6909 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6912 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6916 const WCHAR *action;
6917 UINT (*handler)(MSIPACKAGE *);
6921 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6922 { szAppSearch, ACTION_AppSearch },
6923 { szBindImage, ACTION_BindImage },
6924 { szCCPSearch, ACTION_CCPSearch },
6925 { szCostFinalize, ACTION_CostFinalize },
6926 { szCostInitialize, ACTION_CostInitialize },
6927 { szCreateFolders, ACTION_CreateFolders },
6928 { szCreateShortcuts, ACTION_CreateShortcuts },
6929 { szDeleteServices, ACTION_DeleteServices },
6930 { szDisableRollback, ACTION_DisableRollback },
6931 { szDuplicateFiles, ACTION_DuplicateFiles },
6932 { szExecuteAction, ACTION_ExecuteAction },
6933 { szFileCost, ACTION_FileCost },
6934 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6935 { szForceReboot, ACTION_ForceReboot },
6936 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6937 { szInstallExecute, ACTION_InstallExecute },
6938 { szInstallExecuteAgain, ACTION_InstallExecute },
6939 { szInstallFiles, ACTION_InstallFiles},
6940 { szInstallFinalize, ACTION_InstallFinalize },
6941 { szInstallInitialize, ACTION_InstallInitialize },
6942 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6943 { szInstallValidate, ACTION_InstallValidate },
6944 { szIsolateComponents, ACTION_IsolateComponents },
6945 { szLaunchConditions, ACTION_LaunchConditions },
6946 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6947 { szMoveFiles, ACTION_MoveFiles },
6948 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6949 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6950 { szInstallODBC, ACTION_InstallODBC },
6951 { szInstallServices, ACTION_InstallServices },
6952 { szPatchFiles, ACTION_PatchFiles },
6953 { szProcessComponents, ACTION_ProcessComponents },
6954 { szPublishComponents, ACTION_PublishComponents },
6955 { szPublishFeatures, ACTION_PublishFeatures },
6956 { szPublishProduct, ACTION_PublishProduct },
6957 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6958 { szRegisterComPlus, ACTION_RegisterComPlus},
6959 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6960 { szRegisterFonts, ACTION_RegisterFonts },
6961 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6962 { szRegisterProduct, ACTION_RegisterProduct },
6963 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6964 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6965 { szRegisterUser, ACTION_RegisterUser },
6966 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6967 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6968 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6969 { szRemoveFiles, ACTION_RemoveFiles },
6970 { szRemoveFolders, ACTION_RemoveFolders },
6971 { szRemoveIniValues, ACTION_RemoveIniValues },
6972 { szRemoveODBC, ACTION_RemoveODBC },
6973 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6974 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6975 { szResolveSource, ACTION_ResolveSource },
6976 { szRMCCPSearch, ACTION_RMCCPSearch },
6977 { szScheduleReboot, ACTION_ScheduleReboot },
6978 { szSelfRegModules, ACTION_SelfRegModules },
6979 { szSelfUnregModules, ACTION_SelfUnregModules },
6980 { szSetODBCFolders, ACTION_SetODBCFolders },
6981 { szStartServices, ACTION_StartServices },
6982 { szStopServices, ACTION_StopServices },
6983 { szUnpublishComponents, ACTION_UnpublishComponents },
6984 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6985 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6986 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6987 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6988 { szUnregisterFonts, ACTION_UnregisterFonts },
6989 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6990 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6991 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6992 { szValidateProductID, ACTION_ValidateProductID },
6993 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6994 { szWriteIniValues, ACTION_WriteIniValues },
6995 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6999 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7000 UINT* rc, BOOL force )
7006 if (!run && !package->script->CurrentlyScripting)
7011 if (strcmpW(action,szInstallFinalize) == 0 ||
7012 strcmpW(action,szInstallExecute) == 0 ||
7013 strcmpW(action,szInstallExecuteAgain) == 0)
7018 while (StandardActions[i].action != NULL)
7020 if (strcmpW(StandardActions[i].action, action)==0)
7024 ui_actioninfo(package, action, TRUE, 0);
7025 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7026 ui_actioninfo(package, action, FALSE, *rc);
7030 ui_actionstart(package, action);
7031 if (StandardActions[i].handler)
7033 *rc = StandardActions[i].handler(package);
7037 FIXME("unhandled standard action %s\n",debugstr_w(action));
7038 *rc = ERROR_SUCCESS;
7049 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7051 UINT rc = ERROR_SUCCESS;
7054 TRACE("Performing action (%s)\n", debugstr_w(action));
7056 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7059 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7063 WARN("unhandled msi action %s\n", debugstr_w(action));
7064 rc = ERROR_FUNCTION_NOT_CALLED;
7070 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7072 UINT rc = ERROR_SUCCESS;
7073 BOOL handled = FALSE;
7075 TRACE("Performing action (%s)\n", debugstr_w(action));
7077 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7080 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7082 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7087 WARN("unhandled msi action %s\n", debugstr_w(action));
7088 rc = ERROR_FUNCTION_NOT_CALLED;
7094 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7096 UINT rc = ERROR_SUCCESS;
7099 static const WCHAR ExecSeqQuery[] =
7100 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7101 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7102 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7103 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7104 static const WCHAR UISeqQuery[] =
7105 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7106 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7107 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7108 ' ', '=',' ','%','i',0};
7110 if (needs_ui_sequence(package))
7111 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7113 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7117 LPCWSTR action, cond;
7119 TRACE("Running the actions\n");
7121 /* check conditions */
7122 cond = MSI_RecordGetString(row, 2);
7124 /* this is a hack to skip errors in the condition code */
7125 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7127 msiobj_release(&row->hdr);
7128 return ERROR_SUCCESS;
7131 action = MSI_RecordGetString(row, 1);
7134 ERR("failed to fetch action\n");
7135 msiobj_release(&row->hdr);
7136 return ERROR_FUNCTION_FAILED;
7139 if (needs_ui_sequence(package))
7140 rc = ACTION_PerformUIAction(package, action, -1);
7142 rc = ACTION_PerformAction(package, action, -1, FALSE);
7144 msiobj_release(&row->hdr);
7150 /****************************************************
7151 * TOP level entry points
7152 *****************************************************/
7154 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7155 LPCWSTR szCommandLine )
7160 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7161 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7163 MSI_SetPropertyW(package, szAction, szInstall);
7165 package->script->InWhatSequence = SEQUENCE_INSTALL;
7172 dir = strdupW(szPackagePath);
7173 p = strrchrW(dir, '\\');
7177 file = szPackagePath + (p - dir);
7182 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7183 GetCurrentDirectoryW(MAX_PATH, dir);
7184 lstrcatW(dir, szBackSlash);
7185 file = szPackagePath;
7188 msi_free( package->PackagePath );
7189 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7190 if (!package->PackagePath)
7193 return ERROR_OUTOFMEMORY;
7196 lstrcpyW(package->PackagePath, dir);
7197 lstrcatW(package->PackagePath, file);
7200 msi_set_sourcedir_props(package, FALSE);
7203 msi_parse_command_line( package, szCommandLine, FALSE );
7205 msi_apply_transforms( package );
7206 msi_apply_patches( package );
7208 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7210 TRACE("setting reinstall property\n");
7211 MSI_SetPropertyW( package, szReinstall, szAll );
7214 /* properties may have been added by a transform */
7215 msi_clone_properties( package );
7216 msi_set_context( package );
7218 if (needs_ui_sequence( package))
7220 package->script->InWhatSequence |= SEQUENCE_UI;
7221 rc = ACTION_ProcessUISequence(package);
7222 ui_exists = ui_sequence_exists(package);
7223 if (rc == ERROR_SUCCESS || !ui_exists)
7225 package->script->InWhatSequence |= SEQUENCE_EXEC;
7226 rc = ACTION_ProcessExecSequence(package, ui_exists);
7230 rc = ACTION_ProcessExecSequence(package, FALSE);
7232 package->script->CurrentlyScripting = FALSE;
7234 /* process the ending type action */
7235 if (rc == ERROR_SUCCESS)
7236 ACTION_PerformActionSequence(package, -1);
7237 else if (rc == ERROR_INSTALL_USEREXIT)
7238 ACTION_PerformActionSequence(package, -2);
7239 else if (rc == ERROR_INSTALL_SUSPEND)
7240 ACTION_PerformActionSequence(package, -4);
7242 ACTION_PerformActionSequence(package, -3);
7244 /* finish up running custom actions */
7245 ACTION_FinishCustomActions(package);
7247 if (rc == ERROR_SUCCESS && package->need_reboot)
7248 return ERROR_SUCCESS_REBOOT_REQUIRED;