2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
38 #include "wine/debug.h"
43 #include "wine/unicode.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 sprintfW(message,template_s,timet,action);
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
300 LPWSTR prop = NULL, val = NULL;
303 return ERROR_SUCCESS;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
368 LPWSTR p, *ret = NULL;
374 /* count the number of substrings */
375 for ( pc = str, count = 0; pc; count++ )
377 pc = strchrW( pc, sep );
382 /* allocate space for an array of substring pointers and the substrings */
383 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384 (lstrlenW(str)+1) * sizeof(WCHAR) );
388 /* copy the string and set the pointers */
389 p = (LPWSTR) &ret[count+1];
391 for( count = 0; (ret[count] = p); count++ )
393 p = strchrW( p, sep );
401 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
403 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
404 LPWSTR prod_code, patch_product;
407 prod_code = msi_dup_property( package, szProductCode );
408 patch_product = msi_get_suminfo_product( patch );
410 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
412 if ( strstrW( patch_product, prod_code ) )
415 ret = ERROR_FUNCTION_FAILED;
417 msi_free( patch_product );
418 msi_free( prod_code );
423 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
424 MSIDATABASE *patch_db, LPCWSTR name )
426 UINT ret = ERROR_FUNCTION_FAILED;
427 IStorage *stg = NULL;
430 TRACE("%p %s\n", package, debugstr_w(name) );
434 ERR("expected a colon in %s\n", debugstr_w(name));
435 return ERROR_FUNCTION_FAILED;
438 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
441 ret = msi_check_transform_applicable( package, stg );
442 if (ret == ERROR_SUCCESS)
443 msi_table_apply_transform( package->db, stg );
445 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
446 IStorage_Release( stg );
449 ERR("failed to open substorage %s\n", debugstr_w(name));
451 return ERROR_SUCCESS;
454 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
456 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
457 LPWSTR guid_list, *guids, product_id;
458 UINT i, ret = ERROR_FUNCTION_FAILED;
460 product_id = msi_dup_property( package, szProdID );
463 /* FIXME: the property ProductID should be written into the DB somewhere */
464 ERR("no product ID to check\n");
465 return ERROR_SUCCESS;
468 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
469 guids = msi_split_string( guid_list, ';' );
470 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
472 if (!lstrcmpW( guids[i], product_id ))
476 msi_free( guid_list );
477 msi_free( product_id );
482 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
485 LPWSTR str, *substorage;
486 UINT i, r = ERROR_SUCCESS;
488 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
490 return ERROR_FUNCTION_FAILED;
492 msi_check_patch_applicable( package, si );
494 /* enumerate the substorage */
495 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
496 substorage = msi_split_string( str, ';' );
497 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
498 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
499 msi_free( substorage );
502 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
504 msiobj_release( &si->hdr );
509 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
511 MSIDATABASE *patch_db = NULL;
514 TRACE("%p %s\n", package, debugstr_w( file ) );
517 * We probably want to make sure we only open a patch collection here.
518 * Patch collections (.msp) and databases (.msi) have different GUIDs
519 * but currently MSI_OpenDatabaseW will accept both.
521 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
522 if ( r != ERROR_SUCCESS )
524 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
528 msi_parse_patch_summary( package, patch_db );
531 * There might be a CAB file in the patch package,
532 * so append it to the list of storage to search for streams.
534 append_storage_to_db( package->db, patch_db->storage );
536 msiobj_release( &patch_db->hdr );
538 return ERROR_SUCCESS;
541 /* get the PATCH property, and apply all the patches it specifies */
542 static UINT msi_apply_patches( MSIPACKAGE *package )
544 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
545 LPWSTR patch_list, *patches;
546 UINT i, r = ERROR_SUCCESS;
548 patch_list = msi_dup_property( package, szPatch );
550 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
552 patches = msi_split_string( patch_list, ';' );
553 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
554 r = msi_apply_patch_package( package, patches[i] );
557 msi_free( patch_list );
562 static UINT msi_apply_transforms( MSIPACKAGE *package )
564 static const WCHAR szTransforms[] = {
565 'T','R','A','N','S','F','O','R','M','S',0 };
566 LPWSTR xform_list, *xforms;
567 UINT i, r = ERROR_SUCCESS;
569 xform_list = msi_dup_property( package, szTransforms );
570 xforms = msi_split_string( xform_list, ';' );
572 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
574 if (xforms[i][0] == ':')
575 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
577 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
581 msi_free( xform_list );
586 /****************************************************
587 * TOP level entry points
588 *****************************************************/
590 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
591 LPCWSTR szCommandLine )
595 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
596 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
597 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
599 MSI_SetPropertyW(package, szAction, szInstall);
601 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
603 package->script->InWhatSequence = SEQUENCE_INSTALL;
607 LPWSTR p, check, path;
609 path = strdupW(szPackagePath);
610 p = strrchrW(path,'\\');
619 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
620 GetCurrentDirectoryW(MAX_PATH,path);
624 check = msi_dup_property( package, cszSourceDir );
626 MSI_SetPropertyW(package, cszSourceDir, path);
628 check = msi_dup_property( package, cszSOURCEDIR );
630 MSI_SetPropertyW(package, cszSOURCEDIR, path);
632 msi_free( package->PackagePath );
633 package->PackagePath = path;
638 msi_parse_command_line( package, szCommandLine );
640 msi_apply_transforms( package );
641 msi_apply_patches( package );
643 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
645 package->script->InWhatSequence |= SEQUENCE_UI;
646 rc = ACTION_ProcessUISequence(package);
648 if (rc == ERROR_SUCCESS)
650 package->script->InWhatSequence |= SEQUENCE_EXEC;
651 rc = ACTION_ProcessExecSequence(package,TRUE);
655 rc = ACTION_ProcessExecSequence(package,FALSE);
659 /* install was halted but should be considered a success */
663 package->script->CurrentlyScripting= FALSE;
665 /* process the ending type action */
666 if (rc == ERROR_SUCCESS)
667 ACTION_PerformActionSequence(package,-1,ui);
668 else if (rc == ERROR_INSTALL_USEREXIT)
669 ACTION_PerformActionSequence(package,-2,ui);
670 else if (rc == ERROR_INSTALL_SUSPEND)
671 ACTION_PerformActionSequence(package,-4,ui);
673 ACTION_PerformActionSequence(package,-3,ui);
675 /* finish up running custom actions */
676 ACTION_FinishCustomActions(package);
681 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
683 UINT rc = ERROR_SUCCESS;
685 static const WCHAR ExecSeqQuery[] =
686 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
687 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
688 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
689 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
691 static const WCHAR UISeqQuery[] =
692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
693 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
694 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
695 ' ', '=',' ','%','i',0};
698 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
700 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
704 LPCWSTR action, cond;
706 TRACE("Running the actions\n");
708 /* check conditions */
709 cond = MSI_RecordGetString(row,2);
711 /* this is a hack to skip errors in the condition code */
712 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
715 action = MSI_RecordGetString(row,1);
718 ERR("failed to fetch action\n");
719 rc = ERROR_FUNCTION_FAILED;
724 rc = ACTION_PerformUIAction(package,action);
726 rc = ACTION_PerformAction(package,action,FALSE);
728 msiobj_release(&row->hdr);
739 } iterate_action_param;
741 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
743 iterate_action_param *iap= (iterate_action_param*)param;
745 LPCWSTR cond, action;
747 action = MSI_RecordGetString(row,1);
750 ERR("Error is retrieving action name\n");
751 return ERROR_FUNCTION_FAILED;
754 /* check conditions */
755 cond = MSI_RecordGetString(row,2);
757 /* this is a hack to skip errors in the condition code */
758 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
760 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
761 return ERROR_SUCCESS;
765 rc = ACTION_PerformUIAction(iap->package,action);
767 rc = ACTION_PerformAction(iap->package,action,FALSE);
769 msi_dialog_check_messages( NULL );
771 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
772 rc = iap->package->CurrentInstallState;
774 if (rc == ERROR_FUNCTION_NOT_CALLED)
777 if (rc != ERROR_SUCCESS)
778 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
783 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
787 static const WCHAR query[] =
788 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
790 ' ','W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ',
792 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0};
794 iterate_action_param iap;
797 * FIXME: probably should be checking UILevel in the
798 * ACTION_PerformUIAction/ACTION_PerformAction
799 * rather than saving the UI level here. Those
800 * two functions can be merged too.
802 iap.package = package;
805 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
807 r = MSI_OpenQuery( package->db, &view, query, szTable );
808 if (r == ERROR_SUCCESS)
810 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
811 msiobj_release(&view->hdr);
817 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
821 static const WCHAR ExecSeqQuery[] =
822 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
823 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
824 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
825 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
826 'O','R','D','E','R',' ', 'B','Y',' ',
827 '`','S','e','q','u','e','n','c','e','`',0 };
829 static const WCHAR IVQuery[] =
830 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
831 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
832 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
833 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
834 ' ','\'', 'I','n','s','t','a','l','l',
835 'V','a','l','i','d','a','t','e','\'', 0};
837 iterate_action_param iap;
839 iap.package = package;
842 if (package->script->ExecuteSequenceRun)
844 TRACE("Execute Sequence already Run\n");
845 return ERROR_SUCCESS;
848 package->script->ExecuteSequenceRun = TRUE;
850 /* get the sequence number */
853 row = MSI_QueryGetRecord(package->db, IVQuery);
855 return ERROR_FUNCTION_FAILED;
856 seq = MSI_RecordGetInteger(row,1);
857 msiobj_release(&row->hdr);
860 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
861 if (rc == ERROR_SUCCESS)
863 TRACE("Running the actions\n");
865 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
866 msiobj_release(&view->hdr);
872 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
876 static const WCHAR ExecSeqQuery [] =
877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
878 '`','I','n','s','t','a','l','l',
879 'U','I','S','e','q','u','e','n','c','e','`',
880 ' ','W','H','E','R','E',' ',
881 '`','S','e','q','u','e','n','c','e','`',' ',
882 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
883 '`','S','e','q','u','e','n','c','e','`',0};
884 iterate_action_param iap;
886 iap.package = package;
889 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
891 if (rc == ERROR_SUCCESS)
893 TRACE("Running the actions\n");
895 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
896 msiobj_release(&view->hdr);
902 /********************************************************
903 * ACTION helper functions and functions that perform the actions
904 *******************************************************/
905 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
906 UINT* rc, BOOL force )
912 if (!run && !package->script->CurrentlyScripting)
917 if (strcmpW(action,szInstallFinalize) == 0 ||
918 strcmpW(action,szInstallExecute) == 0 ||
919 strcmpW(action,szInstallExecuteAgain) == 0)
924 while (StandardActions[i].action != NULL)
926 if (strcmpW(StandardActions[i].action, action)==0)
930 ui_actioninfo(package, action, TRUE, 0);
931 *rc = schedule_action(package,INSTALL_SCRIPT,action);
932 ui_actioninfo(package, action, FALSE, *rc);
936 ui_actionstart(package, action);
937 if (StandardActions[i].handler)
939 *rc = StandardActions[i].handler(package);
943 FIXME("unhandled standard action %s\n",debugstr_w(action));
955 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
956 UINT* rc, BOOL force )
961 arc = ACTION_CustomAction(package,action, force);
963 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
972 * A lot of actions are really important even if they don't do anything
973 * explicit... Lots of properties are set at the beginning of the installation
974 * CostFinalize does a bunch of work to translate the directories and such
976 * But until I get write access to the database that is hard, so I am going to
977 * hack it to see if I can get something to run.
979 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
981 UINT rc = ERROR_SUCCESS;
984 TRACE("Performing action (%s)\n",debugstr_w(action));
986 handled = ACTION_HandleStandardAction(package, action, &rc, force);
989 handled = ACTION_HandleCustomAction(package, action, &rc, force);
993 FIXME("unhandled msi action %s\n",debugstr_w(action));
994 rc = ERROR_FUNCTION_NOT_CALLED;
1000 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1002 UINT rc = ERROR_SUCCESS;
1003 BOOL handled = FALSE;
1005 TRACE("Performing action (%s)\n",debugstr_w(action));
1007 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1010 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1012 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1017 FIXME("unhandled msi action %s\n",debugstr_w(action));
1018 rc = ERROR_FUNCTION_NOT_CALLED;
1026 * Actual Action Handlers
1029 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1031 MSIPACKAGE *package = (MSIPACKAGE*)param;
1037 dir = MSI_RecordGetString(row,1);
1040 ERR("Unable to get folder id\n");
1041 return ERROR_SUCCESS;
1044 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1047 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1048 return ERROR_SUCCESS;
1051 TRACE("Folder is %s\n",debugstr_w(full_path));
1054 uirow = MSI_CreateRecord(1);
1055 MSI_RecordSetStringW(uirow,1,full_path);
1056 ui_actiondata(package,szCreateFolders,uirow);
1057 msiobj_release( &uirow->hdr );
1059 if (folder->State == 0)
1060 create_full_pathW(full_path);
1064 msi_free(full_path);
1065 return ERROR_SUCCESS;
1068 /* FIXME: probably should merge this with the above function */
1069 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1071 UINT rc = ERROR_SUCCESS;
1073 LPWSTR install_path;
1075 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1077 return ERROR_FUNCTION_FAILED;
1079 /* create the path */
1080 if (folder->State == 0)
1082 create_full_pathW(install_path);
1085 msi_free(install_path);
1090 UINT msi_create_component_directories( MSIPACKAGE *package )
1094 /* create all the folders required by the components are going to install */
1095 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1097 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1099 msi_create_directory( package, comp->Directory );
1102 return ERROR_SUCCESS;
1106 * Also we cannot enable/disable components either, so for now I am just going
1107 * to do all the directories for all the components.
1109 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1111 static const WCHAR ExecSeqQuery[] =
1112 {'S','E','L','E','C','T',' ',
1113 '`','D','i','r','e','c','t','o','r','y','_','`',
1114 ' ','F','R','O','M',' ',
1115 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1119 /* create all the empty folders specified in the CreateFolder table */
1120 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1121 if (rc != ERROR_SUCCESS)
1122 return ERROR_SUCCESS;
1124 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1125 msiobj_release(&view->hdr);
1127 msi_create_component_directories( package );
1132 static UINT load_component( MSIRECORD *row, LPVOID param )
1134 MSIPACKAGE *package = param;
1137 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1139 return ERROR_FUNCTION_FAILED;
1141 list_add_tail( &package->components, &comp->entry );
1143 /* fill in the data */
1144 comp->Component = msi_dup_record_field( row, 1 );
1146 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1148 comp->ComponentId = msi_dup_record_field( row, 2 );
1149 comp->Directory = msi_dup_record_field( row, 3 );
1150 comp->Attributes = MSI_RecordGetInteger(row,4);
1151 comp->Condition = msi_dup_record_field( row, 5 );
1152 comp->KeyPath = msi_dup_record_field( row, 6 );
1154 comp->Installed = INSTALLSTATE_UNKNOWN;
1155 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1157 return ERROR_SUCCESS;
1160 static UINT load_all_components( MSIPACKAGE *package )
1162 static const WCHAR query[] = {
1163 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1164 '`','C','o','m','p','o','n','e','n','t','`',0 };
1168 if (!list_empty(&package->components))
1169 return ERROR_SUCCESS;
1171 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1172 if (r != ERROR_SUCCESS)
1175 r = MSI_IterateRecords(view, NULL, load_component, package);
1176 msiobj_release(&view->hdr);
1181 MSIPACKAGE *package;
1182 MSIFEATURE *feature;
1185 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1189 cl = msi_alloc( sizeof (*cl) );
1191 return ERROR_NOT_ENOUGH_MEMORY;
1192 cl->component = comp;
1193 list_add_tail( &feature->Components, &cl->entry );
1195 return ERROR_SUCCESS;
1198 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1202 fl = msi_alloc( sizeof(*fl) );
1204 return ERROR_NOT_ENOUGH_MEMORY;
1205 fl->feature = child;
1206 list_add_tail( &parent->Children, &fl->entry );
1208 return ERROR_SUCCESS;
1211 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1213 _ilfs* ilfs= (_ilfs*)param;
1217 component = MSI_RecordGetString(row,1);
1219 /* check to see if the component is already loaded */
1220 comp = get_loaded_component( ilfs->package, component );
1223 ERR("unknown component %s\n", debugstr_w(component));
1224 return ERROR_FUNCTION_FAILED;
1227 add_feature_component( ilfs->feature, comp );
1228 comp->Enabled = TRUE;
1230 return ERROR_SUCCESS;
1233 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1235 MSIFEATURE *feature;
1237 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1239 if ( !lstrcmpW( feature->Feature, name ) )
1246 static UINT load_feature(MSIRECORD * row, LPVOID param)
1248 MSIPACKAGE* package = (MSIPACKAGE*)param;
1249 MSIFEATURE* feature;
1250 static const WCHAR Query1[] =
1251 {'S','E','L','E','C','T',' ',
1252 '`','C','o','m','p','o','n','e','n','t','_','`',
1253 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1254 'C','o','m','p','o','n','e','n','t','s','`',' ',
1255 'W','H','E','R','E',' ',
1256 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1261 /* fill in the data */
1263 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1265 return ERROR_NOT_ENOUGH_MEMORY;
1267 list_init( &feature->Children );
1268 list_init( &feature->Components );
1270 feature->Feature = msi_dup_record_field( row, 1 );
1272 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1274 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1275 feature->Title = msi_dup_record_field( row, 3 );
1276 feature->Description = msi_dup_record_field( row, 4 );
1278 if (!MSI_RecordIsNull(row,5))
1279 feature->Display = MSI_RecordGetInteger(row,5);
1281 feature->Level= MSI_RecordGetInteger(row,6);
1282 feature->Directory = msi_dup_record_field( row, 7 );
1283 feature->Attributes = MSI_RecordGetInteger(row,8);
1285 feature->Installed = INSTALLSTATE_UNKNOWN;
1286 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1288 list_add_tail( &package->features, &feature->entry );
1290 /* load feature components */
1292 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1293 if (rc != ERROR_SUCCESS)
1294 return ERROR_SUCCESS;
1296 ilfs.package = package;
1297 ilfs.feature = feature;
1299 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1300 msiobj_release(&view->hdr);
1302 return ERROR_SUCCESS;
1305 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1307 MSIPACKAGE* package = (MSIPACKAGE*)param;
1308 MSIFEATURE *parent, *child;
1310 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1312 return ERROR_FUNCTION_FAILED;
1314 if (!child->Feature_Parent)
1315 return ERROR_SUCCESS;
1317 parent = find_feature_by_name( package, child->Feature_Parent );
1319 return ERROR_FUNCTION_FAILED;
1321 add_feature_child( parent, child );
1322 return ERROR_SUCCESS;
1325 static UINT load_all_features( MSIPACKAGE *package )
1327 static const WCHAR query[] = {
1328 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1330 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1334 if (!list_empty(&package->features))
1335 return ERROR_SUCCESS;
1337 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1338 if (r != ERROR_SUCCESS)
1341 r = MSI_IterateRecords( view, NULL, load_feature, package );
1342 if (r != ERROR_SUCCESS)
1345 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1346 msiobj_release( &view->hdr );
1351 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1362 static UINT load_file(MSIRECORD *row, LPVOID param)
1364 MSIPACKAGE* package = (MSIPACKAGE*)param;
1368 /* fill in the data */
1370 file = msi_alloc_zero( sizeof (MSIFILE) );
1372 return ERROR_NOT_ENOUGH_MEMORY;
1374 file->File = msi_dup_record_field( row, 1 );
1376 component = MSI_RecordGetString( row, 2 );
1377 file->Component = get_loaded_component( package, component );
1379 if (!file->Component)
1380 ERR("Unfound Component %s\n",debugstr_w(component));
1382 file->FileName = msi_dup_record_field( row, 3 );
1383 reduce_to_longfilename( file->FileName );
1385 file->ShortName = msi_dup_record_field( row, 3 );
1386 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1388 file->FileSize = MSI_RecordGetInteger( row, 4 );
1389 file->Version = msi_dup_record_field( row, 5 );
1390 file->Language = msi_dup_record_field( row, 6 );
1391 file->Attributes = MSI_RecordGetInteger( row, 7 );
1392 file->Sequence = MSI_RecordGetInteger( row, 8 );
1394 file->state = msifs_invalid;
1396 /* if the compressed bits are not set in the file attributes,
1397 * then read the information from the package word count property
1399 if (file->Attributes & msidbFileAttributesCompressed)
1401 file->IsCompressed = TRUE;
1403 else if (file->Attributes & msidbFileAttributesNoncompressed)
1405 file->IsCompressed = FALSE;
1409 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1412 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1414 list_add_tail( &package->files, &file->entry );
1416 return ERROR_SUCCESS;
1419 static UINT load_all_files(MSIPACKAGE *package)
1423 static const WCHAR Query[] =
1424 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1425 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1426 '`','S','e','q','u','e','n','c','e','`', 0};
1428 if (!list_empty(&package->files))
1429 return ERROR_SUCCESS;
1431 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1432 if (rc != ERROR_SUCCESS)
1433 return ERROR_SUCCESS;
1435 rc = MSI_IterateRecords(view, NULL, load_file, package);
1436 msiobj_release(&view->hdr);
1438 return ERROR_SUCCESS;
1443 * I am not doing any of the costing functionality yet.
1444 * Mostly looking at doing the Component and Feature loading
1446 * The native MSI does A LOT of modification to tables here. Mostly adding
1447 * a lot of temporary columns to the Feature and Component tables.
1449 * note: Native msi also tracks the short filename. But I am only going to
1450 * track the long ones. Also looking at this directory table
1451 * it appears that the directory table does not get the parents
1452 * resolved base on property only based on their entries in the
1455 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1457 static const WCHAR szCosting[] =
1458 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1459 static const WCHAR szZero[] = { '0', 0 };
1461 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1462 return ERROR_SUCCESS;
1464 MSI_SetPropertyW(package, szCosting, szZero);
1465 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1467 load_all_components( package );
1468 load_all_features( package );
1469 load_all_files( package );
1471 return ERROR_SUCCESS;
1474 static UINT execute_script(MSIPACKAGE *package, UINT script )
1477 UINT rc = ERROR_SUCCESS;
1479 TRACE("Executing Script %i\n",script);
1481 if (!package->script)
1483 ERR("no script!\n");
1484 return ERROR_FUNCTION_FAILED;
1487 for (i = 0; i < package->script->ActionCount[script]; i++)
1490 action = package->script->Actions[script][i];
1491 ui_actionstart(package, action);
1492 TRACE("Executing Action (%s)\n",debugstr_w(action));
1493 rc = ACTION_PerformAction(package, action, TRUE);
1494 if (rc != ERROR_SUCCESS)
1497 msi_free_action_script(package, script);
1501 static UINT ACTION_FileCost(MSIPACKAGE *package)
1503 return ERROR_SUCCESS;
1506 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1508 static const WCHAR Query[] =
1509 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1510 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1511 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1512 ' ','=',' ','\'','%','s','\'',
1514 static const WCHAR szDot[] = { '.',0 };
1515 static WCHAR szEmpty[] = { 0 };
1516 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1521 TRACE("Looking for dir %s\n",debugstr_w(dir));
1523 folder = get_loaded_folder( package, dir );
1527 TRACE("Working to load %s\n",debugstr_w(dir));
1529 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1533 folder->Directory = strdupW(dir);
1535 row = MSI_QueryGetRecord(package->db, Query, dir);
1539 p = msi_dup_record_field(row, 3);
1541 /* split src and target dir */
1543 src_short = folder_split_path( p, ':' );
1545 /* split the long and short paths */
1546 tgt_long = folder_split_path( tgt_short, '|' );
1547 src_long = folder_split_path( src_short, '|' );
1549 /* check for no-op dirs */
1550 if (!lstrcmpW(szDot, tgt_short))
1551 tgt_short = szEmpty;
1552 if (!lstrcmpW(szDot, src_short))
1553 src_short = szEmpty;
1556 tgt_long = tgt_short;
1559 src_short = tgt_short;
1560 src_long = tgt_long;
1564 src_long = src_short;
1566 /* FIXME: use the target short path too */
1567 folder->TargetDefault = strdupW(tgt_long);
1568 folder->SourceShortPath = strdupW(src_short);
1569 folder->SourceLongPath = strdupW(src_long);
1572 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1573 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1574 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1576 parent = MSI_RecordGetString(row, 2);
1579 folder->Parent = load_folder( package, parent );
1580 if ( folder->Parent )
1581 TRACE("loaded parent %p %s\n", folder->Parent,
1582 debugstr_w(folder->Parent->Directory));
1584 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1587 folder->Property = msi_dup_property( package, dir );
1589 msiobj_release(&row->hdr);
1591 list_add_tail( &package->folders, &folder->entry );
1593 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1598 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1602 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1606 if (!comp->ComponentId)
1609 res = MsiGetComponentPathW( package->ProductCode,
1610 comp->ComponentId, NULL, NULL);
1612 res = INSTALLSTATE_ABSENT;
1613 comp->Installed = res;
1617 /* scan for and update current install states */
1618 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1621 MSIFEATURE *feature;
1623 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1626 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1628 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1630 comp= cl->component;
1632 if (!comp->ComponentId)
1634 res = INSTALLSTATE_ABSENT;
1638 if (res == INSTALLSTATE_ABSENT)
1639 res = comp->Installed;
1642 if (res == comp->Installed)
1645 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1646 res != INSTALLSTATE_SOURCE)
1648 res = INSTALLSTATE_INCOMPLETE;
1652 feature->Installed = res;
1656 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1659 static const WCHAR all[]={'A','L','L',0};
1661 MSIFEATURE *feature;
1663 override = msi_dup_property( package, property );
1667 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1669 if (strcmpiW(override,all)==0)
1670 msi_feature_set_state( feature, state );
1673 LPWSTR ptr = override;
1674 LPWSTR ptr2 = strchrW(override,',');
1678 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1679 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1681 msi_feature_set_state( feature, state );
1687 ptr2 = strchrW(ptr,',');
1699 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1702 static const WCHAR szlevel[] =
1703 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1704 static const WCHAR szAddLocal[] =
1705 {'A','D','D','L','O','C','A','L',0};
1706 static const WCHAR szRemove[] =
1707 {'R','E','M','O','V','E',0};
1708 static const WCHAR szReinstall[] =
1709 {'R','E','I','N','S','T','A','L','L',0};
1710 BOOL override = FALSE;
1711 MSICOMPONENT* component;
1712 MSIFEATURE *feature;
1715 /* I do not know if this is where it should happen.. but */
1717 TRACE("Checking Install Level\n");
1719 install_level = msi_get_property_int( package, szlevel, 1 );
1721 /* ok here is the _real_ rub
1722 * all these activation/deactivation things happen in order and things
1723 * later on the list override things earlier on the list.
1724 * 1) INSTALLLEVEL processing
1734 * 11) FILEADDDEFAULT
1735 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1736 * ignored for all the features. seems strange, especially since it is not
1737 * documented anywhere, but it is how it works.
1739 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1740 * REMOVE are the big ones, since we don't handle administrative installs
1743 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1744 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1745 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1749 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1751 BOOL feature_state = ((feature->Level > 0) &&
1752 (feature->Level <= install_level));
1754 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1756 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1757 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1758 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1759 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1761 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1765 /* disable child features of unselected parent features */
1766 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1770 if (feature->Level > 0 && feature->Level <= install_level)
1773 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1774 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1779 /* set the Preselected Property */
1780 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1781 static const WCHAR szOne[] = { '1', 0 };
1783 MSI_SetPropertyW(package,szPreselected,szOne);
1787 * now we want to enable or disable components base on feature
1790 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1794 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1795 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1796 feature->ActionRequest);
1798 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1800 component = cl->component;
1802 switch (component->Attributes)
1804 case msidbComponentAttributesLocalOnly:
1805 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1807 case msidbComponentAttributesSourceOnly:
1808 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1810 case msidbComponentAttributesOptional:
1811 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1814 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1817 if (component->ForceLocalState)
1818 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1820 if (!component->Enabled)
1821 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1822 else if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1824 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1825 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1827 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1829 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1830 (component->Action == INSTALLSTATE_ABSENT) ||
1831 (component->Action == INSTALLSTATE_ADVERTISED) ||
1832 (component->Action == INSTALLSTATE_DEFAULT))
1833 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1835 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1837 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1838 (component->Action == INSTALLSTATE_ABSENT))
1839 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1841 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1843 if (component->Action == INSTALLSTATE_UNKNOWN)
1844 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1846 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1847 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1849 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1850 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1854 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1856 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1857 debugstr_w(component->Component), component->Installed,
1858 component->Action, component->ActionRequest);
1862 return ERROR_SUCCESS;
1865 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1867 MSIPACKAGE *package = (MSIPACKAGE*)param;
1871 name = MSI_RecordGetString(row,1);
1873 /* This helper function now does ALL the work */
1874 TRACE("Dir %s ...\n",debugstr_w(name));
1875 load_folder(package,name);
1876 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1877 TRACE("resolves to %s\n",debugstr_w(path));
1880 return ERROR_SUCCESS;
1883 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1885 MSIPACKAGE *package = (MSIPACKAGE*)param;
1887 MSIFEATURE *feature;
1889 name = MSI_RecordGetString( row, 1 );
1891 feature = get_loaded_feature( package, name );
1893 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1897 Condition = MSI_RecordGetString(row,3);
1899 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1901 int level = MSI_RecordGetInteger(row,2);
1902 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1903 feature->Level = level;
1906 return ERROR_SUCCESS;
1909 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1911 static const WCHAR name_fmt[] =
1912 {'%','u','.','%','u','.','%','u','.','%','u',0};
1913 static WCHAR name[] = {'\\',0};
1914 VS_FIXEDFILEINFO *lpVer;
1915 WCHAR filever[0x100];
1921 TRACE("%s\n", debugstr_w(filename));
1923 versize = GetFileVersionInfoSizeW( filename, &handle );
1927 version = msi_alloc( versize );
1928 GetFileVersionInfoW( filename, 0, versize, version );
1930 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1931 msi_free( version );
1933 sprintfW( filever, name_fmt,
1934 HIWORD(lpVer->dwFileVersionMS),
1935 LOWORD(lpVer->dwFileVersionMS),
1936 HIWORD(lpVer->dwFileVersionLS),
1937 LOWORD(lpVer->dwFileVersionLS));
1939 return strdupW( filever );
1942 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1944 LPWSTR file_version;
1947 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1949 MSICOMPONENT* comp = file->Component;
1955 if (file->IsCompressed)
1956 comp->ForceLocalState = TRUE;
1958 /* calculate target */
1959 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1961 msi_free(file->TargetPath);
1963 TRACE("file %s is named %s\n",
1964 debugstr_w(file->File), debugstr_w(file->FileName));
1966 file->TargetPath = build_directory_name(2, p, file->FileName);
1970 TRACE("file %s resolves to %s\n",
1971 debugstr_w(file->File), debugstr_w(file->TargetPath));
1973 /* don't check files of components that aren't installed */
1974 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1975 comp->Installed == INSTALLSTATE_ABSENT)
1977 file->state = msifs_missing; /* assume files are missing */
1981 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1983 file->state = msifs_missing;
1984 comp->Cost += file->FileSize;
1985 comp->Installed = INSTALLSTATE_INCOMPLETE;
1989 if (file->Version &&
1990 (file_version = msi_get_disk_file_version( file->TargetPath )))
1992 TRACE("new %s old %s\n", debugstr_w(file->Version),
1993 debugstr_w(file_version));
1994 /* FIXME: seems like a bad way to compare version numbers */
1995 if (lstrcmpiW(file_version, file->Version)<0)
1997 file->state = msifs_overwrite;
1998 comp->Cost += file->FileSize;
1999 comp->Installed = INSTALLSTATE_INCOMPLETE;
2002 file->state = msifs_present;
2003 msi_free( file_version );
2006 file->state = msifs_present;
2009 return ERROR_SUCCESS;
2013 * A lot is done in this function aside from just the costing.
2014 * The costing needs to be implemented at some point but for now I am going
2015 * to focus on the directory building
2018 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2020 static const WCHAR ExecSeqQuery[] =
2021 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2022 '`','D','i','r','e','c','t','o','r','y','`',0};
2023 static const WCHAR ConditionQuery[] =
2024 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2025 '`','C','o','n','d','i','t','i','o','n','`',0};
2026 static const WCHAR szCosting[] =
2027 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2028 static const WCHAR szlevel[] =
2029 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2030 static const WCHAR szOne[] = { '1', 0 };
2036 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2037 return ERROR_SUCCESS;
2039 TRACE("Building Directory properties\n");
2041 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2042 if (rc == ERROR_SUCCESS)
2044 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2046 msiobj_release(&view->hdr);
2049 /* read components states from the registry */
2050 ACTION_GetComponentInstallStates(package);
2052 TRACE("File calculations\n");
2053 msi_check_file_install_states( package );
2055 TRACE("Evaluating Condition Table\n");
2057 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2058 if (rc == ERROR_SUCCESS)
2060 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2062 msiobj_release(&view->hdr);
2065 TRACE("Enabling or Disabling Components\n");
2066 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2068 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2070 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2071 comp->Enabled = FALSE;
2075 MSI_SetPropertyW(package,szCosting,szOne);
2076 /* set default run level if not set */
2077 level = msi_dup_property( package, szlevel );
2079 MSI_SetPropertyW(package,szlevel, szOne);
2082 ACTION_UpdateFeatureInstallStates(package);
2084 return MSI_SetFeatureStates(package);
2087 /* OK this value is "interpreted" and then formatted based on the
2088 first few characters */
2089 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2093 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2099 LPWSTR deformated = NULL;
2102 deformat_string(package, &value[2], &deformated);
2104 /* binary value type */
2108 *size = (strlenW(ptr)/2)+1;
2110 *size = strlenW(ptr)/2;
2112 data = msi_alloc(*size);
2118 /* if uneven pad with a zero in front */
2124 data[count] = (BYTE)strtol(byte,NULL,0);
2126 TRACE("Uneven byte count\n");
2134 data[count] = (BYTE)strtol(byte,NULL,0);
2137 msi_free(deformated);
2139 TRACE("Data %i bytes(%i)\n",*size,count);
2146 deformat_string(package, &value[1], &deformated);
2149 *size = sizeof(DWORD);
2150 data = msi_alloc(*size);
2156 if ( (*p < '0') || (*p > '9') )
2162 if (deformated[0] == '-')
2165 TRACE("DWORD %i\n",*(LPDWORD)data);
2167 msi_free(deformated);
2172 static const WCHAR szMulti[] = {'[','~',']',0};
2181 *type=REG_EXPAND_SZ;
2189 if (strstrW(value,szMulti))
2190 *type = REG_MULTI_SZ;
2192 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2197 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2199 MSIPACKAGE *package = (MSIPACKAGE*)param;
2200 static const WCHAR szHCR[] =
2201 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2202 'R','O','O','T','\\',0};
2203 static const WCHAR szHCU[] =
2204 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2205 'U','S','E','R','\\',0};
2206 static const WCHAR szHLM[] =
2207 {'H','K','E','Y','_','L','O','C','A','L','_',
2208 'M','A','C','H','I','N','E','\\',0};
2209 static const WCHAR szHU[] =
2210 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2212 LPSTR value_data = NULL;
2213 HKEY root_key, hkey;
2216 LPCWSTR szRoot, component, name, key, value;
2221 BOOL check_first = FALSE;
2224 ui_progress(package,2,0,0,0);
2231 component = MSI_RecordGetString(row, 6);
2232 comp = get_loaded_component(package,component);
2234 return ERROR_SUCCESS;
2236 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2238 TRACE("Skipping write due to disabled component %s\n",
2239 debugstr_w(component));
2241 comp->Action = comp->Installed;
2243 return ERROR_SUCCESS;
2246 comp->Action = INSTALLSTATE_LOCAL;
2248 name = MSI_RecordGetString(row, 4);
2249 if( MSI_RecordIsNull(row,5) && name )
2251 /* null values can have special meanings */
2252 if (name[0]=='-' && name[1] == 0)
2253 return ERROR_SUCCESS;
2254 else if ((name[0]=='+' && name[1] == 0) ||
2255 (name[0] == '*' && name[1] == 0))
2260 root = MSI_RecordGetInteger(row,2);
2261 key = MSI_RecordGetString(row, 3);
2263 /* get the root key */
2268 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2269 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2270 if (all_users && all_users[0] == '1')
2272 root_key = HKEY_LOCAL_MACHINE;
2277 root_key = HKEY_CURRENT_USER;
2280 msi_free(all_users);
2283 case 0: root_key = HKEY_CLASSES_ROOT;
2286 case 1: root_key = HKEY_CURRENT_USER;
2289 case 2: root_key = HKEY_LOCAL_MACHINE;
2292 case 3: root_key = HKEY_USERS;
2296 ERR("Unknown root %i\n",root);
2302 return ERROR_SUCCESS;
2304 deformat_string(package, key , &deformated);
2305 size = strlenW(deformated) + strlenW(szRoot) + 1;
2306 uikey = msi_alloc(size*sizeof(WCHAR));
2307 strcpyW(uikey,szRoot);
2308 strcatW(uikey,deformated);
2310 if (RegCreateKeyW( root_key, deformated, &hkey))
2312 ERR("Could not create key %s\n",debugstr_w(deformated));
2313 msi_free(deformated);
2315 return ERROR_SUCCESS;
2317 msi_free(deformated);
2319 value = MSI_RecordGetString(row,5);
2321 value_data = parse_value(package, value, &type, &size);
2324 static const WCHAR szEmpty[] = {0};
2325 value_data = (LPSTR)strdupW(szEmpty);
2330 deformat_string(package, name, &deformated);
2332 /* get the double nulls to terminate SZ_MULTI */
2333 if (type == REG_MULTI_SZ)
2334 size +=sizeof(WCHAR);
2338 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2340 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2345 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2346 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2348 TRACE("value %s of %s checked already exists\n",
2349 debugstr_w(deformated), debugstr_w(uikey));
2353 TRACE("Checked and setting value %s of %s\n",
2354 debugstr_w(deformated), debugstr_w(uikey));
2355 if (deformated || size)
2356 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2361 uirow = MSI_CreateRecord(3);
2362 MSI_RecordSetStringW(uirow,2,deformated);
2363 MSI_RecordSetStringW(uirow,1,uikey);
2366 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2368 MSI_RecordSetStringW(uirow,3,value);
2370 ui_actiondata(package,szWriteRegistryValues,uirow);
2371 msiobj_release( &uirow->hdr );
2373 msi_free(value_data);
2374 msi_free(deformated);
2377 return ERROR_SUCCESS;
2380 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2384 static const WCHAR ExecSeqQuery[] =
2385 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2386 '`','R','e','g','i','s','t','r','y','`',0 };
2388 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2389 if (rc != ERROR_SUCCESS)
2390 return ERROR_SUCCESS;
2392 /* increment progress bar each time action data is sent */
2393 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2395 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2397 msiobj_release(&view->hdr);
2401 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2403 package->script->CurrentlyScripting = TRUE;
2405 return ERROR_SUCCESS;
2409 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2414 static const WCHAR q1[]=
2415 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2416 '`','R','e','g','i','s','t','r','y','`',0};
2419 MSIFEATURE *feature;
2422 TRACE("InstallValidate\n");
2424 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2425 if (rc == ERROR_SUCCESS)
2427 MSI_IterateRecords( view, &progress, NULL, package );
2428 msiobj_release( &view->hdr );
2429 total += progress * REG_PROGRESS_VALUE;
2432 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2433 total += COMPONENT_PROGRESS_VALUE;
2435 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2436 total += file->FileSize;
2438 ui_progress(package,0,total,0,0);
2440 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2442 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2443 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2444 feature->ActionRequest);
2447 return ERROR_SUCCESS;
2450 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2452 MSIPACKAGE* package = (MSIPACKAGE*)param;
2453 LPCWSTR cond = NULL;
2454 LPCWSTR message = NULL;
2455 static const WCHAR title[]=
2456 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2458 cond = MSI_RecordGetString(row,1);
2460 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2463 message = MSI_RecordGetString(row,2);
2464 deformat_string(package,message,&deformated);
2465 MessageBoxW(NULL,deformated,title,MB_OK);
2466 msi_free(deformated);
2467 return ERROR_FUNCTION_FAILED;
2470 return ERROR_SUCCESS;
2473 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2476 MSIQUERY * view = NULL;
2477 static const WCHAR ExecSeqQuery[] =
2478 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2479 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2481 TRACE("Checking launch conditions\n");
2483 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2484 if (rc != ERROR_SUCCESS)
2485 return ERROR_SUCCESS;
2487 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2488 msiobj_release(&view->hdr);
2493 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2497 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2499 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2501 MSIRECORD * row = 0;
2503 LPWSTR deformated,buffer,deformated_name;
2505 static const WCHAR ExecSeqQuery[] =
2506 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2507 '`','R','e','g','i','s','t','r','y','`',' ',
2508 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2509 ' ','=',' ' ,'\'','%','s','\'',0 };
2510 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2511 static const WCHAR fmt2[]=
2512 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2514 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2518 root = MSI_RecordGetInteger(row,2);
2519 key = MSI_RecordGetString(row, 3);
2520 name = MSI_RecordGetString(row, 4);
2521 deformat_string(package, key , &deformated);
2522 deformat_string(package, name, &deformated_name);
2524 len = strlenW(deformated) + 6;
2525 if (deformated_name)
2526 len+=strlenW(deformated_name);
2528 buffer = msi_alloc( len *sizeof(WCHAR));
2530 if (deformated_name)
2531 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2533 sprintfW(buffer,fmt,root,deformated);
2535 msi_free(deformated);
2536 msi_free(deformated_name);
2537 msiobj_release(&row->hdr);
2541 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2543 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2548 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2551 return strdupW( file->TargetPath );
2556 static HKEY openSharedDLLsKey(void)
2559 static const WCHAR path[] =
2560 {'S','o','f','t','w','a','r','e','\\',
2561 'M','i','c','r','o','s','o','f','t','\\',
2562 'W','i','n','d','o','w','s','\\',
2563 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2564 'S','h','a','r','e','d','D','L','L','s',0};
2566 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2570 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2575 DWORD sz = sizeof(count);
2578 hkey = openSharedDLLsKey();
2579 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2580 if (rc != ERROR_SUCCESS)
2586 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2590 hkey = openSharedDLLsKey();
2592 msi_reg_set_val_dword( hkey, path, count );
2594 RegDeleteValueW(hkey,path);
2600 * Return TRUE if the count should be written out and FALSE if not
2602 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2604 MSIFEATURE *feature;
2608 /* only refcount DLLs */
2609 if (comp->KeyPath == NULL ||
2610 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2611 comp->Attributes & msidbComponentAttributesODBCDataSource)
2615 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2616 write = (count > 0);
2618 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2622 /* increment counts */
2623 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2627 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2630 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2632 if ( cl->component == comp )
2637 /* decrement counts */
2638 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2642 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2645 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2647 if ( cl->component == comp )
2652 /* ref count all the files in the component */
2657 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2659 if (file->Component == comp)
2660 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2664 /* add a count for permenent */
2665 if (comp->Attributes & msidbComponentAttributesPermanent)
2668 comp->RefCount = count;
2671 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2675 * Ok further analysis makes me think that this work is
2676 * actually done in the PublishComponents and PublishFeatures
2677 * step, and not here. It appears like the keypath and all that is
2678 * resolved in this step, however actually written in the Publish steps.
2679 * But we will leave it here for now because it is unclear
2681 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2683 WCHAR squished_pc[GUID_SIZE];
2684 WCHAR squished_cc[GUID_SIZE];
2687 HKEY hkey=0,hkey2=0;
2689 /* writes the Component and Features values to the registry */
2691 rc = MSIREG_OpenComponents(&hkey);
2692 if (rc != ERROR_SUCCESS)
2695 squash_guid(package->ProductCode,squished_pc);
2696 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2698 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2702 ui_progress(package,2,0,0,0);
2703 if (!comp->ComponentId)
2706 squash_guid(comp->ComponentId,squished_cc);
2708 msi_free(comp->FullKeypath);
2709 comp->FullKeypath = resolve_keypath( package, comp );
2711 /* do the refcounting */
2712 ACTION_RefCountComponent( package, comp );
2714 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2715 debugstr_w(comp->Component),
2716 debugstr_w(squished_cc),
2717 debugstr_w(comp->FullKeypath),
2720 * Write the keypath out if the component is to be registered
2721 * and delete the key if the component is to be deregistered
2723 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2725 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2726 if (rc != ERROR_SUCCESS)
2729 if (!comp->FullKeypath)
2732 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2734 if (comp->Attributes & msidbComponentAttributesPermanent)
2736 static const WCHAR szPermKey[] =
2737 { '0','0','0','0','0','0','0','0','0','0','0','0',
2738 '0','0','0','0','0','0','0','0','0','0','0','0',
2739 '0','0','0','0','0','0','0','0',0 };
2741 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2747 uirow = MSI_CreateRecord(3);
2748 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2749 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2750 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2751 ui_actiondata(package,szProcessComponents,uirow);
2752 msiobj_release( &uirow->hdr );
2754 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2758 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2759 if (rc != ERROR_SUCCESS)
2762 RegDeleteValueW(hkey2,squished_pc);
2764 /* if the key is empty delete it */
2765 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2767 if (res == ERROR_NO_MORE_ITEMS)
2768 RegDeleteKeyW(hkey,squished_cc);
2771 uirow = MSI_CreateRecord(2);
2772 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2773 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2774 ui_actiondata(package,szProcessComponents,uirow);
2775 msiobj_release( &uirow->hdr );
2790 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2791 LPWSTR lpszName, LONG_PTR lParam)
2794 typelib_struct *tl_struct = (typelib_struct*) lParam;
2795 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2799 if (!IS_INTRESOURCE(lpszName))
2801 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2805 sz = strlenW(tl_struct->source)+4;
2806 sz *= sizeof(WCHAR);
2808 if ((INT_PTR)lpszName == 1)
2809 tl_struct->path = strdupW(tl_struct->source);
2812 tl_struct->path = msi_alloc(sz);
2813 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2816 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2817 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2818 if (!SUCCEEDED(res))
2820 msi_free(tl_struct->path);
2821 tl_struct->path = NULL;
2826 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2827 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2829 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2833 msi_free(tl_struct->path);
2834 tl_struct->path = NULL;
2836 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2837 ITypeLib_Release(tl_struct->ptLib);
2842 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2844 MSIPACKAGE* package = (MSIPACKAGE*)param;
2848 typelib_struct tl_struct;
2850 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2852 component = MSI_RecordGetString(row,3);
2853 comp = get_loaded_component(package,component);
2855 return ERROR_SUCCESS;
2857 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2859 TRACE("Skipping typelib reg due to disabled component\n");
2861 comp->Action = comp->Installed;
2863 return ERROR_SUCCESS;
2866 comp->Action = INSTALLSTATE_LOCAL;
2868 file = get_loaded_file( package, comp->KeyPath );
2870 return ERROR_SUCCESS;
2872 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2876 guid = MSI_RecordGetString(row,1);
2877 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2878 tl_struct.source = strdupW( file->TargetPath );
2879 tl_struct.path = NULL;
2881 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2882 (LONG_PTR)&tl_struct);
2890 helpid = MSI_RecordGetString(row,6);
2893 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2894 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2897 if (!SUCCEEDED(res))
2898 ERR("Failed to register type library %s\n",
2899 debugstr_w(tl_struct.path));
2902 ui_actiondata(package,szRegisterTypeLibraries,row);
2904 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2907 ITypeLib_Release(tl_struct.ptLib);
2908 msi_free(tl_struct.path);
2911 ERR("Failed to load type library %s\n",
2912 debugstr_w(tl_struct.source));
2914 FreeLibrary(module);
2915 msi_free(tl_struct.source);
2918 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2920 return ERROR_SUCCESS;
2923 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2926 * OK this is a bit confusing.. I am given a _Component key and I believe
2927 * that the file that is being registered as a type library is the "key file
2928 * of that component" which I interpret to mean "The file in the KeyPath of
2933 static const WCHAR Query[] =
2934 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2935 '`','T','y','p','e','L','i','b','`',0};
2937 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2938 if (rc != ERROR_SUCCESS)
2939 return ERROR_SUCCESS;
2941 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2942 msiobj_release(&view->hdr);
2946 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2948 MSIPACKAGE *package = (MSIPACKAGE*)param;
2949 LPWSTR target_file, target_folder, filename;
2950 LPCWSTR buffer, extension;
2952 static const WCHAR szlnk[]={'.','l','n','k',0};
2953 IShellLinkW *sl = NULL;
2954 IPersistFile *pf = NULL;
2957 buffer = MSI_RecordGetString(row,4);
2958 comp = get_loaded_component(package,buffer);
2960 return ERROR_SUCCESS;
2962 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2964 TRACE("Skipping shortcut creation due to disabled component\n");
2966 comp->Action = comp->Installed;
2968 return ERROR_SUCCESS;
2971 comp->Action = INSTALLSTATE_LOCAL;
2973 ui_actiondata(package,szCreateShortcuts,row);
2975 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2976 &IID_IShellLinkW, (LPVOID *) &sl );
2980 ERR("CLSID_ShellLink not available\n");
2984 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2987 ERR("QueryInterface(IID_IPersistFile) failed\n");
2991 buffer = MSI_RecordGetString(row,2);
2992 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2994 /* may be needed because of a bug somehwere else */
2995 create_full_pathW(target_folder);
2997 filename = msi_dup_record_field( row, 3 );
2998 reduce_to_longfilename(filename);
3000 extension = strchrW(filename,'.');
3001 if (!extension || strcmpiW(extension,szlnk))
3003 int len = strlenW(filename);
3004 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3005 memcpy(filename + len, szlnk, sizeof(szlnk));
3007 target_file = build_directory_name(2, target_folder, filename);
3008 msi_free(target_folder);
3011 buffer = MSI_RecordGetString(row,5);
3012 if (strchrW(buffer,'['))
3015 deformat_string(package,buffer,&deformated);
3016 IShellLinkW_SetPath(sl,deformated);
3017 msi_free(deformated);
3021 FIXME("poorly handled shortcut format, advertised shortcut\n");
3022 IShellLinkW_SetPath(sl,comp->FullKeypath);
3025 if (!MSI_RecordIsNull(row,6))
3028 buffer = MSI_RecordGetString(row,6);
3029 deformat_string(package,buffer,&deformated);
3030 IShellLinkW_SetArguments(sl,deformated);
3031 msi_free(deformated);
3034 if (!MSI_RecordIsNull(row,7))
3036 buffer = MSI_RecordGetString(row,7);
3037 IShellLinkW_SetDescription(sl,buffer);
3040 if (!MSI_RecordIsNull(row,8))
3041 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3043 if (!MSI_RecordIsNull(row,9))
3048 buffer = MSI_RecordGetString(row,9);
3050 Path = build_icon_path(package,buffer);
3051 index = MSI_RecordGetInteger(row,10);
3053 /* no value means 0 */
3054 if (index == MSI_NULL_INTEGER)
3057 IShellLinkW_SetIconLocation(sl,Path,index);
3061 if (!MSI_RecordIsNull(row,11))
3062 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3064 if (!MSI_RecordIsNull(row,12))
3067 buffer = MSI_RecordGetString(row,12);
3068 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3070 IShellLinkW_SetWorkingDirectory(sl,Path);
3074 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3075 IPersistFile_Save(pf,target_file,FALSE);
3077 msi_free(target_file);
3081 IPersistFile_Release( pf );
3083 IShellLinkW_Release( sl );
3085 return ERROR_SUCCESS;
3088 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3093 static const WCHAR Query[] =
3094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3095 '`','S','h','o','r','t','c','u','t','`',0};
3097 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3098 if (rc != ERROR_SUCCESS)
3099 return ERROR_SUCCESS;
3101 res = CoInitialize( NULL );
3104 ERR("CoInitialize failed\n");
3105 return ERROR_FUNCTION_FAILED;
3108 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3109 msiobj_release(&view->hdr);
3116 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3118 MSIPACKAGE* package = (MSIPACKAGE*)param;
3127 FileName = MSI_RecordGetString(row,1);
3130 ERR("Unable to get FileName\n");
3131 return ERROR_SUCCESS;
3134 FilePath = build_icon_path(package,FileName);
3136 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3138 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3139 FILE_ATTRIBUTE_NORMAL, NULL);
3141 if (the_file == INVALID_HANDLE_VALUE)
3143 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3145 return ERROR_SUCCESS;
3152 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3153 if (rc != ERROR_SUCCESS)
3155 ERR("Failed to get stream\n");
3156 CloseHandle(the_file);
3157 DeleteFileW(FilePath);
3160 WriteFile(the_file,buffer,sz,&write,NULL);
3161 } while (sz == 1024);
3165 CloseHandle(the_file);
3167 uirow = MSI_CreateRecord(1);
3168 MSI_RecordSetStringW(uirow,1,FileName);
3169 ui_actiondata(package,szPublishProduct,uirow);
3170 msiobj_release( &uirow->hdr );
3172 return ERROR_SUCCESS;
3176 * 99% of the work done here is only done for
3177 * advertised installs. However this is where the
3178 * Icon table is processed and written out
3179 * so that is what I am going to do here.
3181 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3185 static const WCHAR Query[]=
3186 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3187 '`','I','c','o','n','`',0};
3188 /* for registry stuff */
3191 static const WCHAR szProductLanguage[] =
3192 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3193 static const WCHAR szARPProductIcon[] =
3194 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3195 static const WCHAR szProductVersion[] =
3196 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3200 MSIHANDLE hDb, hSumInfo;
3202 /* write out icon files */
3204 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3205 if (rc == ERROR_SUCCESS)
3207 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3208 msiobj_release(&view->hdr);
3211 /* ok there is a lot more done here but i need to figure out what */
3213 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3214 if (rc != ERROR_SUCCESS)
3217 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3218 if (rc != ERROR_SUCCESS)
3222 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3223 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3226 langid = msi_get_property_int( package, szProductLanguage, 0 );
3227 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3229 buffer = msi_dup_property( package, szARPProductIcon );
3232 LPWSTR path = build_icon_path(package,buffer);
3233 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3238 buffer = msi_dup_property( package, szProductVersion );
3241 DWORD verdword = msi_version_str_to_dword(buffer);
3242 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3246 /* FIXME: Need to write more keys to the user registry */
3248 hDb= alloc_msihandle( &package->db->hdr );
3250 rc = ERROR_NOT_ENOUGH_MEMORY;
3253 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3254 MsiCloseHandle(hDb);
3255 if (rc == ERROR_SUCCESS)
3257 WCHAR guidbuffer[0x200];
3259 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3261 if (rc == ERROR_SUCCESS)
3263 WCHAR squashed[GUID_SIZE];
3264 /* for now we only care about the first guid */
3265 LPWSTR ptr = strchrW(guidbuffer,';');
3267 squash_guid(guidbuffer,squashed);
3268 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3272 ERR("Unable to query Revision_Number...\n");
3275 MsiCloseHandle(hSumInfo);
3279 ERR("Unable to open Summary Information\n");
3291 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3293 MSIPACKAGE *package = (MSIPACKAGE*)param;
3294 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3295 LPWSTR deformated_section, deformated_key, deformated_value;
3296 LPWSTR folder, fullname = NULL;
3300 static const WCHAR szWindowsFolder[] =
3301 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3303 component = MSI_RecordGetString(row, 8);
3304 comp = get_loaded_component(package,component);
3306 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3308 TRACE("Skipping ini file due to disabled component %s\n",
3309 debugstr_w(component));
3311 comp->Action = comp->Installed;
3313 return ERROR_SUCCESS;
3316 comp->Action = INSTALLSTATE_LOCAL;
3318 identifier = MSI_RecordGetString(row,1);
3319 filename = MSI_RecordGetString(row,2);
3320 dirproperty = MSI_RecordGetString(row,3);
3321 section = MSI_RecordGetString(row,4);
3322 key = MSI_RecordGetString(row,5);
3323 value = MSI_RecordGetString(row,6);
3324 action = MSI_RecordGetInteger(row,7);
3326 deformat_string(package,section,&deformated_section);
3327 deformat_string(package,key,&deformated_key);
3328 deformat_string(package,value,&deformated_value);
3332 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3334 folder = msi_dup_property( package, dirproperty );
3337 folder = msi_dup_property( package, szWindowsFolder );
3341 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3345 fullname = build_directory_name(2, folder, filename);
3349 TRACE("Adding value %s to section %s in %s\n",
3350 debugstr_w(deformated_key), debugstr_w(deformated_section),
3351 debugstr_w(fullname));
3352 WritePrivateProfileStringW(deformated_section, deformated_key,
3353 deformated_value, fullname);
3355 else if (action == 1)
3358 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3359 returned, 10, fullname);
3360 if (returned[0] == 0)
3362 TRACE("Adding value %s to section %s in %s\n",
3363 debugstr_w(deformated_key), debugstr_w(deformated_section),
3364 debugstr_w(fullname));
3366 WritePrivateProfileStringW(deformated_section, deformated_key,
3367 deformated_value, fullname);
3370 else if (action == 3)
3371 FIXME("Append to existing section not yet implemented\n");
3373 uirow = MSI_CreateRecord(4);
3374 MSI_RecordSetStringW(uirow,1,identifier);
3375 MSI_RecordSetStringW(uirow,2,deformated_section);
3376 MSI_RecordSetStringW(uirow,3,deformated_key);
3377 MSI_RecordSetStringW(uirow,4,deformated_value);
3378 ui_actiondata(package,szWriteIniValues,uirow);
3379 msiobj_release( &uirow->hdr );
3383 msi_free(deformated_key);
3384 msi_free(deformated_value);
3385 msi_free(deformated_section);
3386 return ERROR_SUCCESS;
3389 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3393 static const WCHAR ExecSeqQuery[] =
3394 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3395 '`','I','n','i','F','i','l','e','`',0};
3397 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3398 if (rc != ERROR_SUCCESS)
3400 TRACE("no IniFile table\n");
3401 return ERROR_SUCCESS;
3404 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3405 msiobj_release(&view->hdr);
3409 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3411 MSIPACKAGE *package = (MSIPACKAGE*)param;
3416 static const WCHAR ExeStr[] =
3417 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3418 static const WCHAR close[] = {'\"',0};
3420 PROCESS_INFORMATION info;
3425 memset(&si,0,sizeof(STARTUPINFOW));
3427 filename = MSI_RecordGetString(row,1);
3428 file = get_loaded_file( package, filename );
3432 ERR("Unable to find file id %s\n",debugstr_w(filename));
3433 return ERROR_SUCCESS;
3436 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3438 FullName = msi_alloc(len*sizeof(WCHAR));
3439 strcpyW(FullName,ExeStr);
3440 strcatW( FullName, file->TargetPath );
3441 strcatW(FullName,close);
3443 TRACE("Registering %s\n",debugstr_w(FullName));
3444 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3448 msi_dialog_check_messages(info.hProcess);
3453 uirow = MSI_CreateRecord( 2 );
3454 uipath = strdupW( file->TargetPath );
3455 p = strrchrW(uipath,'\\');
3458 MSI_RecordSetStringW( uirow, 1, &p[2] );
3459 MSI_RecordSetStringW( uirow, 2, uipath);
3460 ui_actiondata( package, szSelfRegModules, uirow);
3461 msiobj_release( &uirow->hdr );
3463 /* FIXME: call ui_progress? */
3465 return ERROR_SUCCESS;
3468 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3472 static const WCHAR ExecSeqQuery[] =
3473 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3474 '`','S','e','l','f','R','e','g','`',0};
3476 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3477 if (rc != ERROR_SUCCESS)
3479 TRACE("no SelfReg table\n");
3480 return ERROR_SUCCESS;
3483 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3484 msiobj_release(&view->hdr);
3486 return ERROR_SUCCESS;
3489 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3491 MSIFEATURE *feature;
3496 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3497 if (rc != ERROR_SUCCESS)
3500 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3501 if (rc != ERROR_SUCCESS)
3504 /* here the guids are base 85 encoded */
3505 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3511 BOOL absent = FALSE;
3514 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3515 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3516 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3520 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3524 if (feature->Feature_Parent)
3525 size += strlenW( feature->Feature_Parent )+2;
3527 data = msi_alloc(size * sizeof(WCHAR));
3530 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3532 MSICOMPONENT* component = cl->component;
3536 if (component->ComponentId)
3538 TRACE("From %s\n",debugstr_w(component->ComponentId));
3539 CLSIDFromString(component->ComponentId, &clsid);
3540 encode_base85_guid(&clsid,buf);
3541 TRACE("to %s\n",debugstr_w(buf));
3545 if (feature->Feature_Parent)
3547 static const WCHAR sep[] = {'\2',0};
3549 strcatW(data,feature->Feature_Parent);
3552 msi_reg_set_val_str( hkey, feature->Feature, data );
3556 if (feature->Feature_Parent)
3557 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3560 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3561 (LPBYTE)feature->Feature_Parent,size);
3565 size += 2*sizeof(WCHAR);
3566 data = msi_alloc(size);
3569 if (feature->Feature_Parent)
3570 strcpyW( &data[1], feature->Feature_Parent );
3571 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3577 uirow = MSI_CreateRecord( 1 );
3578 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3579 ui_actiondata( package, szPublishFeatures, uirow);
3580 msiobj_release( &uirow->hdr );
3581 /* FIXME: call ui_progress? */
3590 static UINT msi_get_local_package_name( LPWSTR path )
3592 static const WCHAR szInstaller[] = {
3593 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3594 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3598 time = GetTickCount();
3599 GetWindowsDirectoryW( path, MAX_PATH );
3600 lstrcatW( path, szInstaller );
3601 CreateDirectoryW( path, NULL );
3603 len = lstrlenW(path);
3604 for (i=0; i<0x10000; i++)
3606 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3607 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3608 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3609 if (handle != INVALID_HANDLE_VALUE)
3611 CloseHandle(handle);
3614 if (GetLastError() != ERROR_FILE_EXISTS &&
3615 GetLastError() != ERROR_SHARING_VIOLATION)
3616 return ERROR_FUNCTION_FAILED;
3619 return ERROR_SUCCESS;
3622 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3624 static const WCHAR szOriginalDatabase[] =
3625 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3626 WCHAR packagefile[MAX_PATH];
3630 r = msi_get_local_package_name( packagefile );
3631 if (r != ERROR_SUCCESS)
3634 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3636 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3637 r = CopyFileW( msiFilePath, packagefile, FALSE);
3638 msi_free( msiFilePath );
3642 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3643 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3644 return ERROR_FUNCTION_FAILED;
3647 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3648 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3649 return ERROR_SUCCESS;
3652 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3654 LPWSTR prop, val, key;
3655 static const LPCSTR propval[] = {
3656 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3657 "ARPCONTACT", "Contact",
3658 "ARPCOMMENTS", "Comments",
3659 "ProductName", "DisplayName",
3660 "ProductVersion", "DisplayVersion",
3661 "ARPHELPLINK", "HelpLink",
3662 "ARPHELPTELEPHONE", "HelpTelephone",
3663 "ARPINSTALLLOCATION", "InstallLocation",
3664 "SourceDir", "InstallSource",
3665 "Manufacturer", "Publisher",
3666 "ARPREADME", "Readme",
3668 "ARPURLINFOABOUT", "URLInfoAbout",
3669 "ARPURLUPDATEINFO", "URLUpdateInfo",
3672 const LPCSTR *p = propval;
3676 prop = strdupAtoW( *p++ );
3677 key = strdupAtoW( *p++ );
3678 val = msi_dup_property( package, prop );
3679 msi_reg_set_val_str( hkey, key, val );
3684 return ERROR_SUCCESS;
3687 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3690 LPWSTR buffer = NULL;
3693 static const WCHAR szWindowsInstaller[] =
3694 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3695 static const WCHAR szUpgradeCode[] =
3696 {'U','p','g','r','a','d','e','C','o','d','e',0};
3697 static const WCHAR modpath_fmt[] =
3698 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3699 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3700 static const WCHAR szModifyPath[] =
3701 {'M','o','d','i','f','y','P','a','t','h',0};
3702 static const WCHAR szUninstallString[] =
3703 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3704 static const WCHAR szEstimatedSize[] =
3705 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3706 static const WCHAR szProductLanguage[] =
3707 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3708 static const WCHAR szProductVersion[] =
3709 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3712 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3713 LPWSTR upgrade_code;
3716 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3717 if (rc != ERROR_SUCCESS)
3720 /* dump all the info i can grab */
3721 /* FIXME: Flesh out more information */
3723 msi_write_uninstall_property_vals( package, hkey );
3725 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3727 msi_make_package_local( package, hkey );
3729 /* do ModifyPath and UninstallString */
3730 size = deformat_string(package,modpath_fmt,&buffer);
3731 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3732 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3735 /* FIXME: Write real Estimated Size when we have it */
3736 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3738 GetLocalTime(&systime);
3739 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3740 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3742 langid = msi_get_property_int( package, szProductLanguage, 0 );
3743 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3745 buffer = msi_dup_property( package, szProductVersion );
3748 DWORD verdword = msi_version_str_to_dword(buffer);
3750 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3751 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3752 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3756 /* Handle Upgrade Codes */
3757 upgrade_code = msi_dup_property( package, szUpgradeCode );
3762 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3763 squash_guid(package->ProductCode,squashed);
3764 msi_reg_set_val_str( hkey2, squashed, NULL );
3766 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3767 squash_guid(package->ProductCode,squashed);
3768 msi_reg_set_val_str( hkey2, squashed, NULL );
3771 msi_free(upgrade_code);
3776 /* FIXME: call ui_actiondata */
3778 return ERROR_SUCCESS;
3781 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3783 return execute_script(package,INSTALL_SCRIPT);
3786 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3790 /* turn off scheduleing */
3791 package->script->CurrentlyScripting= FALSE;
3793 /* first do the same as an InstallExecute */
3794 rc = ACTION_InstallExecute(package);
3795 if (rc != ERROR_SUCCESS)
3798 /* then handle Commit Actions */
3799 rc = execute_script(package,COMMIT_SCRIPT);
3804 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3806 static const WCHAR RunOnce[] = {
3807 'S','o','f','t','w','a','r','e','\\',
3808 'M','i','c','r','o','s','o','f','t','\\',
3809 'W','i','n','d','o','w','s','\\',
3810 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3811 'R','u','n','O','n','c','e',0};
3812 static const WCHAR InstallRunOnce[] = {
3813 'S','o','f','t','w','a','r','e','\\',
3814 'M','i','c','r','o','s','o','f','t','\\',
3815 'W','i','n','d','o','w','s','\\',
3816 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3817 'I','n','s','t','a','l','l','e','r','\\',
3818 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3820 static const WCHAR msiexec_fmt[] = {
3822 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3823 '\"','%','s','\"',0};
3824 static const WCHAR install_fmt[] = {
3825 '/','I',' ','\"','%','s','\"',' ',
3826 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3827 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3828 WCHAR buffer[256], sysdir[MAX_PATH];
3830 WCHAR squished_pc[100];
3832 squash_guid(package->ProductCode,squished_pc);
3834 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3835 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3836 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3839 msi_reg_set_val_str( hkey, squished_pc, buffer );
3842 TRACE("Reboot command %s\n",debugstr_w(buffer));
3844 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3845 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3847 msi_reg_set_val_str( hkey, squished_pc, buffer );
3850 return ERROR_INSTALL_SUSPEND;
3853 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3860 * we are currently doing what should be done here in the top level Install
3861 * however for Adminastrative and uninstalls this step will be needed
3863 if (!package->PackagePath)
3864 return ERROR_SUCCESS;
3866 ptr = strrchrW(package->PackagePath, '\\');
3868 return ERROR_SUCCESS;
3870 len = ptr - package->PackagePath + 2;
3871 source = msi_alloc(len * sizeof(WCHAR));
3872 lstrcpynW(source, package->PackagePath, len);
3874 MSI_SetPropertyW(package, cszSourceDir, source);
3875 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3879 attrib = GetFileAttributesW(package->PackagePath);
3880 if (attrib == INVALID_FILE_ATTRIBUTES)
3886 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3887 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3888 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3889 if (rc == ERROR_MORE_DATA)
3891 prompt = msi_alloc(size * sizeof(WCHAR));
3892 MsiSourceListGetInfoW(package->ProductCode, NULL,
3893 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3894 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3897 prompt = strdupW(package->PackagePath);
3899 msg = generate_error_string(package,1302,1,prompt);
3900 while(attrib == INVALID_FILE_ATTRIBUTES)
3902 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3905 rc = ERROR_INSTALL_USEREXIT;
3908 attrib = GetFileAttributesW(package->PackagePath);
3914 return ERROR_SUCCESS;
3919 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3926 static const WCHAR szPropKeys[][80] =
3928 {'P','r','o','d','u','c','t','I','D',0},
3929 {'U','S','E','R','N','A','M','E',0},
3930 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3934 static const WCHAR szRegKeys[][80] =
3936 {'P','r','o','d','u','c','t','I','D',0},
3937 {'R','e','g','O','w','n','e','r',0},
3938 {'R','e','g','C','o','m','p','a','n','y',0},
3942 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3944 return ERROR_SUCCESS;
3946 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3947 if (rc != ERROR_SUCCESS)
3950 for( i = 0; szPropKeys[i][0]; i++ )
3952 buffer = msi_dup_property( package, szPropKeys[i] );
3953 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3958 msi_free(productid);
3961 /* FIXME: call ui_actiondata */
3963 return ERROR_SUCCESS;
3967 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3971 package->script->InWhatSequence |= SEQUENCE_EXEC;
3972 rc = ACTION_ProcessExecSequence(package,FALSE);
3977 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3979 MSIPACKAGE *package = (MSIPACKAGE*)param;
3980 LPCWSTR compgroupid=NULL;
3981 LPCWSTR feature=NULL;
3982 LPCWSTR text = NULL;
3983 LPCWSTR qualifier = NULL;
3984 LPCWSTR component = NULL;
3985 LPWSTR advertise = NULL;
3986 LPWSTR output = NULL;
3988 UINT rc = ERROR_SUCCESS;
3993 component = MSI_RecordGetString(rec,3);
3994 comp = get_loaded_component(package,component);
3996 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3997 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3998 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4000 TRACE("Skipping: Component %s not scheduled for install\n",
4001 debugstr_w(component));
4003 return ERROR_SUCCESS;
4006 compgroupid = MSI_RecordGetString(rec,1);
4007 qualifier = MSI_RecordGetString(rec,2);
4009 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4010 if (rc != ERROR_SUCCESS)
4013 text = MSI_RecordGetString(rec,4);
4014 feature = MSI_RecordGetString(rec,5);
4016 advertise = create_component_advertise_string(package, comp, feature);
4018 sz = strlenW(advertise);
4021 sz += lstrlenW(text);
4024 sz *= sizeof(WCHAR);
4026 output = msi_alloc_zero(sz);
4027 strcpyW(output,advertise);
4028 msi_free(advertise);
4031 strcatW(output,text);
4033 msi_reg_set_val_multi_str( hkey, qualifier, output );
4040 uirow = MSI_CreateRecord( 2 );
4041 MSI_RecordSetStringW( uirow, 1, compgroupid );
4042 MSI_RecordSetStringW( uirow, 2, qualifier);
4043 ui_actiondata( package, szPublishComponents, uirow);
4044 msiobj_release( &uirow->hdr );
4045 /* FIXME: call ui_progress? */
4051 * At present I am ignorning the advertised components part of this and only
4052 * focusing on the qualified component sets
4054 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4058 static const WCHAR ExecSeqQuery[] =
4059 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4060 '`','P','u','b','l','i','s','h',
4061 'C','o','m','p','o','n','e','n','t','`',0};
4063 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4064 if (rc != ERROR_SUCCESS)
4065 return ERROR_SUCCESS;
4067 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4068 msiobj_release(&view->hdr);
4073 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4075 MSIPACKAGE *package = (MSIPACKAGE*)param;
4078 SC_HANDLE hscm, service = NULL;
4079 LPCWSTR name, disp, comp, depends, pass;
4080 LPCWSTR load_order, serv_name, key;
4081 DWORD serv_type, start_type;
4084 static const WCHAR query[] =
4085 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4086 '`','C','o','m','p','o','n','e','n','t','`',' ',
4087 'W','H','E','R','E',' ',
4088 '`','C','o','m','p','o','n','e','n','t','`',' ',
4089 '=','\'','%','s','\'',0};
4091 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4094 ERR("Failed to open the SC Manager!\n");
4098 start_type = MSI_RecordGetInteger(rec, 5);
4099 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4102 depends = MSI_RecordGetString(rec, 8);
4103 if (depends && *depends)
4104 FIXME("Dependency list unhandled!\n");
4106 name = MSI_RecordGetString(rec, 2);
4107 disp = MSI_RecordGetString(rec, 3);
4108 serv_type = MSI_RecordGetInteger(rec, 4);
4109 err_control = MSI_RecordGetInteger(rec, 6);
4110 load_order = MSI_RecordGetString(rec, 7);
4111 serv_name = MSI_RecordGetString(rec, 9);
4112 pass = MSI_RecordGetString(rec, 10);
4113 comp = MSI_RecordGetString(rec, 12);
4115 /* fetch the service path */
4116 row = MSI_QueryGetRecord(package->db, query, comp);
4119 ERR("Control query failed!\n");
4123 key = MSI_RecordGetString(row, 6);
4124 msiobj_release(&row->hdr);
4126 file = get_loaded_file(package, key);
4129 ERR("Failed to load the service file\n");
4133 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4134 start_type, err_control, file->TargetPath,
4135 load_order, NULL, NULL, serv_name, pass);
4138 if (GetLastError() != ERROR_SERVICE_EXISTS)
4139 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4143 CloseServiceHandle(service);
4144 CloseServiceHandle(hscm);
4146 return ERROR_SUCCESS;
4149 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4153 static const WCHAR ExecSeqQuery[] =
4154 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4155 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4157 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4158 if (rc != ERROR_SUCCESS)
4159 return ERROR_SUCCESS;
4161 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4162 msiobj_release(&view->hdr);
4167 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4168 LPCSTR action, LPCWSTR table )
4170 static const WCHAR query[] = {
4171 'S','E','L','E','C','T',' ','*',' ',
4172 'F','R','O','M',' ','`','%','s','`',0 };
4173 MSIQUERY *view = NULL;
4177 r = MSI_OpenQuery( package->db, &view, query, table );
4178 if (r == ERROR_SUCCESS)
4180 r = MSI_IterateRecords(view, &count, NULL, package);
4181 msiobj_release(&view->hdr);
4185 FIXME("%s -> %u ignored %s table values\n",
4186 action, count, debugstr_w(table));
4188 return ERROR_SUCCESS;
4191 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4193 TRACE("%p\n", package);
4194 return ERROR_SUCCESS;
4197 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4199 static const WCHAR table[] =
4200 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4201 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4204 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4206 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4207 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4210 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4212 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4213 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4216 static UINT ACTION_BindImage( MSIPACKAGE *package )
4218 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4219 return msi_unimplemented_action_stub( package, "BindImage", table );
4222 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4224 static const WCHAR table[] = {
4225 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4226 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4229 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4231 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4232 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4235 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4237 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4238 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4241 static UINT ACTION_StartServices( MSIPACKAGE *package )
4243 static const WCHAR table[] = {
4244 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4245 return msi_unimplemented_action_stub( package, "StartServices", table );
4248 static UINT ACTION_StopServices( MSIPACKAGE *package )
4250 static const WCHAR table[] = {
4251 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4252 return msi_unimplemented_action_stub( package, "StopServices", table );
4255 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4257 static const WCHAR table[] = {
4258 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4259 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4262 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4264 static const WCHAR table[] = {
4265 'E','n','v','i','r','o','n','m','e','n','t',0 };
4266 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4269 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4271 static const WCHAR table[] = {
4272 'E','n','v','i','r','o','n','m','e','n','t',0 };
4273 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4276 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4278 static const WCHAR table[] = {
4279 'M','s','i','A','s','s','e','m','b','l','y',0 };
4280 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4283 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4285 static const WCHAR table[] = {
4286 'M','s','i','A','s','s','e','m','b','l','y',0 };
4287 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4290 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4292 static const WCHAR table[] = { 'F','o','n','t',0 };
4293 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4296 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4298 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4299 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4302 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4304 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4305 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4308 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4310 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4311 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4314 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4316 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4317 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4320 static struct _actions StandardActions[] = {
4321 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4322 { szAppSearch, ACTION_AppSearch },
4323 { szBindImage, ACTION_BindImage },
4324 { szCCPSearch, ACTION_CCPSearch},
4325 { szCostFinalize, ACTION_CostFinalize },
4326 { szCostInitialize, ACTION_CostInitialize },
4327 { szCreateFolders, ACTION_CreateFolders },
4328 { szCreateShortcuts, ACTION_CreateShortcuts },
4329 { szDeleteServices, ACTION_DeleteServices },
4330 { szDisableRollback, NULL},
4331 { szDuplicateFiles, ACTION_DuplicateFiles },
4332 { szExecuteAction, ACTION_ExecuteAction },
4333 { szFileCost, ACTION_FileCost },
4334 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4335 { szForceReboot, ACTION_ForceReboot },
4336 { szInstallAdminPackage, NULL},
4337 { szInstallExecute, ACTION_InstallExecute },
4338 { szInstallExecuteAgain, ACTION_InstallExecute },
4339 { szInstallFiles, ACTION_InstallFiles},
4340 { szInstallFinalize, ACTION_InstallFinalize },
4341 { szInstallInitialize, ACTION_InstallInitialize },
4342 { szInstallSFPCatalogFile, NULL},
4343 { szInstallValidate, ACTION_InstallValidate },
4344 { szIsolateComponents, ACTION_IsolateComponents },
4345 { szLaunchConditions, ACTION_LaunchConditions },
4346 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4347 { szMoveFiles, ACTION_MoveFiles },
4348 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4349 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4350 { szInstallODBC, NULL},
4351 { szInstallServices, ACTION_InstallServices },
4352 { szPatchFiles, ACTION_PatchFiles },
4353 { szProcessComponents, ACTION_ProcessComponents },
4354 { szPublishComponents, ACTION_PublishComponents },
4355 { szPublishFeatures, ACTION_PublishFeatures },
4356 { szPublishProduct, ACTION_PublishProduct },
4357 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4358 { szRegisterComPlus, ACTION_RegisterComPlus},
4359 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4360 { szRegisterFonts, ACTION_RegisterFonts },
4361 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4362 { szRegisterProduct, ACTION_RegisterProduct },
4363 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4364 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4365 { szRegisterUser, ACTION_RegisterUser},
4366 { szRemoveDuplicateFiles, NULL},
4367 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4368 { szRemoveExistingProducts, NULL},
4369 { szRemoveFiles, ACTION_RemoveFiles},
4370 { szRemoveFolders, NULL},
4371 { szRemoveIniValues, ACTION_RemoveIniValues },
4372 { szRemoveODBC, NULL},
4373 { szRemoveRegistryValues, NULL},
4374 { szRemoveShortcuts, NULL},
4375 { szResolveSource, ACTION_ResolveSource},
4376 { szRMCCPSearch, ACTION_RMCCPSearch},
4377 { szScheduleReboot, NULL},
4378 { szSelfRegModules, ACTION_SelfRegModules },
4379 { szSelfUnregModules, ACTION_SelfUnregModules },
4380 { szSetODBCFolders, NULL},
4381 { szStartServices, ACTION_StartServices },
4382 { szStopServices, ACTION_StopServices },
4383 { szUnpublishComponents, NULL},
4384 { szUnpublishFeatures, NULL},
4385 { szUnregisterClassInfo, NULL},
4386 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4387 { szUnregisterExtensionInfo, NULL},
4388 { szUnregisterFonts, ACTION_UnregisterFonts },
4389 { szUnregisterMIMEInfo, NULL},
4390 { szUnregisterProgIdInfo, NULL},
4391 { szUnregisterTypeLibraries, NULL},
4392 { szValidateProductID, NULL},
4393 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4394 { szWriteIniValues, ACTION_WriteIniValues },
4395 { szWriteRegistryValues, ACTION_WriteRegistryValues},