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 );
529 msiobj_release( &patch_db->hdr );
531 return ERROR_SUCCESS;
534 /* get the PATCH property, and apply all the patches it specifies */
535 static UINT msi_apply_patches( MSIPACKAGE *package )
537 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
538 LPWSTR patch_list, *patches;
539 UINT i, r = ERROR_SUCCESS;
541 patch_list = msi_dup_property( package, szPatch );
543 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
545 patches = msi_split_string( patch_list, ';' );
546 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
547 r = msi_apply_patch_package( package, patches[i] );
550 msi_free( patch_list );
555 static UINT msi_apply_transforms( MSIPACKAGE *package )
557 static const WCHAR szTransforms[] = {
558 'T','R','A','N','S','F','O','R','M','S',0 };
559 LPWSTR xform_list, *xforms;
560 UINT i, r = ERROR_SUCCESS;
562 xform_list = msi_dup_property( package, szTransforms );
563 xforms = msi_split_string( xform_list, ';' );
565 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
567 if (xforms[i][0] == ':')
568 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
570 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
574 msi_free( xform_list );
579 /****************************************************
580 * TOP level entry points
581 *****************************************************/
583 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
584 LPCWSTR szCommandLine )
588 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
589 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
590 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
592 MSI_SetPropertyW(package, szAction, szInstall);
594 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
596 package->script->InWhatSequence = SEQUENCE_INSTALL;
600 LPWSTR p, check, path;
602 path = strdupW(szPackagePath);
603 p = strrchrW(path,'\\');
612 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
613 GetCurrentDirectoryW(MAX_PATH,path);
617 check = msi_dup_property( package, cszSourceDir );
619 MSI_SetPropertyW(package, cszSourceDir, path);
621 check = msi_dup_property( package, cszSOURCEDIR );
623 MSI_SetPropertyW(package, cszSOURCEDIR, path);
625 msi_free( package->PackagePath );
626 package->PackagePath = path;
631 msi_parse_command_line( package, szCommandLine );
633 msi_apply_transforms( package );
634 msi_apply_patches( package );
636 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
638 package->script->InWhatSequence |= SEQUENCE_UI;
639 rc = ACTION_ProcessUISequence(package);
641 if (rc == ERROR_SUCCESS)
643 package->script->InWhatSequence |= SEQUENCE_EXEC;
644 rc = ACTION_ProcessExecSequence(package,TRUE);
648 rc = ACTION_ProcessExecSequence(package,FALSE);
652 /* install was halted but should be considered a success */
656 package->script->CurrentlyScripting= FALSE;
658 /* process the ending type action */
659 if (rc == ERROR_SUCCESS)
660 ACTION_PerformActionSequence(package,-1,ui);
661 else if (rc == ERROR_INSTALL_USEREXIT)
662 ACTION_PerformActionSequence(package,-2,ui);
663 else if (rc == ERROR_INSTALL_SUSPEND)
664 ACTION_PerformActionSequence(package,-4,ui);
666 ACTION_PerformActionSequence(package,-3,ui);
668 /* finish up running custom actions */
669 ACTION_FinishCustomActions(package);
674 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
676 UINT rc = ERROR_SUCCESS;
678 static const WCHAR ExecSeqQuery[] =
679 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
680 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
681 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
682 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
684 static const WCHAR UISeqQuery[] =
685 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
686 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
687 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
688 ' ', '=',' ','%','i',0};
691 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
693 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
697 LPCWSTR action, cond;
699 TRACE("Running the actions\n");
701 /* check conditions */
702 cond = MSI_RecordGetString(row,2);
704 /* this is a hack to skip errors in the condition code */
705 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
708 action = MSI_RecordGetString(row,1);
711 ERR("failed to fetch action\n");
712 rc = ERROR_FUNCTION_FAILED;
717 rc = ACTION_PerformUIAction(package,action);
719 rc = ACTION_PerformAction(package,action,FALSE);
721 msiobj_release(&row->hdr);
732 } iterate_action_param;
734 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
736 iterate_action_param *iap= (iterate_action_param*)param;
738 LPCWSTR cond, action;
740 action = MSI_RecordGetString(row,1);
743 ERR("Error is retrieving action name\n");
744 return ERROR_FUNCTION_FAILED;
747 /* check conditions */
748 cond = MSI_RecordGetString(row,2);
750 /* this is a hack to skip errors in the condition code */
751 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
753 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
754 return ERROR_SUCCESS;
758 rc = ACTION_PerformUIAction(iap->package,action);
760 rc = ACTION_PerformAction(iap->package,action,FALSE);
762 msi_dialog_check_messages( NULL );
764 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
765 rc = iap->package->CurrentInstallState;
767 if (rc == ERROR_FUNCTION_NOT_CALLED)
770 if (rc != ERROR_SUCCESS)
771 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
776 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
780 static const WCHAR query[] =
781 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
783 ' ','W','H','E','R','E',' ',
784 '`','S','e','q','u','e','n','c','e','`',' ',
785 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
786 '`','S','e','q','u','e','n','c','e','`',0};
787 iterate_action_param iap;
790 * FIXME: probably should be checking UILevel in the
791 * ACTION_PerformUIAction/ACTION_PerformAction
792 * rather than saving the UI level here. Those
793 * two functions can be merged too.
795 iap.package = package;
798 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
800 r = MSI_OpenQuery( package->db, &view, query, szTable );
801 if (r == ERROR_SUCCESS)
803 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
804 msiobj_release(&view->hdr);
810 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
814 static const WCHAR ExecSeqQuery[] =
815 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
816 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
817 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
818 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
819 'O','R','D','E','R',' ', 'B','Y',' ',
820 '`','S','e','q','u','e','n','c','e','`',0 };
822 static const WCHAR IVQuery[] =
823 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
824 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
825 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
826 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
827 ' ','\'', 'I','n','s','t','a','l','l',
828 'V','a','l','i','d','a','t','e','\'', 0};
830 iterate_action_param iap;
832 iap.package = package;
835 if (package->script->ExecuteSequenceRun)
837 TRACE("Execute Sequence already Run\n");
838 return ERROR_SUCCESS;
841 package->script->ExecuteSequenceRun = TRUE;
843 /* get the sequence number */
846 row = MSI_QueryGetRecord(package->db, IVQuery);
848 return ERROR_FUNCTION_FAILED;
849 seq = MSI_RecordGetInteger(row,1);
850 msiobj_release(&row->hdr);
853 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
854 if (rc == ERROR_SUCCESS)
856 TRACE("Running the actions\n");
858 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
859 msiobj_release(&view->hdr);
865 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
869 static const WCHAR ExecSeqQuery [] =
870 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
871 '`','I','n','s','t','a','l','l',
872 'U','I','S','e','q','u','e','n','c','e','`',
873 ' ','W','H','E','R','E',' ',
874 '`','S','e','q','u','e','n','c','e','`',' ',
875 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
876 '`','S','e','q','u','e','n','c','e','`',0};
877 iterate_action_param iap;
879 iap.package = package;
882 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
884 if (rc == ERROR_SUCCESS)
886 TRACE("Running the actions\n");
888 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
889 msiobj_release(&view->hdr);
895 /********************************************************
896 * ACTION helper functions and functions that perform the actions
897 *******************************************************/
898 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
899 UINT* rc, BOOL force )
905 if (!run && !package->script->CurrentlyScripting)
910 if (strcmpW(action,szInstallFinalize) == 0 ||
911 strcmpW(action,szInstallExecute) == 0 ||
912 strcmpW(action,szInstallExecuteAgain) == 0)
917 while (StandardActions[i].action != NULL)
919 if (strcmpW(StandardActions[i].action, action)==0)
923 ui_actioninfo(package, action, TRUE, 0);
924 *rc = schedule_action(package,INSTALL_SCRIPT,action);
925 ui_actioninfo(package, action, FALSE, *rc);
929 ui_actionstart(package, action);
930 if (StandardActions[i].handler)
932 *rc = StandardActions[i].handler(package);
936 FIXME("unhandled standard action %s\n",debugstr_w(action));
948 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
949 UINT* rc, BOOL force )
954 arc = ACTION_CustomAction(package,action, force);
956 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
965 * A lot of actions are really important even if they don't do anything
966 * explicit... Lots of properties are set at the beginning of the installation
967 * CostFinalize does a bunch of work to translate the directories and such
969 * But until I get write access to the database that is hard, so I am going to
970 * hack it to see if I can get something to run.
972 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
974 UINT rc = ERROR_SUCCESS;
977 TRACE("Performing action (%s)\n",debugstr_w(action));
979 handled = ACTION_HandleStandardAction(package, action, &rc, force);
982 handled = ACTION_HandleCustomAction(package, action, &rc, force);
986 FIXME("unhandled msi action %s\n",debugstr_w(action));
987 rc = ERROR_FUNCTION_NOT_CALLED;
993 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
995 UINT rc = ERROR_SUCCESS;
996 BOOL handled = FALSE;
998 TRACE("Performing action (%s)\n",debugstr_w(action));
1000 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1003 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1005 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1010 FIXME("unhandled msi action %s\n",debugstr_w(action));
1011 rc = ERROR_FUNCTION_NOT_CALLED;
1019 * Actual Action Handlers
1022 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1024 MSIPACKAGE *package = (MSIPACKAGE*)param;
1030 dir = MSI_RecordGetString(row,1);
1033 ERR("Unable to get folder id\n");
1034 return ERROR_SUCCESS;
1037 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1040 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1041 return ERROR_SUCCESS;
1044 TRACE("Folder is %s\n",debugstr_w(full_path));
1047 uirow = MSI_CreateRecord(1);
1048 MSI_RecordSetStringW(uirow,1,full_path);
1049 ui_actiondata(package,szCreateFolders,uirow);
1050 msiobj_release( &uirow->hdr );
1052 if (folder->State == 0)
1053 create_full_pathW(full_path);
1057 msi_free(full_path);
1058 return ERROR_SUCCESS;
1061 /* FIXME: probably should merge this with the above function */
1062 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1064 UINT rc = ERROR_SUCCESS;
1066 LPWSTR install_path;
1068 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1070 return ERROR_FUNCTION_FAILED;
1072 /* create the path */
1073 if (folder->State == 0)
1075 create_full_pathW(install_path);
1078 msi_free(install_path);
1083 UINT msi_create_component_directories( MSIPACKAGE *package )
1087 /* create all the folders required by the components are going to install */
1088 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1090 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1092 msi_create_directory( package, comp->Directory );
1095 return ERROR_SUCCESS;
1099 * Also we cannot enable/disable components either, so for now I am just going
1100 * to do all the directories for all the components.
1102 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1104 static const WCHAR ExecSeqQuery[] =
1105 {'S','E','L','E','C','T',' ',
1106 '`','D','i','r','e','c','t','o','r','y','_','`',
1107 ' ','F','R','O','M',' ',
1108 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1112 /* create all the empty folders specified in the CreateFolder table */
1113 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1114 if (rc != ERROR_SUCCESS)
1115 return ERROR_SUCCESS;
1117 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1118 msiobj_release(&view->hdr);
1120 msi_create_component_directories( package );
1125 static UINT load_component( MSIRECORD *row, LPVOID param )
1127 MSIPACKAGE *package = param;
1130 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1132 return ERROR_FUNCTION_FAILED;
1134 list_add_tail( &package->components, &comp->entry );
1136 /* fill in the data */
1137 comp->Component = msi_dup_record_field( row, 1 );
1139 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1141 comp->ComponentId = msi_dup_record_field( row, 2 );
1142 comp->Directory = msi_dup_record_field( row, 3 );
1143 comp->Attributes = MSI_RecordGetInteger(row,4);
1144 comp->Condition = msi_dup_record_field( row, 5 );
1145 comp->KeyPath = msi_dup_record_field( row, 6 );
1147 comp->Installed = INSTALLSTATE_UNKNOWN;
1148 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1150 return ERROR_SUCCESS;
1153 static UINT load_all_components( MSIPACKAGE *package )
1155 static const WCHAR query[] = {
1156 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1157 '`','C','o','m','p','o','n','e','n','t','`',0 };
1161 if (!list_empty(&package->components))
1162 return ERROR_SUCCESS;
1164 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1165 if (r != ERROR_SUCCESS)
1168 r = MSI_IterateRecords(view, NULL, load_component, package);
1169 msiobj_release(&view->hdr);
1174 MSIPACKAGE *package;
1175 MSIFEATURE *feature;
1178 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1182 cl = msi_alloc( sizeof (*cl) );
1184 return ERROR_NOT_ENOUGH_MEMORY;
1185 cl->component = comp;
1186 list_add_tail( &feature->Components, &cl->entry );
1188 return ERROR_SUCCESS;
1191 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1195 fl = msi_alloc( sizeof(*fl) );
1197 return ERROR_NOT_ENOUGH_MEMORY;
1198 fl->feature = child;
1199 list_add_tail( &parent->Children, &fl->entry );
1201 return ERROR_SUCCESS;
1204 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1206 _ilfs* ilfs= (_ilfs*)param;
1210 component = MSI_RecordGetString(row,1);
1212 /* check to see if the component is already loaded */
1213 comp = get_loaded_component( ilfs->package, component );
1216 ERR("unknown component %s\n", debugstr_w(component));
1217 return ERROR_FUNCTION_FAILED;
1220 add_feature_component( ilfs->feature, comp );
1221 comp->Enabled = TRUE;
1223 return ERROR_SUCCESS;
1226 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1228 MSIFEATURE *feature;
1230 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1232 if ( !lstrcmpW( feature->Feature, name ) )
1239 static UINT load_feature(MSIRECORD * row, LPVOID param)
1241 MSIPACKAGE* package = (MSIPACKAGE*)param;
1242 MSIFEATURE* feature;
1243 static const WCHAR Query1[] =
1244 {'S','E','L','E','C','T',' ',
1245 '`','C','o','m','p','o','n','e','n','t','_','`',
1246 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1247 'C','o','m','p','o','n','e','n','t','s','`',' ',
1248 'W','H','E','R','E',' ',
1249 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1254 /* fill in the data */
1256 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1258 return ERROR_NOT_ENOUGH_MEMORY;
1260 list_init( &feature->Children );
1261 list_init( &feature->Components );
1263 feature->Feature = msi_dup_record_field( row, 1 );
1265 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1267 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1268 feature->Title = msi_dup_record_field( row, 3 );
1269 feature->Description = msi_dup_record_field( row, 4 );
1271 if (!MSI_RecordIsNull(row,5))
1272 feature->Display = MSI_RecordGetInteger(row,5);
1274 feature->Level= MSI_RecordGetInteger(row,6);
1275 feature->Directory = msi_dup_record_field( row, 7 );
1276 feature->Attributes = MSI_RecordGetInteger(row,8);
1278 feature->Installed = INSTALLSTATE_UNKNOWN;
1279 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1281 list_add_tail( &package->features, &feature->entry );
1283 /* load feature components */
1285 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1286 if (rc != ERROR_SUCCESS)
1287 return ERROR_SUCCESS;
1289 ilfs.package = package;
1290 ilfs.feature = feature;
1292 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1293 msiobj_release(&view->hdr);
1295 return ERROR_SUCCESS;
1298 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1300 MSIPACKAGE* package = (MSIPACKAGE*)param;
1301 MSIFEATURE *parent, *child;
1303 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1305 return ERROR_FUNCTION_FAILED;
1307 if (!child->Feature_Parent)
1308 return ERROR_SUCCESS;
1310 parent = find_feature_by_name( package, child->Feature_Parent );
1312 return ERROR_FUNCTION_FAILED;
1314 add_feature_child( parent, child );
1315 return ERROR_SUCCESS;
1318 static UINT load_all_features( MSIPACKAGE *package )
1320 static const WCHAR query[] = {
1321 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1322 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1323 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1327 if (!list_empty(&package->features))
1328 return ERROR_SUCCESS;
1330 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1331 if (r != ERROR_SUCCESS)
1334 r = MSI_IterateRecords( view, NULL, load_feature, package );
1335 if (r != ERROR_SUCCESS)
1338 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1339 msiobj_release( &view->hdr );
1344 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1355 static UINT load_file(MSIRECORD *row, LPVOID param)
1357 MSIPACKAGE* package = (MSIPACKAGE*)param;
1361 /* fill in the data */
1363 file = msi_alloc_zero( sizeof (MSIFILE) );
1365 return ERROR_NOT_ENOUGH_MEMORY;
1367 file->File = msi_dup_record_field( row, 1 );
1369 component = MSI_RecordGetString( row, 2 );
1370 file->Component = get_loaded_component( package, component );
1372 if (!file->Component)
1373 ERR("Unfound Component %s\n",debugstr_w(component));
1375 file->FileName = msi_dup_record_field( row, 3 );
1376 reduce_to_longfilename( file->FileName );
1378 file->ShortName = msi_dup_record_field( row, 3 );
1379 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1381 file->FileSize = MSI_RecordGetInteger( row, 4 );
1382 file->Version = msi_dup_record_field( row, 5 );
1383 file->Language = msi_dup_record_field( row, 6 );
1384 file->Attributes = MSI_RecordGetInteger( row, 7 );
1385 file->Sequence = MSI_RecordGetInteger( row, 8 );
1387 file->state = msifs_invalid;
1389 /* if the compressed bits are not set in the file attributes,
1390 * then read the information from the package word count property
1392 if (file->Attributes & msidbFileAttributesCompressed)
1394 file->IsCompressed = TRUE;
1396 else if (file->Attributes & msidbFileAttributesNoncompressed)
1398 file->IsCompressed = FALSE;
1402 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1405 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1407 list_add_tail( &package->files, &file->entry );
1409 return ERROR_SUCCESS;
1412 static UINT load_all_files(MSIPACKAGE *package)
1416 static const WCHAR Query[] =
1417 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1418 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1419 '`','S','e','q','u','e','n','c','e','`', 0};
1421 if (!list_empty(&package->files))
1422 return ERROR_SUCCESS;
1424 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1425 if (rc != ERROR_SUCCESS)
1426 return ERROR_SUCCESS;
1428 rc = MSI_IterateRecords(view, NULL, load_file, package);
1429 msiobj_release(&view->hdr);
1431 return ERROR_SUCCESS;
1436 * I am not doing any of the costing functionality yet.
1437 * Mostly looking at doing the Component and Feature loading
1439 * The native MSI does A LOT of modification to tables here. Mostly adding
1440 * a lot of temporary columns to the Feature and Component tables.
1442 * note: Native msi also tracks the short filename. But I am only going to
1443 * track the long ones. Also looking at this directory table
1444 * it appears that the directory table does not get the parents
1445 * resolved base on property only based on their entries in the
1448 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1450 static const WCHAR szCosting[] =
1451 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1452 static const WCHAR szZero[] = { '0', 0 };
1454 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1455 return ERROR_SUCCESS;
1457 MSI_SetPropertyW(package, szCosting, szZero);
1458 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1460 load_all_components( package );
1461 load_all_features( package );
1462 load_all_files( package );
1464 return ERROR_SUCCESS;
1467 static UINT execute_script(MSIPACKAGE *package, UINT script )
1470 UINT rc = ERROR_SUCCESS;
1472 TRACE("Executing Script %i\n",script);
1474 if (!package->script)
1476 ERR("no script!\n");
1477 return ERROR_FUNCTION_FAILED;
1480 for (i = 0; i < package->script->ActionCount[script]; i++)
1483 action = package->script->Actions[script][i];
1484 ui_actionstart(package, action);
1485 TRACE("Executing Action (%s)\n",debugstr_w(action));
1486 rc = ACTION_PerformAction(package, action, TRUE);
1487 msi_free(package->script->Actions[script][i]);
1488 if (rc != ERROR_SUCCESS)
1491 msi_free(package->script->Actions[script]);
1493 package->script->ActionCount[script] = 0;
1494 package->script->Actions[script] = NULL;
1498 static UINT ACTION_FileCost(MSIPACKAGE *package)
1500 return ERROR_SUCCESS;
1503 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1505 static const WCHAR Query[] =
1506 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1507 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1508 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1509 ' ','=',' ','\'','%','s','\'',
1511 static const WCHAR szDot[] = { '.',0 };
1512 static WCHAR szEmpty[] = { 0 };
1513 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1518 TRACE("Looking for dir %s\n",debugstr_w(dir));
1520 folder = get_loaded_folder( package, dir );
1524 TRACE("Working to load %s\n",debugstr_w(dir));
1526 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1530 folder->Directory = strdupW(dir);
1532 row = MSI_QueryGetRecord(package->db, Query, dir);
1536 p = msi_dup_record_field(row, 3);
1538 /* split src and target dir */
1540 src_short = folder_split_path( p, ':' );
1542 /* split the long and short paths */
1543 tgt_long = folder_split_path( tgt_short, '|' );
1544 src_long = folder_split_path( src_short, '|' );
1546 /* check for no-op dirs */
1547 if (!lstrcmpW(szDot, tgt_short))
1548 tgt_short = szEmpty;
1549 if (!lstrcmpW(szDot, src_short))
1550 src_short = szEmpty;
1553 tgt_long = tgt_short;
1556 src_short = tgt_short;
1557 src_long = tgt_long;
1561 src_long = src_short;
1563 /* FIXME: use the target short path too */
1564 folder->TargetDefault = strdupW(tgt_long);
1565 folder->SourceShortPath = strdupW(src_short);
1566 folder->SourceLongPath = strdupW(src_long);
1569 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1570 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1571 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1573 parent = MSI_RecordGetString(row, 2);
1576 folder->Parent = load_folder( package, parent );
1577 if ( folder->Parent )
1578 TRACE("loaded parent %p %s\n", folder->Parent,
1579 debugstr_w(folder->Parent->Directory));
1581 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1584 folder->Property = msi_dup_property( package, dir );
1586 msiobj_release(&row->hdr);
1588 list_add_tail( &package->folders, &folder->entry );
1590 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1595 /* scan for and update current install states */
1596 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1599 MSIFEATURE *feature;
1601 /* FIXME: component's installed state should be determined
1602 * by the component's registration
1604 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1608 if (!comp->ComponentId)
1611 res = MsiGetComponentPathW( package->ProductCode,
1612 comp->ComponentId, NULL, NULL);
1614 res = INSTALLSTATE_ABSENT;
1615 comp->Installed = res;
1618 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1621 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1623 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1625 comp= cl->component;
1627 if (!comp->ComponentId)
1629 res = INSTALLSTATE_ABSENT;
1633 if (res == INSTALLSTATE_ABSENT)
1634 res = comp->Installed;
1637 if (res == comp->Installed)
1640 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1641 res != INSTALLSTATE_SOURCE)
1643 res = INSTALLSTATE_INCOMPLETE;
1647 feature->Installed = res;
1651 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1654 static const WCHAR all[]={'A','L','L',0};
1656 MSIFEATURE *feature;
1658 override = msi_dup_property( package, property );
1662 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1664 if (strcmpiW(override,all)==0)
1665 msi_feature_set_state( feature, state );
1668 LPWSTR ptr = override;
1669 LPWSTR ptr2 = strchrW(override,',');
1673 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1674 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1676 msi_feature_set_state( feature, state );
1682 ptr2 = strchrW(ptr,',');
1694 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1697 static const WCHAR szlevel[] =
1698 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1699 static const WCHAR szAddLocal[] =
1700 {'A','D','D','L','O','C','A','L',0};
1701 static const WCHAR szRemove[] =
1702 {'R','E','M','O','V','E',0};
1703 static const WCHAR szReinstall[] =
1704 {'R','E','I','N','S','T','A','L','L',0};
1705 BOOL override = FALSE;
1706 MSICOMPONENT* component;
1707 MSIFEATURE *feature;
1710 /* I do not know if this is where it should happen.. but */
1712 TRACE("Checking Install Level\n");
1714 install_level = msi_get_property_int( package, szlevel, 1 );
1716 /* ok here is the _real_ rub
1717 * all these activation/deactivation things happen in order and things
1718 * later on the list override things earlier on the list.
1719 * 1) INSTALLLEVEL processing
1729 * 11) FILEADDDEFAULT
1730 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1731 * ignored for all the features. seems strange, especially since it is not
1732 * documented anywhere, but it is how it works.
1734 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1735 * REMOVE are the big ones, since we don't handle administrative installs
1738 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1739 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1740 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1744 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1746 BOOL feature_state = ((feature->Level > 0) &&
1747 (feature->Level <= install_level));
1749 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1751 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1752 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1753 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1754 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1756 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1760 /* disable child features of unselected parent features */
1761 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1765 if (feature->Level > 0 && feature->Level <= install_level)
1768 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1769 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1774 /* set the Preselected Property */
1775 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1776 static const WCHAR szOne[] = { '1', 0 };
1778 MSI_SetPropertyW(package,szPreselected,szOne);
1782 * now we want to enable or disable components base on feature
1785 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1789 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1790 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1791 feature->ActionRequest);
1793 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1795 component = cl->component;
1797 switch (component->Attributes)
1799 case msidbComponentAttributesLocalOnly:
1800 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1802 case msidbComponentAttributesSourceOnly:
1803 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1805 case msidbComponentAttributesOptional:
1806 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1809 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1812 if (component->ForceLocalState)
1813 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1815 if (!component->Enabled)
1816 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1817 else if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1819 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1820 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1822 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1824 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1825 (component->Action == INSTALLSTATE_ABSENT) ||
1826 (component->Action == INSTALLSTATE_ADVERTISED) ||
1827 (component->Action == INSTALLSTATE_DEFAULT))
1828 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1830 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1832 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1833 (component->Action == INSTALLSTATE_ABSENT))
1834 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1836 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1838 if (component->Action == INSTALLSTATE_UNKNOWN)
1839 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1841 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1842 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1844 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1845 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1849 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1851 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1852 debugstr_w(component->Component), component->Installed,
1853 component->Action, component->ActionRequest);
1857 return ERROR_SUCCESS;
1860 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1862 MSIPACKAGE *package = (MSIPACKAGE*)param;
1866 name = MSI_RecordGetString(row,1);
1868 /* This helper function now does ALL the work */
1869 TRACE("Dir %s ...\n",debugstr_w(name));
1870 load_folder(package,name);
1871 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1872 TRACE("resolves to %s\n",debugstr_w(path));
1875 return ERROR_SUCCESS;
1878 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1880 MSIPACKAGE *package = (MSIPACKAGE*)param;
1882 MSIFEATURE *feature;
1884 name = MSI_RecordGetString( row, 1 );
1886 feature = get_loaded_feature( package, name );
1888 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1892 Condition = MSI_RecordGetString(row,3);
1894 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1896 int level = MSI_RecordGetInteger(row,2);
1897 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1898 feature->Level = level;
1901 return ERROR_SUCCESS;
1904 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1906 static const WCHAR name_fmt[] =
1907 {'%','u','.','%','u','.','%','u','.','%','u',0};
1908 static WCHAR name[] = {'\\',0};
1909 VS_FIXEDFILEINFO *lpVer;
1910 WCHAR filever[0x100];
1916 TRACE("%s\n", debugstr_w(filename));
1918 versize = GetFileVersionInfoSizeW( filename, &handle );
1922 version = msi_alloc( versize );
1923 GetFileVersionInfoW( filename, 0, versize, version );
1925 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1926 msi_free( version );
1928 sprintfW( filever, name_fmt,
1929 HIWORD(lpVer->dwFileVersionMS),
1930 LOWORD(lpVer->dwFileVersionMS),
1931 HIWORD(lpVer->dwFileVersionLS),
1932 LOWORD(lpVer->dwFileVersionLS));
1934 return strdupW( filever );
1938 * A lot is done in this function aside from just the costing.
1939 * The costing needs to be implemented at some point but for now I am going
1940 * to focus on the directory building
1943 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1945 static const WCHAR ExecSeqQuery[] =
1946 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1947 '`','D','i','r','e','c','t','o','r','y','`',0};
1948 static const WCHAR ConditionQuery[] =
1949 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1950 '`','C','o','n','d','i','t','i','o','n','`',0};
1951 static const WCHAR szCosting[] =
1952 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1953 static const WCHAR szlevel[] =
1954 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1955 static const WCHAR szOne[] = { '1', 0 };
1960 LPWSTR level, file_version;
1962 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1963 return ERROR_SUCCESS;
1965 TRACE("Building Directory properties\n");
1967 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1968 if (rc == ERROR_SUCCESS)
1970 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1972 msiobj_release(&view->hdr);
1975 TRACE("File calculations\n");
1977 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1979 MSICOMPONENT* comp = file->Component;
1985 if (file->IsCompressed)
1986 comp->ForceLocalState = TRUE;
1988 /* calculate target */
1989 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1991 msi_free(file->TargetPath);
1993 TRACE("file %s is named %s\n",
1994 debugstr_w(file->File), debugstr_w(file->FileName));
1996 file->TargetPath = build_directory_name(2, p, file->FileName);
2000 TRACE("file %s resolves to %s\n",
2001 debugstr_w(file->File), debugstr_w(file->TargetPath));
2003 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2005 file->state = msifs_missing;
2006 comp->Cost += file->FileSize;
2010 if (file->Version &&
2011 (file_version = msi_get_disk_file_version( file->TargetPath )))
2013 TRACE("new %s old %s\n", debugstr_w(file->Version),
2014 debugstr_w(file_version));
2015 /* FIXME: seems like a bad way to compare version numbers */
2016 if (lstrcmpiW(file_version, file->Version)<0)
2018 file->state = msifs_overwrite;
2019 comp->Cost += file->FileSize;
2022 file->state = msifs_present;
2023 msi_free( file_version );
2026 file->state = msifs_present;
2029 TRACE("Evaluating Condition Table\n");
2031 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2032 if (rc == ERROR_SUCCESS)
2034 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2036 msiobj_release(&view->hdr);
2039 TRACE("Enabling or Disabling Components\n");
2040 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2042 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2044 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2045 comp->Enabled = FALSE;
2049 MSI_SetPropertyW(package,szCosting,szOne);
2050 /* set default run level if not set */
2051 level = msi_dup_property( package, szlevel );
2053 MSI_SetPropertyW(package,szlevel, szOne);
2056 ACTION_UpdateInstallStates(package);
2058 return MSI_SetFeatureStates(package);
2061 /* OK this value is "interpreted" and then formatted based on the
2062 first few characters */
2063 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2067 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2073 LPWSTR deformated = NULL;
2076 deformat_string(package, &value[2], &deformated);
2078 /* binary value type */
2082 *size = (strlenW(ptr)/2)+1;
2084 *size = strlenW(ptr)/2;
2086 data = msi_alloc(*size);
2092 /* if uneven pad with a zero in front */
2098 data[count] = (BYTE)strtol(byte,NULL,0);
2100 TRACE("Uneven byte count\n");
2108 data[count] = (BYTE)strtol(byte,NULL,0);
2111 msi_free(deformated);
2113 TRACE("Data %i bytes(%i)\n",*size,count);
2120 deformat_string(package, &value[1], &deformated);
2123 *size = sizeof(DWORD);
2124 data = msi_alloc(*size);
2130 if ( (*p < '0') || (*p > '9') )
2136 if (deformated[0] == '-')
2139 TRACE("DWORD %i\n",*(LPDWORD)data);
2141 msi_free(deformated);
2146 static const WCHAR szMulti[] = {'[','~',']',0};
2155 *type=REG_EXPAND_SZ;
2163 if (strstrW(value,szMulti))
2164 *type = REG_MULTI_SZ;
2166 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2171 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2173 MSIPACKAGE *package = (MSIPACKAGE*)param;
2174 static const WCHAR szHCR[] =
2175 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2176 'R','O','O','T','\\',0};
2177 static const WCHAR szHCU[] =
2178 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2179 'U','S','E','R','\\',0};
2180 static const WCHAR szHLM[] =
2181 {'H','K','E','Y','_','L','O','C','A','L','_',
2182 'M','A','C','H','I','N','E','\\',0};
2183 static const WCHAR szHU[] =
2184 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2186 LPSTR value_data = NULL;
2187 HKEY root_key, hkey;
2190 LPCWSTR szRoot, component, name, key, value;
2195 BOOL check_first = FALSE;
2198 ui_progress(package,2,0,0,0);
2205 component = MSI_RecordGetString(row, 6);
2206 comp = get_loaded_component(package,component);
2208 return ERROR_SUCCESS;
2210 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2212 TRACE("Skipping write due to disabled component %s\n",
2213 debugstr_w(component));
2215 comp->Action = comp->Installed;
2217 return ERROR_SUCCESS;
2220 comp->Action = INSTALLSTATE_LOCAL;
2222 name = MSI_RecordGetString(row, 4);
2223 if( MSI_RecordIsNull(row,5) && name )
2225 /* null values can have special meanings */
2226 if (name[0]=='-' && name[1] == 0)
2227 return ERROR_SUCCESS;
2228 else if ((name[0]=='+' && name[1] == 0) ||
2229 (name[0] == '*' && name[1] == 0))
2234 root = MSI_RecordGetInteger(row,2);
2235 key = MSI_RecordGetString(row, 3);
2237 /* get the root key */
2242 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2243 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2244 if (all_users && all_users[0] == '1')
2246 root_key = HKEY_LOCAL_MACHINE;
2251 root_key = HKEY_CURRENT_USER;
2254 msi_free(all_users);
2257 case 0: root_key = HKEY_CLASSES_ROOT;
2260 case 1: root_key = HKEY_CURRENT_USER;
2263 case 2: root_key = HKEY_LOCAL_MACHINE;
2266 case 3: root_key = HKEY_USERS;
2270 ERR("Unknown root %i\n",root);
2276 return ERROR_SUCCESS;
2278 deformat_string(package, key , &deformated);
2279 size = strlenW(deformated) + strlenW(szRoot) + 1;
2280 uikey = msi_alloc(size*sizeof(WCHAR));
2281 strcpyW(uikey,szRoot);
2282 strcatW(uikey,deformated);
2284 if (RegCreateKeyW( root_key, deformated, &hkey))
2286 ERR("Could not create key %s\n",debugstr_w(deformated));
2287 msi_free(deformated);
2289 return ERROR_SUCCESS;
2291 msi_free(deformated);
2293 value = MSI_RecordGetString(row,5);
2295 value_data = parse_value(package, value, &type, &size);
2298 static const WCHAR szEmpty[] = {0};
2299 value_data = (LPSTR)strdupW(szEmpty);
2304 deformat_string(package, name, &deformated);
2306 /* get the double nulls to terminate SZ_MULTI */
2307 if (type == REG_MULTI_SZ)
2308 size +=sizeof(WCHAR);
2312 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2314 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2319 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2320 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2322 TRACE("value %s of %s checked already exists\n",
2323 debugstr_w(deformated), debugstr_w(uikey));
2327 TRACE("Checked and setting value %s of %s\n",
2328 debugstr_w(deformated), debugstr_w(uikey));
2329 if (deformated || size)
2330 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2335 uirow = MSI_CreateRecord(3);
2336 MSI_RecordSetStringW(uirow,2,deformated);
2337 MSI_RecordSetStringW(uirow,1,uikey);
2340 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2342 MSI_RecordSetStringW(uirow,3,value);
2344 ui_actiondata(package,szWriteRegistryValues,uirow);
2345 msiobj_release( &uirow->hdr );
2347 msi_free(value_data);
2348 msi_free(deformated);
2351 return ERROR_SUCCESS;
2354 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2358 static const WCHAR ExecSeqQuery[] =
2359 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2360 '`','R','e','g','i','s','t','r','y','`',0 };
2362 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2363 if (rc != ERROR_SUCCESS)
2364 return ERROR_SUCCESS;
2366 /* increment progress bar each time action data is sent */
2367 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2369 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2371 msiobj_release(&view->hdr);
2375 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2377 package->script->CurrentlyScripting = TRUE;
2379 return ERROR_SUCCESS;
2383 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2388 static const WCHAR q1[]=
2389 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2390 '`','R','e','g','i','s','t','r','y','`',0};
2393 MSIFEATURE *feature;
2396 TRACE("InstallValidate\n");
2398 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2399 if (rc == ERROR_SUCCESS)
2401 MSI_IterateRecords( view, &progress, NULL, package );
2402 msiobj_release( &view->hdr );
2403 total += progress * REG_PROGRESS_VALUE;
2406 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2407 total += COMPONENT_PROGRESS_VALUE;
2409 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2410 total += file->FileSize;
2412 ui_progress(package,0,total,0,0);
2414 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2416 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2417 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2418 feature->ActionRequest);
2421 return ERROR_SUCCESS;
2424 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2426 MSIPACKAGE* package = (MSIPACKAGE*)param;
2427 LPCWSTR cond = NULL;
2428 LPCWSTR message = NULL;
2429 static const WCHAR title[]=
2430 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2432 cond = MSI_RecordGetString(row,1);
2434 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2437 message = MSI_RecordGetString(row,2);
2438 deformat_string(package,message,&deformated);
2439 MessageBoxW(NULL,deformated,title,MB_OK);
2440 msi_free(deformated);
2441 return ERROR_FUNCTION_FAILED;
2444 return ERROR_SUCCESS;
2447 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2450 MSIQUERY * view = NULL;
2451 static const WCHAR ExecSeqQuery[] =
2452 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2453 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2455 TRACE("Checking launch conditions\n");
2457 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2458 if (rc != ERROR_SUCCESS)
2459 return ERROR_SUCCESS;
2461 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2462 msiobj_release(&view->hdr);
2467 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2471 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2473 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2475 MSIRECORD * row = 0;
2477 LPWSTR deformated,buffer,deformated_name;
2479 static const WCHAR ExecSeqQuery[] =
2480 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2481 '`','R','e','g','i','s','t','r','y','`',' ',
2482 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2483 ' ','=',' ' ,'\'','%','s','\'',0 };
2484 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2485 static const WCHAR fmt2[]=
2486 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2488 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2492 root = MSI_RecordGetInteger(row,2);
2493 key = MSI_RecordGetString(row, 3);
2494 name = MSI_RecordGetString(row, 4);
2495 deformat_string(package, key , &deformated);
2496 deformat_string(package, name, &deformated_name);
2498 len = strlenW(deformated) + 6;
2499 if (deformated_name)
2500 len+=strlenW(deformated_name);
2502 buffer = msi_alloc( len *sizeof(WCHAR));
2504 if (deformated_name)
2505 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2507 sprintfW(buffer,fmt,root,deformated);
2509 msi_free(deformated);
2510 msi_free(deformated_name);
2511 msiobj_release(&row->hdr);
2515 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2517 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2522 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2525 return strdupW( file->TargetPath );
2530 static HKEY openSharedDLLsKey(void)
2533 static const WCHAR path[] =
2534 {'S','o','f','t','w','a','r','e','\\',
2535 'M','i','c','r','o','s','o','f','t','\\',
2536 'W','i','n','d','o','w','s','\\',
2537 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2538 'S','h','a','r','e','d','D','L','L','s',0};
2540 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2544 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2549 DWORD sz = sizeof(count);
2552 hkey = openSharedDLLsKey();
2553 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2554 if (rc != ERROR_SUCCESS)
2560 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2564 hkey = openSharedDLLsKey();
2566 msi_reg_set_val_dword( hkey, path, count );
2568 RegDeleteValueW(hkey,path);
2574 * Return TRUE if the count should be written out and FALSE if not
2576 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2578 MSIFEATURE *feature;
2582 /* only refcount DLLs */
2583 if (comp->KeyPath == NULL ||
2584 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2585 comp->Attributes & msidbComponentAttributesODBCDataSource)
2589 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2590 write = (count > 0);
2592 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2596 /* increment counts */
2597 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2601 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2604 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2606 if ( cl->component == comp )
2611 /* decrement counts */
2612 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2616 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2619 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2621 if ( cl->component == comp )
2626 /* ref count all the files in the component */
2631 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2633 if (file->Component == comp)
2634 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2638 /* add a count for permenent */
2639 if (comp->Attributes & msidbComponentAttributesPermanent)
2642 comp->RefCount = count;
2645 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2649 * Ok further analysis makes me think that this work is
2650 * actually done in the PublishComponents and PublishFeatures
2651 * step, and not here. It appears like the keypath and all that is
2652 * resolved in this step, however actually written in the Publish steps.
2653 * But we will leave it here for now because it is unclear
2655 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2657 WCHAR squished_pc[GUID_SIZE];
2658 WCHAR squished_cc[GUID_SIZE];
2661 HKEY hkey=0,hkey2=0;
2663 /* writes the Component and Features values to the registry */
2665 rc = MSIREG_OpenComponents(&hkey);
2666 if (rc != ERROR_SUCCESS)
2669 squash_guid(package->ProductCode,squished_pc);
2670 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2672 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2676 ui_progress(package,2,0,0,0);
2677 if (!comp->ComponentId)
2680 squash_guid(comp->ComponentId,squished_cc);
2682 msi_free(comp->FullKeypath);
2683 comp->FullKeypath = resolve_keypath( package, comp );
2685 /* do the refcounting */
2686 ACTION_RefCountComponent( package, comp );
2688 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2689 debugstr_w(comp->Component),
2690 debugstr_w(squished_cc),
2691 debugstr_w(comp->FullKeypath),
2694 * Write the keypath out if the component is to be registered
2695 * and delete the key if the component is to be deregistered
2697 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2699 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2700 if (rc != ERROR_SUCCESS)
2703 if (!comp->FullKeypath)
2706 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2708 if (comp->Attributes & msidbComponentAttributesPermanent)
2710 static const WCHAR szPermKey[] =
2711 { '0','0','0','0','0','0','0','0','0','0','0','0',
2712 '0','0','0','0','0','0','0','0','0','0','0','0',
2713 '0','0','0','0','0','0','0','0',0 };
2715 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2721 uirow = MSI_CreateRecord(3);
2722 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2723 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2724 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2725 ui_actiondata(package,szProcessComponents,uirow);
2726 msiobj_release( &uirow->hdr );
2728 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2732 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2733 if (rc != ERROR_SUCCESS)
2736 RegDeleteValueW(hkey2,squished_pc);
2738 /* if the key is empty delete it */
2739 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2741 if (res == ERROR_NO_MORE_ITEMS)
2742 RegDeleteKeyW(hkey,squished_cc);
2745 uirow = MSI_CreateRecord(2);
2746 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2747 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2748 ui_actiondata(package,szProcessComponents,uirow);
2749 msiobj_release( &uirow->hdr );
2764 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2765 LPWSTR lpszName, LONG_PTR lParam)
2768 typelib_struct *tl_struct = (typelib_struct*) lParam;
2769 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2773 if (!IS_INTRESOURCE(lpszName))
2775 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2779 sz = strlenW(tl_struct->source)+4;
2780 sz *= sizeof(WCHAR);
2782 if ((INT_PTR)lpszName == 1)
2783 tl_struct->path = strdupW(tl_struct->source);
2786 tl_struct->path = msi_alloc(sz);
2787 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2790 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2791 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2792 if (!SUCCEEDED(res))
2794 msi_free(tl_struct->path);
2795 tl_struct->path = NULL;
2800 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2801 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2803 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2807 msi_free(tl_struct->path);
2808 tl_struct->path = NULL;
2810 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2811 ITypeLib_Release(tl_struct->ptLib);
2816 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2818 MSIPACKAGE* package = (MSIPACKAGE*)param;
2822 typelib_struct tl_struct;
2824 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2826 component = MSI_RecordGetString(row,3);
2827 comp = get_loaded_component(package,component);
2829 return ERROR_SUCCESS;
2831 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2833 TRACE("Skipping typelib reg due to disabled component\n");
2835 comp->Action = comp->Installed;
2837 return ERROR_SUCCESS;
2840 comp->Action = INSTALLSTATE_LOCAL;
2842 file = get_loaded_file( package, comp->KeyPath );
2844 return ERROR_SUCCESS;
2846 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2850 guid = MSI_RecordGetString(row,1);
2851 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2852 tl_struct.source = strdupW( file->TargetPath );
2853 tl_struct.path = NULL;
2855 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2856 (LONG_PTR)&tl_struct);
2864 helpid = MSI_RecordGetString(row,6);
2867 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2868 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2871 if (!SUCCEEDED(res))
2872 ERR("Failed to register type library %s\n",
2873 debugstr_w(tl_struct.path));
2876 ui_actiondata(package,szRegisterTypeLibraries,row);
2878 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2881 ITypeLib_Release(tl_struct.ptLib);
2882 msi_free(tl_struct.path);
2885 ERR("Failed to load type library %s\n",
2886 debugstr_w(tl_struct.source));
2888 FreeLibrary(module);
2889 msi_free(tl_struct.source);
2892 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2894 return ERROR_SUCCESS;
2897 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2900 * OK this is a bit confusing.. I am given a _Component key and I believe
2901 * that the file that is being registered as a type library is the "key file
2902 * of that component" which I interpret to mean "The file in the KeyPath of
2907 static const WCHAR Query[] =
2908 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2909 '`','T','y','p','e','L','i','b','`',0};
2911 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2912 if (rc != ERROR_SUCCESS)
2913 return ERROR_SUCCESS;
2915 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2916 msiobj_release(&view->hdr);
2920 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2922 MSIPACKAGE *package = (MSIPACKAGE*)param;
2923 LPWSTR target_file, target_folder, filename;
2924 LPCWSTR buffer, extension;
2926 static const WCHAR szlnk[]={'.','l','n','k',0};
2927 IShellLinkW *sl = NULL;
2928 IPersistFile *pf = NULL;
2931 buffer = MSI_RecordGetString(row,4);
2932 comp = get_loaded_component(package,buffer);
2934 return ERROR_SUCCESS;
2936 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2938 TRACE("Skipping shortcut creation due to disabled component\n");
2940 comp->Action = comp->Installed;
2942 return ERROR_SUCCESS;
2945 comp->Action = INSTALLSTATE_LOCAL;
2947 ui_actiondata(package,szCreateShortcuts,row);
2949 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2950 &IID_IShellLinkW, (LPVOID *) &sl );
2954 ERR("CLSID_ShellLink not available\n");
2958 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2961 ERR("QueryInterface(IID_IPersistFile) failed\n");
2965 buffer = MSI_RecordGetString(row,2);
2966 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2968 /* may be needed because of a bug somehwere else */
2969 create_full_pathW(target_folder);
2971 filename = msi_dup_record_field( row, 3 );
2972 reduce_to_longfilename(filename);
2974 extension = strchrW(filename,'.');
2975 if (!extension || strcmpiW(extension,szlnk))
2977 int len = strlenW(filename);
2978 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2979 memcpy(filename + len, szlnk, sizeof(szlnk));
2981 target_file = build_directory_name(2, target_folder, filename);
2982 msi_free(target_folder);
2985 buffer = MSI_RecordGetString(row,5);
2986 if (strchrW(buffer,'['))
2989 deformat_string(package,buffer,&deformated);
2990 IShellLinkW_SetPath(sl,deformated);
2991 msi_free(deformated);
2995 FIXME("poorly handled shortcut format, advertised shortcut\n");
2996 IShellLinkW_SetPath(sl,comp->FullKeypath);
2999 if (!MSI_RecordIsNull(row,6))
3002 buffer = MSI_RecordGetString(row,6);
3003 deformat_string(package,buffer,&deformated);
3004 IShellLinkW_SetArguments(sl,deformated);
3005 msi_free(deformated);
3008 if (!MSI_RecordIsNull(row,7))
3010 buffer = MSI_RecordGetString(row,7);
3011 IShellLinkW_SetDescription(sl,buffer);
3014 if (!MSI_RecordIsNull(row,8))
3015 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3017 if (!MSI_RecordIsNull(row,9))
3022 buffer = MSI_RecordGetString(row,9);
3024 Path = build_icon_path(package,buffer);
3025 index = MSI_RecordGetInteger(row,10);
3027 /* no value means 0 */
3028 if (index == MSI_NULL_INTEGER)
3031 IShellLinkW_SetIconLocation(sl,Path,index);
3035 if (!MSI_RecordIsNull(row,11))
3036 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3038 if (!MSI_RecordIsNull(row,12))
3041 buffer = MSI_RecordGetString(row,12);
3042 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3044 IShellLinkW_SetWorkingDirectory(sl,Path);
3048 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3049 IPersistFile_Save(pf,target_file,FALSE);
3051 msi_free(target_file);
3055 IPersistFile_Release( pf );
3057 IShellLinkW_Release( sl );
3059 return ERROR_SUCCESS;
3062 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3067 static const WCHAR Query[] =
3068 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3069 '`','S','h','o','r','t','c','u','t','`',0};
3071 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3072 if (rc != ERROR_SUCCESS)
3073 return ERROR_SUCCESS;
3075 res = CoInitialize( NULL );
3078 ERR("CoInitialize failed\n");
3079 return ERROR_FUNCTION_FAILED;
3082 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3083 msiobj_release(&view->hdr);
3090 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3092 MSIPACKAGE* package = (MSIPACKAGE*)param;
3101 FileName = MSI_RecordGetString(row,1);
3104 ERR("Unable to get FileName\n");
3105 return ERROR_SUCCESS;
3108 FilePath = build_icon_path(package,FileName);
3110 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3112 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3113 FILE_ATTRIBUTE_NORMAL, NULL);
3115 if (the_file == INVALID_HANDLE_VALUE)
3117 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3119 return ERROR_SUCCESS;
3126 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3127 if (rc != ERROR_SUCCESS)
3129 ERR("Failed to get stream\n");
3130 CloseHandle(the_file);
3131 DeleteFileW(FilePath);
3134 WriteFile(the_file,buffer,sz,&write,NULL);
3135 } while (sz == 1024);
3139 CloseHandle(the_file);
3141 uirow = MSI_CreateRecord(1);
3142 MSI_RecordSetStringW(uirow,1,FileName);
3143 ui_actiondata(package,szPublishProduct,uirow);
3144 msiobj_release( &uirow->hdr );
3146 return ERROR_SUCCESS;
3150 * 99% of the work done here is only done for
3151 * advertised installs. However this is where the
3152 * Icon table is processed and written out
3153 * so that is what I am going to do here.
3155 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3159 static const WCHAR Query[]=
3160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3161 '`','I','c','o','n','`',0};
3162 /* for registry stuff */
3165 static const WCHAR szProductLanguage[] =
3166 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3167 static const WCHAR szARPProductIcon[] =
3168 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3169 static const WCHAR szProductVersion[] =
3170 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3174 MSIHANDLE hDb, hSumInfo;
3176 /* write out icon files */
3178 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3179 if (rc == ERROR_SUCCESS)
3181 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3182 msiobj_release(&view->hdr);
3185 /* ok there is a lot more done here but i need to figure out what */
3187 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3188 if (rc != ERROR_SUCCESS)
3191 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3192 if (rc != ERROR_SUCCESS)
3196 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3197 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3200 langid = msi_get_property_int( package, szProductLanguage, 0 );
3201 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3203 buffer = msi_dup_property( package, szARPProductIcon );
3206 LPWSTR path = build_icon_path(package,buffer);
3207 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3212 buffer = msi_dup_property( package, szProductVersion );
3215 DWORD verdword = msi_version_str_to_dword(buffer);
3216 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3220 /* FIXME: Need to write more keys to the user registry */
3222 hDb= alloc_msihandle( &package->db->hdr );
3224 rc = ERROR_NOT_ENOUGH_MEMORY;
3227 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3228 MsiCloseHandle(hDb);
3229 if (rc == ERROR_SUCCESS)
3231 WCHAR guidbuffer[0x200];
3233 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3235 if (rc == ERROR_SUCCESS)
3237 WCHAR squashed[GUID_SIZE];
3238 /* for now we only care about the first guid */
3239 LPWSTR ptr = strchrW(guidbuffer,';');
3241 squash_guid(guidbuffer,squashed);
3242 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3246 ERR("Unable to query Revision_Number...\n");
3249 MsiCloseHandle(hSumInfo);
3253 ERR("Unable to open Summary Information\n");
3265 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3267 MSIPACKAGE *package = (MSIPACKAGE*)param;
3268 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3269 LPWSTR deformated_section, deformated_key, deformated_value;
3270 LPWSTR folder, fullname = NULL;
3274 static const WCHAR szWindowsFolder[] =
3275 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3277 component = MSI_RecordGetString(row, 8);
3278 comp = get_loaded_component(package,component);
3280 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3282 TRACE("Skipping ini file due to disabled component %s\n",
3283 debugstr_w(component));
3285 comp->Action = comp->Installed;
3287 return ERROR_SUCCESS;
3290 comp->Action = INSTALLSTATE_LOCAL;
3292 identifier = MSI_RecordGetString(row,1);
3293 filename = MSI_RecordGetString(row,2);
3294 dirproperty = MSI_RecordGetString(row,3);
3295 section = MSI_RecordGetString(row,4);
3296 key = MSI_RecordGetString(row,5);
3297 value = MSI_RecordGetString(row,6);
3298 action = MSI_RecordGetInteger(row,7);
3300 deformat_string(package,section,&deformated_section);
3301 deformat_string(package,key,&deformated_key);
3302 deformat_string(package,value,&deformated_value);
3306 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3308 folder = msi_dup_property( package, dirproperty );
3311 folder = msi_dup_property( package, szWindowsFolder );
3315 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3319 fullname = build_directory_name(2, folder, filename);
3323 TRACE("Adding value %s to section %s in %s\n",
3324 debugstr_w(deformated_key), debugstr_w(deformated_section),
3325 debugstr_w(fullname));
3326 WritePrivateProfileStringW(deformated_section, deformated_key,
3327 deformated_value, fullname);
3329 else if (action == 1)
3332 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3333 returned, 10, fullname);
3334 if (returned[0] == 0)
3336 TRACE("Adding value %s to section %s in %s\n",
3337 debugstr_w(deformated_key), debugstr_w(deformated_section),
3338 debugstr_w(fullname));
3340 WritePrivateProfileStringW(deformated_section, deformated_key,
3341 deformated_value, fullname);
3344 else if (action == 3)
3345 FIXME("Append to existing section not yet implemented\n");
3347 uirow = MSI_CreateRecord(4);
3348 MSI_RecordSetStringW(uirow,1,identifier);
3349 MSI_RecordSetStringW(uirow,2,deformated_section);
3350 MSI_RecordSetStringW(uirow,3,deformated_key);
3351 MSI_RecordSetStringW(uirow,4,deformated_value);
3352 ui_actiondata(package,szWriteIniValues,uirow);
3353 msiobj_release( &uirow->hdr );
3357 msi_free(deformated_key);
3358 msi_free(deformated_value);
3359 msi_free(deformated_section);
3360 return ERROR_SUCCESS;
3363 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3367 static const WCHAR ExecSeqQuery[] =
3368 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3369 '`','I','n','i','F','i','l','e','`',0};
3371 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3372 if (rc != ERROR_SUCCESS)
3374 TRACE("no IniFile table\n");
3375 return ERROR_SUCCESS;
3378 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3379 msiobj_release(&view->hdr);
3383 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3385 MSIPACKAGE *package = (MSIPACKAGE*)param;
3390 static const WCHAR ExeStr[] =
3391 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3392 static const WCHAR close[] = {'\"',0};
3394 PROCESS_INFORMATION info;
3399 memset(&si,0,sizeof(STARTUPINFOW));
3401 filename = MSI_RecordGetString(row,1);
3402 file = get_loaded_file( package, filename );
3406 ERR("Unable to find file id %s\n",debugstr_w(filename));
3407 return ERROR_SUCCESS;
3410 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3412 FullName = msi_alloc(len*sizeof(WCHAR));
3413 strcpyW(FullName,ExeStr);
3414 strcatW( FullName, file->TargetPath );
3415 strcatW(FullName,close);
3417 TRACE("Registering %s\n",debugstr_w(FullName));
3418 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3422 msi_dialog_check_messages(info.hProcess);
3427 uirow = MSI_CreateRecord( 2 );
3428 uipath = strdupW( file->TargetPath );
3429 p = strrchrW(uipath,'\\');
3432 MSI_RecordSetStringW( uirow, 1, &p[2] );
3433 MSI_RecordSetStringW( uirow, 2, uipath);
3434 ui_actiondata( package, szSelfRegModules, uirow);
3435 msiobj_release( &uirow->hdr );
3437 /* FIXME: call ui_progress? */
3439 return ERROR_SUCCESS;
3442 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3446 static const WCHAR ExecSeqQuery[] =
3447 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3448 '`','S','e','l','f','R','e','g','`',0};
3450 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3451 if (rc != ERROR_SUCCESS)
3453 TRACE("no SelfReg table\n");
3454 return ERROR_SUCCESS;
3457 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3458 msiobj_release(&view->hdr);
3460 return ERROR_SUCCESS;
3463 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3465 MSIFEATURE *feature;
3470 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3471 if (rc != ERROR_SUCCESS)
3474 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3475 if (rc != ERROR_SUCCESS)
3478 /* here the guids are base 85 encoded */
3479 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3485 BOOL absent = FALSE;
3488 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3489 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3490 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3494 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3498 if (feature->Feature_Parent)
3499 size += strlenW( feature->Feature_Parent )+2;
3501 data = msi_alloc(size * sizeof(WCHAR));
3504 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3506 MSICOMPONENT* component = cl->component;
3510 if (component->ComponentId)
3512 TRACE("From %s\n",debugstr_w(component->ComponentId));
3513 CLSIDFromString(component->ComponentId, &clsid);
3514 encode_base85_guid(&clsid,buf);
3515 TRACE("to %s\n",debugstr_w(buf));
3519 if (feature->Feature_Parent)
3521 static const WCHAR sep[] = {'\2',0};
3523 strcatW(data,feature->Feature_Parent);
3526 msi_reg_set_val_str( hkey, feature->Feature, data );
3530 if (feature->Feature_Parent)
3531 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3534 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3535 (LPBYTE)feature->Feature_Parent,size);
3539 size += 2*sizeof(WCHAR);
3540 data = msi_alloc(size);
3543 if (feature->Feature_Parent)
3544 strcpyW( &data[1], feature->Feature_Parent );
3545 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3551 uirow = MSI_CreateRecord( 1 );
3552 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3553 ui_actiondata( package, szPublishFeatures, uirow);
3554 msiobj_release( &uirow->hdr );
3555 /* FIXME: call ui_progress? */
3564 static UINT msi_get_local_package_name( LPWSTR path )
3566 static const WCHAR szInstaller[] = {
3567 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3568 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3572 time = GetTickCount();
3573 GetWindowsDirectoryW( path, MAX_PATH );
3574 lstrcatW( path, szInstaller );
3575 CreateDirectoryW( path, NULL );
3577 len = lstrlenW(path);
3578 for (i=0; i<0x10000; i++)
3580 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3581 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3582 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3583 if (handle != INVALID_HANDLE_VALUE)
3585 CloseHandle(handle);
3588 if (GetLastError() != ERROR_FILE_EXISTS &&
3589 GetLastError() != ERROR_SHARING_VIOLATION)
3590 return ERROR_FUNCTION_FAILED;
3593 return ERROR_SUCCESS;
3596 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3598 static const WCHAR szOriginalDatabase[] =
3599 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3600 WCHAR packagefile[MAX_PATH];
3604 r = msi_get_local_package_name( packagefile );
3605 if (r != ERROR_SUCCESS)
3608 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3610 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3611 r = CopyFileW( msiFilePath, packagefile, FALSE);
3612 msi_free( msiFilePath );
3616 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3617 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3618 return ERROR_FUNCTION_FAILED;
3621 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3622 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3623 return ERROR_SUCCESS;
3626 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3628 LPWSTR prop, val, key;
3629 static const LPCSTR propval[] = {
3630 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3631 "ARPCONTACT", "Contact",
3632 "ARPCOMMENTS", "Comments",
3633 "ProductName", "DisplayName",
3634 "ProductVersion", "DisplayVersion",
3635 "ARPHELPLINK", "HelpLink",
3636 "ARPHELPTELEPHONE", "HelpTelephone",
3637 "ARPINSTALLLOCATION", "InstallLocation",
3638 "SourceDir", "InstallSource",
3639 "Manufacturer", "Publisher",
3640 "ARPREADME", "Readme",
3642 "ARPURLINFOABOUT", "URLInfoAbout",
3643 "ARPURLUPDATEINFO", "URLUpdateInfo",
3646 const LPCSTR *p = propval;
3650 prop = strdupAtoW( *p++ );
3651 key = strdupAtoW( *p++ );
3652 val = msi_dup_property( package, prop );
3653 msi_reg_set_val_str( hkey, key, val );
3658 return ERROR_SUCCESS;
3661 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3664 LPWSTR buffer = NULL;
3667 static const WCHAR szWindowsInstaller[] =
3668 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3669 static const WCHAR szUpgradeCode[] =
3670 {'U','p','g','r','a','d','e','C','o','d','e',0};
3671 static const WCHAR modpath_fmt[] =
3672 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3673 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3674 static const WCHAR szModifyPath[] =
3675 {'M','o','d','i','f','y','P','a','t','h',0};
3676 static const WCHAR szUninstallString[] =
3677 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3678 static const WCHAR szEstimatedSize[] =
3679 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3680 static const WCHAR szProductLanguage[] =
3681 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3682 static const WCHAR szProductVersion[] =
3683 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3686 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3687 LPWSTR upgrade_code;
3690 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3691 if (rc != ERROR_SUCCESS)
3694 /* dump all the info i can grab */
3695 /* FIXME: Flesh out more information */
3697 msi_write_uninstall_property_vals( package, hkey );
3699 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3701 msi_make_package_local( package, hkey );
3703 /* do ModifyPath and UninstallString */
3704 size = deformat_string(package,modpath_fmt,&buffer);
3705 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3706 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3709 /* FIXME: Write real Estimated Size when we have it */
3710 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3712 GetLocalTime(&systime);
3713 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3714 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3716 langid = msi_get_property_int( package, szProductLanguage, 0 );
3717 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3719 buffer = msi_dup_property( package, szProductVersion );
3722 DWORD verdword = msi_version_str_to_dword(buffer);
3724 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3725 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3726 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3730 /* Handle Upgrade Codes */
3731 upgrade_code = msi_dup_property( package, szUpgradeCode );
3736 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3737 squash_guid(package->ProductCode,squashed);
3738 msi_reg_set_val_str( hkey2, squashed, NULL );
3740 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3741 squash_guid(package->ProductCode,squashed);
3742 msi_reg_set_val_str( hkey2, squashed, NULL );
3745 msi_free(upgrade_code);
3750 /* FIXME: call ui_actiondata */
3752 return ERROR_SUCCESS;
3755 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3757 return execute_script(package,INSTALL_SCRIPT);
3760 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3764 /* turn off scheduleing */
3765 package->script->CurrentlyScripting= FALSE;
3767 /* first do the same as an InstallExecute */
3768 rc = ACTION_InstallExecute(package);
3769 if (rc != ERROR_SUCCESS)
3772 /* then handle Commit Actions */
3773 rc = execute_script(package,COMMIT_SCRIPT);
3778 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3780 static const WCHAR RunOnce[] = {
3781 'S','o','f','t','w','a','r','e','\\',
3782 'M','i','c','r','o','s','o','f','t','\\',
3783 'W','i','n','d','o','w','s','\\',
3784 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3785 'R','u','n','O','n','c','e',0};
3786 static const WCHAR InstallRunOnce[] = {
3787 'S','o','f','t','w','a','r','e','\\',
3788 'M','i','c','r','o','s','o','f','t','\\',
3789 'W','i','n','d','o','w','s','\\',
3790 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3791 'I','n','s','t','a','l','l','e','r','\\',
3792 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3794 static const WCHAR msiexec_fmt[] = {
3796 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3797 '\"','%','s','\"',0};
3798 static const WCHAR install_fmt[] = {
3799 '/','I',' ','\"','%','s','\"',' ',
3800 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3801 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3802 WCHAR buffer[256], sysdir[MAX_PATH];
3804 WCHAR squished_pc[100];
3806 squash_guid(package->ProductCode,squished_pc);
3808 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3809 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3810 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3813 msi_reg_set_val_str( hkey, squished_pc, buffer );
3816 TRACE("Reboot command %s\n",debugstr_w(buffer));
3818 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3819 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3821 msi_reg_set_val_str( hkey, squished_pc, buffer );
3824 return ERROR_INSTALL_SUSPEND;
3827 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3834 * we are currently doing what should be done here in the top level Install
3835 * however for Adminastrative and uninstalls this step will be needed
3837 if (!package->PackagePath)
3838 return ERROR_SUCCESS;
3840 ptr = strrchrW(package->PackagePath, '\\');
3842 return ERROR_SUCCESS;
3844 len = ptr - package->PackagePath + 2;
3845 source = msi_alloc(len * sizeof(WCHAR));
3846 lstrcpynW(source, package->PackagePath, len);
3848 MSI_SetPropertyW(package, cszSourceDir, source);
3849 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3853 attrib = GetFileAttributesW(package->PackagePath);
3854 if (attrib == INVALID_FILE_ATTRIBUTES)
3860 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3861 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3862 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3863 if (rc == ERROR_MORE_DATA)
3865 prompt = msi_alloc(size * sizeof(WCHAR));
3866 MsiSourceListGetInfoW(package->ProductCode, NULL,
3867 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3868 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3871 prompt = strdupW(package->PackagePath);
3873 msg = generate_error_string(package,1302,1,prompt);
3874 while(attrib == INVALID_FILE_ATTRIBUTES)
3876 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3879 rc = ERROR_INSTALL_USEREXIT;
3882 attrib = GetFileAttributesW(package->PackagePath);
3888 return ERROR_SUCCESS;
3893 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3900 static const WCHAR szPropKeys[][80] =
3902 {'P','r','o','d','u','c','t','I','D',0},
3903 {'U','S','E','R','N','A','M','E',0},
3904 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3908 static const WCHAR szRegKeys[][80] =
3910 {'P','r','o','d','u','c','t','I','D',0},
3911 {'R','e','g','O','w','n','e','r',0},
3912 {'R','e','g','C','o','m','p','a','n','y',0},
3916 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3918 return ERROR_SUCCESS;
3920 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3921 if (rc != ERROR_SUCCESS)
3924 for( i = 0; szPropKeys[i][0]; i++ )
3926 buffer = msi_dup_property( package, szPropKeys[i] );
3927 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3932 msi_free(productid);
3935 /* FIXME: call ui_actiondata */
3937 return ERROR_SUCCESS;
3941 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3945 package->script->InWhatSequence |= SEQUENCE_EXEC;
3946 rc = ACTION_ProcessExecSequence(package,FALSE);
3951 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3953 MSIPACKAGE *package = (MSIPACKAGE*)param;
3954 LPCWSTR compgroupid=NULL;
3955 LPCWSTR feature=NULL;
3956 LPCWSTR text = NULL;
3957 LPCWSTR qualifier = NULL;
3958 LPCWSTR component = NULL;
3959 LPWSTR advertise = NULL;
3960 LPWSTR output = NULL;
3962 UINT rc = ERROR_SUCCESS;
3967 component = MSI_RecordGetString(rec,3);
3968 comp = get_loaded_component(package,component);
3970 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3971 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3972 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3974 TRACE("Skipping: Component %s not scheduled for install\n",
3975 debugstr_w(component));
3977 return ERROR_SUCCESS;
3980 compgroupid = MSI_RecordGetString(rec,1);
3981 qualifier = MSI_RecordGetString(rec,2);
3983 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
3984 if (rc != ERROR_SUCCESS)
3987 text = MSI_RecordGetString(rec,4);
3988 feature = MSI_RecordGetString(rec,5);
3990 advertise = create_component_advertise_string(package, comp, feature);
3992 sz = strlenW(advertise);
3995 sz += lstrlenW(text);
3998 sz *= sizeof(WCHAR);
4000 output = msi_alloc_zero(sz);
4001 strcpyW(output,advertise);
4002 msi_free(advertise);
4005 strcatW(output,text);
4007 msi_reg_set_val_multi_str( hkey, qualifier, output );
4014 uirow = MSI_CreateRecord( 2 );
4015 MSI_RecordSetStringW( uirow, 1, compgroupid );
4016 MSI_RecordSetStringW( uirow, 2, qualifier);
4017 ui_actiondata( package, szPublishComponents, uirow);
4018 msiobj_release( &uirow->hdr );
4019 /* FIXME: call ui_progress? */
4025 * At present I am ignorning the advertised components part of this and only
4026 * focusing on the qualified component sets
4028 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4032 static const WCHAR ExecSeqQuery[] =
4033 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4034 '`','P','u','b','l','i','s','h',
4035 'C','o','m','p','o','n','e','n','t','`',0};
4037 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4038 if (rc != ERROR_SUCCESS)
4039 return ERROR_SUCCESS;
4041 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4042 msiobj_release(&view->hdr);
4047 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4049 MSIPACKAGE *package = (MSIPACKAGE*)param;
4052 SC_HANDLE hscm, service = NULL;
4053 LPCWSTR name, disp, comp, depends, pass;
4054 LPCWSTR load_order, serv_name, key;
4055 DWORD serv_type, start_type;
4058 static const WCHAR query[] =
4059 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4060 '`','C','o','m','p','o','n','e','n','t','`',' ',
4061 'W','H','E','R','E',' ',
4062 '`','C','o','m','p','o','n','e','n','t','`',' ',
4063 '=','\'','%','s','\'',0};
4065 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4068 ERR("Failed to open the SC Manager!\n");
4072 start_type = MSI_RecordGetInteger(rec, 5);
4073 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4076 depends = MSI_RecordGetString(rec, 8);
4077 if (depends && *depends)
4078 FIXME("Dependency list unhandled!\n");
4080 name = MSI_RecordGetString(rec, 2);
4081 disp = MSI_RecordGetString(rec, 3);
4082 serv_type = MSI_RecordGetInteger(rec, 4);
4083 err_control = MSI_RecordGetInteger(rec, 6);
4084 load_order = MSI_RecordGetString(rec, 7);
4085 serv_name = MSI_RecordGetString(rec, 9);
4086 pass = MSI_RecordGetString(rec, 10);
4087 comp = MSI_RecordGetString(rec, 12);
4089 /* fetch the service path */
4090 row = MSI_QueryGetRecord(package->db, query, comp);
4093 ERR("Control query failed!\n");
4097 key = MSI_RecordGetString(row, 6);
4098 msiobj_release(&row->hdr);
4100 file = get_loaded_file(package, key);
4103 ERR("Failed to load the service file\n");
4107 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4108 start_type, err_control, file->TargetPath,
4109 load_order, NULL, NULL, serv_name, pass);
4112 if (GetLastError() != ERROR_SERVICE_EXISTS)
4113 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4117 CloseServiceHandle(service);
4118 CloseServiceHandle(hscm);
4120 return ERROR_SUCCESS;
4123 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4127 static const WCHAR ExecSeqQuery[] =
4128 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4129 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4131 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4132 if (rc != ERROR_SUCCESS)
4133 return ERROR_SUCCESS;
4135 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4136 msiobj_release(&view->hdr);
4141 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4142 LPCSTR action, LPCWSTR table )
4144 static const WCHAR query[] = {
4145 'S','E','L','E','C','T',' ','*',' ',
4146 'F','R','O','M',' ','`','%','s','`',0 };
4147 MSIQUERY *view = NULL;
4151 r = MSI_OpenQuery( package->db, &view, query, table );
4152 if (r == ERROR_SUCCESS)
4154 r = MSI_IterateRecords(view, &count, NULL, package);
4155 msiobj_release(&view->hdr);
4159 FIXME("%s -> %u ignored %s table values\n",
4160 action, count, debugstr_w(table));
4162 return ERROR_SUCCESS;
4165 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4167 TRACE("%p\n", package);
4168 return ERROR_SUCCESS;
4171 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4173 static const WCHAR table[] =
4174 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4175 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4178 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4180 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4181 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4184 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4186 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4187 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4190 static UINT ACTION_BindImage( MSIPACKAGE *package )
4192 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4193 return msi_unimplemented_action_stub( package, "BindImage", table );
4196 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4198 static const WCHAR table[] = {
4199 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4200 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4203 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4205 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4206 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4209 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4211 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4212 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4215 static UINT ACTION_StartServices( MSIPACKAGE *package )
4217 static const WCHAR table[] = {
4218 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4219 return msi_unimplemented_action_stub( package, "StartServices", table );
4222 static UINT ACTION_StopServices( MSIPACKAGE *package )
4224 static const WCHAR table[] = {
4225 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4226 return msi_unimplemented_action_stub( package, "StopServices", table );
4229 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4231 static const WCHAR table[] = {
4232 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4233 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4236 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4238 static const WCHAR table[] = {
4239 'E','n','v','i','r','o','n','m','e','n','t',0 };
4240 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4243 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4245 static const WCHAR table[] = {
4246 'E','n','v','i','r','o','n','m','e','n','t',0 };
4247 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4250 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4252 static const WCHAR table[] = {
4253 'M','s','i','A','s','s','e','m','b','l','y',0 };
4254 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4257 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4259 static const WCHAR table[] = {
4260 'M','s','i','A','s','s','e','m','b','l','y',0 };
4261 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4264 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4266 static const WCHAR table[] = { 'F','o','n','t',0 };
4267 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4270 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4272 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4273 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4276 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4278 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4279 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4282 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4284 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4285 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4288 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4290 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4291 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4294 static struct _actions StandardActions[] = {
4295 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4296 { szAppSearch, ACTION_AppSearch },
4297 { szBindImage, ACTION_BindImage },
4298 { szCCPSearch, ACTION_CCPSearch},
4299 { szCostFinalize, ACTION_CostFinalize },
4300 { szCostInitialize, ACTION_CostInitialize },
4301 { szCreateFolders, ACTION_CreateFolders },
4302 { szCreateShortcuts, ACTION_CreateShortcuts },
4303 { szDeleteServices, ACTION_DeleteServices },
4304 { szDisableRollback, NULL},
4305 { szDuplicateFiles, ACTION_DuplicateFiles },
4306 { szExecuteAction, ACTION_ExecuteAction },
4307 { szFileCost, ACTION_FileCost },
4308 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4309 { szForceReboot, ACTION_ForceReboot },
4310 { szInstallAdminPackage, NULL},
4311 { szInstallExecute, ACTION_InstallExecute },
4312 { szInstallExecuteAgain, ACTION_InstallExecute },
4313 { szInstallFiles, ACTION_InstallFiles},
4314 { szInstallFinalize, ACTION_InstallFinalize },
4315 { szInstallInitialize, ACTION_InstallInitialize },
4316 { szInstallSFPCatalogFile, NULL},
4317 { szInstallValidate, ACTION_InstallValidate },
4318 { szIsolateComponents, ACTION_IsolateComponents },
4319 { szLaunchConditions, ACTION_LaunchConditions },
4320 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4321 { szMoveFiles, ACTION_MoveFiles },
4322 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4323 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4324 { szInstallODBC, NULL},
4325 { szInstallServices, ACTION_InstallServices },
4326 { szPatchFiles, ACTION_PatchFiles },
4327 { szProcessComponents, ACTION_ProcessComponents },
4328 { szPublishComponents, ACTION_PublishComponents },
4329 { szPublishFeatures, ACTION_PublishFeatures },
4330 { szPublishProduct, ACTION_PublishProduct },
4331 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4332 { szRegisterComPlus, ACTION_RegisterComPlus},
4333 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4334 { szRegisterFonts, ACTION_RegisterFonts },
4335 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4336 { szRegisterProduct, ACTION_RegisterProduct },
4337 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4338 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4339 { szRegisterUser, ACTION_RegisterUser},
4340 { szRemoveDuplicateFiles, NULL},
4341 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4342 { szRemoveExistingProducts, NULL},
4343 { szRemoveFiles, ACTION_RemoveFiles},
4344 { szRemoveFolders, NULL},
4345 { szRemoveIniValues, ACTION_RemoveIniValues },
4346 { szRemoveODBC, NULL},
4347 { szRemoveRegistryValues, NULL},
4348 { szRemoveShortcuts, NULL},
4349 { szResolveSource, ACTION_ResolveSource},
4350 { szRMCCPSearch, ACTION_RMCCPSearch},
4351 { szScheduleReboot, NULL},
4352 { szSelfRegModules, ACTION_SelfRegModules },
4353 { szSelfUnregModules, ACTION_SelfUnregModules },
4354 { szSetODBCFolders, NULL},
4355 { szStartServices, ACTION_StartServices },
4356 { szStopServices, ACTION_StopServices },
4357 { szUnpublishComponents, NULL},
4358 { szUnpublishFeatures, NULL},
4359 { szUnregisterClassInfo, NULL},
4360 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4361 { szUnregisterExtensionInfo, NULL},
4362 { szUnregisterFonts, ACTION_UnregisterFonts },
4363 { szUnregisterMIMEInfo, NULL},
4364 { szUnregisterProgIdInfo, NULL},
4365 { szUnregisterTypeLibraries, NULL},
4366 { szValidateProductID, NULL},
4367 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4368 { szWriteIniValues, ACTION_WriteIniValues },
4369 { szWriteRegistryValues, ACTION_WriteRegistryValues},