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
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
38 #include "wine/debug.h"
43 #include "wine/unicode.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 sprintfW(message,template_s,timet,action);
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
300 LPWSTR prop = NULL, val = NULL;
303 return ERROR_SUCCESS;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
368 LPWSTR p, *ret = NULL;
374 /* count the number of substrings */
375 for ( pc = str, count = 0; pc; count++ )
377 pc = strchrW( pc, sep );
382 /* allocate space for an array of substring pointers and the substrings */
383 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384 (lstrlenW(str)+1) * sizeof(WCHAR) );
388 /* copy the string and set the pointers */
389 p = (LPWSTR) &ret[count+1];
391 for( count = 0; (ret[count] = p); count++ )
393 p = strchrW( p, sep );
401 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
403 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
404 LPWSTR prod_code, patch_product;
407 prod_code = msi_dup_property( package, szProductCode );
408 patch_product = msi_get_suminfo_product( patch );
410 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
412 if ( strstrW( patch_product, prod_code ) )
415 ret = ERROR_FUNCTION_FAILED;
417 msi_free( patch_product );
418 msi_free( prod_code );
423 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
424 MSIDATABASE *patch_db, LPCWSTR name )
426 UINT ret = ERROR_FUNCTION_FAILED;
427 IStorage *stg = NULL;
430 TRACE("%p %s\n", package, debugstr_w(name) );
434 ERR("expected a colon in %s\n", debugstr_w(name));
435 return ERROR_FUNCTION_FAILED;
438 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
441 ret = msi_check_transform_applicable( package, stg );
442 if (ret == ERROR_SUCCESS)
443 msi_table_apply_transform( package->db, stg );
445 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
446 IStorage_Release( stg );
449 ERR("failed to open substorage %s\n", debugstr_w(name));
451 return ERROR_SUCCESS;
454 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
456 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
457 LPWSTR guid_list, *guids, product_id;
458 UINT i, ret = ERROR_FUNCTION_FAILED;
460 product_id = msi_dup_property( package, szProdID );
463 /* FIXME: the property ProductID should be written into the DB somewhere */
464 ERR("no product ID to check\n");
465 return ERROR_SUCCESS;
468 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
469 guids = msi_split_string( guid_list, ';' );
470 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
472 if (!lstrcmpW( guids[i], product_id ))
476 msi_free( guid_list );
477 msi_free( product_id );
482 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
485 LPWSTR str, *substorage;
486 UINT i, r = ERROR_SUCCESS;
488 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
490 return ERROR_FUNCTION_FAILED;
492 msi_check_patch_applicable( package, si );
494 /* enumerate the substorage */
495 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
496 substorage = msi_split_string( str, ';' );
497 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
498 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
499 msi_free( substorage );
502 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
504 msiobj_release( &si->hdr );
509 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
511 MSIDATABASE *patch_db = NULL;
514 TRACE("%p %s\n", package, debugstr_w( file ) );
517 * We probably want to make sure we only open a patch collection here.
518 * Patch collections (.msp) and databases (.msi) have different GUIDs
519 * but currently MSI_OpenDatabaseW will accept both.
521 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
522 if ( r != ERROR_SUCCESS )
524 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
528 msi_parse_patch_summary( package, patch_db );
531 * There might be a CAB file in the patch package,
532 * so append it to the list of storage to search for streams.
534 append_storage_to_db( package->db, patch_db->storage );
536 msiobj_release( &patch_db->hdr );
538 return ERROR_SUCCESS;
541 /* get the PATCH property, and apply all the patches it specifies */
542 static UINT msi_apply_patches( MSIPACKAGE *package )
544 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
545 LPWSTR patch_list, *patches;
546 UINT i, r = ERROR_SUCCESS;
548 patch_list = msi_dup_property( package, szPatch );
550 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
552 patches = msi_split_string( patch_list, ';' );
553 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
554 r = msi_apply_patch_package( package, patches[i] );
557 msi_free( patch_list );
562 static UINT msi_apply_transforms( MSIPACKAGE *package )
564 static const WCHAR szTransforms[] = {
565 'T','R','A','N','S','F','O','R','M','S',0 };
566 LPWSTR xform_list, *xforms;
567 UINT i, r = ERROR_SUCCESS;
569 xform_list = msi_dup_property( package, szTransforms );
570 xforms = msi_split_string( xform_list, ';' );
572 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
574 if (xforms[i][0] == ':')
575 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
577 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
581 msi_free( xform_list );
586 /****************************************************
587 * TOP level entry points
588 *****************************************************/
590 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
591 LPCWSTR szCommandLine )
595 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
596 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
597 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
599 MSI_SetPropertyW(package, szAction, szInstall);
601 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
603 package->script->InWhatSequence = SEQUENCE_INSTALL;
607 LPWSTR p, check, path;
609 path = strdupW(szPackagePath);
610 p = strrchrW(path,'\\');
619 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
620 GetCurrentDirectoryW(MAX_PATH,path);
624 check = msi_dup_property( package, cszSourceDir );
626 MSI_SetPropertyW(package, cszSourceDir, path);
629 check = msi_dup_property( package, cszSOURCEDIR );
631 MSI_SetPropertyW(package, cszSOURCEDIR, path);
633 msi_free( package->PackagePath );
634 package->PackagePath = path;
639 msi_parse_command_line( package, szCommandLine );
641 msi_apply_transforms( package );
642 msi_apply_patches( package );
644 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
646 package->script->InWhatSequence |= SEQUENCE_UI;
647 rc = ACTION_ProcessUISequence(package);
649 if (rc == ERROR_SUCCESS)
651 package->script->InWhatSequence |= SEQUENCE_EXEC;
652 rc = ACTION_ProcessExecSequence(package,TRUE);
656 rc = ACTION_ProcessExecSequence(package,FALSE);
660 /* install was halted but should be considered a success */
664 package->script->CurrentlyScripting= FALSE;
666 /* process the ending type action */
667 if (rc == ERROR_SUCCESS)
668 ACTION_PerformActionSequence(package,-1,ui);
669 else if (rc == ERROR_INSTALL_USEREXIT)
670 ACTION_PerformActionSequence(package,-2,ui);
671 else if (rc == ERROR_INSTALL_SUSPEND)
672 ACTION_PerformActionSequence(package,-4,ui);
674 ACTION_PerformActionSequence(package,-3,ui);
676 /* finish up running custom actions */
677 ACTION_FinishCustomActions(package);
682 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
684 UINT rc = ERROR_SUCCESS;
686 static const WCHAR ExecSeqQuery[] =
687 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
688 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
689 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
690 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
692 static const WCHAR UISeqQuery[] =
693 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
694 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
695 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
696 ' ', '=',' ','%','i',0};
699 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
701 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
705 LPCWSTR action, cond;
707 TRACE("Running the actions\n");
709 /* check conditions */
710 cond = MSI_RecordGetString(row,2);
712 /* this is a hack to skip errors in the condition code */
713 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
716 action = MSI_RecordGetString(row,1);
719 ERR("failed to fetch action\n");
720 rc = ERROR_FUNCTION_FAILED;
725 rc = ACTION_PerformUIAction(package,action);
727 rc = ACTION_PerformAction(package,action,FALSE);
729 msiobj_release(&row->hdr);
740 } iterate_action_param;
742 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
744 iterate_action_param *iap= (iterate_action_param*)param;
746 LPCWSTR cond, action;
748 action = MSI_RecordGetString(row,1);
751 ERR("Error is retrieving action name\n");
752 return ERROR_FUNCTION_FAILED;
755 /* check conditions */
756 cond = MSI_RecordGetString(row,2);
758 /* this is a hack to skip errors in the condition code */
759 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
761 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
762 return ERROR_SUCCESS;
766 rc = ACTION_PerformUIAction(iap->package,action);
768 rc = ACTION_PerformAction(iap->package,action,FALSE);
770 msi_dialog_check_messages( NULL );
772 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
773 rc = iap->package->CurrentInstallState;
775 if (rc == ERROR_FUNCTION_NOT_CALLED)
778 if (rc != ERROR_SUCCESS)
779 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
784 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
788 static const WCHAR query[] =
789 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
791 ' ','W','H','E','R','E',' ',
792 '`','S','e','q','u','e','n','c','e','`',' ',
793 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
794 '`','S','e','q','u','e','n','c','e','`',0};
795 iterate_action_param iap;
798 * FIXME: probably should be checking UILevel in the
799 * ACTION_PerformUIAction/ACTION_PerformAction
800 * rather than saving the UI level here. Those
801 * two functions can be merged too.
803 iap.package = package;
806 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
808 r = MSI_OpenQuery( package->db, &view, query, szTable );
809 if (r == ERROR_SUCCESS)
811 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
812 msiobj_release(&view->hdr);
818 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
822 static const WCHAR ExecSeqQuery[] =
823 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
824 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
825 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
826 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
827 'O','R','D','E','R',' ', 'B','Y',' ',
828 '`','S','e','q','u','e','n','c','e','`',0 };
830 static const WCHAR IVQuery[] =
831 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
832 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
833 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
834 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
835 ' ','\'', 'I','n','s','t','a','l','l',
836 'V','a','l','i','d','a','t','e','\'', 0};
838 iterate_action_param iap;
840 iap.package = package;
843 if (package->script->ExecuteSequenceRun)
845 TRACE("Execute Sequence already Run\n");
846 return ERROR_SUCCESS;
849 package->script->ExecuteSequenceRun = TRUE;
851 /* get the sequence number */
854 row = MSI_QueryGetRecord(package->db, IVQuery);
856 return ERROR_FUNCTION_FAILED;
857 seq = MSI_RecordGetInteger(row,1);
858 msiobj_release(&row->hdr);
861 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
862 if (rc == ERROR_SUCCESS)
864 TRACE("Running the actions\n");
866 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
867 msiobj_release(&view->hdr);
873 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
877 static const WCHAR ExecSeqQuery [] =
878 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879 '`','I','n','s','t','a','l','l',
880 'U','I','S','e','q','u','e','n','c','e','`',
881 ' ','W','H','E','R','E',' ',
882 '`','S','e','q','u','e','n','c','e','`',' ',
883 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
884 '`','S','e','q','u','e','n','c','e','`',0};
885 iterate_action_param iap;
887 iap.package = package;
890 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
892 if (rc == ERROR_SUCCESS)
894 TRACE("Running the actions\n");
896 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
897 msiobj_release(&view->hdr);
903 /********************************************************
904 * ACTION helper functions and functions that perform the actions
905 *******************************************************/
906 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
907 UINT* rc, BOOL force )
913 if (!run && !package->script->CurrentlyScripting)
918 if (strcmpW(action,szInstallFinalize) == 0 ||
919 strcmpW(action,szInstallExecute) == 0 ||
920 strcmpW(action,szInstallExecuteAgain) == 0)
925 while (StandardActions[i].action != NULL)
927 if (strcmpW(StandardActions[i].action, action)==0)
931 ui_actioninfo(package, action, TRUE, 0);
932 *rc = schedule_action(package,INSTALL_SCRIPT,action);
933 ui_actioninfo(package, action, FALSE, *rc);
937 ui_actionstart(package, action);
938 if (StandardActions[i].handler)
940 *rc = StandardActions[i].handler(package);
944 FIXME("unhandled standard action %s\n",debugstr_w(action));
956 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
957 UINT* rc, BOOL force )
962 arc = ACTION_CustomAction(package,action, force);
964 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
973 * A lot of actions are really important even if they don't do anything
974 * explicit... Lots of properties are set at the beginning of the installation
975 * CostFinalize does a bunch of work to translate the directories and such
977 * But until I get write access to the database that is hard, so I am going to
978 * hack it to see if I can get something to run.
980 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
982 UINT rc = ERROR_SUCCESS;
985 TRACE("Performing action (%s)\n",debugstr_w(action));
987 handled = ACTION_HandleStandardAction(package, action, &rc, force);
990 handled = ACTION_HandleCustomAction(package, action, &rc, force);
994 FIXME("unhandled msi action %s\n",debugstr_w(action));
995 rc = ERROR_FUNCTION_NOT_CALLED;
1001 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1003 UINT rc = ERROR_SUCCESS;
1004 BOOL handled = FALSE;
1006 TRACE("Performing action (%s)\n",debugstr_w(action));
1008 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1011 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1013 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1018 FIXME("unhandled msi action %s\n",debugstr_w(action));
1019 rc = ERROR_FUNCTION_NOT_CALLED;
1027 * Actual Action Handlers
1030 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1032 MSIPACKAGE *package = (MSIPACKAGE*)param;
1038 dir = MSI_RecordGetString(row,1);
1041 ERR("Unable to get folder id\n");
1042 return ERROR_SUCCESS;
1045 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1048 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1049 return ERROR_SUCCESS;
1052 TRACE("Folder is %s\n",debugstr_w(full_path));
1055 uirow = MSI_CreateRecord(1);
1056 MSI_RecordSetStringW(uirow,1,full_path);
1057 ui_actiondata(package,szCreateFolders,uirow);
1058 msiobj_release( &uirow->hdr );
1060 if (folder->State == 0)
1061 create_full_pathW(full_path);
1065 msi_free(full_path);
1066 return ERROR_SUCCESS;
1069 /* FIXME: probably should merge this with the above function */
1070 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1072 UINT rc = ERROR_SUCCESS;
1074 LPWSTR install_path;
1076 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1078 return ERROR_FUNCTION_FAILED;
1080 /* create the path */
1081 if (folder->State == 0)
1083 create_full_pathW(install_path);
1086 msi_free(install_path);
1091 UINT msi_create_component_directories( MSIPACKAGE *package )
1095 /* create all the folders required by the components are going to install */
1096 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1098 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1100 msi_create_directory( package, comp->Directory );
1103 return ERROR_SUCCESS;
1107 * Also we cannot enable/disable components either, so for now I am just going
1108 * to do all the directories for all the components.
1110 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1112 static const WCHAR ExecSeqQuery[] =
1113 {'S','E','L','E','C','T',' ',
1114 '`','D','i','r','e','c','t','o','r','y','_','`',
1115 ' ','F','R','O','M',' ',
1116 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1120 /* create all the empty folders specified in the CreateFolder table */
1121 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1126 msiobj_release(&view->hdr);
1128 msi_create_component_directories( package );
1133 static UINT load_component( MSIRECORD *row, LPVOID param )
1135 MSIPACKAGE *package = param;
1138 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1140 return ERROR_FUNCTION_FAILED;
1142 list_add_tail( &package->components, &comp->entry );
1144 /* fill in the data */
1145 comp->Component = msi_dup_record_field( row, 1 );
1147 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1149 comp->ComponentId = msi_dup_record_field( row, 2 );
1150 comp->Directory = msi_dup_record_field( row, 3 );
1151 comp->Attributes = MSI_RecordGetInteger(row,4);
1152 comp->Condition = msi_dup_record_field( row, 5 );
1153 comp->KeyPath = msi_dup_record_field( row, 6 );
1155 comp->Installed = INSTALLSTATE_UNKNOWN;
1156 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1158 return ERROR_SUCCESS;
1161 static UINT load_all_components( MSIPACKAGE *package )
1163 static const WCHAR query[] = {
1164 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1165 '`','C','o','m','p','o','n','e','n','t','`',0 };
1169 if (!list_empty(&package->components))
1170 return ERROR_SUCCESS;
1172 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1173 if (r != ERROR_SUCCESS)
1176 r = MSI_IterateRecords(view, NULL, load_component, package);
1177 msiobj_release(&view->hdr);
1182 MSIPACKAGE *package;
1183 MSIFEATURE *feature;
1186 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1190 cl = msi_alloc( sizeof (*cl) );
1192 return ERROR_NOT_ENOUGH_MEMORY;
1193 cl->component = comp;
1194 list_add_tail( &feature->Components, &cl->entry );
1196 return ERROR_SUCCESS;
1199 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1203 fl = msi_alloc( sizeof(*fl) );
1205 return ERROR_NOT_ENOUGH_MEMORY;
1206 fl->feature = child;
1207 list_add_tail( &parent->Children, &fl->entry );
1209 return ERROR_SUCCESS;
1212 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1214 _ilfs* ilfs= (_ilfs*)param;
1218 component = MSI_RecordGetString(row,1);
1220 /* check to see if the component is already loaded */
1221 comp = get_loaded_component( ilfs->package, component );
1224 ERR("unknown component %s\n", debugstr_w(component));
1225 return ERROR_FUNCTION_FAILED;
1228 add_feature_component( ilfs->feature, comp );
1229 comp->Enabled = TRUE;
1231 return ERROR_SUCCESS;
1234 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1236 MSIFEATURE *feature;
1238 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1240 if ( !lstrcmpW( feature->Feature, name ) )
1247 static UINT load_feature(MSIRECORD * row, LPVOID param)
1249 MSIPACKAGE* package = (MSIPACKAGE*)param;
1250 MSIFEATURE* feature;
1251 static const WCHAR Query1[] =
1252 {'S','E','L','E','C','T',' ',
1253 '`','C','o','m','p','o','n','e','n','t','_','`',
1254 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1255 'C','o','m','p','o','n','e','n','t','s','`',' ',
1256 'W','H','E','R','E',' ',
1257 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1262 /* fill in the data */
1264 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1266 return ERROR_NOT_ENOUGH_MEMORY;
1268 list_init( &feature->Children );
1269 list_init( &feature->Components );
1271 feature->Feature = msi_dup_record_field( row, 1 );
1273 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1275 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1276 feature->Title = msi_dup_record_field( row, 3 );
1277 feature->Description = msi_dup_record_field( row, 4 );
1279 if (!MSI_RecordIsNull(row,5))
1280 feature->Display = MSI_RecordGetInteger(row,5);
1282 feature->Level= MSI_RecordGetInteger(row,6);
1283 feature->Directory = msi_dup_record_field( row, 7 );
1284 feature->Attributes = MSI_RecordGetInteger(row,8);
1286 feature->Installed = INSTALLSTATE_UNKNOWN;
1287 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1289 list_add_tail( &package->features, &feature->entry );
1291 /* load feature components */
1293 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1294 if (rc != ERROR_SUCCESS)
1295 return ERROR_SUCCESS;
1297 ilfs.package = package;
1298 ilfs.feature = feature;
1300 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1301 msiobj_release(&view->hdr);
1303 return ERROR_SUCCESS;
1306 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1308 MSIPACKAGE* package = (MSIPACKAGE*)param;
1309 MSIFEATURE *parent, *child;
1311 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1313 return ERROR_FUNCTION_FAILED;
1315 if (!child->Feature_Parent)
1316 return ERROR_SUCCESS;
1318 parent = find_feature_by_name( package, child->Feature_Parent );
1320 return ERROR_FUNCTION_FAILED;
1322 add_feature_child( parent, child );
1323 return ERROR_SUCCESS;
1326 static UINT load_all_features( MSIPACKAGE *package )
1328 static const WCHAR query[] = {
1329 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1330 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1331 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1335 if (!list_empty(&package->features))
1336 return ERROR_SUCCESS;
1338 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1339 if (r != ERROR_SUCCESS)
1342 r = MSI_IterateRecords( view, NULL, load_feature, package );
1343 if (r != ERROR_SUCCESS)
1346 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1347 msiobj_release( &view->hdr );
1352 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1363 static UINT load_file(MSIRECORD *row, LPVOID param)
1365 MSIPACKAGE* package = (MSIPACKAGE*)param;
1369 /* fill in the data */
1371 file = msi_alloc_zero( sizeof (MSIFILE) );
1373 return ERROR_NOT_ENOUGH_MEMORY;
1375 file->File = msi_dup_record_field( row, 1 );
1377 component = MSI_RecordGetString( row, 2 );
1378 file->Component = get_loaded_component( package, component );
1380 if (!file->Component)
1381 ERR("Unfound Component %s\n",debugstr_w(component));
1383 file->FileName = msi_dup_record_field( row, 3 );
1384 reduce_to_longfilename( file->FileName );
1386 file->ShortName = msi_dup_record_field( row, 3 );
1387 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1389 file->FileSize = MSI_RecordGetInteger( row, 4 );
1390 file->Version = msi_dup_record_field( row, 5 );
1391 file->Language = msi_dup_record_field( row, 6 );
1392 file->Attributes = MSI_RecordGetInteger( row, 7 );
1393 file->Sequence = MSI_RecordGetInteger( row, 8 );
1395 file->state = msifs_invalid;
1397 /* if the compressed bits are not set in the file attributes,
1398 * then read the information from the package word count property
1400 if (file->Attributes & msidbFileAttributesCompressed)
1402 file->IsCompressed = TRUE;
1404 else if (file->Attributes & msidbFileAttributesNoncompressed)
1406 file->IsCompressed = FALSE;
1410 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1413 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1415 list_add_tail( &package->files, &file->entry );
1417 return ERROR_SUCCESS;
1420 static UINT load_all_files(MSIPACKAGE *package)
1424 static const WCHAR Query[] =
1425 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1426 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1427 '`','S','e','q','u','e','n','c','e','`', 0};
1429 if (!list_empty(&package->files))
1430 return ERROR_SUCCESS;
1432 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1433 if (rc != ERROR_SUCCESS)
1434 return ERROR_SUCCESS;
1436 rc = MSI_IterateRecords(view, NULL, load_file, package);
1437 msiobj_release(&view->hdr);
1439 return ERROR_SUCCESS;
1442 static UINT load_folder( MSIRECORD *row, LPVOID param )
1444 MSIPACKAGE *package = param;
1445 static const WCHAR szDot[] = { '.',0 };
1446 static WCHAR szEmpty[] = { 0 };
1447 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1450 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1452 return ERROR_NOT_ENOUGH_MEMORY;
1454 folder->Directory = msi_dup_record_field( row, 1 );
1456 TRACE("%s\n", debugstr_w(folder->Directory));
1458 p = msi_dup_record_field(row, 3);
1460 /* split src and target dir */
1462 src_short = folder_split_path( p, ':' );
1464 /* split the long and short paths */
1465 tgt_long = folder_split_path( tgt_short, '|' );
1466 src_long = folder_split_path( src_short, '|' );
1468 /* check for no-op dirs */
1469 if (!lstrcmpW(szDot, tgt_short))
1470 tgt_short = szEmpty;
1471 if (!lstrcmpW(szDot, src_short))
1472 src_short = szEmpty;
1475 tgt_long = tgt_short;
1478 src_short = tgt_short;
1479 src_long = tgt_long;
1483 src_long = src_short;
1485 /* FIXME: use the target short path too */
1486 folder->TargetDefault = strdupW(tgt_long);
1487 folder->SourceShortPath = strdupW(src_short);
1488 folder->SourceLongPath = strdupW(src_long);
1491 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1492 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1493 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1495 folder->Parent = msi_dup_record_field( row, 2 );
1497 folder->Property = msi_dup_property( package, folder->Directory );
1499 list_add_tail( &package->folders, &folder->entry );
1501 TRACE("returning %p\n", folder);
1503 return ERROR_SUCCESS;
1506 static UINT load_all_folders( MSIPACKAGE *package )
1508 static const WCHAR query[] = {
1509 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1510 '`','D','i','r','e','c','t','o','r','y','`',0 };
1514 if (!list_empty(&package->folders))
1515 return ERROR_SUCCESS;
1517 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1518 if (r != ERROR_SUCCESS)
1521 r = MSI_IterateRecords(view, NULL, load_folder, package);
1522 msiobj_release(&view->hdr);
1527 * I am not doing any of the costing functionality yet.
1528 * Mostly looking at doing the Component and Feature loading
1530 * The native MSI does A LOT of modification to tables here. Mostly adding
1531 * a lot of temporary columns to the Feature and Component tables.
1533 * note: Native msi also tracks the short filename. But I am only going to
1534 * track the long ones. Also looking at this directory table
1535 * it appears that the directory table does not get the parents
1536 * resolved base on property only based on their entries in the
1539 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1541 static const WCHAR szCosting[] =
1542 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1543 static const WCHAR szZero[] = { '0', 0 };
1545 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1546 return ERROR_SUCCESS;
1548 MSI_SetPropertyW(package, szCosting, szZero);
1549 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1551 load_all_components( package );
1552 load_all_features( package );
1553 load_all_files( package );
1554 load_all_folders( package );
1556 return ERROR_SUCCESS;
1559 static UINT execute_script(MSIPACKAGE *package, UINT script )
1562 UINT rc = ERROR_SUCCESS;
1564 TRACE("Executing Script %i\n",script);
1566 if (!package->script)
1568 ERR("no script!\n");
1569 return ERROR_FUNCTION_FAILED;
1572 for (i = 0; i < package->script->ActionCount[script]; i++)
1575 action = package->script->Actions[script][i];
1576 ui_actionstart(package, action);
1577 TRACE("Executing Action (%s)\n",debugstr_w(action));
1578 rc = ACTION_PerformAction(package, action, TRUE);
1579 if (rc != ERROR_SUCCESS)
1582 msi_free_action_script(package, script);
1586 static UINT ACTION_FileCost(MSIPACKAGE *package)
1588 return ERROR_SUCCESS;
1591 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1595 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1599 if (!comp->ComponentId)
1602 res = MsiGetComponentPathW( package->ProductCode,
1603 comp->ComponentId, NULL, NULL);
1605 res = INSTALLSTATE_ABSENT;
1606 comp->Installed = res;
1610 /* scan for and update current install states */
1611 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1614 MSIFEATURE *feature;
1616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1619 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1621 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1623 comp= cl->component;
1625 if (!comp->ComponentId)
1627 res = INSTALLSTATE_ABSENT;
1631 if (res == INSTALLSTATE_ABSENT)
1632 res = comp->Installed;
1635 if (res == comp->Installed)
1638 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1639 res != INSTALLSTATE_SOURCE)
1641 res = INSTALLSTATE_INCOMPLETE;
1645 feature->Installed = res;
1649 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1652 static const WCHAR all[]={'A','L','L',0};
1654 MSIFEATURE *feature;
1656 override = msi_dup_property( package, property );
1660 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1662 if (strcmpiW(override,all)==0)
1663 msi_feature_set_state( feature, state );
1666 LPWSTR ptr = override;
1667 LPWSTR ptr2 = strchrW(override,',');
1671 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1672 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1674 msi_feature_set_state( feature, state );
1680 ptr2 = strchrW(ptr,',');
1692 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1695 static const WCHAR szlevel[] =
1696 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1697 static const WCHAR szAddLocal[] =
1698 {'A','D','D','L','O','C','A','L',0};
1699 static const WCHAR szRemove[] =
1700 {'R','E','M','O','V','E',0};
1701 static const WCHAR szReinstall[] =
1702 {'R','E','I','N','S','T','A','L','L',0};
1703 BOOL override = FALSE;
1704 MSICOMPONENT* component;
1705 MSIFEATURE *feature;
1708 /* I do not know if this is where it should happen.. but */
1710 TRACE("Checking Install Level\n");
1712 install_level = msi_get_property_int( package, szlevel, 1 );
1714 /* ok here is the _real_ rub
1715 * all these activation/deactivation things happen in order and things
1716 * later on the list override things earlier on the list.
1717 * 1) INSTALLLEVEL processing
1727 * 11) FILEADDDEFAULT
1728 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1729 * ignored for all the features. seems strange, especially since it is not
1730 * documented anywhere, but it is how it works.
1732 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1733 * REMOVE are the big ones, since we don't handle administrative installs
1736 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1737 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1738 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1742 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1744 BOOL feature_state = ((feature->Level > 0) &&
1745 (feature->Level <= install_level));
1747 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1749 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1750 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1751 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1752 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1754 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1758 /* disable child features of unselected parent features */
1759 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1763 if (feature->Level > 0 && feature->Level <= install_level)
1766 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1767 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1772 /* set the Preselected Property */
1773 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1774 static const WCHAR szOne[] = { '1', 0 };
1776 MSI_SetPropertyW(package,szPreselected,szOne);
1780 * now we want to enable or disable components base on feature
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1787 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1788 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1790 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1792 component = cl->component;
1794 if (!component->Enabled)
1797 if (component->Attributes & msidbComponentAttributesOptional)
1798 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1801 if (component->Attributes & msidbComponentAttributesSourceOnly)
1802 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1804 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1807 if (component->ForceLocalState)
1808 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1810 if (feature->Attributes == msidbFeatureAttributesFavorAdvertise)
1812 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1814 else if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1816 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1817 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1819 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1821 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1822 (component->Action == INSTALLSTATE_ABSENT) ||
1823 (component->Action == INSTALLSTATE_ADVERTISED) ||
1824 (component->Action == INSTALLSTATE_DEFAULT))
1825 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1827 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1829 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1830 (component->Action == INSTALLSTATE_ABSENT))
1831 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1833 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1835 if (component->Action == INSTALLSTATE_UNKNOWN)
1836 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1838 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1839 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1841 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1842 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1846 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1848 if (component->Action == INSTALLSTATE_DEFAULT)
1850 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1851 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1854 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1855 debugstr_w(component->Component), component->Installed, component->Action);
1859 return ERROR_SUCCESS;
1862 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1864 MSIPACKAGE *package = (MSIPACKAGE*)param;
1868 name = MSI_RecordGetString(row,1);
1870 /* This helper function now does ALL the work */
1871 TRACE("Dir %s ...\n",debugstr_w(name));
1872 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1873 TRACE("resolves to %s\n",debugstr_w(path));
1876 return ERROR_SUCCESS;
1879 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1881 MSIPACKAGE *package = (MSIPACKAGE*)param;
1883 MSIFEATURE *feature;
1885 name = MSI_RecordGetString( row, 1 );
1887 feature = get_loaded_feature( package, name );
1889 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1893 Condition = MSI_RecordGetString(row,3);
1895 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1897 int level = MSI_RecordGetInteger(row,2);
1898 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1899 feature->Level = level;
1902 return ERROR_SUCCESS;
1905 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1907 static const WCHAR name_fmt[] =
1908 {'%','u','.','%','u','.','%','u','.','%','u',0};
1909 static WCHAR name[] = {'\\',0};
1910 VS_FIXEDFILEINFO *lpVer;
1911 WCHAR filever[0x100];
1917 TRACE("%s\n", debugstr_w(filename));
1919 versize = GetFileVersionInfoSizeW( filename, &handle );
1923 version = msi_alloc( versize );
1924 GetFileVersionInfoW( filename, 0, versize, version );
1926 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1927 msi_free( version );
1929 sprintfW( filever, name_fmt,
1930 HIWORD(lpVer->dwFileVersionMS),
1931 LOWORD(lpVer->dwFileVersionMS),
1932 HIWORD(lpVer->dwFileVersionLS),
1933 LOWORD(lpVer->dwFileVersionLS));
1935 return strdupW( filever );
1938 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1940 LPWSTR file_version;
1943 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1945 MSICOMPONENT* comp = file->Component;
1951 if (file->IsCompressed)
1952 comp->ForceLocalState = TRUE;
1954 /* calculate target */
1955 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1957 msi_free(file->TargetPath);
1959 TRACE("file %s is named %s\n",
1960 debugstr_w(file->File), debugstr_w(file->FileName));
1962 file->TargetPath = build_directory_name(2, p, file->FileName);
1966 TRACE("file %s resolves to %s\n",
1967 debugstr_w(file->File), debugstr_w(file->TargetPath));
1969 /* don't check files of components that aren't installed */
1970 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1971 comp->Installed == INSTALLSTATE_ABSENT)
1973 file->state = msifs_missing; /* assume files are missing */
1977 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1979 file->state = msifs_missing;
1980 comp->Cost += file->FileSize;
1981 comp->Installed = INSTALLSTATE_INCOMPLETE;
1985 if (file->Version &&
1986 (file_version = msi_get_disk_file_version( file->TargetPath )))
1988 TRACE("new %s old %s\n", debugstr_w(file->Version),
1989 debugstr_w(file_version));
1990 /* FIXME: seems like a bad way to compare version numbers */
1991 if (lstrcmpiW(file_version, file->Version)<0)
1993 file->state = msifs_overwrite;
1994 comp->Cost += file->FileSize;
1995 comp->Installed = INSTALLSTATE_INCOMPLETE;
1998 file->state = msifs_present;
1999 msi_free( file_version );
2002 file->state = msifs_present;
2005 return ERROR_SUCCESS;
2009 * A lot is done in this function aside from just the costing.
2010 * The costing needs to be implemented at some point but for now I am going
2011 * to focus on the directory building
2014 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2016 static const WCHAR ExecSeqQuery[] =
2017 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2018 '`','D','i','r','e','c','t','o','r','y','`',0};
2019 static const WCHAR ConditionQuery[] =
2020 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2021 '`','C','o','n','d','i','t','i','o','n','`',0};
2022 static const WCHAR szCosting[] =
2023 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2024 static const WCHAR szlevel[] =
2025 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2026 static const WCHAR szOne[] = { '1', 0 };
2032 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2033 return ERROR_SUCCESS;
2035 TRACE("Building Directory properties\n");
2037 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2038 if (rc == ERROR_SUCCESS)
2040 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2042 msiobj_release(&view->hdr);
2045 /* read components states from the registry */
2046 ACTION_GetComponentInstallStates(package);
2048 TRACE("File calculations\n");
2049 msi_check_file_install_states( package );
2051 TRACE("Evaluating Condition Table\n");
2053 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2054 if (rc == ERROR_SUCCESS)
2056 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2058 msiobj_release(&view->hdr);
2061 TRACE("Enabling or Disabling Components\n");
2062 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2064 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2066 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2067 comp->Enabled = FALSE;
2071 MSI_SetPropertyW(package,szCosting,szOne);
2072 /* set default run level if not set */
2073 level = msi_dup_property( package, szlevel );
2075 MSI_SetPropertyW(package,szlevel, szOne);
2078 ACTION_UpdateFeatureInstallStates(package);
2080 return MSI_SetFeatureStates(package);
2083 /* OK this value is "interpreted" and then formatted based on the
2084 first few characters */
2085 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2089 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2095 LPWSTR deformated = NULL;
2098 deformat_string(package, &value[2], &deformated);
2100 /* binary value type */
2104 *size = (strlenW(ptr)/2)+1;
2106 *size = strlenW(ptr)/2;
2108 data = msi_alloc(*size);
2114 /* if uneven pad with a zero in front */
2120 data[count] = (BYTE)strtol(byte,NULL,0);
2122 TRACE("Uneven byte count\n");
2130 data[count] = (BYTE)strtol(byte,NULL,0);
2133 msi_free(deformated);
2135 TRACE("Data %i bytes(%i)\n",*size,count);
2142 deformat_string(package, &value[1], &deformated);
2145 *size = sizeof(DWORD);
2146 data = msi_alloc(*size);
2152 if ( (*p < '0') || (*p > '9') )
2158 if (deformated[0] == '-')
2161 TRACE("DWORD %i\n",*(LPDWORD)data);
2163 msi_free(deformated);
2168 static const WCHAR szMulti[] = {'[','~',']',0};
2177 *type=REG_EXPAND_SZ;
2185 if (strstrW(value,szMulti))
2186 *type = REG_MULTI_SZ;
2188 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2193 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2195 MSIPACKAGE *package = (MSIPACKAGE*)param;
2196 static const WCHAR szHCR[] =
2197 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2198 'R','O','O','T','\\',0};
2199 static const WCHAR szHCU[] =
2200 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2201 'U','S','E','R','\\',0};
2202 static const WCHAR szHLM[] =
2203 {'H','K','E','Y','_','L','O','C','A','L','_',
2204 'M','A','C','H','I','N','E','\\',0};
2205 static const WCHAR szHU[] =
2206 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2208 LPSTR value_data = NULL;
2209 HKEY root_key, hkey;
2212 LPCWSTR szRoot, component, name, key, value;
2217 BOOL check_first = FALSE;
2220 ui_progress(package,2,0,0,0);
2227 component = MSI_RecordGetString(row, 6);
2228 comp = get_loaded_component(package,component);
2230 return ERROR_SUCCESS;
2232 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2234 TRACE("Skipping write due to disabled component %s\n",
2235 debugstr_w(component));
2237 comp->Action = comp->Installed;
2239 return ERROR_SUCCESS;
2242 comp->Action = INSTALLSTATE_LOCAL;
2244 name = MSI_RecordGetString(row, 4);
2245 if( MSI_RecordIsNull(row,5) && name )
2247 /* null values can have special meanings */
2248 if (name[0]=='-' && name[1] == 0)
2249 return ERROR_SUCCESS;
2250 else if ((name[0]=='+' && name[1] == 0) ||
2251 (name[0] == '*' && name[1] == 0))
2256 root = MSI_RecordGetInteger(row,2);
2257 key = MSI_RecordGetString(row, 3);
2259 /* get the root key */
2264 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2265 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2266 if (all_users && all_users[0] == '1')
2268 root_key = HKEY_LOCAL_MACHINE;
2273 root_key = HKEY_CURRENT_USER;
2276 msi_free(all_users);
2279 case 0: root_key = HKEY_CLASSES_ROOT;
2282 case 1: root_key = HKEY_CURRENT_USER;
2285 case 2: root_key = HKEY_LOCAL_MACHINE;
2288 case 3: root_key = HKEY_USERS;
2292 ERR("Unknown root %i\n",root);
2298 return ERROR_SUCCESS;
2300 deformat_string(package, key , &deformated);
2301 size = strlenW(deformated) + strlenW(szRoot) + 1;
2302 uikey = msi_alloc(size*sizeof(WCHAR));
2303 strcpyW(uikey,szRoot);
2304 strcatW(uikey,deformated);
2306 if (RegCreateKeyW( root_key, deformated, &hkey))
2308 ERR("Could not create key %s\n",debugstr_w(deformated));
2309 msi_free(deformated);
2311 return ERROR_SUCCESS;
2313 msi_free(deformated);
2315 value = MSI_RecordGetString(row,5);
2317 value_data = parse_value(package, value, &type, &size);
2320 static const WCHAR szEmpty[] = {0};
2321 value_data = (LPSTR)strdupW(szEmpty);
2326 deformat_string(package, name, &deformated);
2328 /* get the double nulls to terminate SZ_MULTI */
2329 if (type == REG_MULTI_SZ)
2330 size +=sizeof(WCHAR);
2334 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2336 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2341 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2342 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2344 TRACE("value %s of %s checked already exists\n",
2345 debugstr_w(deformated), debugstr_w(uikey));
2349 TRACE("Checked and setting value %s of %s\n",
2350 debugstr_w(deformated), debugstr_w(uikey));
2351 if (deformated || size)
2352 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2357 uirow = MSI_CreateRecord(3);
2358 MSI_RecordSetStringW(uirow,2,deformated);
2359 MSI_RecordSetStringW(uirow,1,uikey);
2362 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2364 MSI_RecordSetStringW(uirow,3,value);
2366 ui_actiondata(package,szWriteRegistryValues,uirow);
2367 msiobj_release( &uirow->hdr );
2369 msi_free(value_data);
2370 msi_free(deformated);
2373 return ERROR_SUCCESS;
2376 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2380 static const WCHAR ExecSeqQuery[] =
2381 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2382 '`','R','e','g','i','s','t','r','y','`',0 };
2384 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2385 if (rc != ERROR_SUCCESS)
2386 return ERROR_SUCCESS;
2388 /* increment progress bar each time action data is sent */
2389 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2391 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2393 msiobj_release(&view->hdr);
2397 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2399 package->script->CurrentlyScripting = TRUE;
2401 return ERROR_SUCCESS;
2405 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2410 static const WCHAR q1[]=
2411 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2412 '`','R','e','g','i','s','t','r','y','`',0};
2415 MSIFEATURE *feature;
2418 TRACE("InstallValidate\n");
2420 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2421 if (rc == ERROR_SUCCESS)
2423 MSI_IterateRecords( view, &progress, NULL, package );
2424 msiobj_release( &view->hdr );
2425 total += progress * REG_PROGRESS_VALUE;
2428 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2429 total += COMPONENT_PROGRESS_VALUE;
2431 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2432 total += file->FileSize;
2434 ui_progress(package,0,total,0,0);
2436 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2438 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2439 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2440 feature->ActionRequest);
2443 return ERROR_SUCCESS;
2446 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2448 MSIPACKAGE* package = (MSIPACKAGE*)param;
2449 LPCWSTR cond = NULL;
2450 LPCWSTR message = NULL;
2451 static const WCHAR title[]=
2452 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2454 cond = MSI_RecordGetString(row,1);
2456 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2459 message = MSI_RecordGetString(row,2);
2460 deformat_string(package,message,&deformated);
2461 MessageBoxW(NULL,deformated,title,MB_OK);
2462 msi_free(deformated);
2463 return ERROR_FUNCTION_FAILED;
2466 return ERROR_SUCCESS;
2469 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2472 MSIQUERY * view = NULL;
2473 static const WCHAR ExecSeqQuery[] =
2474 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2475 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2477 TRACE("Checking launch conditions\n");
2479 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2480 if (rc != ERROR_SUCCESS)
2481 return ERROR_SUCCESS;
2483 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2484 msiobj_release(&view->hdr);
2489 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2493 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2495 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2497 MSIRECORD * row = 0;
2499 LPWSTR deformated,buffer,deformated_name;
2501 static const WCHAR ExecSeqQuery[] =
2502 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2503 '`','R','e','g','i','s','t','r','y','`',' ',
2504 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2505 ' ','=',' ' ,'\'','%','s','\'',0 };
2506 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2507 static const WCHAR fmt2[]=
2508 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2510 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2514 root = MSI_RecordGetInteger(row,2);
2515 key = MSI_RecordGetString(row, 3);
2516 name = MSI_RecordGetString(row, 4);
2517 deformat_string(package, key , &deformated);
2518 deformat_string(package, name, &deformated_name);
2520 len = strlenW(deformated) + 6;
2521 if (deformated_name)
2522 len+=strlenW(deformated_name);
2524 buffer = msi_alloc( len *sizeof(WCHAR));
2526 if (deformated_name)
2527 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2529 sprintfW(buffer,fmt,root,deformated);
2531 msi_free(deformated);
2532 msi_free(deformated_name);
2533 msiobj_release(&row->hdr);
2537 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2539 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2544 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2547 return strdupW( file->TargetPath );
2552 static HKEY openSharedDLLsKey(void)
2555 static const WCHAR path[] =
2556 {'S','o','f','t','w','a','r','e','\\',
2557 'M','i','c','r','o','s','o','f','t','\\',
2558 'W','i','n','d','o','w','s','\\',
2559 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2560 'S','h','a','r','e','d','D','L','L','s',0};
2562 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2566 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2571 DWORD sz = sizeof(count);
2574 hkey = openSharedDLLsKey();
2575 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2576 if (rc != ERROR_SUCCESS)
2582 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2586 hkey = openSharedDLLsKey();
2588 msi_reg_set_val_dword( hkey, path, count );
2590 RegDeleteValueW(hkey,path);
2596 * Return TRUE if the count should be written out and FALSE if not
2598 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2600 MSIFEATURE *feature;
2604 /* only refcount DLLs */
2605 if (comp->KeyPath == NULL ||
2606 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2607 comp->Attributes & msidbComponentAttributesODBCDataSource)
2611 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2612 write = (count > 0);
2614 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2618 /* increment counts */
2619 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2623 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2626 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2628 if ( cl->component == comp )
2633 /* decrement counts */
2634 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2638 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2641 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2643 if ( cl->component == comp )
2648 /* ref count all the files in the component */
2653 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2655 if (file->Component == comp)
2656 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2660 /* add a count for permenent */
2661 if (comp->Attributes & msidbComponentAttributesPermanent)
2664 comp->RefCount = count;
2667 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2671 * Ok further analysis makes me think that this work is
2672 * actually done in the PublishComponents and PublishFeatures
2673 * step, and not here. It appears like the keypath and all that is
2674 * resolved in this step, however actually written in the Publish steps.
2675 * But we will leave it here for now because it is unclear
2677 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2679 WCHAR squished_pc[GUID_SIZE];
2680 WCHAR squished_cc[GUID_SIZE];
2683 HKEY hkey=0,hkey2=0;
2685 /* writes the Component and Features values to the registry */
2687 rc = MSIREG_OpenComponents(&hkey);
2688 if (rc != ERROR_SUCCESS)
2691 squash_guid(package->ProductCode,squished_pc);
2692 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2694 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2698 ui_progress(package,2,0,0,0);
2699 if (!comp->ComponentId)
2702 squash_guid(comp->ComponentId,squished_cc);
2704 msi_free(comp->FullKeypath);
2705 comp->FullKeypath = resolve_keypath( package, comp );
2707 /* do the refcounting */
2708 ACTION_RefCountComponent( package, comp );
2710 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2711 debugstr_w(comp->Component),
2712 debugstr_w(squished_cc),
2713 debugstr_w(comp->FullKeypath),
2716 * Write the keypath out if the component is to be registered
2717 * and delete the key if the component is to be deregistered
2719 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2721 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2722 if (rc != ERROR_SUCCESS)
2725 if (!comp->FullKeypath)
2728 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2730 if (comp->Attributes & msidbComponentAttributesPermanent)
2732 static const WCHAR szPermKey[] =
2733 { '0','0','0','0','0','0','0','0','0','0','0','0',
2734 '0','0','0','0','0','0','0','0','0','0','0','0',
2735 '0','0','0','0','0','0','0','0',0 };
2737 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2742 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2746 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2747 if (rc != ERROR_SUCCESS)
2750 RegDeleteValueW(hkey2,squished_pc);
2752 /* if the key is empty delete it */
2753 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2755 if (res == ERROR_NO_MORE_ITEMS)
2756 RegDeleteKeyW(hkey,squished_cc);
2761 uirow = MSI_CreateRecord(3);
2762 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2763 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2764 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2765 ui_actiondata(package,szProcessComponents,uirow);
2766 msiobj_release( &uirow->hdr );
2780 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2781 LPWSTR lpszName, LONG_PTR lParam)
2784 typelib_struct *tl_struct = (typelib_struct*) lParam;
2785 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2789 if (!IS_INTRESOURCE(lpszName))
2791 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2795 sz = strlenW(tl_struct->source)+4;
2796 sz *= sizeof(WCHAR);
2798 if ((INT_PTR)lpszName == 1)
2799 tl_struct->path = strdupW(tl_struct->source);
2802 tl_struct->path = msi_alloc(sz);
2803 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2806 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2807 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2808 if (!SUCCEEDED(res))
2810 msi_free(tl_struct->path);
2811 tl_struct->path = NULL;
2816 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2817 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2819 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2823 msi_free(tl_struct->path);
2824 tl_struct->path = NULL;
2826 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2827 ITypeLib_Release(tl_struct->ptLib);
2832 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2834 MSIPACKAGE* package = (MSIPACKAGE*)param;
2838 typelib_struct tl_struct;
2840 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2842 component = MSI_RecordGetString(row,3);
2843 comp = get_loaded_component(package,component);
2845 return ERROR_SUCCESS;
2847 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2849 TRACE("Skipping typelib reg due to disabled component\n");
2851 comp->Action = comp->Installed;
2853 return ERROR_SUCCESS;
2856 comp->Action = INSTALLSTATE_LOCAL;
2858 file = get_loaded_file( package, comp->KeyPath );
2860 return ERROR_SUCCESS;
2862 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2866 guid = MSI_RecordGetString(row,1);
2867 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2868 tl_struct.source = strdupW( file->TargetPath );
2869 tl_struct.path = NULL;
2871 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2872 (LONG_PTR)&tl_struct);
2880 helpid = MSI_RecordGetString(row,6);
2883 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2884 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2887 if (!SUCCEEDED(res))
2888 ERR("Failed to register type library %s\n",
2889 debugstr_w(tl_struct.path));
2892 ui_actiondata(package,szRegisterTypeLibraries,row);
2894 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2897 ITypeLib_Release(tl_struct.ptLib);
2898 msi_free(tl_struct.path);
2901 ERR("Failed to load type library %s\n",
2902 debugstr_w(tl_struct.source));
2904 FreeLibrary(module);
2905 msi_free(tl_struct.source);
2908 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2910 return ERROR_SUCCESS;
2913 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2916 * OK this is a bit confusing.. I am given a _Component key and I believe
2917 * that the file that is being registered as a type library is the "key file
2918 * of that component" which I interpret to mean "The file in the KeyPath of
2923 static const WCHAR Query[] =
2924 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2925 '`','T','y','p','e','L','i','b','`',0};
2927 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2928 if (rc != ERROR_SUCCESS)
2929 return ERROR_SUCCESS;
2931 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2932 msiobj_release(&view->hdr);
2936 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2938 MSIPACKAGE *package = (MSIPACKAGE*)param;
2939 LPWSTR target_file, target_folder, filename;
2940 LPCWSTR buffer, extension;
2942 static const WCHAR szlnk[]={'.','l','n','k',0};
2943 IShellLinkW *sl = NULL;
2944 IPersistFile *pf = NULL;
2947 buffer = MSI_RecordGetString(row,4);
2948 comp = get_loaded_component(package,buffer);
2950 return ERROR_SUCCESS;
2952 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2954 TRACE("Skipping shortcut creation due to disabled component\n");
2956 comp->Action = comp->Installed;
2958 return ERROR_SUCCESS;
2961 comp->Action = INSTALLSTATE_LOCAL;
2963 ui_actiondata(package,szCreateShortcuts,row);
2965 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2966 &IID_IShellLinkW, (LPVOID *) &sl );
2970 ERR("CLSID_ShellLink not available\n");
2974 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2977 ERR("QueryInterface(IID_IPersistFile) failed\n");
2981 buffer = MSI_RecordGetString(row,2);
2982 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2984 /* may be needed because of a bug somehwere else */
2985 create_full_pathW(target_folder);
2987 filename = msi_dup_record_field( row, 3 );
2988 reduce_to_longfilename(filename);
2990 extension = strchrW(filename,'.');
2991 if (!extension || strcmpiW(extension,szlnk))
2993 int len = strlenW(filename);
2994 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2995 memcpy(filename + len, szlnk, sizeof(szlnk));
2997 target_file = build_directory_name(2, target_folder, filename);
2998 msi_free(target_folder);
3001 buffer = MSI_RecordGetString(row,5);
3002 if (strchrW(buffer,'['))
3005 deformat_string(package,buffer,&deformated);
3006 IShellLinkW_SetPath(sl,deformated);
3007 msi_free(deformated);
3011 FIXME("poorly handled shortcut format, advertised shortcut\n");
3012 IShellLinkW_SetPath(sl,comp->FullKeypath);
3015 if (!MSI_RecordIsNull(row,6))
3018 buffer = MSI_RecordGetString(row,6);
3019 deformat_string(package,buffer,&deformated);
3020 IShellLinkW_SetArguments(sl,deformated);
3021 msi_free(deformated);
3024 if (!MSI_RecordIsNull(row,7))
3026 buffer = MSI_RecordGetString(row,7);
3027 IShellLinkW_SetDescription(sl,buffer);
3030 if (!MSI_RecordIsNull(row,8))
3031 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3033 if (!MSI_RecordIsNull(row,9))
3038 buffer = MSI_RecordGetString(row,9);
3040 Path = build_icon_path(package,buffer);
3041 index = MSI_RecordGetInteger(row,10);
3043 /* no value means 0 */
3044 if (index == MSI_NULL_INTEGER)
3047 IShellLinkW_SetIconLocation(sl,Path,index);
3051 if (!MSI_RecordIsNull(row,11))
3052 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3054 if (!MSI_RecordIsNull(row,12))
3057 buffer = MSI_RecordGetString(row,12);
3058 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3060 IShellLinkW_SetWorkingDirectory(sl,Path);
3064 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3065 IPersistFile_Save(pf,target_file,FALSE);
3067 msi_free(target_file);
3071 IPersistFile_Release( pf );
3073 IShellLinkW_Release( sl );
3075 return ERROR_SUCCESS;
3078 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3083 static const WCHAR Query[] =
3084 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3085 '`','S','h','o','r','t','c','u','t','`',0};
3087 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3088 if (rc != ERROR_SUCCESS)
3089 return ERROR_SUCCESS;
3091 res = CoInitialize( NULL );
3094 ERR("CoInitialize failed\n");
3095 return ERROR_FUNCTION_FAILED;
3098 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3099 msiobj_release(&view->hdr);
3106 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3108 MSIPACKAGE* package = (MSIPACKAGE*)param;
3117 FileName = MSI_RecordGetString(row,1);
3120 ERR("Unable to get FileName\n");
3121 return ERROR_SUCCESS;
3124 FilePath = build_icon_path(package,FileName);
3126 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3128 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3129 FILE_ATTRIBUTE_NORMAL, NULL);
3131 if (the_file == INVALID_HANDLE_VALUE)
3133 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3135 return ERROR_SUCCESS;
3142 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3143 if (rc != ERROR_SUCCESS)
3145 ERR("Failed to get stream\n");
3146 CloseHandle(the_file);
3147 DeleteFileW(FilePath);
3150 WriteFile(the_file,buffer,sz,&write,NULL);
3151 } while (sz == 1024);
3155 CloseHandle(the_file);
3157 uirow = MSI_CreateRecord(1);
3158 MSI_RecordSetStringW(uirow,1,FileName);
3159 ui_actiondata(package,szPublishProduct,uirow);
3160 msiobj_release( &uirow->hdr );
3162 return ERROR_SUCCESS;
3166 * 99% of the work done here is only done for
3167 * advertised installs. However this is where the
3168 * Icon table is processed and written out
3169 * so that is what I am going to do here.
3171 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3175 static const WCHAR Query[]=
3176 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3177 '`','I','c','o','n','`',0};
3178 /* for registry stuff */
3181 static const WCHAR szProductLanguage[] =
3182 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3183 static const WCHAR szARPProductIcon[] =
3184 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3185 static const WCHAR szProductVersion[] =
3186 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3190 MSIHANDLE hDb, hSumInfo;
3192 /* write out icon files */
3194 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3195 if (rc == ERROR_SUCCESS)
3197 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3198 msiobj_release(&view->hdr);
3201 /* ok there is a lot more done here but i need to figure out what */
3203 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3204 if (rc != ERROR_SUCCESS)
3207 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3208 if (rc != ERROR_SUCCESS)
3212 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3213 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3216 langid = msi_get_property_int( package, szProductLanguage, 0 );
3217 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3219 buffer = msi_dup_property( package, szARPProductIcon );
3222 LPWSTR path = build_icon_path(package,buffer);
3223 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3228 buffer = msi_dup_property( package, szProductVersion );
3231 DWORD verdword = msi_version_str_to_dword(buffer);
3232 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3236 /* FIXME: Need to write more keys to the user registry */
3238 hDb= alloc_msihandle( &package->db->hdr );
3240 rc = ERROR_NOT_ENOUGH_MEMORY;
3243 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3244 MsiCloseHandle(hDb);
3245 if (rc == ERROR_SUCCESS)
3247 WCHAR guidbuffer[0x200];
3249 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3251 if (rc == ERROR_SUCCESS)
3253 WCHAR squashed[GUID_SIZE];
3254 /* for now we only care about the first guid */
3255 LPWSTR ptr = strchrW(guidbuffer,';');
3257 squash_guid(guidbuffer,squashed);
3258 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3262 ERR("Unable to query Revision_Number...\n");
3265 MsiCloseHandle(hSumInfo);
3269 ERR("Unable to open Summary Information\n");
3281 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3283 MSIPACKAGE *package = (MSIPACKAGE*)param;
3284 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3285 LPWSTR deformated_section, deformated_key, deformated_value;
3286 LPWSTR folder, fullname = NULL;
3290 static const WCHAR szWindowsFolder[] =
3291 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3293 component = MSI_RecordGetString(row, 8);
3294 comp = get_loaded_component(package,component);
3296 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3298 TRACE("Skipping ini file due to disabled component %s\n",
3299 debugstr_w(component));
3301 comp->Action = comp->Installed;
3303 return ERROR_SUCCESS;
3306 comp->Action = INSTALLSTATE_LOCAL;
3308 identifier = MSI_RecordGetString(row,1);
3309 filename = MSI_RecordGetString(row,2);
3310 dirproperty = MSI_RecordGetString(row,3);
3311 section = MSI_RecordGetString(row,4);
3312 key = MSI_RecordGetString(row,5);
3313 value = MSI_RecordGetString(row,6);
3314 action = MSI_RecordGetInteger(row,7);
3316 deformat_string(package,section,&deformated_section);
3317 deformat_string(package,key,&deformated_key);
3318 deformat_string(package,value,&deformated_value);
3322 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3324 folder = msi_dup_property( package, dirproperty );
3327 folder = msi_dup_property( package, szWindowsFolder );
3331 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3335 fullname = build_directory_name(2, folder, filename);
3339 TRACE("Adding value %s to section %s in %s\n",
3340 debugstr_w(deformated_key), debugstr_w(deformated_section),
3341 debugstr_w(fullname));
3342 WritePrivateProfileStringW(deformated_section, deformated_key,
3343 deformated_value, fullname);
3345 else if (action == 1)
3348 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3349 returned, 10, fullname);
3350 if (returned[0] == 0)
3352 TRACE("Adding value %s to section %s in %s\n",
3353 debugstr_w(deformated_key), debugstr_w(deformated_section),
3354 debugstr_w(fullname));
3356 WritePrivateProfileStringW(deformated_section, deformated_key,
3357 deformated_value, fullname);
3360 else if (action == 3)
3361 FIXME("Append to existing section not yet implemented\n");
3363 uirow = MSI_CreateRecord(4);
3364 MSI_RecordSetStringW(uirow,1,identifier);
3365 MSI_RecordSetStringW(uirow,2,deformated_section);
3366 MSI_RecordSetStringW(uirow,3,deformated_key);
3367 MSI_RecordSetStringW(uirow,4,deformated_value);
3368 ui_actiondata(package,szWriteIniValues,uirow);
3369 msiobj_release( &uirow->hdr );
3373 msi_free(deformated_key);
3374 msi_free(deformated_value);
3375 msi_free(deformated_section);
3376 return ERROR_SUCCESS;
3379 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3383 static const WCHAR ExecSeqQuery[] =
3384 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3385 '`','I','n','i','F','i','l','e','`',0};
3387 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3388 if (rc != ERROR_SUCCESS)
3390 TRACE("no IniFile table\n");
3391 return ERROR_SUCCESS;
3394 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3395 msiobj_release(&view->hdr);
3399 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3401 MSIPACKAGE *package = (MSIPACKAGE*)param;
3406 static const WCHAR ExeStr[] =
3407 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3408 static const WCHAR close[] = {'\"',0};
3410 PROCESS_INFORMATION info;
3415 memset(&si,0,sizeof(STARTUPINFOW));
3417 filename = MSI_RecordGetString(row,1);
3418 file = get_loaded_file( package, filename );
3422 ERR("Unable to find file id %s\n",debugstr_w(filename));
3423 return ERROR_SUCCESS;
3426 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3428 FullName = msi_alloc(len*sizeof(WCHAR));
3429 strcpyW(FullName,ExeStr);
3430 strcatW( FullName, file->TargetPath );
3431 strcatW(FullName,close);
3433 TRACE("Registering %s\n",debugstr_w(FullName));
3434 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3438 msi_dialog_check_messages(info.hProcess);
3443 uirow = MSI_CreateRecord( 2 );
3444 uipath = strdupW( file->TargetPath );
3445 p = strrchrW(uipath,'\\');
3448 MSI_RecordSetStringW( uirow, 1, &p[2] );
3449 MSI_RecordSetStringW( uirow, 2, uipath);
3450 ui_actiondata( package, szSelfRegModules, uirow);
3451 msiobj_release( &uirow->hdr );
3453 /* FIXME: call ui_progress? */
3455 return ERROR_SUCCESS;
3458 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3462 static const WCHAR ExecSeqQuery[] =
3463 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3464 '`','S','e','l','f','R','e','g','`',0};
3466 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3467 if (rc != ERROR_SUCCESS)
3469 TRACE("no SelfReg table\n");
3470 return ERROR_SUCCESS;
3473 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3474 msiobj_release(&view->hdr);
3476 return ERROR_SUCCESS;
3479 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3481 MSIFEATURE *feature;
3486 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3487 if (rc != ERROR_SUCCESS)
3490 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3491 if (rc != ERROR_SUCCESS)
3494 /* here the guids are base 85 encoded */
3495 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3501 BOOL absent = FALSE;
3504 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3505 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3506 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3510 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3514 if (feature->Feature_Parent)
3515 size += strlenW( feature->Feature_Parent )+2;
3517 data = msi_alloc(size * sizeof(WCHAR));
3520 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3522 MSICOMPONENT* component = cl->component;
3526 if (component->ComponentId)
3528 TRACE("From %s\n",debugstr_w(component->ComponentId));
3529 CLSIDFromString(component->ComponentId, &clsid);
3530 encode_base85_guid(&clsid,buf);
3531 TRACE("to %s\n",debugstr_w(buf));
3535 if (feature->Feature_Parent)
3537 static const WCHAR sep[] = {'\2',0};
3539 strcatW(data,feature->Feature_Parent);
3542 msi_reg_set_val_str( hkey, feature->Feature, data );
3546 if (feature->Feature_Parent)
3547 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3550 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3551 (LPBYTE)feature->Feature_Parent,size);
3555 size += 2*sizeof(WCHAR);
3556 data = msi_alloc(size);
3559 if (feature->Feature_Parent)
3560 strcpyW( &data[1], feature->Feature_Parent );
3561 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3567 uirow = MSI_CreateRecord( 1 );
3568 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3569 ui_actiondata( package, szPublishFeatures, uirow);
3570 msiobj_release( &uirow->hdr );
3571 /* FIXME: call ui_progress? */
3580 static UINT msi_get_local_package_name( LPWSTR path )
3582 static const WCHAR szInstaller[] = {
3583 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3584 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3588 time = GetTickCount();
3589 GetWindowsDirectoryW( path, MAX_PATH );
3590 lstrcatW( path, szInstaller );
3591 CreateDirectoryW( path, NULL );
3593 len = lstrlenW(path);
3594 for (i=0; i<0x10000; i++)
3596 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3597 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3598 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3599 if (handle != INVALID_HANDLE_VALUE)
3601 CloseHandle(handle);
3604 if (GetLastError() != ERROR_FILE_EXISTS &&
3605 GetLastError() != ERROR_SHARING_VIOLATION)
3606 return ERROR_FUNCTION_FAILED;
3609 return ERROR_SUCCESS;
3612 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3614 static const WCHAR szOriginalDatabase[] =
3615 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3616 WCHAR packagefile[MAX_PATH];
3620 r = msi_get_local_package_name( packagefile );
3621 if (r != ERROR_SUCCESS)
3624 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3626 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3627 r = CopyFileW( msiFilePath, packagefile, FALSE);
3628 msi_free( msiFilePath );
3632 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3633 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3634 return ERROR_FUNCTION_FAILED;
3637 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3638 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3639 return ERROR_SUCCESS;
3642 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3644 LPWSTR prop, val, key;
3645 static const LPCSTR propval[] = {
3646 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3647 "ARPCONTACT", "Contact",
3648 "ARPCOMMENTS", "Comments",
3649 "ProductName", "DisplayName",
3650 "ProductVersion", "DisplayVersion",
3651 "ARPHELPLINK", "HelpLink",
3652 "ARPHELPTELEPHONE", "HelpTelephone",
3653 "ARPINSTALLLOCATION", "InstallLocation",
3654 "SourceDir", "InstallSource",
3655 "Manufacturer", "Publisher",
3656 "ARPREADME", "Readme",
3658 "ARPURLINFOABOUT", "URLInfoAbout",
3659 "ARPURLUPDATEINFO", "URLUpdateInfo",
3662 const LPCSTR *p = propval;
3666 prop = strdupAtoW( *p++ );
3667 key = strdupAtoW( *p++ );
3668 val = msi_dup_property( package, prop );
3669 msi_reg_set_val_str( hkey, key, val );
3674 return ERROR_SUCCESS;
3677 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3680 LPWSTR buffer = NULL;
3683 static const WCHAR szWindowsInstaller[] =
3684 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3685 static const WCHAR szUpgradeCode[] =
3686 {'U','p','g','r','a','d','e','C','o','d','e',0};
3687 static const WCHAR modpath_fmt[] =
3688 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3689 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3690 static const WCHAR szModifyPath[] =
3691 {'M','o','d','i','f','y','P','a','t','h',0};
3692 static const WCHAR szUninstallString[] =
3693 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3694 static const WCHAR szEstimatedSize[] =
3695 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3696 static const WCHAR szProductLanguage[] =
3697 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3698 static const WCHAR szProductVersion[] =
3699 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3702 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3703 LPWSTR upgrade_code;
3706 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3707 if (rc != ERROR_SUCCESS)
3710 /* dump all the info i can grab */
3711 /* FIXME: Flesh out more information */
3713 msi_write_uninstall_property_vals( package, hkey );
3715 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3717 msi_make_package_local( package, hkey );
3719 /* do ModifyPath and UninstallString */
3720 size = deformat_string(package,modpath_fmt,&buffer);
3721 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3722 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3725 /* FIXME: Write real Estimated Size when we have it */
3726 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3728 GetLocalTime(&systime);
3729 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3730 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3732 langid = msi_get_property_int( package, szProductLanguage, 0 );
3733 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3735 buffer = msi_dup_property( package, szProductVersion );
3738 DWORD verdword = msi_version_str_to_dword(buffer);
3740 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3741 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3742 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3746 /* Handle Upgrade Codes */
3747 upgrade_code = msi_dup_property( package, szUpgradeCode );
3752 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3753 squash_guid(package->ProductCode,squashed);
3754 msi_reg_set_val_str( hkey2, squashed, NULL );
3756 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3757 squash_guid(package->ProductCode,squashed);
3758 msi_reg_set_val_str( hkey2, squashed, NULL );
3761 msi_free(upgrade_code);
3766 /* FIXME: call ui_actiondata */
3768 return ERROR_SUCCESS;
3771 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3773 return execute_script(package,INSTALL_SCRIPT);
3776 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3780 /* turn off scheduling */
3781 package->script->CurrentlyScripting= FALSE;
3783 /* first do the same as an InstallExecute */
3784 rc = ACTION_InstallExecute(package);
3785 if (rc != ERROR_SUCCESS)
3788 /* then handle Commit Actions */
3789 rc = execute_script(package,COMMIT_SCRIPT);
3794 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3796 static const WCHAR RunOnce[] = {
3797 'S','o','f','t','w','a','r','e','\\',
3798 'M','i','c','r','o','s','o','f','t','\\',
3799 'W','i','n','d','o','w','s','\\',
3800 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3801 'R','u','n','O','n','c','e',0};
3802 static const WCHAR InstallRunOnce[] = {
3803 'S','o','f','t','w','a','r','e','\\',
3804 'M','i','c','r','o','s','o','f','t','\\',
3805 'W','i','n','d','o','w','s','\\',
3806 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3807 'I','n','s','t','a','l','l','e','r','\\',
3808 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3810 static const WCHAR msiexec_fmt[] = {
3812 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3813 '\"','%','s','\"',0};
3814 static const WCHAR install_fmt[] = {
3815 '/','I',' ','\"','%','s','\"',' ',
3816 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3817 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3818 WCHAR buffer[256], sysdir[MAX_PATH];
3820 WCHAR squished_pc[100];
3822 squash_guid(package->ProductCode,squished_pc);
3824 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3825 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3826 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3829 msi_reg_set_val_str( hkey, squished_pc, buffer );
3832 TRACE("Reboot command %s\n",debugstr_w(buffer));
3834 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3835 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3837 msi_reg_set_val_str( hkey, squished_pc, buffer );
3840 return ERROR_INSTALL_SUSPEND;
3843 UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3848 p = strrchrW( package->PackagePath, '\\' );
3850 return ERROR_SUCCESS;
3852 len = p - package->PackagePath + 2;
3853 source = msi_alloc( len * sizeof(WCHAR) );
3854 lstrcpynW( source, package->PackagePath, len );
3856 MSI_SetPropertyW( package, cszSourceDir, source );
3857 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3861 return ERROR_SUCCESS;
3864 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3870 * We are currently doing what should be done here in the top level Install
3871 * however for Administrative and uninstalls this step will be needed
3873 if (!package->PackagePath)
3874 return ERROR_SUCCESS;
3876 msi_set_sourcedir_props(package);
3878 attrib = GetFileAttributesW(package->PackagePath);
3879 if (attrib == INVALID_FILE_ATTRIBUTES)
3885 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3886 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3887 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3888 if (rc == ERROR_MORE_DATA)
3890 prompt = msi_alloc(size * sizeof(WCHAR));
3891 MsiSourceListGetInfoW(package->ProductCode, NULL,
3892 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3893 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3896 prompt = strdupW(package->PackagePath);
3898 msg = generate_error_string(package,1302,1,prompt);
3899 while(attrib == INVALID_FILE_ATTRIBUTES)
3901 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3904 rc = ERROR_INSTALL_USEREXIT;
3907 attrib = GetFileAttributesW(package->PackagePath);
3913 return ERROR_SUCCESS;
3918 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3925 static const WCHAR szPropKeys[][80] =
3927 {'P','r','o','d','u','c','t','I','D',0},
3928 {'U','S','E','R','N','A','M','E',0},
3929 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3933 static const WCHAR szRegKeys[][80] =
3935 {'P','r','o','d','u','c','t','I','D',0},
3936 {'R','e','g','O','w','n','e','r',0},
3937 {'R','e','g','C','o','m','p','a','n','y',0},
3941 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3943 return ERROR_SUCCESS;
3945 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3946 if (rc != ERROR_SUCCESS)
3949 for( i = 0; szPropKeys[i][0]; i++ )
3951 buffer = msi_dup_property( package, szPropKeys[i] );
3952 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3957 msi_free(productid);
3960 /* FIXME: call ui_actiondata */
3962 return ERROR_SUCCESS;
3966 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3970 package->script->InWhatSequence |= SEQUENCE_EXEC;
3971 rc = ACTION_ProcessExecSequence(package,FALSE);
3976 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3978 MSIPACKAGE *package = (MSIPACKAGE*)param;
3979 LPCWSTR compgroupid=NULL;
3980 LPCWSTR feature=NULL;
3981 LPCWSTR text = NULL;
3982 LPCWSTR qualifier = NULL;
3983 LPCWSTR component = NULL;
3984 LPWSTR advertise = NULL;
3985 LPWSTR output = NULL;
3987 UINT rc = ERROR_SUCCESS;
3992 component = MSI_RecordGetString(rec,3);
3993 comp = get_loaded_component(package,component);
3995 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3996 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3997 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3999 TRACE("Skipping: Component %s not scheduled for install\n",
4000 debugstr_w(component));
4002 return ERROR_SUCCESS;
4005 compgroupid = MSI_RecordGetString(rec,1);
4006 qualifier = MSI_RecordGetString(rec,2);
4008 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4009 if (rc != ERROR_SUCCESS)
4012 text = MSI_RecordGetString(rec,4);
4013 feature = MSI_RecordGetString(rec,5);
4015 advertise = create_component_advertise_string(package, comp, feature);
4017 sz = strlenW(advertise);
4020 sz += lstrlenW(text);
4023 sz *= sizeof(WCHAR);
4025 output = msi_alloc_zero(sz);
4026 strcpyW(output,advertise);
4027 msi_free(advertise);
4030 strcatW(output,text);
4032 msi_reg_set_val_multi_str( hkey, qualifier, output );
4039 uirow = MSI_CreateRecord( 2 );
4040 MSI_RecordSetStringW( uirow, 1, compgroupid );
4041 MSI_RecordSetStringW( uirow, 2, qualifier);
4042 ui_actiondata( package, szPublishComponents, uirow);
4043 msiobj_release( &uirow->hdr );
4044 /* FIXME: call ui_progress? */
4050 * At present I am ignorning the advertised components part of this and only
4051 * focusing on the qualified component sets
4053 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4057 static const WCHAR ExecSeqQuery[] =
4058 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4059 '`','P','u','b','l','i','s','h',
4060 'C','o','m','p','o','n','e','n','t','`',0};
4062 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4063 if (rc != ERROR_SUCCESS)
4064 return ERROR_SUCCESS;
4066 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4067 msiobj_release(&view->hdr);
4072 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4074 MSIPACKAGE *package = (MSIPACKAGE*)param;
4077 SC_HANDLE hscm, service = NULL;
4078 LPCWSTR name, disp, comp, depends, pass;
4079 LPCWSTR load_order, serv_name, key;
4080 DWORD serv_type, start_type;
4083 static const WCHAR query[] =
4084 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4085 '`','C','o','m','p','o','n','e','n','t','`',' ',
4086 'W','H','E','R','E',' ',
4087 '`','C','o','m','p','o','n','e','n','t','`',' ',
4088 '=','\'','%','s','\'',0};
4090 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4093 ERR("Failed to open the SC Manager!\n");
4097 start_type = MSI_RecordGetInteger(rec, 5);
4098 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4101 depends = MSI_RecordGetString(rec, 8);
4102 if (depends && *depends)
4103 FIXME("Dependency list unhandled!\n");
4105 name = MSI_RecordGetString(rec, 2);
4106 disp = MSI_RecordGetString(rec, 3);
4107 serv_type = MSI_RecordGetInteger(rec, 4);
4108 err_control = MSI_RecordGetInteger(rec, 6);
4109 load_order = MSI_RecordGetString(rec, 7);
4110 serv_name = MSI_RecordGetString(rec, 9);
4111 pass = MSI_RecordGetString(rec, 10);
4112 comp = MSI_RecordGetString(rec, 12);
4114 /* fetch the service path */
4115 row = MSI_QueryGetRecord(package->db, query, comp);
4118 ERR("Control query failed!\n");
4122 key = MSI_RecordGetString(row, 6);
4123 msiobj_release(&row->hdr);
4125 file = get_loaded_file(package, key);
4128 ERR("Failed to load the service file\n");
4132 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4133 start_type, err_control, file->TargetPath,
4134 load_order, NULL, NULL, serv_name, pass);
4137 if (GetLastError() != ERROR_SERVICE_EXISTS)
4138 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4142 CloseServiceHandle(service);
4143 CloseServiceHandle(hscm);
4145 return ERROR_SUCCESS;
4148 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4152 static const WCHAR ExecSeqQuery[] =
4153 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4154 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4156 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4157 if (rc != ERROR_SUCCESS)
4158 return ERROR_SUCCESS;
4160 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4161 msiobj_release(&view->hdr);
4166 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4167 LPCSTR action, LPCWSTR table )
4169 static const WCHAR query[] = {
4170 'S','E','L','E','C','T',' ','*',' ',
4171 'F','R','O','M',' ','`','%','s','`',0 };
4172 MSIQUERY *view = NULL;
4176 r = MSI_OpenQuery( package->db, &view, query, table );
4177 if (r == ERROR_SUCCESS)
4179 r = MSI_IterateRecords(view, &count, NULL, package);
4180 msiobj_release(&view->hdr);
4184 FIXME("%s -> %u ignored %s table values\n",
4185 action, count, debugstr_w(table));
4187 return ERROR_SUCCESS;
4190 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4192 TRACE("%p\n", package);
4193 return ERROR_SUCCESS;
4196 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4198 static const WCHAR table[] =
4199 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4200 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4203 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4205 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4206 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4209 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4211 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4212 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4215 static UINT ACTION_BindImage( MSIPACKAGE *package )
4217 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4218 return msi_unimplemented_action_stub( package, "BindImage", table );
4221 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4223 static const WCHAR table[] = {
4224 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4225 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4228 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4230 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4231 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4234 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4236 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4237 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4240 static UINT ACTION_StartServices( MSIPACKAGE *package )
4242 static const WCHAR table[] = {
4243 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4244 return msi_unimplemented_action_stub( package, "StartServices", table );
4247 static UINT ACTION_StopServices( MSIPACKAGE *package )
4249 static const WCHAR table[] = {
4250 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4251 return msi_unimplemented_action_stub( package, "StopServices", table );
4254 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4256 static const WCHAR table[] = {
4257 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4258 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4261 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4263 static const WCHAR table[] = {
4264 'E','n','v','i','r','o','n','m','e','n','t',0 };
4265 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4268 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4270 static const WCHAR table[] = {
4271 'E','n','v','i','r','o','n','m','e','n','t',0 };
4272 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4275 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4277 static const WCHAR table[] = {
4278 'M','s','i','A','s','s','e','m','b','l','y',0 };
4279 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4282 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4284 static const WCHAR table[] = {
4285 'M','s','i','A','s','s','e','m','b','l','y',0 };
4286 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4289 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4291 static const WCHAR table[] = { 'F','o','n','t',0 };
4292 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4295 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4297 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4298 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4301 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4303 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4304 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4307 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4309 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4310 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4313 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4315 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4316 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4319 static struct _actions StandardActions[] = {
4320 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4321 { szAppSearch, ACTION_AppSearch },
4322 { szBindImage, ACTION_BindImage },
4323 { szCCPSearch, ACTION_CCPSearch},
4324 { szCostFinalize, ACTION_CostFinalize },
4325 { szCostInitialize, ACTION_CostInitialize },
4326 { szCreateFolders, ACTION_CreateFolders },
4327 { szCreateShortcuts, ACTION_CreateShortcuts },
4328 { szDeleteServices, ACTION_DeleteServices },
4329 { szDisableRollback, NULL},
4330 { szDuplicateFiles, ACTION_DuplicateFiles },
4331 { szExecuteAction, ACTION_ExecuteAction },
4332 { szFileCost, ACTION_FileCost },
4333 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4334 { szForceReboot, ACTION_ForceReboot },
4335 { szInstallAdminPackage, NULL},
4336 { szInstallExecute, ACTION_InstallExecute },
4337 { szInstallExecuteAgain, ACTION_InstallExecute },
4338 { szInstallFiles, ACTION_InstallFiles},
4339 { szInstallFinalize, ACTION_InstallFinalize },
4340 { szInstallInitialize, ACTION_InstallInitialize },
4341 { szInstallSFPCatalogFile, NULL},
4342 { szInstallValidate, ACTION_InstallValidate },
4343 { szIsolateComponents, ACTION_IsolateComponents },
4344 { szLaunchConditions, ACTION_LaunchConditions },
4345 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4346 { szMoveFiles, ACTION_MoveFiles },
4347 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4348 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4349 { szInstallODBC, NULL},
4350 { szInstallServices, ACTION_InstallServices },
4351 { szPatchFiles, ACTION_PatchFiles },
4352 { szProcessComponents, ACTION_ProcessComponents },
4353 { szPublishComponents, ACTION_PublishComponents },
4354 { szPublishFeatures, ACTION_PublishFeatures },
4355 { szPublishProduct, ACTION_PublishProduct },
4356 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4357 { szRegisterComPlus, ACTION_RegisterComPlus},
4358 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4359 { szRegisterFonts, ACTION_RegisterFonts },
4360 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4361 { szRegisterProduct, ACTION_RegisterProduct },
4362 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4363 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4364 { szRegisterUser, ACTION_RegisterUser},
4365 { szRemoveDuplicateFiles, NULL},
4366 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4367 { szRemoveExistingProducts, NULL},
4368 { szRemoveFiles, ACTION_RemoveFiles},
4369 { szRemoveFolders, NULL},
4370 { szRemoveIniValues, ACTION_RemoveIniValues },
4371 { szRemoveODBC, NULL},
4372 { szRemoveRegistryValues, NULL},
4373 { szRemoveShortcuts, NULL},
4374 { szResolveSource, ACTION_ResolveSource},
4375 { szRMCCPSearch, ACTION_RMCCPSearch},
4376 { szScheduleReboot, NULL},
4377 { szSelfRegModules, ACTION_SelfRegModules },
4378 { szSelfUnregModules, ACTION_SelfUnregModules },
4379 { szSetODBCFolders, NULL},
4380 { szStartServices, ACTION_StartServices },
4381 { szStopServices, ACTION_StopServices },
4382 { szUnpublishComponents, NULL},
4383 { szUnpublishFeatures, NULL},
4384 { szUnregisterClassInfo, NULL},
4385 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4386 { szUnregisterExtensionInfo, NULL},
4387 { szUnregisterFonts, ACTION_UnregisterFonts },
4388 { szUnregisterMIMEInfo, NULL},
4389 { szUnregisterProgIdInfo, NULL},
4390 { szUnregisterTypeLibraries, NULL},
4391 { szValidateProductID, NULL},
4392 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4393 { szWriteIniValues, ACTION_WriteIniValues },
4394 { szWriteRegistryValues, ACTION_WriteRegistryValues},