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)\n",
1796 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1798 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1800 component = cl->component;
1802 if (!component->Enabled)
1805 if (component->Attributes & msidbComponentAttributesOptional)
1806 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1809 if (component->Attributes & msidbComponentAttributesSourceOnly)
1810 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1812 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1815 if (component->ForceLocalState)
1816 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1818 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1820 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1821 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1823 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1825 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1826 (component->Action == INSTALLSTATE_ABSENT) ||
1827 (component->Action == INSTALLSTATE_ADVERTISED) ||
1828 (component->Action == INSTALLSTATE_DEFAULT))
1829 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1831 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1833 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1834 (component->Action == INSTALLSTATE_ABSENT))
1835 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1837 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1839 if (component->Action == INSTALLSTATE_UNKNOWN)
1840 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1842 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1843 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1845 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1846 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1850 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1852 if (component->Action == INSTALLSTATE_DEFAULT)
1854 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1855 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1858 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1859 debugstr_w(component->Component), component->Installed, component->Action);
1863 return ERROR_SUCCESS;
1866 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1868 MSIPACKAGE *package = (MSIPACKAGE*)param;
1872 name = MSI_RecordGetString(row,1);
1874 /* This helper function now does ALL the work */
1875 TRACE("Dir %s ...\n",debugstr_w(name));
1876 load_folder(package,name);
1877 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1878 TRACE("resolves to %s\n",debugstr_w(path));
1881 return ERROR_SUCCESS;
1884 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1886 MSIPACKAGE *package = (MSIPACKAGE*)param;
1888 MSIFEATURE *feature;
1890 name = MSI_RecordGetString( row, 1 );
1892 feature = get_loaded_feature( package, name );
1894 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1898 Condition = MSI_RecordGetString(row,3);
1900 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1902 int level = MSI_RecordGetInteger(row,2);
1903 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1904 feature->Level = level;
1907 return ERROR_SUCCESS;
1910 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1912 static const WCHAR name_fmt[] =
1913 {'%','u','.','%','u','.','%','u','.','%','u',0};
1914 static WCHAR name[] = {'\\',0};
1915 VS_FIXEDFILEINFO *lpVer;
1916 WCHAR filever[0x100];
1922 TRACE("%s\n", debugstr_w(filename));
1924 versize = GetFileVersionInfoSizeW( filename, &handle );
1928 version = msi_alloc( versize );
1929 GetFileVersionInfoW( filename, 0, versize, version );
1931 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1932 msi_free( version );
1934 sprintfW( filever, name_fmt,
1935 HIWORD(lpVer->dwFileVersionMS),
1936 LOWORD(lpVer->dwFileVersionMS),
1937 HIWORD(lpVer->dwFileVersionLS),
1938 LOWORD(lpVer->dwFileVersionLS));
1940 return strdupW( filever );
1943 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1945 LPWSTR file_version;
1948 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1950 MSICOMPONENT* comp = file->Component;
1956 if (file->IsCompressed)
1957 comp->ForceLocalState = TRUE;
1959 /* calculate target */
1960 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1962 msi_free(file->TargetPath);
1964 TRACE("file %s is named %s\n",
1965 debugstr_w(file->File), debugstr_w(file->FileName));
1967 file->TargetPath = build_directory_name(2, p, file->FileName);
1971 TRACE("file %s resolves to %s\n",
1972 debugstr_w(file->File), debugstr_w(file->TargetPath));
1974 /* don't check files of components that aren't installed */
1975 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1976 comp->Installed == INSTALLSTATE_ABSENT)
1978 file->state = msifs_missing; /* assume files are missing */
1982 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1984 file->state = msifs_missing;
1985 comp->Cost += file->FileSize;
1986 comp->Installed = INSTALLSTATE_INCOMPLETE;
1990 if (file->Version &&
1991 (file_version = msi_get_disk_file_version( file->TargetPath )))
1993 TRACE("new %s old %s\n", debugstr_w(file->Version),
1994 debugstr_w(file_version));
1995 /* FIXME: seems like a bad way to compare version numbers */
1996 if (lstrcmpiW(file_version, file->Version)<0)
1998 file->state = msifs_overwrite;
1999 comp->Cost += file->FileSize;
2000 comp->Installed = INSTALLSTATE_INCOMPLETE;
2003 file->state = msifs_present;
2004 msi_free( file_version );
2007 file->state = msifs_present;
2010 return ERROR_SUCCESS;
2014 * A lot is done in this function aside from just the costing.
2015 * The costing needs to be implemented at some point but for now I am going
2016 * to focus on the directory building
2019 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2021 static const WCHAR ExecSeqQuery[] =
2022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023 '`','D','i','r','e','c','t','o','r','y','`',0};
2024 static const WCHAR ConditionQuery[] =
2025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026 '`','C','o','n','d','i','t','i','o','n','`',0};
2027 static const WCHAR szCosting[] =
2028 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029 static const WCHAR szlevel[] =
2030 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2031 static const WCHAR szOne[] = { '1', 0 };
2037 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2038 return ERROR_SUCCESS;
2040 TRACE("Building Directory properties\n");
2042 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2043 if (rc == ERROR_SUCCESS)
2045 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2047 msiobj_release(&view->hdr);
2050 /* read components states from the registry */
2051 ACTION_GetComponentInstallStates(package);
2053 TRACE("File calculations\n");
2054 msi_check_file_install_states( package );
2056 TRACE("Evaluating Condition Table\n");
2058 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2059 if (rc == ERROR_SUCCESS)
2061 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2063 msiobj_release(&view->hdr);
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2069 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2071 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2072 comp->Enabled = FALSE;
2076 MSI_SetPropertyW(package,szCosting,szOne);
2077 /* set default run level if not set */
2078 level = msi_dup_property( package, szlevel );
2080 MSI_SetPropertyW(package,szlevel, szOne);
2083 ACTION_UpdateFeatureInstallStates(package);
2085 return MSI_SetFeatureStates(package);
2088 /* OK this value is "interpreted" and then formatted based on the
2089 first few characters */
2090 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2094 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2100 LPWSTR deformated = NULL;
2103 deformat_string(package, &value[2], &deformated);
2105 /* binary value type */
2109 *size = (strlenW(ptr)/2)+1;
2111 *size = strlenW(ptr)/2;
2113 data = msi_alloc(*size);
2119 /* if uneven pad with a zero in front */
2125 data[count] = (BYTE)strtol(byte,NULL,0);
2127 TRACE("Uneven byte count\n");
2135 data[count] = (BYTE)strtol(byte,NULL,0);
2138 msi_free(deformated);
2140 TRACE("Data %i bytes(%i)\n",*size,count);
2147 deformat_string(package, &value[1], &deformated);
2150 *size = sizeof(DWORD);
2151 data = msi_alloc(*size);
2157 if ( (*p < '0') || (*p > '9') )
2163 if (deformated[0] == '-')
2166 TRACE("DWORD %i\n",*(LPDWORD)data);
2168 msi_free(deformated);
2173 static const WCHAR szMulti[] = {'[','~',']',0};
2182 *type=REG_EXPAND_SZ;
2190 if (strstrW(value,szMulti))
2191 *type = REG_MULTI_SZ;
2193 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2198 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2200 MSIPACKAGE *package = (MSIPACKAGE*)param;
2201 static const WCHAR szHCR[] =
2202 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2203 'R','O','O','T','\\',0};
2204 static const WCHAR szHCU[] =
2205 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2206 'U','S','E','R','\\',0};
2207 static const WCHAR szHLM[] =
2208 {'H','K','E','Y','_','L','O','C','A','L','_',
2209 'M','A','C','H','I','N','E','\\',0};
2210 static const WCHAR szHU[] =
2211 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2213 LPSTR value_data = NULL;
2214 HKEY root_key, hkey;
2217 LPCWSTR szRoot, component, name, key, value;
2222 BOOL check_first = FALSE;
2225 ui_progress(package,2,0,0,0);
2232 component = MSI_RecordGetString(row, 6);
2233 comp = get_loaded_component(package,component);
2235 return ERROR_SUCCESS;
2237 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2239 TRACE("Skipping write due to disabled component %s\n",
2240 debugstr_w(component));
2242 comp->Action = comp->Installed;
2244 return ERROR_SUCCESS;
2247 comp->Action = INSTALLSTATE_LOCAL;
2249 name = MSI_RecordGetString(row, 4);
2250 if( MSI_RecordIsNull(row,5) && name )
2252 /* null values can have special meanings */
2253 if (name[0]=='-' && name[1] == 0)
2254 return ERROR_SUCCESS;
2255 else if ((name[0]=='+' && name[1] == 0) ||
2256 (name[0] == '*' && name[1] == 0))
2261 root = MSI_RecordGetInteger(row,2);
2262 key = MSI_RecordGetString(row, 3);
2264 /* get the root key */
2269 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2270 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2271 if (all_users && all_users[0] == '1')
2273 root_key = HKEY_LOCAL_MACHINE;
2278 root_key = HKEY_CURRENT_USER;
2281 msi_free(all_users);
2284 case 0: root_key = HKEY_CLASSES_ROOT;
2287 case 1: root_key = HKEY_CURRENT_USER;
2290 case 2: root_key = HKEY_LOCAL_MACHINE;
2293 case 3: root_key = HKEY_USERS;
2297 ERR("Unknown root %i\n",root);
2303 return ERROR_SUCCESS;
2305 deformat_string(package, key , &deformated);
2306 size = strlenW(deformated) + strlenW(szRoot) + 1;
2307 uikey = msi_alloc(size*sizeof(WCHAR));
2308 strcpyW(uikey,szRoot);
2309 strcatW(uikey,deformated);
2311 if (RegCreateKeyW( root_key, deformated, &hkey))
2313 ERR("Could not create key %s\n",debugstr_w(deformated));
2314 msi_free(deformated);
2316 return ERROR_SUCCESS;
2318 msi_free(deformated);
2320 value = MSI_RecordGetString(row,5);
2322 value_data = parse_value(package, value, &type, &size);
2325 static const WCHAR szEmpty[] = {0};
2326 value_data = (LPSTR)strdupW(szEmpty);
2331 deformat_string(package, name, &deformated);
2333 /* get the double nulls to terminate SZ_MULTI */
2334 if (type == REG_MULTI_SZ)
2335 size +=sizeof(WCHAR);
2339 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2341 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2346 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2347 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2349 TRACE("value %s of %s checked already exists\n",
2350 debugstr_w(deformated), debugstr_w(uikey));
2354 TRACE("Checked and setting value %s of %s\n",
2355 debugstr_w(deformated), debugstr_w(uikey));
2356 if (deformated || size)
2357 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2362 uirow = MSI_CreateRecord(3);
2363 MSI_RecordSetStringW(uirow,2,deformated);
2364 MSI_RecordSetStringW(uirow,1,uikey);
2367 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2369 MSI_RecordSetStringW(uirow,3,value);
2371 ui_actiondata(package,szWriteRegistryValues,uirow);
2372 msiobj_release( &uirow->hdr );
2374 msi_free(value_data);
2375 msi_free(deformated);
2378 return ERROR_SUCCESS;
2381 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2385 static const WCHAR ExecSeqQuery[] =
2386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2387 '`','R','e','g','i','s','t','r','y','`',0 };
2389 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2390 if (rc != ERROR_SUCCESS)
2391 return ERROR_SUCCESS;
2393 /* increment progress bar each time action data is sent */
2394 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2396 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2398 msiobj_release(&view->hdr);
2402 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2404 package->script->CurrentlyScripting = TRUE;
2406 return ERROR_SUCCESS;
2410 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2415 static const WCHAR q1[]=
2416 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2417 '`','R','e','g','i','s','t','r','y','`',0};
2420 MSIFEATURE *feature;
2423 TRACE("InstallValidate\n");
2425 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2426 if (rc == ERROR_SUCCESS)
2428 MSI_IterateRecords( view, &progress, NULL, package );
2429 msiobj_release( &view->hdr );
2430 total += progress * REG_PROGRESS_VALUE;
2433 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2434 total += COMPONENT_PROGRESS_VALUE;
2436 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2437 total += file->FileSize;
2439 ui_progress(package,0,total,0,0);
2441 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2443 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2444 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2445 feature->ActionRequest);
2448 return ERROR_SUCCESS;
2451 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2453 MSIPACKAGE* package = (MSIPACKAGE*)param;
2454 LPCWSTR cond = NULL;
2455 LPCWSTR message = NULL;
2456 static const WCHAR title[]=
2457 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2459 cond = MSI_RecordGetString(row,1);
2461 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2464 message = MSI_RecordGetString(row,2);
2465 deformat_string(package,message,&deformated);
2466 MessageBoxW(NULL,deformated,title,MB_OK);
2467 msi_free(deformated);
2468 return ERROR_FUNCTION_FAILED;
2471 return ERROR_SUCCESS;
2474 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2477 MSIQUERY * view = NULL;
2478 static const WCHAR ExecSeqQuery[] =
2479 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2480 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2482 TRACE("Checking launch conditions\n");
2484 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2485 if (rc != ERROR_SUCCESS)
2486 return ERROR_SUCCESS;
2488 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2489 msiobj_release(&view->hdr);
2494 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2498 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2500 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2502 MSIRECORD * row = 0;
2504 LPWSTR deformated,buffer,deformated_name;
2506 static const WCHAR ExecSeqQuery[] =
2507 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2508 '`','R','e','g','i','s','t','r','y','`',' ',
2509 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2510 ' ','=',' ' ,'\'','%','s','\'',0 };
2511 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2512 static const WCHAR fmt2[]=
2513 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2515 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2519 root = MSI_RecordGetInteger(row,2);
2520 key = MSI_RecordGetString(row, 3);
2521 name = MSI_RecordGetString(row, 4);
2522 deformat_string(package, key , &deformated);
2523 deformat_string(package, name, &deformated_name);
2525 len = strlenW(deformated) + 6;
2526 if (deformated_name)
2527 len+=strlenW(deformated_name);
2529 buffer = msi_alloc( len *sizeof(WCHAR));
2531 if (deformated_name)
2532 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2534 sprintfW(buffer,fmt,root,deformated);
2536 msi_free(deformated);
2537 msi_free(deformated_name);
2538 msiobj_release(&row->hdr);
2542 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2544 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2549 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2552 return strdupW( file->TargetPath );
2557 static HKEY openSharedDLLsKey(void)
2560 static const WCHAR path[] =
2561 {'S','o','f','t','w','a','r','e','\\',
2562 'M','i','c','r','o','s','o','f','t','\\',
2563 'W','i','n','d','o','w','s','\\',
2564 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2565 'S','h','a','r','e','d','D','L','L','s',0};
2567 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2571 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2576 DWORD sz = sizeof(count);
2579 hkey = openSharedDLLsKey();
2580 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2581 if (rc != ERROR_SUCCESS)
2587 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2591 hkey = openSharedDLLsKey();
2593 msi_reg_set_val_dword( hkey, path, count );
2595 RegDeleteValueW(hkey,path);
2601 * Return TRUE if the count should be written out and FALSE if not
2603 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2605 MSIFEATURE *feature;
2609 /* only refcount DLLs */
2610 if (comp->KeyPath == NULL ||
2611 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2612 comp->Attributes & msidbComponentAttributesODBCDataSource)
2616 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2617 write = (count > 0);
2619 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2623 /* increment counts */
2624 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2628 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2631 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2633 if ( cl->component == comp )
2638 /* decrement counts */
2639 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2643 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2646 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2648 if ( cl->component == comp )
2653 /* ref count all the files in the component */
2658 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2660 if (file->Component == comp)
2661 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2665 /* add a count for permenent */
2666 if (comp->Attributes & msidbComponentAttributesPermanent)
2669 comp->RefCount = count;
2672 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2676 * Ok further analysis makes me think that this work is
2677 * actually done in the PublishComponents and PublishFeatures
2678 * step, and not here. It appears like the keypath and all that is
2679 * resolved in this step, however actually written in the Publish steps.
2680 * But we will leave it here for now because it is unclear
2682 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2684 WCHAR squished_pc[GUID_SIZE];
2685 WCHAR squished_cc[GUID_SIZE];
2688 HKEY hkey=0,hkey2=0;
2690 /* writes the Component and Features values to the registry */
2692 rc = MSIREG_OpenComponents(&hkey);
2693 if (rc != ERROR_SUCCESS)
2696 squash_guid(package->ProductCode,squished_pc);
2697 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2699 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2703 ui_progress(package,2,0,0,0);
2704 if (!comp->ComponentId)
2707 squash_guid(comp->ComponentId,squished_cc);
2709 msi_free(comp->FullKeypath);
2710 comp->FullKeypath = resolve_keypath( package, comp );
2712 /* do the refcounting */
2713 ACTION_RefCountComponent( package, comp );
2715 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2716 debugstr_w(comp->Component),
2717 debugstr_w(squished_cc),
2718 debugstr_w(comp->FullKeypath),
2721 * Write the keypath out if the component is to be registered
2722 * and delete the key if the component is to be deregistered
2724 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2726 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2727 if (rc != ERROR_SUCCESS)
2730 if (!comp->FullKeypath)
2733 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2735 if (comp->Attributes & msidbComponentAttributesPermanent)
2737 static const WCHAR szPermKey[] =
2738 { '0','0','0','0','0','0','0','0','0','0','0','0',
2739 '0','0','0','0','0','0','0','0','0','0','0','0',
2740 '0','0','0','0','0','0','0','0',0 };
2742 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2748 uirow = MSI_CreateRecord(3);
2749 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2750 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2751 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2752 ui_actiondata(package,szProcessComponents,uirow);
2753 msiobj_release( &uirow->hdr );
2755 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2759 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2760 if (rc != ERROR_SUCCESS)
2763 RegDeleteValueW(hkey2,squished_pc);
2765 /* if the key is empty delete it */
2766 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2768 if (res == ERROR_NO_MORE_ITEMS)
2769 RegDeleteKeyW(hkey,squished_cc);
2772 uirow = MSI_CreateRecord(2);
2773 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2774 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2775 ui_actiondata(package,szProcessComponents,uirow);
2776 msiobj_release( &uirow->hdr );
2791 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2792 LPWSTR lpszName, LONG_PTR lParam)
2795 typelib_struct *tl_struct = (typelib_struct*) lParam;
2796 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2800 if (!IS_INTRESOURCE(lpszName))
2802 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2806 sz = strlenW(tl_struct->source)+4;
2807 sz *= sizeof(WCHAR);
2809 if ((INT_PTR)lpszName == 1)
2810 tl_struct->path = strdupW(tl_struct->source);
2813 tl_struct->path = msi_alloc(sz);
2814 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2817 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2818 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2819 if (!SUCCEEDED(res))
2821 msi_free(tl_struct->path);
2822 tl_struct->path = NULL;
2827 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2828 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2830 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2834 msi_free(tl_struct->path);
2835 tl_struct->path = NULL;
2837 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2838 ITypeLib_Release(tl_struct->ptLib);
2843 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2845 MSIPACKAGE* package = (MSIPACKAGE*)param;
2849 typelib_struct tl_struct;
2851 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2853 component = MSI_RecordGetString(row,3);
2854 comp = get_loaded_component(package,component);
2856 return ERROR_SUCCESS;
2858 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2860 TRACE("Skipping typelib reg due to disabled component\n");
2862 comp->Action = comp->Installed;
2864 return ERROR_SUCCESS;
2867 comp->Action = INSTALLSTATE_LOCAL;
2869 file = get_loaded_file( package, comp->KeyPath );
2871 return ERROR_SUCCESS;
2873 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2877 guid = MSI_RecordGetString(row,1);
2878 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2879 tl_struct.source = strdupW( file->TargetPath );
2880 tl_struct.path = NULL;
2882 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2883 (LONG_PTR)&tl_struct);
2891 helpid = MSI_RecordGetString(row,6);
2894 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2895 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2898 if (!SUCCEEDED(res))
2899 ERR("Failed to register type library %s\n",
2900 debugstr_w(tl_struct.path));
2903 ui_actiondata(package,szRegisterTypeLibraries,row);
2905 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2908 ITypeLib_Release(tl_struct.ptLib);
2909 msi_free(tl_struct.path);
2912 ERR("Failed to load type library %s\n",
2913 debugstr_w(tl_struct.source));
2915 FreeLibrary(module);
2916 msi_free(tl_struct.source);
2919 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2921 return ERROR_SUCCESS;
2924 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2927 * OK this is a bit confusing.. I am given a _Component key and I believe
2928 * that the file that is being registered as a type library is the "key file
2929 * of that component" which I interpret to mean "The file in the KeyPath of
2934 static const WCHAR Query[] =
2935 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2936 '`','T','y','p','e','L','i','b','`',0};
2938 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2939 if (rc != ERROR_SUCCESS)
2940 return ERROR_SUCCESS;
2942 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2943 msiobj_release(&view->hdr);
2947 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2949 MSIPACKAGE *package = (MSIPACKAGE*)param;
2950 LPWSTR target_file, target_folder, filename;
2951 LPCWSTR buffer, extension;
2953 static const WCHAR szlnk[]={'.','l','n','k',0};
2954 IShellLinkW *sl = NULL;
2955 IPersistFile *pf = NULL;
2958 buffer = MSI_RecordGetString(row,4);
2959 comp = get_loaded_component(package,buffer);
2961 return ERROR_SUCCESS;
2963 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2965 TRACE("Skipping shortcut creation due to disabled component\n");
2967 comp->Action = comp->Installed;
2969 return ERROR_SUCCESS;
2972 comp->Action = INSTALLSTATE_LOCAL;
2974 ui_actiondata(package,szCreateShortcuts,row);
2976 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2977 &IID_IShellLinkW, (LPVOID *) &sl );
2981 ERR("CLSID_ShellLink not available\n");
2985 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2988 ERR("QueryInterface(IID_IPersistFile) failed\n");
2992 buffer = MSI_RecordGetString(row,2);
2993 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2995 /* may be needed because of a bug somehwere else */
2996 create_full_pathW(target_folder);
2998 filename = msi_dup_record_field( row, 3 );
2999 reduce_to_longfilename(filename);
3001 extension = strchrW(filename,'.');
3002 if (!extension || strcmpiW(extension,szlnk))
3004 int len = strlenW(filename);
3005 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3006 memcpy(filename + len, szlnk, sizeof(szlnk));
3008 target_file = build_directory_name(2, target_folder, filename);
3009 msi_free(target_folder);
3012 buffer = MSI_RecordGetString(row,5);
3013 if (strchrW(buffer,'['))
3016 deformat_string(package,buffer,&deformated);
3017 IShellLinkW_SetPath(sl,deformated);
3018 msi_free(deformated);
3022 FIXME("poorly handled shortcut format, advertised shortcut\n");
3023 IShellLinkW_SetPath(sl,comp->FullKeypath);
3026 if (!MSI_RecordIsNull(row,6))
3029 buffer = MSI_RecordGetString(row,6);
3030 deformat_string(package,buffer,&deformated);
3031 IShellLinkW_SetArguments(sl,deformated);
3032 msi_free(deformated);
3035 if (!MSI_RecordIsNull(row,7))
3037 buffer = MSI_RecordGetString(row,7);
3038 IShellLinkW_SetDescription(sl,buffer);
3041 if (!MSI_RecordIsNull(row,8))
3042 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3044 if (!MSI_RecordIsNull(row,9))
3049 buffer = MSI_RecordGetString(row,9);
3051 Path = build_icon_path(package,buffer);
3052 index = MSI_RecordGetInteger(row,10);
3054 /* no value means 0 */
3055 if (index == MSI_NULL_INTEGER)
3058 IShellLinkW_SetIconLocation(sl,Path,index);
3062 if (!MSI_RecordIsNull(row,11))
3063 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3065 if (!MSI_RecordIsNull(row,12))
3068 buffer = MSI_RecordGetString(row,12);
3069 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3071 IShellLinkW_SetWorkingDirectory(sl,Path);
3075 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3076 IPersistFile_Save(pf,target_file,FALSE);
3078 msi_free(target_file);
3082 IPersistFile_Release( pf );
3084 IShellLinkW_Release( sl );
3086 return ERROR_SUCCESS;
3089 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3094 static const WCHAR Query[] =
3095 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3096 '`','S','h','o','r','t','c','u','t','`',0};
3098 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3099 if (rc != ERROR_SUCCESS)
3100 return ERROR_SUCCESS;
3102 res = CoInitialize( NULL );
3105 ERR("CoInitialize failed\n");
3106 return ERROR_FUNCTION_FAILED;
3109 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3110 msiobj_release(&view->hdr);
3117 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3119 MSIPACKAGE* package = (MSIPACKAGE*)param;
3128 FileName = MSI_RecordGetString(row,1);
3131 ERR("Unable to get FileName\n");
3132 return ERROR_SUCCESS;
3135 FilePath = build_icon_path(package,FileName);
3137 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3139 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3140 FILE_ATTRIBUTE_NORMAL, NULL);
3142 if (the_file == INVALID_HANDLE_VALUE)
3144 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3146 return ERROR_SUCCESS;
3153 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3154 if (rc != ERROR_SUCCESS)
3156 ERR("Failed to get stream\n");
3157 CloseHandle(the_file);
3158 DeleteFileW(FilePath);
3161 WriteFile(the_file,buffer,sz,&write,NULL);
3162 } while (sz == 1024);
3166 CloseHandle(the_file);
3168 uirow = MSI_CreateRecord(1);
3169 MSI_RecordSetStringW(uirow,1,FileName);
3170 ui_actiondata(package,szPublishProduct,uirow);
3171 msiobj_release( &uirow->hdr );
3173 return ERROR_SUCCESS;
3177 * 99% of the work done here is only done for
3178 * advertised installs. However this is where the
3179 * Icon table is processed and written out
3180 * so that is what I am going to do here.
3182 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3186 static const WCHAR Query[]=
3187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3188 '`','I','c','o','n','`',0};
3189 /* for registry stuff */
3192 static const WCHAR szProductLanguage[] =
3193 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3194 static const WCHAR szARPProductIcon[] =
3195 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3196 static const WCHAR szProductVersion[] =
3197 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3201 MSIHANDLE hDb, hSumInfo;
3203 /* write out icon files */
3205 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3206 if (rc == ERROR_SUCCESS)
3208 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3209 msiobj_release(&view->hdr);
3212 /* ok there is a lot more done here but i need to figure out what */
3214 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3215 if (rc != ERROR_SUCCESS)
3218 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3219 if (rc != ERROR_SUCCESS)
3223 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3224 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3227 langid = msi_get_property_int( package, szProductLanguage, 0 );
3228 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3230 buffer = msi_dup_property( package, szARPProductIcon );
3233 LPWSTR path = build_icon_path(package,buffer);
3234 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3239 buffer = msi_dup_property( package, szProductVersion );
3242 DWORD verdword = msi_version_str_to_dword(buffer);
3243 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3247 /* FIXME: Need to write more keys to the user registry */
3249 hDb= alloc_msihandle( &package->db->hdr );
3251 rc = ERROR_NOT_ENOUGH_MEMORY;
3254 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3255 MsiCloseHandle(hDb);
3256 if (rc == ERROR_SUCCESS)
3258 WCHAR guidbuffer[0x200];
3260 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3262 if (rc == ERROR_SUCCESS)
3264 WCHAR squashed[GUID_SIZE];
3265 /* for now we only care about the first guid */
3266 LPWSTR ptr = strchrW(guidbuffer,';');
3268 squash_guid(guidbuffer,squashed);
3269 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3273 ERR("Unable to query Revision_Number...\n");
3276 MsiCloseHandle(hSumInfo);
3280 ERR("Unable to open Summary Information\n");
3292 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3294 MSIPACKAGE *package = (MSIPACKAGE*)param;
3295 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3296 LPWSTR deformated_section, deformated_key, deformated_value;
3297 LPWSTR folder, fullname = NULL;
3301 static const WCHAR szWindowsFolder[] =
3302 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3304 component = MSI_RecordGetString(row, 8);
3305 comp = get_loaded_component(package,component);
3307 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3309 TRACE("Skipping ini file due to disabled component %s\n",
3310 debugstr_w(component));
3312 comp->Action = comp->Installed;
3314 return ERROR_SUCCESS;
3317 comp->Action = INSTALLSTATE_LOCAL;
3319 identifier = MSI_RecordGetString(row,1);
3320 filename = MSI_RecordGetString(row,2);
3321 dirproperty = MSI_RecordGetString(row,3);
3322 section = MSI_RecordGetString(row,4);
3323 key = MSI_RecordGetString(row,5);
3324 value = MSI_RecordGetString(row,6);
3325 action = MSI_RecordGetInteger(row,7);
3327 deformat_string(package,section,&deformated_section);
3328 deformat_string(package,key,&deformated_key);
3329 deformat_string(package,value,&deformated_value);
3333 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3335 folder = msi_dup_property( package, dirproperty );
3338 folder = msi_dup_property( package, szWindowsFolder );
3342 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3346 fullname = build_directory_name(2, folder, filename);
3350 TRACE("Adding value %s to section %s in %s\n",
3351 debugstr_w(deformated_key), debugstr_w(deformated_section),
3352 debugstr_w(fullname));
3353 WritePrivateProfileStringW(deformated_section, deformated_key,
3354 deformated_value, fullname);
3356 else if (action == 1)
3359 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3360 returned, 10, fullname);
3361 if (returned[0] == 0)
3363 TRACE("Adding value %s to section %s in %s\n",
3364 debugstr_w(deformated_key), debugstr_w(deformated_section),
3365 debugstr_w(fullname));
3367 WritePrivateProfileStringW(deformated_section, deformated_key,
3368 deformated_value, fullname);
3371 else if (action == 3)
3372 FIXME("Append to existing section not yet implemented\n");
3374 uirow = MSI_CreateRecord(4);
3375 MSI_RecordSetStringW(uirow,1,identifier);
3376 MSI_RecordSetStringW(uirow,2,deformated_section);
3377 MSI_RecordSetStringW(uirow,3,deformated_key);
3378 MSI_RecordSetStringW(uirow,4,deformated_value);
3379 ui_actiondata(package,szWriteIniValues,uirow);
3380 msiobj_release( &uirow->hdr );
3384 msi_free(deformated_key);
3385 msi_free(deformated_value);
3386 msi_free(deformated_section);
3387 return ERROR_SUCCESS;
3390 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3394 static const WCHAR ExecSeqQuery[] =
3395 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3396 '`','I','n','i','F','i','l','e','`',0};
3398 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3399 if (rc != ERROR_SUCCESS)
3401 TRACE("no IniFile table\n");
3402 return ERROR_SUCCESS;
3405 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3406 msiobj_release(&view->hdr);
3410 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3412 MSIPACKAGE *package = (MSIPACKAGE*)param;
3417 static const WCHAR ExeStr[] =
3418 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3419 static const WCHAR close[] = {'\"',0};
3421 PROCESS_INFORMATION info;
3426 memset(&si,0,sizeof(STARTUPINFOW));
3428 filename = MSI_RecordGetString(row,1);
3429 file = get_loaded_file( package, filename );
3433 ERR("Unable to find file id %s\n",debugstr_w(filename));
3434 return ERROR_SUCCESS;
3437 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3439 FullName = msi_alloc(len*sizeof(WCHAR));
3440 strcpyW(FullName,ExeStr);
3441 strcatW( FullName, file->TargetPath );
3442 strcatW(FullName,close);
3444 TRACE("Registering %s\n",debugstr_w(FullName));
3445 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3449 msi_dialog_check_messages(info.hProcess);
3454 uirow = MSI_CreateRecord( 2 );
3455 uipath = strdupW( file->TargetPath );
3456 p = strrchrW(uipath,'\\');
3459 MSI_RecordSetStringW( uirow, 1, &p[2] );
3460 MSI_RecordSetStringW( uirow, 2, uipath);
3461 ui_actiondata( package, szSelfRegModules, uirow);
3462 msiobj_release( &uirow->hdr );
3464 /* FIXME: call ui_progress? */
3466 return ERROR_SUCCESS;
3469 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3473 static const WCHAR ExecSeqQuery[] =
3474 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3475 '`','S','e','l','f','R','e','g','`',0};
3477 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3478 if (rc != ERROR_SUCCESS)
3480 TRACE("no SelfReg table\n");
3481 return ERROR_SUCCESS;
3484 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3485 msiobj_release(&view->hdr);
3487 return ERROR_SUCCESS;
3490 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3492 MSIFEATURE *feature;
3497 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3498 if (rc != ERROR_SUCCESS)
3501 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3502 if (rc != ERROR_SUCCESS)
3505 /* here the guids are base 85 encoded */
3506 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3512 BOOL absent = FALSE;
3515 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3516 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3517 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3521 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3525 if (feature->Feature_Parent)
3526 size += strlenW( feature->Feature_Parent )+2;
3528 data = msi_alloc(size * sizeof(WCHAR));
3531 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3533 MSICOMPONENT* component = cl->component;
3537 if (component->ComponentId)
3539 TRACE("From %s\n",debugstr_w(component->ComponentId));
3540 CLSIDFromString(component->ComponentId, &clsid);
3541 encode_base85_guid(&clsid,buf);
3542 TRACE("to %s\n",debugstr_w(buf));
3546 if (feature->Feature_Parent)
3548 static const WCHAR sep[] = {'\2',0};
3550 strcatW(data,feature->Feature_Parent);
3553 msi_reg_set_val_str( hkey, feature->Feature, data );
3557 if (feature->Feature_Parent)
3558 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3561 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3562 (LPBYTE)feature->Feature_Parent,size);
3566 size += 2*sizeof(WCHAR);
3567 data = msi_alloc(size);
3570 if (feature->Feature_Parent)
3571 strcpyW( &data[1], feature->Feature_Parent );
3572 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3578 uirow = MSI_CreateRecord( 1 );
3579 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3580 ui_actiondata( package, szPublishFeatures, uirow);
3581 msiobj_release( &uirow->hdr );
3582 /* FIXME: call ui_progress? */
3591 static UINT msi_get_local_package_name( LPWSTR path )
3593 static const WCHAR szInstaller[] = {
3594 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3595 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3599 time = GetTickCount();
3600 GetWindowsDirectoryW( path, MAX_PATH );
3601 lstrcatW( path, szInstaller );
3602 CreateDirectoryW( path, NULL );
3604 len = lstrlenW(path);
3605 for (i=0; i<0x10000; i++)
3607 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3608 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3609 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3610 if (handle != INVALID_HANDLE_VALUE)
3612 CloseHandle(handle);
3615 if (GetLastError() != ERROR_FILE_EXISTS &&
3616 GetLastError() != ERROR_SHARING_VIOLATION)
3617 return ERROR_FUNCTION_FAILED;
3620 return ERROR_SUCCESS;
3623 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3625 static const WCHAR szOriginalDatabase[] =
3626 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3627 WCHAR packagefile[MAX_PATH];
3631 r = msi_get_local_package_name( packagefile );
3632 if (r != ERROR_SUCCESS)
3635 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3637 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3638 r = CopyFileW( msiFilePath, packagefile, FALSE);
3639 msi_free( msiFilePath );
3643 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3644 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3645 return ERROR_FUNCTION_FAILED;
3648 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3649 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3650 return ERROR_SUCCESS;
3653 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3655 LPWSTR prop, val, key;
3656 static const LPCSTR propval[] = {
3657 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3658 "ARPCONTACT", "Contact",
3659 "ARPCOMMENTS", "Comments",
3660 "ProductName", "DisplayName",
3661 "ProductVersion", "DisplayVersion",
3662 "ARPHELPLINK", "HelpLink",
3663 "ARPHELPTELEPHONE", "HelpTelephone",
3664 "ARPINSTALLLOCATION", "InstallLocation",
3665 "SourceDir", "InstallSource",
3666 "Manufacturer", "Publisher",
3667 "ARPREADME", "Readme",
3669 "ARPURLINFOABOUT", "URLInfoAbout",
3670 "ARPURLUPDATEINFO", "URLUpdateInfo",
3673 const LPCSTR *p = propval;
3677 prop = strdupAtoW( *p++ );
3678 key = strdupAtoW( *p++ );
3679 val = msi_dup_property( package, prop );
3680 msi_reg_set_val_str( hkey, key, val );
3685 return ERROR_SUCCESS;
3688 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3691 LPWSTR buffer = NULL;
3694 static const WCHAR szWindowsInstaller[] =
3695 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3696 static const WCHAR szUpgradeCode[] =
3697 {'U','p','g','r','a','d','e','C','o','d','e',0};
3698 static const WCHAR modpath_fmt[] =
3699 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3700 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3701 static const WCHAR szModifyPath[] =
3702 {'M','o','d','i','f','y','P','a','t','h',0};
3703 static const WCHAR szUninstallString[] =
3704 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3705 static const WCHAR szEstimatedSize[] =
3706 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3707 static const WCHAR szProductLanguage[] =
3708 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3709 static const WCHAR szProductVersion[] =
3710 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3713 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3714 LPWSTR upgrade_code;
3717 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3718 if (rc != ERROR_SUCCESS)
3721 /* dump all the info i can grab */
3722 /* FIXME: Flesh out more information */
3724 msi_write_uninstall_property_vals( package, hkey );
3726 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3728 msi_make_package_local( package, hkey );
3730 /* do ModifyPath and UninstallString */
3731 size = deformat_string(package,modpath_fmt,&buffer);
3732 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3733 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3736 /* FIXME: Write real Estimated Size when we have it */
3737 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3739 GetLocalTime(&systime);
3740 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3741 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3743 langid = msi_get_property_int( package, szProductLanguage, 0 );
3744 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3746 buffer = msi_dup_property( package, szProductVersion );
3749 DWORD verdword = msi_version_str_to_dword(buffer);
3751 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3752 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3753 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3757 /* Handle Upgrade Codes */
3758 upgrade_code = msi_dup_property( package, szUpgradeCode );
3763 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3764 squash_guid(package->ProductCode,squashed);
3765 msi_reg_set_val_str( hkey2, squashed, NULL );
3767 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3768 squash_guid(package->ProductCode,squashed);
3769 msi_reg_set_val_str( hkey2, squashed, NULL );
3772 msi_free(upgrade_code);
3777 /* FIXME: call ui_actiondata */
3779 return ERROR_SUCCESS;
3782 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3784 return execute_script(package,INSTALL_SCRIPT);
3787 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3791 /* turn off scheduleing */
3792 package->script->CurrentlyScripting= FALSE;
3794 /* first do the same as an InstallExecute */
3795 rc = ACTION_InstallExecute(package);
3796 if (rc != ERROR_SUCCESS)
3799 /* then handle Commit Actions */
3800 rc = execute_script(package,COMMIT_SCRIPT);
3805 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3807 static const WCHAR RunOnce[] = {
3808 'S','o','f','t','w','a','r','e','\\',
3809 'M','i','c','r','o','s','o','f','t','\\',
3810 'W','i','n','d','o','w','s','\\',
3811 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3812 'R','u','n','O','n','c','e',0};
3813 static const WCHAR InstallRunOnce[] = {
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 'I','n','s','t','a','l','l','e','r','\\',
3819 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3821 static const WCHAR msiexec_fmt[] = {
3823 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3824 '\"','%','s','\"',0};
3825 static const WCHAR install_fmt[] = {
3826 '/','I',' ','\"','%','s','\"',' ',
3827 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3828 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3829 WCHAR buffer[256], sysdir[MAX_PATH];
3831 WCHAR squished_pc[100];
3833 squash_guid(package->ProductCode,squished_pc);
3835 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3836 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3837 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3840 msi_reg_set_val_str( hkey, squished_pc, buffer );
3843 TRACE("Reboot command %s\n",debugstr_w(buffer));
3845 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3846 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3848 msi_reg_set_val_str( hkey, squished_pc, buffer );
3851 return ERROR_INSTALL_SUSPEND;
3854 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3861 * we are currently doing what should be done here in the top level Install
3862 * however for Adminastrative and uninstalls this step will be needed
3864 if (!package->PackagePath)
3865 return ERROR_SUCCESS;
3867 ptr = strrchrW(package->PackagePath, '\\');
3869 return ERROR_SUCCESS;
3871 len = ptr - package->PackagePath + 2;
3872 source = msi_alloc(len * sizeof(WCHAR));
3873 lstrcpynW(source, package->PackagePath, len);
3875 MSI_SetPropertyW(package, cszSourceDir, source);
3876 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3880 attrib = GetFileAttributesW(package->PackagePath);
3881 if (attrib == INVALID_FILE_ATTRIBUTES)
3887 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3888 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3889 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3890 if (rc == ERROR_MORE_DATA)
3892 prompt = msi_alloc(size * sizeof(WCHAR));
3893 MsiSourceListGetInfoW(package->ProductCode, NULL,
3894 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3895 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3898 prompt = strdupW(package->PackagePath);
3900 msg = generate_error_string(package,1302,1,prompt);
3901 while(attrib == INVALID_FILE_ATTRIBUTES)
3903 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3906 rc = ERROR_INSTALL_USEREXIT;
3909 attrib = GetFileAttributesW(package->PackagePath);
3915 return ERROR_SUCCESS;
3920 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3927 static const WCHAR szPropKeys[][80] =
3929 {'P','r','o','d','u','c','t','I','D',0},
3930 {'U','S','E','R','N','A','M','E',0},
3931 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3935 static const WCHAR szRegKeys[][80] =
3937 {'P','r','o','d','u','c','t','I','D',0},
3938 {'R','e','g','O','w','n','e','r',0},
3939 {'R','e','g','C','o','m','p','a','n','y',0},
3943 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3945 return ERROR_SUCCESS;
3947 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3948 if (rc != ERROR_SUCCESS)
3951 for( i = 0; szPropKeys[i][0]; i++ )
3953 buffer = msi_dup_property( package, szPropKeys[i] );
3954 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3959 msi_free(productid);
3962 /* FIXME: call ui_actiondata */
3964 return ERROR_SUCCESS;
3968 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3972 package->script->InWhatSequence |= SEQUENCE_EXEC;
3973 rc = ACTION_ProcessExecSequence(package,FALSE);
3978 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3980 MSIPACKAGE *package = (MSIPACKAGE*)param;
3981 LPCWSTR compgroupid=NULL;
3982 LPCWSTR feature=NULL;
3983 LPCWSTR text = NULL;
3984 LPCWSTR qualifier = NULL;
3985 LPCWSTR component = NULL;
3986 LPWSTR advertise = NULL;
3987 LPWSTR output = NULL;
3989 UINT rc = ERROR_SUCCESS;
3994 component = MSI_RecordGetString(rec,3);
3995 comp = get_loaded_component(package,component);
3997 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3998 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3999 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4001 TRACE("Skipping: Component %s not scheduled for install\n",
4002 debugstr_w(component));
4004 return ERROR_SUCCESS;
4007 compgroupid = MSI_RecordGetString(rec,1);
4008 qualifier = MSI_RecordGetString(rec,2);
4010 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4011 if (rc != ERROR_SUCCESS)
4014 text = MSI_RecordGetString(rec,4);
4015 feature = MSI_RecordGetString(rec,5);
4017 advertise = create_component_advertise_string(package, comp, feature);
4019 sz = strlenW(advertise);
4022 sz += lstrlenW(text);
4025 sz *= sizeof(WCHAR);
4027 output = msi_alloc_zero(sz);
4028 strcpyW(output,advertise);
4029 msi_free(advertise);
4032 strcatW(output,text);
4034 msi_reg_set_val_multi_str( hkey, qualifier, output );
4041 uirow = MSI_CreateRecord( 2 );
4042 MSI_RecordSetStringW( uirow, 1, compgroupid );
4043 MSI_RecordSetStringW( uirow, 2, qualifier);
4044 ui_actiondata( package, szPublishComponents, uirow);
4045 msiobj_release( &uirow->hdr );
4046 /* FIXME: call ui_progress? */
4052 * At present I am ignorning the advertised components part of this and only
4053 * focusing on the qualified component sets
4055 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4059 static const WCHAR ExecSeqQuery[] =
4060 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4061 '`','P','u','b','l','i','s','h',
4062 'C','o','m','p','o','n','e','n','t','`',0};
4064 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4065 if (rc != ERROR_SUCCESS)
4066 return ERROR_SUCCESS;
4068 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4069 msiobj_release(&view->hdr);
4074 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4076 MSIPACKAGE *package = (MSIPACKAGE*)param;
4079 SC_HANDLE hscm, service = NULL;
4080 LPCWSTR name, disp, comp, depends, pass;
4081 LPCWSTR load_order, serv_name, key;
4082 DWORD serv_type, start_type;
4085 static const WCHAR query[] =
4086 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4087 '`','C','o','m','p','o','n','e','n','t','`',' ',
4088 'W','H','E','R','E',' ',
4089 '`','C','o','m','p','o','n','e','n','t','`',' ',
4090 '=','\'','%','s','\'',0};
4092 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4095 ERR("Failed to open the SC Manager!\n");
4099 start_type = MSI_RecordGetInteger(rec, 5);
4100 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4103 depends = MSI_RecordGetString(rec, 8);
4104 if (depends && *depends)
4105 FIXME("Dependency list unhandled!\n");
4107 name = MSI_RecordGetString(rec, 2);
4108 disp = MSI_RecordGetString(rec, 3);
4109 serv_type = MSI_RecordGetInteger(rec, 4);
4110 err_control = MSI_RecordGetInteger(rec, 6);
4111 load_order = MSI_RecordGetString(rec, 7);
4112 serv_name = MSI_RecordGetString(rec, 9);
4113 pass = MSI_RecordGetString(rec, 10);
4114 comp = MSI_RecordGetString(rec, 12);
4116 /* fetch the service path */
4117 row = MSI_QueryGetRecord(package->db, query, comp);
4120 ERR("Control query failed!\n");
4124 key = MSI_RecordGetString(row, 6);
4125 msiobj_release(&row->hdr);
4127 file = get_loaded_file(package, key);
4130 ERR("Failed to load the service file\n");
4134 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4135 start_type, err_control, file->TargetPath,
4136 load_order, NULL, NULL, serv_name, pass);
4139 if (GetLastError() != ERROR_SERVICE_EXISTS)
4140 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4144 CloseServiceHandle(service);
4145 CloseServiceHandle(hscm);
4147 return ERROR_SUCCESS;
4150 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4154 static const WCHAR ExecSeqQuery[] =
4155 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4156 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4158 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4159 if (rc != ERROR_SUCCESS)
4160 return ERROR_SUCCESS;
4162 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4163 msiobj_release(&view->hdr);
4168 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4169 LPCSTR action, LPCWSTR table )
4171 static const WCHAR query[] = {
4172 'S','E','L','E','C','T',' ','*',' ',
4173 'F','R','O','M',' ','`','%','s','`',0 };
4174 MSIQUERY *view = NULL;
4178 r = MSI_OpenQuery( package->db, &view, query, table );
4179 if (r == ERROR_SUCCESS)
4181 r = MSI_IterateRecords(view, &count, NULL, package);
4182 msiobj_release(&view->hdr);
4186 FIXME("%s -> %u ignored %s table values\n",
4187 action, count, debugstr_w(table));
4189 return ERROR_SUCCESS;
4192 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4194 TRACE("%p\n", package);
4195 return ERROR_SUCCESS;
4198 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4200 static const WCHAR table[] =
4201 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4202 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4205 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4207 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4208 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4211 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4213 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4214 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4217 static UINT ACTION_BindImage( MSIPACKAGE *package )
4219 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4220 return msi_unimplemented_action_stub( package, "BindImage", table );
4223 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4225 static const WCHAR table[] = {
4226 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4227 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4230 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4232 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4233 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4236 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4238 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4239 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4242 static UINT ACTION_StartServices( MSIPACKAGE *package )
4244 static const WCHAR table[] = {
4245 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4246 return msi_unimplemented_action_stub( package, "StartServices", table );
4249 static UINT ACTION_StopServices( MSIPACKAGE *package )
4251 static const WCHAR table[] = {
4252 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4253 return msi_unimplemented_action_stub( package, "StopServices", table );
4256 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4258 static const WCHAR table[] = {
4259 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4260 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4263 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4265 static const WCHAR table[] = {
4266 'E','n','v','i','r','o','n','m','e','n','t',0 };
4267 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4270 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4272 static const WCHAR table[] = {
4273 'E','n','v','i','r','o','n','m','e','n','t',0 };
4274 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4277 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4279 static const WCHAR table[] = {
4280 'M','s','i','A','s','s','e','m','b','l','y',0 };
4281 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4284 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4286 static const WCHAR table[] = {
4287 'M','s','i','A','s','s','e','m','b','l','y',0 };
4288 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4291 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4293 static const WCHAR table[] = { 'F','o','n','t',0 };
4294 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4297 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4299 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4300 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4303 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4305 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4306 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4309 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4311 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4312 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4315 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4317 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4318 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4321 static struct _actions StandardActions[] = {
4322 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4323 { szAppSearch, ACTION_AppSearch },
4324 { szBindImage, ACTION_BindImage },
4325 { szCCPSearch, ACTION_CCPSearch},
4326 { szCostFinalize, ACTION_CostFinalize },
4327 { szCostInitialize, ACTION_CostInitialize },
4328 { szCreateFolders, ACTION_CreateFolders },
4329 { szCreateShortcuts, ACTION_CreateShortcuts },
4330 { szDeleteServices, ACTION_DeleteServices },
4331 { szDisableRollback, NULL},
4332 { szDuplicateFiles, ACTION_DuplicateFiles },
4333 { szExecuteAction, ACTION_ExecuteAction },
4334 { szFileCost, ACTION_FileCost },
4335 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4336 { szForceReboot, ACTION_ForceReboot },
4337 { szInstallAdminPackage, NULL},
4338 { szInstallExecute, ACTION_InstallExecute },
4339 { szInstallExecuteAgain, ACTION_InstallExecute },
4340 { szInstallFiles, ACTION_InstallFiles},
4341 { szInstallFinalize, ACTION_InstallFinalize },
4342 { szInstallInitialize, ACTION_InstallInitialize },
4343 { szInstallSFPCatalogFile, NULL},
4344 { szInstallValidate, ACTION_InstallValidate },
4345 { szIsolateComponents, ACTION_IsolateComponents },
4346 { szLaunchConditions, ACTION_LaunchConditions },
4347 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4348 { szMoveFiles, ACTION_MoveFiles },
4349 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4350 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4351 { szInstallODBC, NULL},
4352 { szInstallServices, ACTION_InstallServices },
4353 { szPatchFiles, ACTION_PatchFiles },
4354 { szProcessComponents, ACTION_ProcessComponents },
4355 { szPublishComponents, ACTION_PublishComponents },
4356 { szPublishFeatures, ACTION_PublishFeatures },
4357 { szPublishProduct, ACTION_PublishProduct },
4358 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4359 { szRegisterComPlus, ACTION_RegisterComPlus},
4360 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4361 { szRegisterFonts, ACTION_RegisterFonts },
4362 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4363 { szRegisterProduct, ACTION_RegisterProduct },
4364 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4365 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4366 { szRegisterUser, ACTION_RegisterUser},
4367 { szRemoveDuplicateFiles, NULL},
4368 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4369 { szRemoveExistingProducts, NULL},
4370 { szRemoveFiles, ACTION_RemoveFiles},
4371 { szRemoveFolders, NULL},
4372 { szRemoveIniValues, ACTION_RemoveIniValues },
4373 { szRemoveODBC, NULL},
4374 { szRemoveRegistryValues, NULL},
4375 { szRemoveShortcuts, NULL},
4376 { szResolveSource, ACTION_ResolveSource},
4377 { szRMCCPSearch, ACTION_RMCCPSearch},
4378 { szScheduleReboot, NULL},
4379 { szSelfRegModules, ACTION_SelfRegModules },
4380 { szSelfUnregModules, ACTION_SelfUnregModules },
4381 { szSetODBCFolders, NULL},
4382 { szStartServices, ACTION_StartServices },
4383 { szStopServices, ACTION_StopServices },
4384 { szUnpublishComponents, NULL},
4385 { szUnpublishFeatures, NULL},
4386 { szUnregisterClassInfo, NULL},
4387 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4388 { szUnregisterExtensionInfo, NULL},
4389 { szUnregisterFonts, ACTION_UnregisterFonts },
4390 { szUnregisterMIMEInfo, NULL},
4391 { szUnregisterProgIdInfo, NULL},
4392 { szUnregisterTypeLibraries, NULL},
4393 { szValidateProductID, NULL},
4394 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4395 { szWriteIniValues, ACTION_WriteIniValues },
4396 { szWriteRegistryValues, ACTION_WriteRegistryValues},