2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
38 #include "wine/debug.h"
43 #include "wine/unicode.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 sprintfW(message,template_s,timet,action);
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
300 LPWSTR prop = NULL, val = NULL;
303 return ERROR_SUCCESS;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
368 LPWSTR p, *ret = NULL;
374 /* count the number of substrings */
375 for ( pc = str, count = 0; pc; count++ )
377 pc = strchrW( pc, sep );
382 /* allocate space for an array of substring pointers and the substrings */
383 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384 (lstrlenW(str)+1) * sizeof(WCHAR) );
388 /* copy the string and set the pointers */
389 p = (LPWSTR) &ret[count+1];
391 for( count = 0; (ret[count] = p); count++ )
393 p = strchrW( p, sep );
401 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
403 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
404 LPWSTR prod_code, patch_product;
407 prod_code = msi_dup_property( package, szProductCode );
408 patch_product = msi_get_suminfo_product( patch );
410 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
412 if ( strstrW( patch_product, prod_code ) )
415 ret = ERROR_FUNCTION_FAILED;
417 msi_free( patch_product );
418 msi_free( prod_code );
423 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
424 MSIDATABASE *patch_db, LPCWSTR name )
426 UINT ret = ERROR_FUNCTION_FAILED;
427 IStorage *stg = NULL;
430 TRACE("%p %s\n", package, debugstr_w(name) );
434 ERR("expected a colon in %s\n", debugstr_w(name));
435 return ERROR_FUNCTION_FAILED;
438 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
441 ret = msi_check_transform_applicable( package, stg );
442 if (ret == ERROR_SUCCESS)
443 msi_table_apply_transform( package->db, stg );
445 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
446 IStorage_Release( stg );
449 ERR("failed to open substorage %s\n", debugstr_w(name));
451 return ERROR_SUCCESS;
454 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
456 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
457 LPWSTR guid_list, *guids, product_id;
458 UINT i, ret = ERROR_FUNCTION_FAILED;
460 product_id = msi_dup_property( package, szProdID );
463 /* FIXME: the property ProductID should be written into the DB somewhere */
464 ERR("no product ID to check\n");
465 return ERROR_SUCCESS;
468 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
469 guids = msi_split_string( guid_list, ';' );
470 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
472 if (!lstrcmpW( guids[i], product_id ))
476 msi_free( guid_list );
477 msi_free( product_id );
482 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
485 LPWSTR str, *substorage;
486 UINT i, r = ERROR_SUCCESS;
488 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
490 return ERROR_FUNCTION_FAILED;
492 msi_check_patch_applicable( package, si );
494 /* enumerate the substorage */
495 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
496 substorage = msi_split_string( str, ';' );
497 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
498 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
499 msi_free( substorage );
502 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
504 msiobj_release( &si->hdr );
509 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
511 MSIDATABASE *patch_db = NULL;
514 TRACE("%p %s\n", package, debugstr_w( file ) );
517 * We probably want to make sure we only open a patch collection here.
518 * Patch collections (.msp) and databases (.msi) have different GUIDs
519 * but currently MSI_OpenDatabaseW will accept both.
521 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
522 if ( r != ERROR_SUCCESS )
524 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
528 msi_parse_patch_summary( package, patch_db );
531 * There might be a CAB file in the patch package,
532 * so append it to the list of storage to search for streams.
534 append_storage_to_db( package->db, patch_db->storage );
536 msiobj_release( &patch_db->hdr );
538 return ERROR_SUCCESS;
541 /* get the PATCH property, and apply all the patches it specifies */
542 static UINT msi_apply_patches( MSIPACKAGE *package )
544 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
545 LPWSTR patch_list, *patches;
546 UINT i, r = ERROR_SUCCESS;
548 patch_list = msi_dup_property( package, szPatch );
550 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
552 patches = msi_split_string( patch_list, ';' );
553 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
554 r = msi_apply_patch_package( package, patches[i] );
557 msi_free( patch_list );
562 static UINT msi_apply_transforms( MSIPACKAGE *package )
564 static const WCHAR szTransforms[] = {
565 'T','R','A','N','S','F','O','R','M','S',0 };
566 LPWSTR xform_list, *xforms;
567 UINT i, r = ERROR_SUCCESS;
569 xform_list = msi_dup_property( package, szTransforms );
570 xforms = msi_split_string( xform_list, ';' );
572 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
574 if (xforms[i][0] == ':')
575 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
577 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
581 msi_free( xform_list );
586 /****************************************************
587 * TOP level entry points
588 *****************************************************/
590 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
591 LPCWSTR szCommandLine )
595 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
596 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
597 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
599 MSI_SetPropertyW(package, szAction, szInstall);
601 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
603 package->script->InWhatSequence = SEQUENCE_INSTALL;
607 LPWSTR p, check, path;
609 path = strdupW(szPackagePath);
610 p = strrchrW(path,'\\');
619 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
620 GetCurrentDirectoryW(MAX_PATH,path);
624 check = msi_dup_property( package, cszSourceDir );
626 MSI_SetPropertyW(package, cszSourceDir, path);
629 check = msi_dup_property( package, cszSOURCEDIR );
631 MSI_SetPropertyW(package, cszSOURCEDIR, path);
633 msi_free( package->PackagePath );
634 package->PackagePath = path;
639 msi_parse_command_line( package, szCommandLine );
641 msi_apply_transforms( package );
642 msi_apply_patches( package );
644 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
646 package->script->InWhatSequence |= SEQUENCE_UI;
647 rc = ACTION_ProcessUISequence(package);
649 if (rc == ERROR_SUCCESS)
651 package->script->InWhatSequence |= SEQUENCE_EXEC;
652 rc = ACTION_ProcessExecSequence(package,TRUE);
656 rc = ACTION_ProcessExecSequence(package,FALSE);
660 /* install was halted but should be considered a success */
664 package->script->CurrentlyScripting= FALSE;
666 /* process the ending type action */
667 if (rc == ERROR_SUCCESS)
668 ACTION_PerformActionSequence(package,-1,ui);
669 else if (rc == ERROR_INSTALL_USEREXIT)
670 ACTION_PerformActionSequence(package,-2,ui);
671 else if (rc == ERROR_INSTALL_SUSPEND)
672 ACTION_PerformActionSequence(package,-4,ui);
674 ACTION_PerformActionSequence(package,-3,ui);
676 /* finish up running custom actions */
677 ACTION_FinishCustomActions(package);
682 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
684 UINT rc = ERROR_SUCCESS;
686 static const WCHAR ExecSeqQuery[] =
687 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
688 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
689 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
690 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
692 static const WCHAR UISeqQuery[] =
693 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
694 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
695 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
696 ' ', '=',' ','%','i',0};
699 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
701 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
705 LPCWSTR action, cond;
707 TRACE("Running the actions\n");
709 /* check conditions */
710 cond = MSI_RecordGetString(row,2);
712 /* this is a hack to skip errors in the condition code */
713 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
716 action = MSI_RecordGetString(row,1);
719 ERR("failed to fetch action\n");
720 rc = ERROR_FUNCTION_FAILED;
725 rc = ACTION_PerformUIAction(package,action);
727 rc = ACTION_PerformAction(package,action,FALSE);
729 msiobj_release(&row->hdr);
740 } iterate_action_param;
742 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
744 iterate_action_param *iap= (iterate_action_param*)param;
746 LPCWSTR cond, action;
748 action = MSI_RecordGetString(row,1);
751 ERR("Error is retrieving action name\n");
752 return ERROR_FUNCTION_FAILED;
755 /* check conditions */
756 cond = MSI_RecordGetString(row,2);
758 /* this is a hack to skip errors in the condition code */
759 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
761 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
762 return ERROR_SUCCESS;
766 rc = ACTION_PerformUIAction(iap->package,action);
768 rc = ACTION_PerformAction(iap->package,action,FALSE);
770 msi_dialog_check_messages( NULL );
772 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
773 rc = iap->package->CurrentInstallState;
775 if (rc == ERROR_FUNCTION_NOT_CALLED)
778 if (rc != ERROR_SUCCESS)
779 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
784 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
788 static const WCHAR query[] =
789 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
791 ' ','W','H','E','R','E',' ',
792 '`','S','e','q','u','e','n','c','e','`',' ',
793 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
794 '`','S','e','q','u','e','n','c','e','`',0};
795 iterate_action_param iap;
798 * FIXME: probably should be checking UILevel in the
799 * ACTION_PerformUIAction/ACTION_PerformAction
800 * rather than saving the UI level here. Those
801 * two functions can be merged too.
803 iap.package = package;
806 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
808 r = MSI_OpenQuery( package->db, &view, query, szTable );
809 if (r == ERROR_SUCCESS)
811 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
812 msiobj_release(&view->hdr);
818 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
822 static const WCHAR ExecSeqQuery[] =
823 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
824 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
825 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
826 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
827 'O','R','D','E','R',' ', 'B','Y',' ',
828 '`','S','e','q','u','e','n','c','e','`',0 };
830 static const WCHAR IVQuery[] =
831 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
832 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
833 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
834 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
835 ' ','\'', 'I','n','s','t','a','l','l',
836 'V','a','l','i','d','a','t','e','\'', 0};
838 iterate_action_param iap;
840 iap.package = package;
843 if (package->script->ExecuteSequenceRun)
845 TRACE("Execute Sequence already Run\n");
846 return ERROR_SUCCESS;
849 package->script->ExecuteSequenceRun = TRUE;
851 /* get the sequence number */
854 row = MSI_QueryGetRecord(package->db, IVQuery);
856 return ERROR_FUNCTION_FAILED;
857 seq = MSI_RecordGetInteger(row,1);
858 msiobj_release(&row->hdr);
861 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
862 if (rc == ERROR_SUCCESS)
864 TRACE("Running the actions\n");
866 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
867 msiobj_release(&view->hdr);
873 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
877 static const WCHAR ExecSeqQuery [] =
878 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879 '`','I','n','s','t','a','l','l',
880 'U','I','S','e','q','u','e','n','c','e','`',
881 ' ','W','H','E','R','E',' ',
882 '`','S','e','q','u','e','n','c','e','`',' ',
883 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
884 '`','S','e','q','u','e','n','c','e','`',0};
885 iterate_action_param iap;
887 iap.package = package;
890 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
892 if (rc == ERROR_SUCCESS)
894 TRACE("Running the actions\n");
896 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
897 msiobj_release(&view->hdr);
903 /********************************************************
904 * ACTION helper functions and functions that perform the actions
905 *******************************************************/
906 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
907 UINT* rc, BOOL force )
913 if (!run && !package->script->CurrentlyScripting)
918 if (strcmpW(action,szInstallFinalize) == 0 ||
919 strcmpW(action,szInstallExecute) == 0 ||
920 strcmpW(action,szInstallExecuteAgain) == 0)
925 while (StandardActions[i].action != NULL)
927 if (strcmpW(StandardActions[i].action, action)==0)
931 ui_actioninfo(package, action, TRUE, 0);
932 *rc = schedule_action(package,INSTALL_SCRIPT,action);
933 ui_actioninfo(package, action, FALSE, *rc);
937 ui_actionstart(package, action);
938 if (StandardActions[i].handler)
940 *rc = StandardActions[i].handler(package);
944 FIXME("unhandled standard action %s\n",debugstr_w(action));
956 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
957 UINT* rc, BOOL force )
962 arc = ACTION_CustomAction(package,action, force);
964 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
973 * A lot of actions are really important even if they don't do anything
974 * explicit... Lots of properties are set at the beginning of the installation
975 * CostFinalize does a bunch of work to translate the directories and such
977 * But until I get write access to the database that is hard, so I am going to
978 * hack it to see if I can get something to run.
980 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
982 UINT rc = ERROR_SUCCESS;
985 TRACE("Performing action (%s)\n",debugstr_w(action));
987 handled = ACTION_HandleStandardAction(package, action, &rc, force);
990 handled = ACTION_HandleCustomAction(package, action, &rc, force);
994 FIXME("unhandled msi action %s\n",debugstr_w(action));
995 rc = ERROR_FUNCTION_NOT_CALLED;
1001 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1003 UINT rc = ERROR_SUCCESS;
1004 BOOL handled = FALSE;
1006 TRACE("Performing action (%s)\n",debugstr_w(action));
1008 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1011 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1013 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1018 FIXME("unhandled msi action %s\n",debugstr_w(action));
1019 rc = ERROR_FUNCTION_NOT_CALLED;
1027 * Actual Action Handlers
1030 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1032 MSIPACKAGE *package = (MSIPACKAGE*)param;
1038 dir = MSI_RecordGetString(row,1);
1041 ERR("Unable to get folder id\n");
1042 return ERROR_SUCCESS;
1045 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1048 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1049 return ERROR_SUCCESS;
1052 TRACE("Folder is %s\n",debugstr_w(full_path));
1055 uirow = MSI_CreateRecord(1);
1056 MSI_RecordSetStringW(uirow,1,full_path);
1057 ui_actiondata(package,szCreateFolders,uirow);
1058 msiobj_release( &uirow->hdr );
1060 if (folder->State == 0)
1061 create_full_pathW(full_path);
1065 msi_free(full_path);
1066 return ERROR_SUCCESS;
1069 /* FIXME: probably should merge this with the above function */
1070 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1072 UINT rc = ERROR_SUCCESS;
1074 LPWSTR install_path;
1076 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1078 return ERROR_FUNCTION_FAILED;
1080 /* create the path */
1081 if (folder->State == 0)
1083 create_full_pathW(install_path);
1086 msi_free(install_path);
1091 UINT msi_create_component_directories( MSIPACKAGE *package )
1095 /* create all the folders required by the components are going to install */
1096 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1098 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1100 msi_create_directory( package, comp->Directory );
1103 return ERROR_SUCCESS;
1107 * Also we cannot enable/disable components either, so for now I am just going
1108 * to do all the directories for all the components.
1110 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1112 static const WCHAR ExecSeqQuery[] =
1113 {'S','E','L','E','C','T',' ',
1114 '`','D','i','r','e','c','t','o','r','y','_','`',
1115 ' ','F','R','O','M',' ',
1116 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1120 /* create all the empty folders specified in the CreateFolder table */
1121 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1126 msiobj_release(&view->hdr);
1128 msi_create_component_directories( package );
1133 static UINT load_component( MSIRECORD *row, LPVOID param )
1135 MSIPACKAGE *package = param;
1138 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1140 return ERROR_FUNCTION_FAILED;
1142 list_add_tail( &package->components, &comp->entry );
1144 /* fill in the data */
1145 comp->Component = msi_dup_record_field( row, 1 );
1147 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1149 comp->ComponentId = msi_dup_record_field( row, 2 );
1150 comp->Directory = msi_dup_record_field( row, 3 );
1151 comp->Attributes = MSI_RecordGetInteger(row,4);
1152 comp->Condition = msi_dup_record_field( row, 5 );
1153 comp->KeyPath = msi_dup_record_field( row, 6 );
1155 comp->Installed = INSTALLSTATE_UNKNOWN;
1156 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1158 return ERROR_SUCCESS;
1161 static UINT load_all_components( MSIPACKAGE *package )
1163 static const WCHAR query[] = {
1164 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1165 '`','C','o','m','p','o','n','e','n','t','`',0 };
1169 if (!list_empty(&package->components))
1170 return ERROR_SUCCESS;
1172 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1173 if (r != ERROR_SUCCESS)
1176 r = MSI_IterateRecords(view, NULL, load_component, package);
1177 msiobj_release(&view->hdr);
1182 MSIPACKAGE *package;
1183 MSIFEATURE *feature;
1186 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1190 cl = msi_alloc( sizeof (*cl) );
1192 return ERROR_NOT_ENOUGH_MEMORY;
1193 cl->component = comp;
1194 list_add_tail( &feature->Components, &cl->entry );
1196 return ERROR_SUCCESS;
1199 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1203 fl = msi_alloc( sizeof(*fl) );
1205 return ERROR_NOT_ENOUGH_MEMORY;
1206 fl->feature = child;
1207 list_add_tail( &parent->Children, &fl->entry );
1209 return ERROR_SUCCESS;
1212 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1214 _ilfs* ilfs= (_ilfs*)param;
1218 component = MSI_RecordGetString(row,1);
1220 /* check to see if the component is already loaded */
1221 comp = get_loaded_component( ilfs->package, component );
1224 ERR("unknown component %s\n", debugstr_w(component));
1225 return ERROR_FUNCTION_FAILED;
1228 add_feature_component( ilfs->feature, comp );
1229 comp->Enabled = TRUE;
1231 return ERROR_SUCCESS;
1234 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1236 MSIFEATURE *feature;
1238 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1240 if ( !lstrcmpW( feature->Feature, name ) )
1247 static UINT load_feature(MSIRECORD * row, LPVOID param)
1249 MSIPACKAGE* package = (MSIPACKAGE*)param;
1250 MSIFEATURE* feature;
1251 static const WCHAR Query1[] =
1252 {'S','E','L','E','C','T',' ',
1253 '`','C','o','m','p','o','n','e','n','t','_','`',
1254 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1255 'C','o','m','p','o','n','e','n','t','s','`',' ',
1256 'W','H','E','R','E',' ',
1257 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1262 /* fill in the data */
1264 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1266 return ERROR_NOT_ENOUGH_MEMORY;
1268 list_init( &feature->Children );
1269 list_init( &feature->Components );
1271 feature->Feature = msi_dup_record_field( row, 1 );
1273 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1275 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1276 feature->Title = msi_dup_record_field( row, 3 );
1277 feature->Description = msi_dup_record_field( row, 4 );
1279 if (!MSI_RecordIsNull(row,5))
1280 feature->Display = MSI_RecordGetInteger(row,5);
1282 feature->Level= MSI_RecordGetInteger(row,6);
1283 feature->Directory = msi_dup_record_field( row, 7 );
1284 feature->Attributes = MSI_RecordGetInteger(row,8);
1286 feature->Installed = INSTALLSTATE_UNKNOWN;
1287 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1289 list_add_tail( &package->features, &feature->entry );
1291 /* load feature components */
1293 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1294 if (rc != ERROR_SUCCESS)
1295 return ERROR_SUCCESS;
1297 ilfs.package = package;
1298 ilfs.feature = feature;
1300 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1301 msiobj_release(&view->hdr);
1303 return ERROR_SUCCESS;
1306 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1308 MSIPACKAGE* package = (MSIPACKAGE*)param;
1309 MSIFEATURE *parent, *child;
1311 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1313 return ERROR_FUNCTION_FAILED;
1315 if (!child->Feature_Parent)
1316 return ERROR_SUCCESS;
1318 parent = find_feature_by_name( package, child->Feature_Parent );
1320 return ERROR_FUNCTION_FAILED;
1322 add_feature_child( parent, child );
1323 return ERROR_SUCCESS;
1326 static UINT load_all_features( MSIPACKAGE *package )
1328 static const WCHAR query[] = {
1329 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1330 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1331 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1335 if (!list_empty(&package->features))
1336 return ERROR_SUCCESS;
1338 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1339 if (r != ERROR_SUCCESS)
1342 r = MSI_IterateRecords( view, NULL, load_feature, package );
1343 if (r != ERROR_SUCCESS)
1346 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1347 msiobj_release( &view->hdr );
1352 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1363 static UINT load_file(MSIRECORD *row, LPVOID param)
1365 MSIPACKAGE* package = (MSIPACKAGE*)param;
1369 /* fill in the data */
1371 file = msi_alloc_zero( sizeof (MSIFILE) );
1373 return ERROR_NOT_ENOUGH_MEMORY;
1375 file->File = msi_dup_record_field( row, 1 );
1377 component = MSI_RecordGetString( row, 2 );
1378 file->Component = get_loaded_component( package, component );
1380 if (!file->Component)
1381 ERR("Unfound Component %s\n",debugstr_w(component));
1383 file->FileName = msi_dup_record_field( row, 3 );
1384 reduce_to_longfilename( file->FileName );
1386 file->ShortName = msi_dup_record_field( row, 3 );
1387 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1389 file->FileSize = MSI_RecordGetInteger( row, 4 );
1390 file->Version = msi_dup_record_field( row, 5 );
1391 file->Language = msi_dup_record_field( row, 6 );
1392 file->Attributes = MSI_RecordGetInteger( row, 7 );
1393 file->Sequence = MSI_RecordGetInteger( row, 8 );
1395 file->state = msifs_invalid;
1397 /* if the compressed bits are not set in the file attributes,
1398 * then read the information from the package word count property
1400 if (file->Attributes & msidbFileAttributesCompressed)
1402 file->IsCompressed = TRUE;
1404 else if (file->Attributes & msidbFileAttributesNoncompressed)
1406 file->IsCompressed = FALSE;
1410 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1413 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1415 list_add_tail( &package->files, &file->entry );
1417 return ERROR_SUCCESS;
1420 static UINT load_all_files(MSIPACKAGE *package)
1424 static const WCHAR Query[] =
1425 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1426 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1427 '`','S','e','q','u','e','n','c','e','`', 0};
1429 if (!list_empty(&package->files))
1430 return ERROR_SUCCESS;
1432 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1433 if (rc != ERROR_SUCCESS)
1434 return ERROR_SUCCESS;
1436 rc = MSI_IterateRecords(view, NULL, load_file, package);
1437 msiobj_release(&view->hdr);
1439 return ERROR_SUCCESS;
1444 * I am not doing any of the costing functionality yet.
1445 * Mostly looking at doing the Component and Feature loading
1447 * The native MSI does A LOT of modification to tables here. Mostly adding
1448 * a lot of temporary columns to the Feature and Component tables.
1450 * note: Native msi also tracks the short filename. But I am only going to
1451 * track the long ones. Also looking at this directory table
1452 * it appears that the directory table does not get the parents
1453 * resolved base on property only based on their entries in the
1456 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1458 static const WCHAR szCosting[] =
1459 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1460 static const WCHAR szZero[] = { '0', 0 };
1462 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1463 return ERROR_SUCCESS;
1465 MSI_SetPropertyW(package, szCosting, szZero);
1466 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1468 load_all_components( package );
1469 load_all_features( package );
1470 load_all_files( package );
1472 return ERROR_SUCCESS;
1475 static UINT execute_script(MSIPACKAGE *package, UINT script )
1478 UINT rc = ERROR_SUCCESS;
1480 TRACE("Executing Script %i\n",script);
1482 if (!package->script)
1484 ERR("no script!\n");
1485 return ERROR_FUNCTION_FAILED;
1488 for (i = 0; i < package->script->ActionCount[script]; i++)
1491 action = package->script->Actions[script][i];
1492 ui_actionstart(package, action);
1493 TRACE("Executing Action (%s)\n",debugstr_w(action));
1494 rc = ACTION_PerformAction(package, action, TRUE);
1495 if (rc != ERROR_SUCCESS)
1498 msi_free_action_script(package, script);
1502 static UINT ACTION_FileCost(MSIPACKAGE *package)
1504 return ERROR_SUCCESS;
1507 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1509 static const WCHAR Query[] =
1510 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1511 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1512 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1513 ' ','=',' ','\'','%','s','\'',
1515 static const WCHAR szDot[] = { '.',0 };
1516 static WCHAR szEmpty[] = { 0 };
1517 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1522 TRACE("Looking for dir %s\n",debugstr_w(dir));
1524 folder = get_loaded_folder( package, dir );
1528 TRACE("Working to load %s\n",debugstr_w(dir));
1530 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1534 folder->Directory = strdupW(dir);
1536 row = MSI_QueryGetRecord(package->db, Query, dir);
1540 p = msi_dup_record_field(row, 3);
1542 /* split src and target dir */
1544 src_short = folder_split_path( p, ':' );
1546 /* split the long and short paths */
1547 tgt_long = folder_split_path( tgt_short, '|' );
1548 src_long = folder_split_path( src_short, '|' );
1550 /* check for no-op dirs */
1551 if (!lstrcmpW(szDot, tgt_short))
1552 tgt_short = szEmpty;
1553 if (!lstrcmpW(szDot, src_short))
1554 src_short = szEmpty;
1557 tgt_long = tgt_short;
1560 src_short = tgt_short;
1561 src_long = tgt_long;
1565 src_long = src_short;
1567 /* FIXME: use the target short path too */
1568 folder->TargetDefault = strdupW(tgt_long);
1569 folder->SourceShortPath = strdupW(src_short);
1570 folder->SourceLongPath = strdupW(src_long);
1573 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1574 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1575 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1577 parent = MSI_RecordGetString(row, 2);
1580 folder->Parent = load_folder( package, parent );
1581 if ( folder->Parent )
1582 TRACE("loaded parent %p %s\n", folder->Parent,
1583 debugstr_w(folder->Parent->Directory));
1585 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1588 folder->Property = msi_dup_property( package, dir );
1590 msiobj_release(&row->hdr);
1592 list_add_tail( &package->folders, &folder->entry );
1594 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1599 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1603 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1607 if (!comp->ComponentId)
1610 res = MsiGetComponentPathW( package->ProductCode,
1611 comp->ComponentId, NULL, NULL);
1613 res = INSTALLSTATE_ABSENT;
1614 comp->Installed = res;
1618 /* scan for and update current install states */
1619 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1622 MSIFEATURE *feature;
1624 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1627 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1629 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1631 comp= cl->component;
1633 if (!comp->ComponentId)
1635 res = INSTALLSTATE_ABSENT;
1639 if (res == INSTALLSTATE_ABSENT)
1640 res = comp->Installed;
1643 if (res == comp->Installed)
1646 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1647 res != INSTALLSTATE_SOURCE)
1649 res = INSTALLSTATE_INCOMPLETE;
1653 feature->Installed = res;
1657 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1660 static const WCHAR all[]={'A','L','L',0};
1662 MSIFEATURE *feature;
1664 override = msi_dup_property( package, property );
1668 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1670 if (strcmpiW(override,all)==0)
1671 msi_feature_set_state( feature, state );
1674 LPWSTR ptr = override;
1675 LPWSTR ptr2 = strchrW(override,',');
1679 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1680 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1682 msi_feature_set_state( feature, state );
1688 ptr2 = strchrW(ptr,',');
1700 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1703 static const WCHAR szlevel[] =
1704 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1705 static const WCHAR szAddLocal[] =
1706 {'A','D','D','L','O','C','A','L',0};
1707 static const WCHAR szRemove[] =
1708 {'R','E','M','O','V','E',0};
1709 static const WCHAR szReinstall[] =
1710 {'R','E','I','N','S','T','A','L','L',0};
1711 BOOL override = FALSE;
1712 MSICOMPONENT* component;
1713 MSIFEATURE *feature;
1716 /* I do not know if this is where it should happen.. but */
1718 TRACE("Checking Install Level\n");
1720 install_level = msi_get_property_int( package, szlevel, 1 );
1722 /* ok here is the _real_ rub
1723 * all these activation/deactivation things happen in order and things
1724 * later on the list override things earlier on the list.
1725 * 1) INSTALLLEVEL processing
1735 * 11) FILEADDDEFAULT
1736 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1737 * ignored for all the features. seems strange, especially since it is not
1738 * documented anywhere, but it is how it works.
1740 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1741 * REMOVE are the big ones, since we don't handle administrative installs
1744 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1745 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1746 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1750 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1752 BOOL feature_state = ((feature->Level > 0) &&
1753 (feature->Level <= install_level));
1755 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1757 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1758 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1759 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1760 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1762 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1766 /* disable child features of unselected parent features */
1767 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1771 if (feature->Level > 0 && feature->Level <= install_level)
1774 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1775 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1780 /* set the Preselected Property */
1781 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1782 static const WCHAR szOne[] = { '1', 0 };
1784 MSI_SetPropertyW(package,szPreselected,szOne);
1788 * now we want to enable or disable components base on feature
1791 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1795 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1796 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1797 feature->ActionRequest);
1799 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1801 component = cl->component;
1803 switch (component->Attributes)
1805 case msidbComponentAttributesLocalOnly:
1806 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1808 case msidbComponentAttributesSourceOnly:
1809 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1811 case msidbComponentAttributesOptional:
1812 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1815 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1818 if (component->ForceLocalState)
1819 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1821 if (!component->Enabled)
1822 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1823 else if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1825 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1826 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1828 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1830 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1831 (component->Action == INSTALLSTATE_ABSENT) ||
1832 (component->Action == INSTALLSTATE_ADVERTISED) ||
1833 (component->Action == INSTALLSTATE_DEFAULT))
1834 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1836 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1838 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1839 (component->Action == INSTALLSTATE_ABSENT))
1840 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1842 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1844 if (component->Action == INSTALLSTATE_UNKNOWN)
1845 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1847 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1848 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1850 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1851 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1855 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1857 if (component->Action == INSTALLSTATE_DEFAULT)
1859 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1860 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1863 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1864 debugstr_w(component->Component), component->Installed,
1865 component->Action, component->ActionRequest);
1869 return ERROR_SUCCESS;
1872 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1874 MSIPACKAGE *package = (MSIPACKAGE*)param;
1878 name = MSI_RecordGetString(row,1);
1880 /* This helper function now does ALL the work */
1881 TRACE("Dir %s ...\n",debugstr_w(name));
1882 load_folder(package,name);
1883 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1884 TRACE("resolves to %s\n",debugstr_w(path));
1887 return ERROR_SUCCESS;
1890 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1892 MSIPACKAGE *package = (MSIPACKAGE*)param;
1894 MSIFEATURE *feature;
1896 name = MSI_RecordGetString( row, 1 );
1898 feature = get_loaded_feature( package, name );
1900 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1904 Condition = MSI_RecordGetString(row,3);
1906 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1908 int level = MSI_RecordGetInteger(row,2);
1909 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1910 feature->Level = level;
1913 return ERROR_SUCCESS;
1916 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1918 static const WCHAR name_fmt[] =
1919 {'%','u','.','%','u','.','%','u','.','%','u',0};
1920 static WCHAR name[] = {'\\',0};
1921 VS_FIXEDFILEINFO *lpVer;
1922 WCHAR filever[0x100];
1928 TRACE("%s\n", debugstr_w(filename));
1930 versize = GetFileVersionInfoSizeW( filename, &handle );
1934 version = msi_alloc( versize );
1935 GetFileVersionInfoW( filename, 0, versize, version );
1937 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1938 msi_free( version );
1940 sprintfW( filever, name_fmt,
1941 HIWORD(lpVer->dwFileVersionMS),
1942 LOWORD(lpVer->dwFileVersionMS),
1943 HIWORD(lpVer->dwFileVersionLS),
1944 LOWORD(lpVer->dwFileVersionLS));
1946 return strdupW( filever );
1949 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1951 LPWSTR file_version;
1954 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1956 MSICOMPONENT* comp = file->Component;
1962 if (file->IsCompressed)
1963 comp->ForceLocalState = TRUE;
1965 /* calculate target */
1966 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1968 msi_free(file->TargetPath);
1970 TRACE("file %s is named %s\n",
1971 debugstr_w(file->File), debugstr_w(file->FileName));
1973 file->TargetPath = build_directory_name(2, p, file->FileName);
1977 TRACE("file %s resolves to %s\n",
1978 debugstr_w(file->File), debugstr_w(file->TargetPath));
1980 /* don't check files of components that aren't installed */
1981 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1982 comp->Installed == INSTALLSTATE_ABSENT)
1984 file->state = msifs_missing; /* assume files are missing */
1988 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1990 file->state = msifs_missing;
1991 comp->Cost += file->FileSize;
1992 comp->Installed = INSTALLSTATE_INCOMPLETE;
1996 if (file->Version &&
1997 (file_version = msi_get_disk_file_version( file->TargetPath )))
1999 TRACE("new %s old %s\n", debugstr_w(file->Version),
2000 debugstr_w(file_version));
2001 /* FIXME: seems like a bad way to compare version numbers */
2002 if (lstrcmpiW(file_version, file->Version)<0)
2004 file->state = msifs_overwrite;
2005 comp->Cost += file->FileSize;
2006 comp->Installed = INSTALLSTATE_INCOMPLETE;
2009 file->state = msifs_present;
2010 msi_free( file_version );
2013 file->state = msifs_present;
2016 return ERROR_SUCCESS;
2020 * A lot is done in this function aside from just the costing.
2021 * The costing needs to be implemented at some point but for now I am going
2022 * to focus on the directory building
2025 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2027 static const WCHAR ExecSeqQuery[] =
2028 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2029 '`','D','i','r','e','c','t','o','r','y','`',0};
2030 static const WCHAR ConditionQuery[] =
2031 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2032 '`','C','o','n','d','i','t','i','o','n','`',0};
2033 static const WCHAR szCosting[] =
2034 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2035 static const WCHAR szlevel[] =
2036 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2037 static const WCHAR szOne[] = { '1', 0 };
2043 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2044 return ERROR_SUCCESS;
2046 TRACE("Building Directory properties\n");
2048 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2049 if (rc == ERROR_SUCCESS)
2051 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2053 msiobj_release(&view->hdr);
2056 /* read components states from the registry */
2057 ACTION_GetComponentInstallStates(package);
2059 TRACE("File calculations\n");
2060 msi_check_file_install_states( package );
2062 TRACE("Evaluating Condition Table\n");
2064 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2065 if (rc == ERROR_SUCCESS)
2067 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2069 msiobj_release(&view->hdr);
2072 TRACE("Enabling or Disabling Components\n");
2073 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2075 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2077 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2078 comp->Enabled = FALSE;
2082 MSI_SetPropertyW(package,szCosting,szOne);
2083 /* set default run level if not set */
2084 level = msi_dup_property( package, szlevel );
2086 MSI_SetPropertyW(package,szlevel, szOne);
2089 ACTION_UpdateFeatureInstallStates(package);
2091 return MSI_SetFeatureStates(package);
2094 /* OK this value is "interpreted" and then formatted based on the
2095 first few characters */
2096 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2100 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2106 LPWSTR deformated = NULL;
2109 deformat_string(package, &value[2], &deformated);
2111 /* binary value type */
2115 *size = (strlenW(ptr)/2)+1;
2117 *size = strlenW(ptr)/2;
2119 data = msi_alloc(*size);
2125 /* if uneven pad with a zero in front */
2131 data[count] = (BYTE)strtol(byte,NULL,0);
2133 TRACE("Uneven byte count\n");
2141 data[count] = (BYTE)strtol(byte,NULL,0);
2144 msi_free(deformated);
2146 TRACE("Data %i bytes(%i)\n",*size,count);
2153 deformat_string(package, &value[1], &deformated);
2156 *size = sizeof(DWORD);
2157 data = msi_alloc(*size);
2163 if ( (*p < '0') || (*p > '9') )
2169 if (deformated[0] == '-')
2172 TRACE("DWORD %i\n",*(LPDWORD)data);
2174 msi_free(deformated);
2179 static const WCHAR szMulti[] = {'[','~',']',0};
2188 *type=REG_EXPAND_SZ;
2196 if (strstrW(value,szMulti))
2197 *type = REG_MULTI_SZ;
2199 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2204 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2206 MSIPACKAGE *package = (MSIPACKAGE*)param;
2207 static const WCHAR szHCR[] =
2208 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2209 'R','O','O','T','\\',0};
2210 static const WCHAR szHCU[] =
2211 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2212 'U','S','E','R','\\',0};
2213 static const WCHAR szHLM[] =
2214 {'H','K','E','Y','_','L','O','C','A','L','_',
2215 'M','A','C','H','I','N','E','\\',0};
2216 static const WCHAR szHU[] =
2217 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2219 LPSTR value_data = NULL;
2220 HKEY root_key, hkey;
2223 LPCWSTR szRoot, component, name, key, value;
2228 BOOL check_first = FALSE;
2231 ui_progress(package,2,0,0,0);
2238 component = MSI_RecordGetString(row, 6);
2239 comp = get_loaded_component(package,component);
2241 return ERROR_SUCCESS;
2243 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2245 TRACE("Skipping write due to disabled component %s\n",
2246 debugstr_w(component));
2248 comp->Action = comp->Installed;
2250 return ERROR_SUCCESS;
2253 comp->Action = INSTALLSTATE_LOCAL;
2255 name = MSI_RecordGetString(row, 4);
2256 if( MSI_RecordIsNull(row,5) && name )
2258 /* null values can have special meanings */
2259 if (name[0]=='-' && name[1] == 0)
2260 return ERROR_SUCCESS;
2261 else if ((name[0]=='+' && name[1] == 0) ||
2262 (name[0] == '*' && name[1] == 0))
2267 root = MSI_RecordGetInteger(row,2);
2268 key = MSI_RecordGetString(row, 3);
2270 /* get the root key */
2275 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2276 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2277 if (all_users && all_users[0] == '1')
2279 root_key = HKEY_LOCAL_MACHINE;
2284 root_key = HKEY_CURRENT_USER;
2287 msi_free(all_users);
2290 case 0: root_key = HKEY_CLASSES_ROOT;
2293 case 1: root_key = HKEY_CURRENT_USER;
2296 case 2: root_key = HKEY_LOCAL_MACHINE;
2299 case 3: root_key = HKEY_USERS;
2303 ERR("Unknown root %i\n",root);
2309 return ERROR_SUCCESS;
2311 deformat_string(package, key , &deformated);
2312 size = strlenW(deformated) + strlenW(szRoot) + 1;
2313 uikey = msi_alloc(size*sizeof(WCHAR));
2314 strcpyW(uikey,szRoot);
2315 strcatW(uikey,deformated);
2317 if (RegCreateKeyW( root_key, deformated, &hkey))
2319 ERR("Could not create key %s\n",debugstr_w(deformated));
2320 msi_free(deformated);
2322 return ERROR_SUCCESS;
2324 msi_free(deformated);
2326 value = MSI_RecordGetString(row,5);
2328 value_data = parse_value(package, value, &type, &size);
2331 static const WCHAR szEmpty[] = {0};
2332 value_data = (LPSTR)strdupW(szEmpty);
2337 deformat_string(package, name, &deformated);
2339 /* get the double nulls to terminate SZ_MULTI */
2340 if (type == REG_MULTI_SZ)
2341 size +=sizeof(WCHAR);
2345 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2347 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2352 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2353 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2355 TRACE("value %s of %s checked already exists\n",
2356 debugstr_w(deformated), debugstr_w(uikey));
2360 TRACE("Checked and setting value %s of %s\n",
2361 debugstr_w(deformated), debugstr_w(uikey));
2362 if (deformated || size)
2363 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2368 uirow = MSI_CreateRecord(3);
2369 MSI_RecordSetStringW(uirow,2,deformated);
2370 MSI_RecordSetStringW(uirow,1,uikey);
2373 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2375 MSI_RecordSetStringW(uirow,3,value);
2377 ui_actiondata(package,szWriteRegistryValues,uirow);
2378 msiobj_release( &uirow->hdr );
2380 msi_free(value_data);
2381 msi_free(deformated);
2384 return ERROR_SUCCESS;
2387 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2391 static const WCHAR ExecSeqQuery[] =
2392 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2393 '`','R','e','g','i','s','t','r','y','`',0 };
2395 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2396 if (rc != ERROR_SUCCESS)
2397 return ERROR_SUCCESS;
2399 /* increment progress bar each time action data is sent */
2400 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2402 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2404 msiobj_release(&view->hdr);
2408 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2410 package->script->CurrentlyScripting = TRUE;
2412 return ERROR_SUCCESS;
2416 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2421 static const WCHAR q1[]=
2422 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2423 '`','R','e','g','i','s','t','r','y','`',0};
2426 MSIFEATURE *feature;
2429 TRACE("InstallValidate\n");
2431 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2432 if (rc == ERROR_SUCCESS)
2434 MSI_IterateRecords( view, &progress, NULL, package );
2435 msiobj_release( &view->hdr );
2436 total += progress * REG_PROGRESS_VALUE;
2439 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2440 total += COMPONENT_PROGRESS_VALUE;
2442 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2443 total += file->FileSize;
2445 ui_progress(package,0,total,0,0);
2447 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2449 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2450 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2451 feature->ActionRequest);
2454 return ERROR_SUCCESS;
2457 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2459 MSIPACKAGE* package = (MSIPACKAGE*)param;
2460 LPCWSTR cond = NULL;
2461 LPCWSTR message = NULL;
2462 static const WCHAR title[]=
2463 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2465 cond = MSI_RecordGetString(row,1);
2467 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2470 message = MSI_RecordGetString(row,2);
2471 deformat_string(package,message,&deformated);
2472 MessageBoxW(NULL,deformated,title,MB_OK);
2473 msi_free(deformated);
2474 return ERROR_FUNCTION_FAILED;
2477 return ERROR_SUCCESS;
2480 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2483 MSIQUERY * view = NULL;
2484 static const WCHAR ExecSeqQuery[] =
2485 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2486 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2488 TRACE("Checking launch conditions\n");
2490 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2491 if (rc != ERROR_SUCCESS)
2492 return ERROR_SUCCESS;
2494 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2495 msiobj_release(&view->hdr);
2500 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2504 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2506 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2508 MSIRECORD * row = 0;
2510 LPWSTR deformated,buffer,deformated_name;
2512 static const WCHAR ExecSeqQuery[] =
2513 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2514 '`','R','e','g','i','s','t','r','y','`',' ',
2515 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2516 ' ','=',' ' ,'\'','%','s','\'',0 };
2517 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2518 static const WCHAR fmt2[]=
2519 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2521 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2525 root = MSI_RecordGetInteger(row,2);
2526 key = MSI_RecordGetString(row, 3);
2527 name = MSI_RecordGetString(row, 4);
2528 deformat_string(package, key , &deformated);
2529 deformat_string(package, name, &deformated_name);
2531 len = strlenW(deformated) + 6;
2532 if (deformated_name)
2533 len+=strlenW(deformated_name);
2535 buffer = msi_alloc( len *sizeof(WCHAR));
2537 if (deformated_name)
2538 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2540 sprintfW(buffer,fmt,root,deformated);
2542 msi_free(deformated);
2543 msi_free(deformated_name);
2544 msiobj_release(&row->hdr);
2548 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2550 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2555 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2558 return strdupW( file->TargetPath );
2563 static HKEY openSharedDLLsKey(void)
2566 static const WCHAR path[] =
2567 {'S','o','f','t','w','a','r','e','\\',
2568 'M','i','c','r','o','s','o','f','t','\\',
2569 'W','i','n','d','o','w','s','\\',
2570 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2571 'S','h','a','r','e','d','D','L','L','s',0};
2573 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2577 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2582 DWORD sz = sizeof(count);
2585 hkey = openSharedDLLsKey();
2586 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2587 if (rc != ERROR_SUCCESS)
2593 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2597 hkey = openSharedDLLsKey();
2599 msi_reg_set_val_dword( hkey, path, count );
2601 RegDeleteValueW(hkey,path);
2607 * Return TRUE if the count should be written out and FALSE if not
2609 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2611 MSIFEATURE *feature;
2615 /* only refcount DLLs */
2616 if (comp->KeyPath == NULL ||
2617 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2618 comp->Attributes & msidbComponentAttributesODBCDataSource)
2622 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2623 write = (count > 0);
2625 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2629 /* increment counts */
2630 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2634 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2637 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2639 if ( cl->component == comp )
2644 /* decrement counts */
2645 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2649 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2652 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2654 if ( cl->component == comp )
2659 /* ref count all the files in the component */
2664 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2666 if (file->Component == comp)
2667 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2671 /* add a count for permenent */
2672 if (comp->Attributes & msidbComponentAttributesPermanent)
2675 comp->RefCount = count;
2678 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2682 * Ok further analysis makes me think that this work is
2683 * actually done in the PublishComponents and PublishFeatures
2684 * step, and not here. It appears like the keypath and all that is
2685 * resolved in this step, however actually written in the Publish steps.
2686 * But we will leave it here for now because it is unclear
2688 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2690 WCHAR squished_pc[GUID_SIZE];
2691 WCHAR squished_cc[GUID_SIZE];
2694 HKEY hkey=0,hkey2=0;
2696 /* writes the Component and Features values to the registry */
2698 rc = MSIREG_OpenComponents(&hkey);
2699 if (rc != ERROR_SUCCESS)
2702 squash_guid(package->ProductCode,squished_pc);
2703 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2705 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2709 ui_progress(package,2,0,0,0);
2710 if (!comp->ComponentId)
2713 squash_guid(comp->ComponentId,squished_cc);
2715 msi_free(comp->FullKeypath);
2716 comp->FullKeypath = resolve_keypath( package, comp );
2718 /* do the refcounting */
2719 ACTION_RefCountComponent( package, comp );
2721 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2722 debugstr_w(comp->Component),
2723 debugstr_w(squished_cc),
2724 debugstr_w(comp->FullKeypath),
2727 * Write the keypath out if the component is to be registered
2728 * and delete the key if the component is to be deregistered
2730 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2732 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2733 if (rc != ERROR_SUCCESS)
2736 if (!comp->FullKeypath)
2739 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2741 if (comp->Attributes & msidbComponentAttributesPermanent)
2743 static const WCHAR szPermKey[] =
2744 { '0','0','0','0','0','0','0','0','0','0','0','0',
2745 '0','0','0','0','0','0','0','0','0','0','0','0',
2746 '0','0','0','0','0','0','0','0',0 };
2748 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2754 uirow = MSI_CreateRecord(3);
2755 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2756 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2757 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2758 ui_actiondata(package,szProcessComponents,uirow);
2759 msiobj_release( &uirow->hdr );
2761 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2765 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2766 if (rc != ERROR_SUCCESS)
2769 RegDeleteValueW(hkey2,squished_pc);
2771 /* if the key is empty delete it */
2772 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2774 if (res == ERROR_NO_MORE_ITEMS)
2775 RegDeleteKeyW(hkey,squished_cc);
2778 uirow = MSI_CreateRecord(2);
2779 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2780 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2781 ui_actiondata(package,szProcessComponents,uirow);
2782 msiobj_release( &uirow->hdr );
2797 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2798 LPWSTR lpszName, LONG_PTR lParam)
2801 typelib_struct *tl_struct = (typelib_struct*) lParam;
2802 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2806 if (!IS_INTRESOURCE(lpszName))
2808 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2812 sz = strlenW(tl_struct->source)+4;
2813 sz *= sizeof(WCHAR);
2815 if ((INT_PTR)lpszName == 1)
2816 tl_struct->path = strdupW(tl_struct->source);
2819 tl_struct->path = msi_alloc(sz);
2820 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2823 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2824 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2825 if (!SUCCEEDED(res))
2827 msi_free(tl_struct->path);
2828 tl_struct->path = NULL;
2833 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2834 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2836 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2840 msi_free(tl_struct->path);
2841 tl_struct->path = NULL;
2843 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2844 ITypeLib_Release(tl_struct->ptLib);
2849 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2851 MSIPACKAGE* package = (MSIPACKAGE*)param;
2855 typelib_struct tl_struct;
2857 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2859 component = MSI_RecordGetString(row,3);
2860 comp = get_loaded_component(package,component);
2862 return ERROR_SUCCESS;
2864 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2866 TRACE("Skipping typelib reg due to disabled component\n");
2868 comp->Action = comp->Installed;
2870 return ERROR_SUCCESS;
2873 comp->Action = INSTALLSTATE_LOCAL;
2875 file = get_loaded_file( package, comp->KeyPath );
2877 return ERROR_SUCCESS;
2879 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2883 guid = MSI_RecordGetString(row,1);
2884 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2885 tl_struct.source = strdupW( file->TargetPath );
2886 tl_struct.path = NULL;
2888 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2889 (LONG_PTR)&tl_struct);
2897 helpid = MSI_RecordGetString(row,6);
2900 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2901 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2904 if (!SUCCEEDED(res))
2905 ERR("Failed to register type library %s\n",
2906 debugstr_w(tl_struct.path));
2909 ui_actiondata(package,szRegisterTypeLibraries,row);
2911 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2914 ITypeLib_Release(tl_struct.ptLib);
2915 msi_free(tl_struct.path);
2918 ERR("Failed to load type library %s\n",
2919 debugstr_w(tl_struct.source));
2921 FreeLibrary(module);
2922 msi_free(tl_struct.source);
2925 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2927 return ERROR_SUCCESS;
2930 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2933 * OK this is a bit confusing.. I am given a _Component key and I believe
2934 * that the file that is being registered as a type library is the "key file
2935 * of that component" which I interpret to mean "The file in the KeyPath of
2940 static const WCHAR Query[] =
2941 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2942 '`','T','y','p','e','L','i','b','`',0};
2944 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2945 if (rc != ERROR_SUCCESS)
2946 return ERROR_SUCCESS;
2948 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2949 msiobj_release(&view->hdr);
2953 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2955 MSIPACKAGE *package = (MSIPACKAGE*)param;
2956 LPWSTR target_file, target_folder, filename;
2957 LPCWSTR buffer, extension;
2959 static const WCHAR szlnk[]={'.','l','n','k',0};
2960 IShellLinkW *sl = NULL;
2961 IPersistFile *pf = NULL;
2964 buffer = MSI_RecordGetString(row,4);
2965 comp = get_loaded_component(package,buffer);
2967 return ERROR_SUCCESS;
2969 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2971 TRACE("Skipping shortcut creation due to disabled component\n");
2973 comp->Action = comp->Installed;
2975 return ERROR_SUCCESS;
2978 comp->Action = INSTALLSTATE_LOCAL;
2980 ui_actiondata(package,szCreateShortcuts,row);
2982 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2983 &IID_IShellLinkW, (LPVOID *) &sl );
2987 ERR("CLSID_ShellLink not available\n");
2991 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2994 ERR("QueryInterface(IID_IPersistFile) failed\n");
2998 buffer = MSI_RecordGetString(row,2);
2999 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
3001 /* may be needed because of a bug somehwere else */
3002 create_full_pathW(target_folder);
3004 filename = msi_dup_record_field( row, 3 );
3005 reduce_to_longfilename(filename);
3007 extension = strchrW(filename,'.');
3008 if (!extension || strcmpiW(extension,szlnk))
3010 int len = strlenW(filename);
3011 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3012 memcpy(filename + len, szlnk, sizeof(szlnk));
3014 target_file = build_directory_name(2, target_folder, filename);
3015 msi_free(target_folder);
3018 buffer = MSI_RecordGetString(row,5);
3019 if (strchrW(buffer,'['))
3022 deformat_string(package,buffer,&deformated);
3023 IShellLinkW_SetPath(sl,deformated);
3024 msi_free(deformated);
3028 FIXME("poorly handled shortcut format, advertised shortcut\n");
3029 IShellLinkW_SetPath(sl,comp->FullKeypath);
3032 if (!MSI_RecordIsNull(row,6))
3035 buffer = MSI_RecordGetString(row,6);
3036 deformat_string(package,buffer,&deformated);
3037 IShellLinkW_SetArguments(sl,deformated);
3038 msi_free(deformated);
3041 if (!MSI_RecordIsNull(row,7))
3043 buffer = MSI_RecordGetString(row,7);
3044 IShellLinkW_SetDescription(sl,buffer);
3047 if (!MSI_RecordIsNull(row,8))
3048 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3050 if (!MSI_RecordIsNull(row,9))
3055 buffer = MSI_RecordGetString(row,9);
3057 Path = build_icon_path(package,buffer);
3058 index = MSI_RecordGetInteger(row,10);
3060 /* no value means 0 */
3061 if (index == MSI_NULL_INTEGER)
3064 IShellLinkW_SetIconLocation(sl,Path,index);
3068 if (!MSI_RecordIsNull(row,11))
3069 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3071 if (!MSI_RecordIsNull(row,12))
3074 buffer = MSI_RecordGetString(row,12);
3075 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3077 IShellLinkW_SetWorkingDirectory(sl,Path);
3081 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3082 IPersistFile_Save(pf,target_file,FALSE);
3084 msi_free(target_file);
3088 IPersistFile_Release( pf );
3090 IShellLinkW_Release( sl );
3092 return ERROR_SUCCESS;
3095 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3100 static const WCHAR Query[] =
3101 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3102 '`','S','h','o','r','t','c','u','t','`',0};
3104 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3105 if (rc != ERROR_SUCCESS)
3106 return ERROR_SUCCESS;
3108 res = CoInitialize( NULL );
3111 ERR("CoInitialize failed\n");
3112 return ERROR_FUNCTION_FAILED;
3115 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3116 msiobj_release(&view->hdr);
3123 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3125 MSIPACKAGE* package = (MSIPACKAGE*)param;
3134 FileName = MSI_RecordGetString(row,1);
3137 ERR("Unable to get FileName\n");
3138 return ERROR_SUCCESS;
3141 FilePath = build_icon_path(package,FileName);
3143 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3145 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3146 FILE_ATTRIBUTE_NORMAL, NULL);
3148 if (the_file == INVALID_HANDLE_VALUE)
3150 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3152 return ERROR_SUCCESS;
3159 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3160 if (rc != ERROR_SUCCESS)
3162 ERR("Failed to get stream\n");
3163 CloseHandle(the_file);
3164 DeleteFileW(FilePath);
3167 WriteFile(the_file,buffer,sz,&write,NULL);
3168 } while (sz == 1024);
3172 CloseHandle(the_file);
3174 uirow = MSI_CreateRecord(1);
3175 MSI_RecordSetStringW(uirow,1,FileName);
3176 ui_actiondata(package,szPublishProduct,uirow);
3177 msiobj_release( &uirow->hdr );
3179 return ERROR_SUCCESS;
3183 * 99% of the work done here is only done for
3184 * advertised installs. However this is where the
3185 * Icon table is processed and written out
3186 * so that is what I am going to do here.
3188 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3192 static const WCHAR Query[]=
3193 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3194 '`','I','c','o','n','`',0};
3195 /* for registry stuff */
3198 static const WCHAR szProductLanguage[] =
3199 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3200 static const WCHAR szARPProductIcon[] =
3201 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3202 static const WCHAR szProductVersion[] =
3203 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3207 MSIHANDLE hDb, hSumInfo;
3209 /* write out icon files */
3211 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3212 if (rc == ERROR_SUCCESS)
3214 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3215 msiobj_release(&view->hdr);
3218 /* ok there is a lot more done here but i need to figure out what */
3220 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3221 if (rc != ERROR_SUCCESS)
3224 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3225 if (rc != ERROR_SUCCESS)
3229 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3230 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3233 langid = msi_get_property_int( package, szProductLanguage, 0 );
3234 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3236 buffer = msi_dup_property( package, szARPProductIcon );
3239 LPWSTR path = build_icon_path(package,buffer);
3240 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3245 buffer = msi_dup_property( package, szProductVersion );
3248 DWORD verdword = msi_version_str_to_dword(buffer);
3249 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3253 /* FIXME: Need to write more keys to the user registry */
3255 hDb= alloc_msihandle( &package->db->hdr );
3257 rc = ERROR_NOT_ENOUGH_MEMORY;
3260 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3261 MsiCloseHandle(hDb);
3262 if (rc == ERROR_SUCCESS)
3264 WCHAR guidbuffer[0x200];
3266 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3268 if (rc == ERROR_SUCCESS)
3270 WCHAR squashed[GUID_SIZE];
3271 /* for now we only care about the first guid */
3272 LPWSTR ptr = strchrW(guidbuffer,';');
3274 squash_guid(guidbuffer,squashed);
3275 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3279 ERR("Unable to query Revision_Number...\n");
3282 MsiCloseHandle(hSumInfo);
3286 ERR("Unable to open Summary Information\n");
3298 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3300 MSIPACKAGE *package = (MSIPACKAGE*)param;
3301 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3302 LPWSTR deformated_section, deformated_key, deformated_value;
3303 LPWSTR folder, fullname = NULL;
3307 static const WCHAR szWindowsFolder[] =
3308 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3310 component = MSI_RecordGetString(row, 8);
3311 comp = get_loaded_component(package,component);
3313 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3315 TRACE("Skipping ini file due to disabled component %s\n",
3316 debugstr_w(component));
3318 comp->Action = comp->Installed;
3320 return ERROR_SUCCESS;
3323 comp->Action = INSTALLSTATE_LOCAL;
3325 identifier = MSI_RecordGetString(row,1);
3326 filename = MSI_RecordGetString(row,2);
3327 dirproperty = MSI_RecordGetString(row,3);
3328 section = MSI_RecordGetString(row,4);
3329 key = MSI_RecordGetString(row,5);
3330 value = MSI_RecordGetString(row,6);
3331 action = MSI_RecordGetInteger(row,7);
3333 deformat_string(package,section,&deformated_section);
3334 deformat_string(package,key,&deformated_key);
3335 deformat_string(package,value,&deformated_value);
3339 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3341 folder = msi_dup_property( package, dirproperty );
3344 folder = msi_dup_property( package, szWindowsFolder );
3348 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3352 fullname = build_directory_name(2, folder, filename);
3356 TRACE("Adding value %s to section %s in %s\n",
3357 debugstr_w(deformated_key), debugstr_w(deformated_section),
3358 debugstr_w(fullname));
3359 WritePrivateProfileStringW(deformated_section, deformated_key,
3360 deformated_value, fullname);
3362 else if (action == 1)
3365 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3366 returned, 10, fullname);
3367 if (returned[0] == 0)
3369 TRACE("Adding value %s to section %s in %s\n",
3370 debugstr_w(deformated_key), debugstr_w(deformated_section),
3371 debugstr_w(fullname));
3373 WritePrivateProfileStringW(deformated_section, deformated_key,
3374 deformated_value, fullname);
3377 else if (action == 3)
3378 FIXME("Append to existing section not yet implemented\n");
3380 uirow = MSI_CreateRecord(4);
3381 MSI_RecordSetStringW(uirow,1,identifier);
3382 MSI_RecordSetStringW(uirow,2,deformated_section);
3383 MSI_RecordSetStringW(uirow,3,deformated_key);
3384 MSI_RecordSetStringW(uirow,4,deformated_value);
3385 ui_actiondata(package,szWriteIniValues,uirow);
3386 msiobj_release( &uirow->hdr );
3390 msi_free(deformated_key);
3391 msi_free(deformated_value);
3392 msi_free(deformated_section);
3393 return ERROR_SUCCESS;
3396 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3400 static const WCHAR ExecSeqQuery[] =
3401 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3402 '`','I','n','i','F','i','l','e','`',0};
3404 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3405 if (rc != ERROR_SUCCESS)
3407 TRACE("no IniFile table\n");
3408 return ERROR_SUCCESS;
3411 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3412 msiobj_release(&view->hdr);
3416 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3418 MSIPACKAGE *package = (MSIPACKAGE*)param;
3423 static const WCHAR ExeStr[] =
3424 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3425 static const WCHAR close[] = {'\"',0};
3427 PROCESS_INFORMATION info;
3432 memset(&si,0,sizeof(STARTUPINFOW));
3434 filename = MSI_RecordGetString(row,1);
3435 file = get_loaded_file( package, filename );
3439 ERR("Unable to find file id %s\n",debugstr_w(filename));
3440 return ERROR_SUCCESS;
3443 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3445 FullName = msi_alloc(len*sizeof(WCHAR));
3446 strcpyW(FullName,ExeStr);
3447 strcatW( FullName, file->TargetPath );
3448 strcatW(FullName,close);
3450 TRACE("Registering %s\n",debugstr_w(FullName));
3451 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3455 msi_dialog_check_messages(info.hProcess);
3460 uirow = MSI_CreateRecord( 2 );
3461 uipath = strdupW( file->TargetPath );
3462 p = strrchrW(uipath,'\\');
3465 MSI_RecordSetStringW( uirow, 1, &p[2] );
3466 MSI_RecordSetStringW( uirow, 2, uipath);
3467 ui_actiondata( package, szSelfRegModules, uirow);
3468 msiobj_release( &uirow->hdr );
3470 /* FIXME: call ui_progress? */
3472 return ERROR_SUCCESS;
3475 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3479 static const WCHAR ExecSeqQuery[] =
3480 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3481 '`','S','e','l','f','R','e','g','`',0};
3483 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3484 if (rc != ERROR_SUCCESS)
3486 TRACE("no SelfReg table\n");
3487 return ERROR_SUCCESS;
3490 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3491 msiobj_release(&view->hdr);
3493 return ERROR_SUCCESS;
3496 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3498 MSIFEATURE *feature;
3503 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3504 if (rc != ERROR_SUCCESS)
3507 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3508 if (rc != ERROR_SUCCESS)
3511 /* here the guids are base 85 encoded */
3512 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3518 BOOL absent = FALSE;
3521 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3522 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3523 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3527 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3531 if (feature->Feature_Parent)
3532 size += strlenW( feature->Feature_Parent )+2;
3534 data = msi_alloc(size * sizeof(WCHAR));
3537 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3539 MSICOMPONENT* component = cl->component;
3543 if (component->ComponentId)
3545 TRACE("From %s\n",debugstr_w(component->ComponentId));
3546 CLSIDFromString(component->ComponentId, &clsid);
3547 encode_base85_guid(&clsid,buf);
3548 TRACE("to %s\n",debugstr_w(buf));
3552 if (feature->Feature_Parent)
3554 static const WCHAR sep[] = {'\2',0};
3556 strcatW(data,feature->Feature_Parent);
3559 msi_reg_set_val_str( hkey, feature->Feature, data );
3563 if (feature->Feature_Parent)
3564 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3567 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3568 (LPBYTE)feature->Feature_Parent,size);
3572 size += 2*sizeof(WCHAR);
3573 data = msi_alloc(size);
3576 if (feature->Feature_Parent)
3577 strcpyW( &data[1], feature->Feature_Parent );
3578 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3584 uirow = MSI_CreateRecord( 1 );
3585 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3586 ui_actiondata( package, szPublishFeatures, uirow);
3587 msiobj_release( &uirow->hdr );
3588 /* FIXME: call ui_progress? */
3597 static UINT msi_get_local_package_name( LPWSTR path )
3599 static const WCHAR szInstaller[] = {
3600 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3601 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3605 time = GetTickCount();
3606 GetWindowsDirectoryW( path, MAX_PATH );
3607 lstrcatW( path, szInstaller );
3608 CreateDirectoryW( path, NULL );
3610 len = lstrlenW(path);
3611 for (i=0; i<0x10000; i++)
3613 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3614 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3615 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3616 if (handle != INVALID_HANDLE_VALUE)
3618 CloseHandle(handle);
3621 if (GetLastError() != ERROR_FILE_EXISTS &&
3622 GetLastError() != ERROR_SHARING_VIOLATION)
3623 return ERROR_FUNCTION_FAILED;
3626 return ERROR_SUCCESS;
3629 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3631 static const WCHAR szOriginalDatabase[] =
3632 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3633 WCHAR packagefile[MAX_PATH];
3637 r = msi_get_local_package_name( packagefile );
3638 if (r != ERROR_SUCCESS)
3641 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3643 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3644 r = CopyFileW( msiFilePath, packagefile, FALSE);
3645 msi_free( msiFilePath );
3649 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3650 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3651 return ERROR_FUNCTION_FAILED;
3654 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3655 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3656 return ERROR_SUCCESS;
3659 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3661 LPWSTR prop, val, key;
3662 static const LPCSTR propval[] = {
3663 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3664 "ARPCONTACT", "Contact",
3665 "ARPCOMMENTS", "Comments",
3666 "ProductName", "DisplayName",
3667 "ProductVersion", "DisplayVersion",
3668 "ARPHELPLINK", "HelpLink",
3669 "ARPHELPTELEPHONE", "HelpTelephone",
3670 "ARPINSTALLLOCATION", "InstallLocation",
3671 "SourceDir", "InstallSource",
3672 "Manufacturer", "Publisher",
3673 "ARPREADME", "Readme",
3675 "ARPURLINFOABOUT", "URLInfoAbout",
3676 "ARPURLUPDATEINFO", "URLUpdateInfo",
3679 const LPCSTR *p = propval;
3683 prop = strdupAtoW( *p++ );
3684 key = strdupAtoW( *p++ );
3685 val = msi_dup_property( package, prop );
3686 msi_reg_set_val_str( hkey, key, val );
3691 return ERROR_SUCCESS;
3694 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3697 LPWSTR buffer = NULL;
3700 static const WCHAR szWindowsInstaller[] =
3701 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3702 static const WCHAR szUpgradeCode[] =
3703 {'U','p','g','r','a','d','e','C','o','d','e',0};
3704 static const WCHAR modpath_fmt[] =
3705 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3706 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3707 static const WCHAR szModifyPath[] =
3708 {'M','o','d','i','f','y','P','a','t','h',0};
3709 static const WCHAR szUninstallString[] =
3710 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3711 static const WCHAR szEstimatedSize[] =
3712 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3713 static const WCHAR szProductLanguage[] =
3714 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3715 static const WCHAR szProductVersion[] =
3716 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3719 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3720 LPWSTR upgrade_code;
3723 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3724 if (rc != ERROR_SUCCESS)
3727 /* dump all the info i can grab */
3728 /* FIXME: Flesh out more information */
3730 msi_write_uninstall_property_vals( package, hkey );
3732 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3734 msi_make_package_local( package, hkey );
3736 /* do ModifyPath and UninstallString */
3737 size = deformat_string(package,modpath_fmt,&buffer);
3738 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3739 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3742 /* FIXME: Write real Estimated Size when we have it */
3743 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3745 GetLocalTime(&systime);
3746 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3747 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3749 langid = msi_get_property_int( package, szProductLanguage, 0 );
3750 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3752 buffer = msi_dup_property( package, szProductVersion );
3755 DWORD verdword = msi_version_str_to_dword(buffer);
3757 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3758 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3759 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3763 /* Handle Upgrade Codes */
3764 upgrade_code = msi_dup_property( package, szUpgradeCode );
3769 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3770 squash_guid(package->ProductCode,squashed);
3771 msi_reg_set_val_str( hkey2, squashed, NULL );
3773 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3774 squash_guid(package->ProductCode,squashed);
3775 msi_reg_set_val_str( hkey2, squashed, NULL );
3778 msi_free(upgrade_code);
3783 /* FIXME: call ui_actiondata */
3785 return ERROR_SUCCESS;
3788 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3790 return execute_script(package,INSTALL_SCRIPT);
3793 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3797 /* turn off scheduleing */
3798 package->script->CurrentlyScripting= FALSE;
3800 /* first do the same as an InstallExecute */
3801 rc = ACTION_InstallExecute(package);
3802 if (rc != ERROR_SUCCESS)
3805 /* then handle Commit Actions */
3806 rc = execute_script(package,COMMIT_SCRIPT);
3811 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3813 static const WCHAR RunOnce[] = {
3814 'S','o','f','t','w','a','r','e','\\',
3815 'M','i','c','r','o','s','o','f','t','\\',
3816 'W','i','n','d','o','w','s','\\',
3817 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3818 'R','u','n','O','n','c','e',0};
3819 static const WCHAR InstallRunOnce[] = {
3820 'S','o','f','t','w','a','r','e','\\',
3821 'M','i','c','r','o','s','o','f','t','\\',
3822 'W','i','n','d','o','w','s','\\',
3823 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3824 'I','n','s','t','a','l','l','e','r','\\',
3825 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3827 static const WCHAR msiexec_fmt[] = {
3829 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3830 '\"','%','s','\"',0};
3831 static const WCHAR install_fmt[] = {
3832 '/','I',' ','\"','%','s','\"',' ',
3833 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3834 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3835 WCHAR buffer[256], sysdir[MAX_PATH];
3837 WCHAR squished_pc[100];
3839 squash_guid(package->ProductCode,squished_pc);
3841 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3842 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3843 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3846 msi_reg_set_val_str( hkey, squished_pc, buffer );
3849 TRACE("Reboot command %s\n",debugstr_w(buffer));
3851 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3852 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3854 msi_reg_set_val_str( hkey, squished_pc, buffer );
3857 return ERROR_INSTALL_SUSPEND;
3860 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3867 * we are currently doing what should be done here in the top level Install
3868 * however for Adminastrative and uninstalls this step will be needed
3870 if (!package->PackagePath)
3871 return ERROR_SUCCESS;
3873 ptr = strrchrW(package->PackagePath, '\\');
3875 return ERROR_SUCCESS;
3877 len = ptr - package->PackagePath + 2;
3878 source = msi_alloc(len * sizeof(WCHAR));
3879 lstrcpynW(source, package->PackagePath, len);
3881 MSI_SetPropertyW(package, cszSourceDir, source);
3882 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3886 attrib = GetFileAttributesW(package->PackagePath);
3887 if (attrib == INVALID_FILE_ATTRIBUTES)
3893 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3894 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3895 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3896 if (rc == ERROR_MORE_DATA)
3898 prompt = msi_alloc(size * sizeof(WCHAR));
3899 MsiSourceListGetInfoW(package->ProductCode, NULL,
3900 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3901 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3904 prompt = strdupW(package->PackagePath);
3906 msg = generate_error_string(package,1302,1,prompt);
3907 while(attrib == INVALID_FILE_ATTRIBUTES)
3909 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3912 rc = ERROR_INSTALL_USEREXIT;
3915 attrib = GetFileAttributesW(package->PackagePath);
3921 return ERROR_SUCCESS;
3926 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3933 static const WCHAR szPropKeys[][80] =
3935 {'P','r','o','d','u','c','t','I','D',0},
3936 {'U','S','E','R','N','A','M','E',0},
3937 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3941 static const WCHAR szRegKeys[][80] =
3943 {'P','r','o','d','u','c','t','I','D',0},
3944 {'R','e','g','O','w','n','e','r',0},
3945 {'R','e','g','C','o','m','p','a','n','y',0},
3949 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3951 return ERROR_SUCCESS;
3953 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3954 if (rc != ERROR_SUCCESS)
3957 for( i = 0; szPropKeys[i][0]; i++ )
3959 buffer = msi_dup_property( package, szPropKeys[i] );
3960 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3965 msi_free(productid);
3968 /* FIXME: call ui_actiondata */
3970 return ERROR_SUCCESS;
3974 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3978 package->script->InWhatSequence |= SEQUENCE_EXEC;
3979 rc = ACTION_ProcessExecSequence(package,FALSE);
3984 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3986 MSIPACKAGE *package = (MSIPACKAGE*)param;
3987 LPCWSTR compgroupid=NULL;
3988 LPCWSTR feature=NULL;
3989 LPCWSTR text = NULL;
3990 LPCWSTR qualifier = NULL;
3991 LPCWSTR component = NULL;
3992 LPWSTR advertise = NULL;
3993 LPWSTR output = NULL;
3995 UINT rc = ERROR_SUCCESS;
4000 component = MSI_RecordGetString(rec,3);
4001 comp = get_loaded_component(package,component);
4003 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4004 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4005 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4007 TRACE("Skipping: Component %s not scheduled for install\n",
4008 debugstr_w(component));
4010 return ERROR_SUCCESS;
4013 compgroupid = MSI_RecordGetString(rec,1);
4014 qualifier = MSI_RecordGetString(rec,2);
4016 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4017 if (rc != ERROR_SUCCESS)
4020 text = MSI_RecordGetString(rec,4);
4021 feature = MSI_RecordGetString(rec,5);
4023 advertise = create_component_advertise_string(package, comp, feature);
4025 sz = strlenW(advertise);
4028 sz += lstrlenW(text);
4031 sz *= sizeof(WCHAR);
4033 output = msi_alloc_zero(sz);
4034 strcpyW(output,advertise);
4035 msi_free(advertise);
4038 strcatW(output,text);
4040 msi_reg_set_val_multi_str( hkey, qualifier, output );
4047 uirow = MSI_CreateRecord( 2 );
4048 MSI_RecordSetStringW( uirow, 1, compgroupid );
4049 MSI_RecordSetStringW( uirow, 2, qualifier);
4050 ui_actiondata( package, szPublishComponents, uirow);
4051 msiobj_release( &uirow->hdr );
4052 /* FIXME: call ui_progress? */
4058 * At present I am ignorning the advertised components part of this and only
4059 * focusing on the qualified component sets
4061 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4065 static const WCHAR ExecSeqQuery[] =
4066 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4067 '`','P','u','b','l','i','s','h',
4068 'C','o','m','p','o','n','e','n','t','`',0};
4070 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4071 if (rc != ERROR_SUCCESS)
4072 return ERROR_SUCCESS;
4074 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4075 msiobj_release(&view->hdr);
4080 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4082 MSIPACKAGE *package = (MSIPACKAGE*)param;
4085 SC_HANDLE hscm, service = NULL;
4086 LPCWSTR name, disp, comp, depends, pass;
4087 LPCWSTR load_order, serv_name, key;
4088 DWORD serv_type, start_type;
4091 static const WCHAR query[] =
4092 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4093 '`','C','o','m','p','o','n','e','n','t','`',' ',
4094 'W','H','E','R','E',' ',
4095 '`','C','o','m','p','o','n','e','n','t','`',' ',
4096 '=','\'','%','s','\'',0};
4098 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4101 ERR("Failed to open the SC Manager!\n");
4105 start_type = MSI_RecordGetInteger(rec, 5);
4106 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4109 depends = MSI_RecordGetString(rec, 8);
4110 if (depends && *depends)
4111 FIXME("Dependency list unhandled!\n");
4113 name = MSI_RecordGetString(rec, 2);
4114 disp = MSI_RecordGetString(rec, 3);
4115 serv_type = MSI_RecordGetInteger(rec, 4);
4116 err_control = MSI_RecordGetInteger(rec, 6);
4117 load_order = MSI_RecordGetString(rec, 7);
4118 serv_name = MSI_RecordGetString(rec, 9);
4119 pass = MSI_RecordGetString(rec, 10);
4120 comp = MSI_RecordGetString(rec, 12);
4122 /* fetch the service path */
4123 row = MSI_QueryGetRecord(package->db, query, comp);
4126 ERR("Control query failed!\n");
4130 key = MSI_RecordGetString(row, 6);
4131 msiobj_release(&row->hdr);
4133 file = get_loaded_file(package, key);
4136 ERR("Failed to load the service file\n");
4140 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4141 start_type, err_control, file->TargetPath,
4142 load_order, NULL, NULL, serv_name, pass);
4145 if (GetLastError() != ERROR_SERVICE_EXISTS)
4146 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4150 CloseServiceHandle(service);
4151 CloseServiceHandle(hscm);
4153 return ERROR_SUCCESS;
4156 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4160 static const WCHAR ExecSeqQuery[] =
4161 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4162 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4164 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4165 if (rc != ERROR_SUCCESS)
4166 return ERROR_SUCCESS;
4168 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4169 msiobj_release(&view->hdr);
4174 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4175 LPCSTR action, LPCWSTR table )
4177 static const WCHAR query[] = {
4178 'S','E','L','E','C','T',' ','*',' ',
4179 'F','R','O','M',' ','`','%','s','`',0 };
4180 MSIQUERY *view = NULL;
4184 r = MSI_OpenQuery( package->db, &view, query, table );
4185 if (r == ERROR_SUCCESS)
4187 r = MSI_IterateRecords(view, &count, NULL, package);
4188 msiobj_release(&view->hdr);
4192 FIXME("%s -> %u ignored %s table values\n",
4193 action, count, debugstr_w(table));
4195 return ERROR_SUCCESS;
4198 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4200 TRACE("%p\n", package);
4201 return ERROR_SUCCESS;
4204 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4206 static const WCHAR table[] =
4207 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4208 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4211 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4213 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4214 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4217 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4219 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4220 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4223 static UINT ACTION_BindImage( MSIPACKAGE *package )
4225 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4226 return msi_unimplemented_action_stub( package, "BindImage", table );
4229 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4231 static const WCHAR table[] = {
4232 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4233 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4236 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4238 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4239 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4242 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4244 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4245 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4248 static UINT ACTION_StartServices( 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, "StartServices", table );
4255 static UINT ACTION_StopServices( 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, "StopServices", table );
4262 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4264 static const WCHAR table[] = {
4265 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4266 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4269 static UINT ACTION_WriteEnvironmentStrings( 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, "WriteEnvironmentStrings", table );
4276 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4278 static const WCHAR table[] = {
4279 'E','n','v','i','r','o','n','m','e','n','t',0 };
4280 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4283 static UINT ACTION_MsiPublishAssemblies( 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, "MsiPublishAssemblies", table );
4290 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4292 static const WCHAR table[] = {
4293 'M','s','i','A','s','s','e','m','b','l','y',0 };
4294 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4297 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4299 static const WCHAR table[] = { 'F','o','n','t',0 };
4300 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4303 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4305 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4306 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4309 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4311 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4312 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4315 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4317 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4318 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4321 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4323 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4324 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4327 static struct _actions StandardActions[] = {
4328 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4329 { szAppSearch, ACTION_AppSearch },
4330 { szBindImage, ACTION_BindImage },
4331 { szCCPSearch, ACTION_CCPSearch},
4332 { szCostFinalize, ACTION_CostFinalize },
4333 { szCostInitialize, ACTION_CostInitialize },
4334 { szCreateFolders, ACTION_CreateFolders },
4335 { szCreateShortcuts, ACTION_CreateShortcuts },
4336 { szDeleteServices, ACTION_DeleteServices },
4337 { szDisableRollback, NULL},
4338 { szDuplicateFiles, ACTION_DuplicateFiles },
4339 { szExecuteAction, ACTION_ExecuteAction },
4340 { szFileCost, ACTION_FileCost },
4341 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4342 { szForceReboot, ACTION_ForceReboot },
4343 { szInstallAdminPackage, NULL},
4344 { szInstallExecute, ACTION_InstallExecute },
4345 { szInstallExecuteAgain, ACTION_InstallExecute },
4346 { szInstallFiles, ACTION_InstallFiles},
4347 { szInstallFinalize, ACTION_InstallFinalize },
4348 { szInstallInitialize, ACTION_InstallInitialize },
4349 { szInstallSFPCatalogFile, NULL},
4350 { szInstallValidate, ACTION_InstallValidate },
4351 { szIsolateComponents, ACTION_IsolateComponents },
4352 { szLaunchConditions, ACTION_LaunchConditions },
4353 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4354 { szMoveFiles, ACTION_MoveFiles },
4355 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4356 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4357 { szInstallODBC, NULL},
4358 { szInstallServices, ACTION_InstallServices },
4359 { szPatchFiles, ACTION_PatchFiles },
4360 { szProcessComponents, ACTION_ProcessComponents },
4361 { szPublishComponents, ACTION_PublishComponents },
4362 { szPublishFeatures, ACTION_PublishFeatures },
4363 { szPublishProduct, ACTION_PublishProduct },
4364 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4365 { szRegisterComPlus, ACTION_RegisterComPlus},
4366 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4367 { szRegisterFonts, ACTION_RegisterFonts },
4368 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4369 { szRegisterProduct, ACTION_RegisterProduct },
4370 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4371 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4372 { szRegisterUser, ACTION_RegisterUser},
4373 { szRemoveDuplicateFiles, NULL},
4374 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4375 { szRemoveExistingProducts, NULL},
4376 { szRemoveFiles, ACTION_RemoveFiles},
4377 { szRemoveFolders, NULL},
4378 { szRemoveIniValues, ACTION_RemoveIniValues },
4379 { szRemoveODBC, NULL},
4380 { szRemoveRegistryValues, NULL},
4381 { szRemoveShortcuts, NULL},
4382 { szResolveSource, ACTION_ResolveSource},
4383 { szRMCCPSearch, ACTION_RMCCPSearch},
4384 { szScheduleReboot, NULL},
4385 { szSelfRegModules, ACTION_SelfRegModules },
4386 { szSelfUnregModules, ACTION_SelfUnregModules },
4387 { szSetODBCFolders, NULL},
4388 { szStartServices, ACTION_StartServices },
4389 { szStopServices, ACTION_StopServices },
4390 { szUnpublishComponents, NULL},
4391 { szUnpublishFeatures, NULL},
4392 { szUnregisterClassInfo, NULL},
4393 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4394 { szUnregisterExtensionInfo, NULL},
4395 { szUnregisterFonts, ACTION_UnregisterFonts },
4396 { szUnregisterMIMEInfo, NULL},
4397 { szUnregisterProgIdInfo, NULL},
4398 { szUnregisterTypeLibraries, NULL},
4399 { szValidateProductID, NULL},
4400 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4401 { szWriteIniValues, ACTION_WriteIniValues },
4402 { szWriteRegistryValues, ACTION_WriteRegistryValues},