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
37 #include "wine/debug.h"
42 #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 )
367 LPWSTR p, *ret = NULL;
373 /* count the number of substrings */
374 for ( p = (LPWSTR)str, count = 0; p; count++ )
376 p = strchrW( p, sep );
381 /* allocate space for an array of substring pointers and the substrings */
382 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
383 (lstrlenW(str)+1) * sizeof(WCHAR) );
387 /* copy the string and set the pointers */
388 p = (LPWSTR) &ret[count+1];
390 for( count = 0; (ret[count] = p); count++ )
392 p = strchrW( p, sep );
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
407 TRACE("%p %s\n", package, debugstr_w(name) );
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
418 ret = msi_table_apply_transform( package->db, stg );
419 IStorage_Release( stg );
423 ERR("failed to open substorage %s\n", debugstr_w(name));
428 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
430 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
431 LPWSTR guid_list, *guids, product_id;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_id = msi_dup_property( package, szProdID );
437 /* FIXME: the property ProductID should be written into the DB somewhere */
438 ERR("no product ID to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_id ))
450 msi_free( guid_list );
451 msi_free( product_id );
456 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
459 LPWSTR str, *substorage;
460 UINT i, r = ERROR_SUCCESS;
462 si = MSI_GetSummaryInformationW( patch_db, 0 );
464 return ERROR_FUNCTION_FAILED;
466 msi_check_patch_applicable( package, si );
468 /* enumerate the substorage */
469 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
470 substorage = msi_split_string( str, ';' );
471 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
472 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
473 msi_free( substorage );
476 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
478 msiobj_release( &si->hdr );
483 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
485 MSIDATABASE *patch_db = NULL;
488 TRACE("%p %s\n", package, debugstr_w( file ) );
491 * We probably want to make sure we only open a patch collection here.
492 * Patch collections (.msp) and databases (.msi) have different GUIDs
493 * but currently MSI_OpenDatabaseW will accept both.
495 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
496 if ( r != ERROR_SUCCESS )
498 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
502 msi_parse_patch_summary( package, patch_db );
503 msiobj_release( &patch_db->hdr );
505 return ERROR_SUCCESS;
508 /* get the PATCH property, and apply all the patches it specifies */
509 static UINT msi_apply_patches( MSIPACKAGE *package )
511 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
512 LPWSTR patch_list, *patches;
513 UINT i, r = ERROR_SUCCESS;
515 patch_list = msi_dup_property( package, szPatch );
517 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
519 patches = msi_split_string( patch_list, ';' );
520 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_patch_package( package, patches[i] );
524 msi_free( patch_list );
529 static UINT msi_apply_transforms( MSIPACKAGE *package )
531 static const WCHAR szTransforms[] = {
532 'T','R','A','N','S','F','O','R','M','S',0 };
533 LPWSTR xform_list, *xforms;
534 UINT i, r = ERROR_SUCCESS;
536 xform_list = msi_dup_property( package, szTransforms );
537 xforms = msi_split_string( xform_list, ';' );
539 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
541 if (xforms[i][0] == ':')
542 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
544 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
548 msi_free( xform_list );
553 /****************************************************
554 * TOP level entry points
555 *****************************************************/
557 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
558 LPCWSTR szCommandLine )
562 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
563 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
564 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
566 MSI_SetPropertyW(package, szAction, szInstall);
568 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
570 package->script->InWhatSequence = SEQUENCE_INSTALL;
574 LPWSTR p, check, path;
576 package->PackagePath = strdupW(szPackagePath);
577 path = strdupW(szPackagePath);
578 p = strrchrW(path,'\\');
587 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
588 GetCurrentDirectoryW(MAX_PATH,path);
592 check = msi_dup_property( package, cszSourceDir );
594 MSI_SetPropertyW(package, cszSourceDir, path);
599 msi_parse_command_line( package, szCommandLine );
601 msi_apply_transforms( package );
602 msi_apply_patches( package );
604 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
606 package->script->InWhatSequence |= SEQUENCE_UI;
607 rc = ACTION_ProcessUISequence(package);
609 if (rc == ERROR_SUCCESS)
611 package->script->InWhatSequence |= SEQUENCE_EXEC;
612 rc = ACTION_ProcessExecSequence(package,TRUE);
616 rc = ACTION_ProcessExecSequence(package,FALSE);
620 /* install was halted but should be considered a success */
624 package->script->CurrentlyScripting= FALSE;
626 /* process the ending type action */
627 if (rc == ERROR_SUCCESS)
628 ACTION_PerformActionSequence(package,-1,ui);
629 else if (rc == ERROR_INSTALL_USEREXIT)
630 ACTION_PerformActionSequence(package,-2,ui);
631 else if (rc == ERROR_INSTALL_SUSPEND)
632 ACTION_PerformActionSequence(package,-4,ui);
634 ACTION_PerformActionSequence(package,-3,ui);
636 /* finish up running custom actions */
637 ACTION_FinishCustomActions(package);
642 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
644 UINT rc = ERROR_SUCCESS;
646 static const WCHAR ExecSeqQuery[] =
647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
648 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
649 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
650 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
652 static const WCHAR UISeqQuery[] =
653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
654 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
655 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
656 ' ', '=',' ','%','i',0};
659 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
661 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
665 LPCWSTR action, cond;
667 TRACE("Running the actions\n");
669 /* check conditions */
670 cond = MSI_RecordGetString(row,2);
673 /* this is a hack to skip errors in the condition code */
674 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
678 action = MSI_RecordGetString(row,1);
681 ERR("failed to fetch action\n");
682 rc = ERROR_FUNCTION_FAILED;
687 rc = ACTION_PerformUIAction(package,action);
689 rc = ACTION_PerformAction(package,action,FALSE);
691 msiobj_release(&row->hdr);
702 } iterate_action_param;
704 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
706 iterate_action_param *iap= (iterate_action_param*)param;
708 LPCWSTR cond, action;
710 action = MSI_RecordGetString(row,1);
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED;
717 /* check conditions */
718 cond = MSI_RecordGetString(row,2);
721 /* this is a hack to skip errors in the condition code */
722 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
724 TRACE("Skipping action: %s (condition is false)\n",
726 return ERROR_SUCCESS;
731 rc = ACTION_PerformUIAction(iap->package,action);
733 rc = ACTION_PerformAction(iap->package,action,FALSE);
735 msi_dialog_check_messages( NULL );
737 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
738 rc = iap->package->CurrentInstallState;
740 if (rc == ERROR_FUNCTION_NOT_CALLED)
743 if (rc != ERROR_SUCCESS)
744 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
749 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
753 static const WCHAR query[] =
754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
756 ' ','W','H','E','R','E',' ',
757 '`','S','e','q','u','e','n','c','e','`',' ',
758 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
759 '`','S','e','q','u','e','n','c','e','`',0};
760 iterate_action_param iap;
763 * FIXME: probably should be checking UILevel in the
764 * ACTION_PerformUIAction/ACTION_PerformAction
765 * rather than saving the UI level here. Those
766 * two functions can be merged too.
768 iap.package = package;
771 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
773 r = MSI_OpenQuery( package->db, &view, query, szTable );
774 if (r == ERROR_SUCCESS)
776 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
777 msiobj_release(&view->hdr);
783 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
787 static const WCHAR ExecSeqQuery[] =
788 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
789 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
790 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
792 'O','R','D','E','R',' ', 'B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0 };
795 static const WCHAR IVQuery[] =
796 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
797 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
798 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
799 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
800 ' ','\'', 'I','n','s','t','a','l','l',
801 'V','a','l','i','d','a','t','e','\'', 0};
803 iterate_action_param iap;
805 iap.package = package;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
819 row = MSI_QueryGetRecord(package->db, IVQuery);
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
832 msiobj_release(&view->hdr);
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
850 iterate_action_param iap;
852 iap.package = package;
855 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
857 if (rc == ERROR_SUCCESS)
859 TRACE("Running the actions\n");
861 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
862 msiobj_release(&view->hdr);
868 /********************************************************
869 * ACTION helper functions and functions that perform the actions
870 *******************************************************/
871 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
872 UINT* rc, BOOL force )
878 if (!run && !package->script->CurrentlyScripting)
883 if (strcmpW(action,szInstallFinalize) == 0 ||
884 strcmpW(action,szInstallExecute) == 0 ||
885 strcmpW(action,szInstallExecuteAgain) == 0)
890 while (StandardActions[i].action != NULL)
892 if (strcmpW(StandardActions[i].action, action)==0)
896 ui_actioninfo(package, action, TRUE, 0);
897 *rc = schedule_action(package,INSTALL_SCRIPT,action);
898 ui_actioninfo(package, action, FALSE, *rc);
902 ui_actionstart(package, action);
903 if (StandardActions[i].handler)
905 *rc = StandardActions[i].handler(package);
909 FIXME("unhandled standard action %s\n",debugstr_w(action));
921 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
922 UINT* rc, BOOL force )
927 arc = ACTION_CustomAction(package,action, force);
929 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
938 * A lot of actions are really important even if they don't do anything
939 * explicit... Lots of properties are set at the beginning of the installation
940 * CostFinalize does a bunch of work to translate the directories and such
942 * But until I get write access to the database that is hard, so I am going to
943 * hack it to see if I can get something to run.
945 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
947 UINT rc = ERROR_SUCCESS;
950 TRACE("Performing action (%s)\n",debugstr_w(action));
952 handled = ACTION_HandleStandardAction(package, action, &rc, force);
955 handled = ACTION_HandleCustomAction(package, action, &rc, force);
959 FIXME("unhandled msi action %s\n",debugstr_w(action));
960 rc = ERROR_FUNCTION_NOT_CALLED;
966 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
968 UINT rc = ERROR_SUCCESS;
969 BOOL handled = FALSE;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
976 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
978 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
983 FIXME("unhandled msi action %s\n",debugstr_w(action));
984 rc = ERROR_FUNCTION_NOT_CALLED;
992 * Actual Action Handlers
995 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
997 MSIPACKAGE *package = (MSIPACKAGE*)param;
1003 dir = MSI_RecordGetString(row,1);
1006 ERR("Unable to get folder id\n");
1007 return ERROR_SUCCESS;
1010 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1013 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1014 return ERROR_SUCCESS;
1017 TRACE("Folder is %s\n",debugstr_w(full_path));
1020 uirow = MSI_CreateRecord(1);
1021 MSI_RecordSetStringW(uirow,1,full_path);
1022 ui_actiondata(package,szCreateFolders,uirow);
1023 msiobj_release( &uirow->hdr );
1025 if (folder->State == 0)
1026 create_full_pathW(full_path);
1030 msi_free(full_path);
1031 return ERROR_SUCCESS;
1034 /* FIXME: probably should merge this with the above function */
1035 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1037 UINT rc = ERROR_SUCCESS;
1039 LPWSTR install_path;
1041 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1043 return ERROR_FUNCTION_FAILED;
1045 /* create the path */
1046 if (folder->State == 0)
1048 create_full_pathW(install_path);
1051 msi_free(install_path);
1056 UINT msi_create_component_directories( MSIPACKAGE *package )
1060 /* create all the folders required by the components are going to install */
1061 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1063 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1065 msi_create_directory( package, comp->Directory );
1068 return ERROR_SUCCESS;
1072 * Also we cannot enable/disable components either, so for now I am just going
1073 * to do all the directories for all the components.
1075 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1077 static const WCHAR ExecSeqQuery[] =
1078 {'S','E','L','E','C','T',' ',
1079 '`','D','i','r','e','c','t','o','r','y','_','`',
1080 ' ','F','R','O','M',' ',
1081 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1085 /* create all the empty folders specified in the CreateFolder table */
1086 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1087 if (rc != ERROR_SUCCESS)
1088 return ERROR_SUCCESS;
1090 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1091 msiobj_release(&view->hdr);
1093 msi_create_component_directories( package );
1098 static UINT load_component( MSIRECORD *row, LPVOID param )
1100 MSIPACKAGE *package = param;
1103 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1105 return ERROR_FUNCTION_FAILED;
1107 list_add_tail( &package->components, &comp->entry );
1109 /* fill in the data */
1110 comp->Component = msi_dup_record_field( row, 1 );
1112 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1114 comp->ComponentId = msi_dup_record_field( row, 2 );
1115 comp->Directory = msi_dup_record_field( row, 3 );
1116 comp->Attributes = MSI_RecordGetInteger(row,4);
1117 comp->Condition = msi_dup_record_field( row, 5 );
1118 comp->KeyPath = msi_dup_record_field( row, 6 );
1120 comp->Installed = INSTALLSTATE_ABSENT;
1122 switch (comp->Attributes)
1124 case msidbComponentAttributesLocalOnly:
1125 comp->Action = INSTALLSTATE_LOCAL;
1126 comp->ActionRequest = INSTALLSTATE_LOCAL;
1128 case msidbComponentAttributesSourceOnly:
1129 comp->Action = INSTALLSTATE_SOURCE;
1130 comp->ActionRequest = INSTALLSTATE_SOURCE;
1132 case msidbComponentAttributesOptional:
1133 comp->Action = INSTALLSTATE_DEFAULT;
1134 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1137 comp->Action = INSTALLSTATE_UNKNOWN;
1138 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1141 return ERROR_SUCCESS;
1144 static UINT load_all_components( MSIPACKAGE *package )
1146 static const WCHAR query[] = {
1147 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1148 '`','C','o','m','p','o','n','e','n','t','`',0 };
1152 if (!list_empty(&package->components))
1153 return ERROR_SUCCESS;
1155 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1156 if (r != ERROR_SUCCESS)
1159 r = MSI_IterateRecords(view, NULL, load_component, package);
1160 msiobj_release(&view->hdr);
1165 MSIPACKAGE *package;
1166 MSIFEATURE *feature;
1169 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1173 cl = msi_alloc( sizeof (*cl) );
1175 return ERROR_NOT_ENOUGH_MEMORY;
1176 cl->component = comp;
1177 list_add_tail( &feature->Components, &cl->entry );
1179 return ERROR_SUCCESS;
1182 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1184 _ilfs* ilfs= (_ilfs*)param;
1188 component = MSI_RecordGetString(row,1);
1190 /* check to see if the component is already loaded */
1191 comp = get_loaded_component( ilfs->package, component );
1194 ERR("unknown component %s\n", debugstr_w(component));
1195 return ERROR_FUNCTION_FAILED;
1198 add_feature_component( ilfs->feature, comp );
1199 comp->Enabled = TRUE;
1201 return ERROR_SUCCESS;
1204 static UINT load_feature(MSIRECORD * row, LPVOID param)
1206 MSIPACKAGE* package = (MSIPACKAGE*)param;
1207 MSIFEATURE* feature;
1208 static const WCHAR Query1[] =
1209 {'S','E','L','E','C','T',' ',
1210 '`','C','o','m','p','o','n','e','n','t','_','`',
1211 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1212 'C','o','m','p','o','n','e','n','t','s','`',' ',
1213 'W','H','E','R','E',' ',
1214 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1219 /* fill in the data */
1221 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1223 return ERROR_NOT_ENOUGH_MEMORY;
1225 list_init( &feature->Components );
1227 feature->Feature = msi_dup_record_field( row, 1 );
1229 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1231 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1232 feature->Title = msi_dup_record_field( row, 3 );
1233 feature->Description = msi_dup_record_field( row, 4 );
1235 if (!MSI_RecordIsNull(row,5))
1236 feature->Display = MSI_RecordGetInteger(row,5);
1238 feature->Level= MSI_RecordGetInteger(row,6);
1239 feature->Directory = msi_dup_record_field( row, 7 );
1240 feature->Attributes = MSI_RecordGetInteger(row,8);
1242 feature->Installed = INSTALLSTATE_ABSENT;
1243 feature->Action = INSTALLSTATE_UNKNOWN;
1244 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1246 list_add_tail( &package->features, &feature->entry );
1248 /* load feature components */
1250 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1251 if (rc != ERROR_SUCCESS)
1252 return ERROR_SUCCESS;
1254 ilfs.package = package;
1255 ilfs.feature = feature;
1257 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1258 msiobj_release(&view->hdr);
1260 return ERROR_SUCCESS;
1263 static UINT load_all_features( MSIPACKAGE *package )
1265 static const WCHAR query[] = {
1266 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1267 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1268 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1272 if (!list_empty(&package->features))
1273 return ERROR_SUCCESS;
1275 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1276 if (r != ERROR_SUCCESS)
1279 r = MSI_IterateRecords( view, NULL, load_feature, package );
1280 msiobj_release( &view->hdr );
1284 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1295 static UINT load_file(MSIRECORD *row, LPVOID param)
1297 MSIPACKAGE* package = (MSIPACKAGE*)param;
1301 /* fill in the data */
1303 file = msi_alloc_zero( sizeof (MSIFILE) );
1305 return ERROR_NOT_ENOUGH_MEMORY;
1307 file->File = msi_dup_record_field( row, 1 );
1309 component = MSI_RecordGetString( row, 2 );
1310 file->Component = get_loaded_component( package, component );
1312 if (!file->Component)
1313 ERR("Unfound Component %s\n",debugstr_w(component));
1315 file->FileName = msi_dup_record_field( row, 3 );
1316 reduce_to_longfilename( file->FileName );
1318 file->ShortName = msi_dup_record_field( row, 3 );
1319 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1321 file->FileSize = MSI_RecordGetInteger( row, 4 );
1322 file->Version = msi_dup_record_field( row, 5 );
1323 file->Language = msi_dup_record_field( row, 6 );
1324 file->Attributes = MSI_RecordGetInteger( row, 7 );
1325 file->Sequence = MSI_RecordGetInteger( row, 8 );
1327 file->state = msifs_invalid;
1329 if (file->Attributes & msidbFileAttributesCompressed)
1331 file->Component->Action = INSTALLSTATE_LOCAL;
1332 file->Component->ActionRequest = INSTALLSTATE_LOCAL;
1335 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1337 list_add_tail( &package->files, &file->entry );
1339 return ERROR_SUCCESS;
1342 static UINT load_all_files(MSIPACKAGE *package)
1346 static const WCHAR Query[] =
1347 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1348 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1349 '`','S','e','q','u','e','n','c','e','`', 0};
1351 if (!list_empty(&package->files))
1352 return ERROR_SUCCESS;
1354 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1355 if (rc != ERROR_SUCCESS)
1356 return ERROR_SUCCESS;
1358 rc = MSI_IterateRecords(view, NULL, load_file, package);
1359 msiobj_release(&view->hdr);
1361 return ERROR_SUCCESS;
1366 * I am not doing any of the costing functionality yet.
1367 * Mostly looking at doing the Component and Feature loading
1369 * The native MSI does A LOT of modification to tables here. Mostly adding
1370 * a lot of temporary columns to the Feature and Component tables.
1372 * note: Native msi also tracks the short filename. But I am only going to
1373 * track the long ones. Also looking at this directory table
1374 * it appears that the directory table does not get the parents
1375 * resolved base on property only based on their entries in the
1378 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1380 static const WCHAR szCosting[] =
1381 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1382 static const WCHAR szZero[] = { '0', 0 };
1384 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1385 return ERROR_SUCCESS;
1387 MSI_SetPropertyW(package, szCosting, szZero);
1388 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1390 load_all_components( package );
1391 load_all_features( package );
1392 load_all_files( package );
1394 return ERROR_SUCCESS;
1397 static UINT execute_script(MSIPACKAGE *package, UINT script )
1400 UINT rc = ERROR_SUCCESS;
1402 TRACE("Executing Script %i\n",script);
1404 if (!package->script)
1406 ERR("no script!\n");
1407 return ERROR_FUNCTION_FAILED;
1410 for (i = 0; i < package->script->ActionCount[script]; i++)
1413 action = package->script->Actions[script][i];
1414 ui_actionstart(package, action);
1415 TRACE("Executing Action (%s)\n",debugstr_w(action));
1416 rc = ACTION_PerformAction(package, action, TRUE);
1417 msi_free(package->script->Actions[script][i]);
1418 if (rc != ERROR_SUCCESS)
1421 msi_free(package->script->Actions[script]);
1423 package->script->ActionCount[script] = 0;
1424 package->script->Actions[script] = NULL;
1428 static UINT ACTION_FileCost(MSIPACKAGE *package)
1430 return ERROR_SUCCESS;
1433 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1435 static const WCHAR Query[] =
1436 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1437 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1438 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1439 ' ','=',' ','\'','%','s','\'',
1441 static const WCHAR szDot[] = { '.',0 };
1442 static WCHAR szEmpty[] = { 0 };
1443 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1448 TRACE("Looking for dir %s\n",debugstr_w(dir));
1450 folder = get_loaded_folder( package, dir );
1454 TRACE("Working to load %s\n",debugstr_w(dir));
1456 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1460 folder->Directory = strdupW(dir);
1462 row = MSI_QueryGetRecord(package->db, Query, dir);
1466 p = msi_dup_record_field(row, 3);
1468 /* split src and target dir */
1470 src_short = folder_split_path( p, ':' );
1472 /* split the long and short paths */
1473 tgt_long = folder_split_path( tgt_short, '|' );
1474 src_long = folder_split_path( src_short, '|' );
1476 /* check for no-op dirs */
1477 if (!lstrcmpW(szDot, tgt_short))
1478 tgt_short = szEmpty;
1479 if (!lstrcmpW(szDot, src_short))
1480 src_short = szEmpty;
1483 tgt_long = tgt_short;
1486 src_short = tgt_short;
1487 src_long = tgt_long;
1491 src_long = src_short;
1493 /* FIXME: use the target short path too */
1494 folder->TargetDefault = strdupW(tgt_long);
1495 folder->SourceShortPath = strdupW(src_short);
1496 folder->SourceLongPath = strdupW(src_long);
1499 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1500 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1501 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1503 parent = MSI_RecordGetString(row, 2);
1506 folder->Parent = load_folder( package, parent );
1507 if ( folder->Parent )
1508 TRACE("loaded parent %p %s\n", folder->Parent,
1509 debugstr_w(folder->Parent->Directory));
1511 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1514 folder->Property = msi_dup_property( package, dir );
1516 msiobj_release(&row->hdr);
1518 list_add_tail( &package->folders, &folder->entry );
1520 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1525 /* scan for and update current install states */
1526 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1529 MSIFEATURE *feature;
1531 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1534 res = MsiGetComponentPathW( package->ProductCode,
1535 comp->ComponentId, NULL, NULL);
1537 res = INSTALLSTATE_ABSENT;
1538 comp->Installed = res;
1541 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1544 INSTALLSTATE res = -10;
1546 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1548 comp= cl->component;
1551 res = comp->Installed;
1554 if (res == comp->Installed)
1557 if (res != comp->Installed)
1558 res = INSTALLSTATE_INCOMPLETE;
1561 feature->Installed = res;
1565 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1568 static const WCHAR all[]={'A','L','L',0};
1570 MSIFEATURE *feature;
1572 override = msi_dup_property( package, property );
1576 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1578 if (strcmpiW(override,all)==0)
1580 feature->ActionRequest= state;
1581 feature->Action = state;
1585 LPWSTR ptr = override;
1586 LPWSTR ptr2 = strchrW(override,',');
1590 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1591 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1593 feature->ActionRequest= state;
1594 feature->Action = state;
1600 ptr2 = strchrW(ptr,',');
1612 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1615 static const WCHAR szlevel[] =
1616 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1617 static const WCHAR szAddLocal[] =
1618 {'A','D','D','L','O','C','A','L',0};
1619 static const WCHAR szRemove[] =
1620 {'R','E','M','O','V','E',0};
1621 static const WCHAR szReinstall[] =
1622 {'R','E','I','N','S','T','A','L','L',0};
1623 BOOL override = FALSE;
1624 MSICOMPONENT* component;
1625 MSIFEATURE *feature;
1628 /* I do not know if this is where it should happen.. but */
1630 TRACE("Checking Install Level\n");
1632 install_level = msi_get_property_int( package, szlevel, 1 );
1634 /* ok hereis the _real_ rub
1635 * all these activation/deactivation things happen in order and things
1636 * later on the list override things earlier on the list.
1637 * 1) INSTALLLEVEL processing
1647 * 11) FILEADDDEFAULT
1648 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1649 * ignored for all the features. seems strange, especially since it is not
1650 * documented anywhere, but it is how it works.
1652 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1653 * REMOVE are the big ones, since we don't handle administrative installs
1656 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1657 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1658 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1662 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1664 BOOL feature_state = ((feature->Level > 0) &&
1665 (feature->Level <= install_level));
1667 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1669 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1671 feature->ActionRequest = INSTALLSTATE_SOURCE;
1672 feature->Action = INSTALLSTATE_SOURCE;
1674 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1676 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1677 feature->Action = INSTALLSTATE_ADVERTISED;
1681 feature->ActionRequest = INSTALLSTATE_LOCAL;
1682 feature->Action = INSTALLSTATE_LOCAL;
1689 /* set the Preselected Property */
1690 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1691 static const WCHAR szOne[] = { '1', 0 };
1693 MSI_SetPropertyW(package,szPreselected,szOne);
1697 * now we want to enable or disable components base on feature
1700 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1704 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1705 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1706 feature->ActionRequest);
1708 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1710 component = cl->component;
1712 if (!component->Enabled)
1714 component->Action = INSTALLSTATE_UNKNOWN;
1715 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1719 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1721 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1723 component->Action = INSTALLSTATE_LOCAL;
1724 component->ActionRequest = INSTALLSTATE_LOCAL;
1727 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1729 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1730 (component->Action == INSTALLSTATE_ABSENT) ||
1731 (component->Action == INSTALLSTATE_ADVERTISED) ||
1732 (component->Action == INSTALLSTATE_DEFAULT))
1735 component->Action = INSTALLSTATE_SOURCE;
1736 component->ActionRequest = INSTALLSTATE_SOURCE;
1739 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1741 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1742 (component->Action == INSTALLSTATE_ABSENT))
1745 component->Action = INSTALLSTATE_ADVERTISED;
1746 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1749 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1751 if (component->Action == INSTALLSTATE_UNKNOWN)
1753 component->Action = INSTALLSTATE_ABSENT;
1754 component->ActionRequest = INSTALLSTATE_ABSENT;
1761 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1763 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1764 debugstr_w(component->Component), component->Installed,
1765 component->Action, component->ActionRequest);
1769 return ERROR_SUCCESS;
1772 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1774 MSIPACKAGE *package = (MSIPACKAGE*)param;
1778 name = MSI_RecordGetString(row,1);
1780 /* This helper function now does ALL the work */
1781 TRACE("Dir %s ...\n",debugstr_w(name));
1782 load_folder(package,name);
1783 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1784 TRACE("resolves to %s\n",debugstr_w(path));
1787 return ERROR_SUCCESS;
1790 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1792 MSIPACKAGE *package = (MSIPACKAGE*)param;
1794 MSIFEATURE *feature;
1796 name = MSI_RecordGetString( row, 1 );
1798 feature = get_loaded_feature( package, name );
1800 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1804 Condition = MSI_RecordGetString(row,3);
1806 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1808 int level = MSI_RecordGetInteger(row,2);
1809 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1810 feature->Level = level;
1813 return ERROR_SUCCESS;
1818 * A lot is done in this function aside from just the costing.
1819 * The costing needs to be implemented at some point but for now I am going
1820 * to focus on the directory building
1823 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1825 static const WCHAR ExecSeqQuery[] =
1826 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1827 '`','D','i','r','e','c','t','o','r','y','`',0};
1828 static const WCHAR ConditionQuery[] =
1829 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1830 '`','C','o','n','d','i','t','i','o','n','`',0};
1831 static const WCHAR szCosting[] =
1832 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1833 static const WCHAR szlevel[] =
1834 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1835 static const WCHAR szOne[] = { '1', 0 };
1842 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1843 return ERROR_SUCCESS;
1845 TRACE("Building Directory properties\n");
1847 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1848 if (rc == ERROR_SUCCESS)
1850 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1852 msiobj_release(&view->hdr);
1855 TRACE("File calculations\n");
1857 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1859 MSICOMPONENT* comp = file->Component;
1865 /* calculate target */
1866 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1868 msi_free(file->TargetPath);
1870 TRACE("file %s is named %s\n",
1871 debugstr_w(file->File),debugstr_w(file->FileName));
1873 file->TargetPath = build_directory_name(2, p, file->FileName);
1877 TRACE("file %s resolves to %s\n",
1878 debugstr_w(file->File),debugstr_w(file->TargetPath));
1880 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1882 file->state = msifs_missing;
1883 comp->Cost += file->FileSize;
1893 static WCHAR name[] = {'\\',0};
1894 static const WCHAR name_fmt[] =
1895 {'%','u','.','%','u','.','%','u','.','%','u',0};
1896 WCHAR filever[0x100];
1897 VS_FIXEDFILEINFO *lpVer;
1899 TRACE("Version comparison..\n");
1900 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1901 version = msi_alloc(versize);
1902 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1904 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1906 sprintfW(filever,name_fmt,
1907 HIWORD(lpVer->dwFileVersionMS),
1908 LOWORD(lpVer->dwFileVersionMS),
1909 HIWORD(lpVer->dwFileVersionLS),
1910 LOWORD(lpVer->dwFileVersionLS));
1912 TRACE("new %s old %s\n", debugstr_w(file->Version),
1913 debugstr_w(filever));
1914 if (strcmpiW(filever,file->Version)<0)
1916 file->state = msifs_overwrite;
1917 /* FIXME: cost should be diff in size */
1918 comp->Cost += file->FileSize;
1921 file->state = msifs_present;
1925 file->state = msifs_present;
1928 TRACE("Evaluating Condition Table\n");
1930 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1931 if (rc == ERROR_SUCCESS)
1933 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1935 msiobj_release(&view->hdr);
1938 TRACE("Enabling or Disabling Components\n");
1939 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1941 if (comp->Condition)
1943 if (MSI_EvaluateConditionW(package,
1944 comp->Condition) == MSICONDITION_FALSE)
1946 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1947 comp->Enabled = FALSE;
1952 MSI_SetPropertyW(package,szCosting,szOne);
1953 /* set default run level if not set */
1954 level = msi_dup_property( package, szlevel );
1956 MSI_SetPropertyW(package,szlevel, szOne);
1959 ACTION_UpdateInstallStates(package);
1961 return MSI_SetFeatureStates(package);
1964 /* OK this value is "interpreted" and then formatted based on the
1965 first few characters */
1966 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1970 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1976 LPWSTR deformated = NULL;
1979 deformat_string(package, &value[2], &deformated);
1981 /* binary value type */
1985 *size = (strlenW(ptr)/2)+1;
1987 *size = strlenW(ptr)/2;
1989 data = msi_alloc(*size);
1995 /* if uneven pad with a zero in front */
2001 data[count] = (BYTE)strtol(byte,NULL,0);
2003 TRACE("Uneven byte count\n");
2011 data[count] = (BYTE)strtol(byte,NULL,0);
2014 msi_free(deformated);
2016 TRACE("Data %li bytes(%i)\n",*size,count);
2023 deformat_string(package, &value[1], &deformated);
2026 *size = sizeof(DWORD);
2027 data = msi_alloc(*size);
2033 if ( (*p < '0') || (*p > '9') )
2039 if (deformated[0] == '-')
2042 TRACE("DWORD %li\n",*(LPDWORD)data);
2044 msi_free(deformated);
2049 static const WCHAR szMulti[] = {'[','~',']',0};
2058 *type=REG_EXPAND_SZ;
2066 if (strstrW(value,szMulti))
2067 *type = REG_MULTI_SZ;
2069 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2074 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2076 MSIPACKAGE *package = (MSIPACKAGE*)param;
2077 static const WCHAR szHCR[] =
2078 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2079 'R','O','O','T','\\',0};
2080 static const WCHAR szHCU[] =
2081 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2082 'U','S','E','R','\\',0};
2083 static const WCHAR szHLM[] =
2084 {'H','K','E','Y','_','L','O','C','A','L','_',
2085 'M','A','C','H','I','N','E','\\',0};
2086 static const WCHAR szHU[] =
2087 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2089 LPSTR value_data = NULL;
2090 HKEY root_key, hkey;
2093 LPCWSTR szRoot, component, name, key, value;
2098 BOOL check_first = FALSE;
2101 ui_progress(package,2,0,0,0);
2108 component = MSI_RecordGetString(row, 6);
2109 comp = get_loaded_component(package,component);
2111 return ERROR_SUCCESS;
2113 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2115 TRACE("Skipping write due to disabled component %s\n",
2116 debugstr_w(component));
2118 comp->Action = comp->Installed;
2120 return ERROR_SUCCESS;
2123 comp->Action = INSTALLSTATE_LOCAL;
2125 name = MSI_RecordGetString(row, 4);
2126 if( MSI_RecordIsNull(row,5) && name )
2128 /* null values can have special meanings */
2129 if (name[0]=='-' && name[1] == 0)
2130 return ERROR_SUCCESS;
2131 else if ((name[0]=='+' && name[1] == 0) ||
2132 (name[0] == '*' && name[1] == 0))
2137 root = MSI_RecordGetInteger(row,2);
2138 key = MSI_RecordGetString(row, 3);
2140 /* get the root key */
2145 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2146 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2147 if (all_users && all_users[0] == '1')
2149 root_key = HKEY_LOCAL_MACHINE;
2154 root_key = HKEY_CURRENT_USER;
2157 msi_free(all_users);
2160 case 0: root_key = HKEY_CLASSES_ROOT;
2163 case 1: root_key = HKEY_CURRENT_USER;
2166 case 2: root_key = HKEY_LOCAL_MACHINE;
2169 case 3: root_key = HKEY_USERS;
2173 ERR("Unknown root %i\n",root);
2179 return ERROR_SUCCESS;
2181 deformat_string(package, key , &deformated);
2182 size = strlenW(deformated) + strlenW(szRoot) + 1;
2183 uikey = msi_alloc(size*sizeof(WCHAR));
2184 strcpyW(uikey,szRoot);
2185 strcatW(uikey,deformated);
2187 if (RegCreateKeyW( root_key, deformated, &hkey))
2189 ERR("Could not create key %s\n",debugstr_w(deformated));
2190 msi_free(deformated);
2192 return ERROR_SUCCESS;
2194 msi_free(deformated);
2196 value = MSI_RecordGetString(row,5);
2198 value_data = parse_value(package, value, &type, &size);
2201 static const WCHAR szEmpty[] = {0};
2202 value_data = (LPSTR)strdupW(szEmpty);
2207 deformat_string(package, name, &deformated);
2209 /* get the double nulls to terminate SZ_MULTI */
2210 if (type == REG_MULTI_SZ)
2211 size +=sizeof(WCHAR);
2215 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2217 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2222 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2223 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2225 TRACE("value %s of %s checked already exists\n",
2226 debugstr_w(deformated), debugstr_w(uikey));
2230 TRACE("Checked and setting value %s of %s\n",
2231 debugstr_w(deformated), debugstr_w(uikey));
2232 if (deformated || size)
2233 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2238 uirow = MSI_CreateRecord(3);
2239 MSI_RecordSetStringW(uirow,2,deformated);
2240 MSI_RecordSetStringW(uirow,1,uikey);
2243 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2245 MSI_RecordSetStringW(uirow,3,value);
2247 ui_actiondata(package,szWriteRegistryValues,uirow);
2248 msiobj_release( &uirow->hdr );
2250 msi_free(value_data);
2251 msi_free(deformated);
2254 return ERROR_SUCCESS;
2257 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2261 static const WCHAR ExecSeqQuery[] =
2262 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2263 '`','R','e','g','i','s','t','r','y','`',0 };
2265 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2266 if (rc != ERROR_SUCCESS)
2267 return ERROR_SUCCESS;
2269 /* increment progress bar each time action data is sent */
2270 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2272 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2274 msiobj_release(&view->hdr);
2278 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2280 package->script->CurrentlyScripting = TRUE;
2282 return ERROR_SUCCESS;
2286 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2291 static const WCHAR q1[]=
2292 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2293 '`','R','e','g','i','s','t','r','y','`',0};
2296 MSIFEATURE *feature;
2299 TRACE("InstallValidate\n");
2301 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2302 if (rc == ERROR_SUCCESS)
2304 MSI_IterateRecords( view, &progress, NULL, package );
2305 msiobj_release( &view->hdr );
2306 total += progress * REG_PROGRESS_VALUE;
2309 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2310 total += COMPONENT_PROGRESS_VALUE;
2312 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2313 total += file->FileSize;
2315 ui_progress(package,0,total,0,0);
2317 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2319 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2320 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2321 feature->ActionRequest);
2324 return ERROR_SUCCESS;
2327 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2329 MSIPACKAGE* package = (MSIPACKAGE*)param;
2330 LPCWSTR cond = NULL;
2331 LPCWSTR message = NULL;
2332 static const WCHAR title[]=
2333 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2335 cond = MSI_RecordGetString(row,1);
2337 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2340 message = MSI_RecordGetString(row,2);
2341 deformat_string(package,message,&deformated);
2342 MessageBoxW(NULL,deformated,title,MB_OK);
2343 msi_free(deformated);
2344 return ERROR_FUNCTION_FAILED;
2347 return ERROR_SUCCESS;
2350 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2353 MSIQUERY * view = NULL;
2354 static const WCHAR ExecSeqQuery[] =
2355 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2356 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2358 TRACE("Checking launch conditions\n");
2360 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2361 if (rc != ERROR_SUCCESS)
2362 return ERROR_SUCCESS;
2364 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2365 msiobj_release(&view->hdr);
2370 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2374 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2376 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2378 MSIRECORD * row = 0;
2380 LPWSTR deformated,buffer,deformated_name;
2382 static const WCHAR ExecSeqQuery[] =
2383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2384 '`','R','e','g','i','s','t','r','y','`',' ',
2385 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2386 ' ','=',' ' ,'\'','%','s','\'',0 };
2387 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2388 static const WCHAR fmt2[]=
2389 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2391 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2395 root = MSI_RecordGetInteger(row,2);
2396 key = MSI_RecordGetString(row, 3);
2397 name = MSI_RecordGetString(row, 4);
2398 deformat_string(package, key , &deformated);
2399 deformat_string(package, name, &deformated_name);
2401 len = strlenW(deformated) + 6;
2402 if (deformated_name)
2403 len+=strlenW(deformated_name);
2405 buffer = msi_alloc( len *sizeof(WCHAR));
2407 if (deformated_name)
2408 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2410 sprintfW(buffer,fmt,root,deformated);
2412 msi_free(deformated);
2413 msi_free(deformated_name);
2414 msiobj_release(&row->hdr);
2418 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2420 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2425 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2428 return strdupW( file->TargetPath );
2433 static HKEY openSharedDLLsKey(void)
2436 static const WCHAR path[] =
2437 {'S','o','f','t','w','a','r','e','\\',
2438 'M','i','c','r','o','s','o','f','t','\\',
2439 'W','i','n','d','o','w','s','\\',
2440 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2441 'S','h','a','r','e','d','D','L','L','s',0};
2443 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2447 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2452 DWORD sz = sizeof(count);
2455 hkey = openSharedDLLsKey();
2456 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2457 if (rc != ERROR_SUCCESS)
2463 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2467 hkey = openSharedDLLsKey();
2469 msi_reg_set_val_dword( hkey, path, count );
2471 RegDeleteValueW(hkey,path);
2477 * Return TRUE if the count should be written out and FALSE if not
2479 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2481 MSIFEATURE *feature;
2485 /* only refcount DLLs */
2486 if (comp->KeyPath == NULL ||
2487 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2488 comp->Attributes & msidbComponentAttributesODBCDataSource)
2492 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2493 write = (count > 0);
2495 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2499 /* increment counts */
2500 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2504 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2507 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2509 if ( cl->component == comp )
2514 /* decrement counts */
2515 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2519 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2522 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2524 if ( cl->component == comp )
2529 /* ref count all the files in the component */
2534 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2536 if (file->Component == comp)
2537 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2541 /* add a count for permenent */
2542 if (comp->Attributes & msidbComponentAttributesPermanent)
2545 comp->RefCount = count;
2548 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2552 * Ok further analysis makes me think that this work is
2553 * actually done in the PublishComponents and PublishFeatures
2554 * step, and not here. It appears like the keypath and all that is
2555 * resolved in this step, however actually written in the Publish steps.
2556 * But we will leave it here for now because it is unclear
2558 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2560 WCHAR squished_pc[GUID_SIZE];
2561 WCHAR squished_cc[GUID_SIZE];
2564 HKEY hkey=0,hkey2=0;
2566 /* writes the Component and Features values to the registry */
2568 rc = MSIREG_OpenComponents(&hkey);
2569 if (rc != ERROR_SUCCESS)
2572 squash_guid(package->ProductCode,squished_pc);
2573 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2575 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2579 ui_progress(package,2,0,0,0);
2580 if (!comp->ComponentId)
2583 squash_guid(comp->ComponentId,squished_cc);
2585 msi_free(comp->FullKeypath);
2586 comp->FullKeypath = resolve_keypath( package, comp );
2588 /* do the refcounting */
2589 ACTION_RefCountComponent( package, comp );
2591 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2592 debugstr_w(comp->Component),
2593 debugstr_w(squished_cc),
2594 debugstr_w(comp->FullKeypath),
2597 * Write the keypath out if the component is to be registered
2598 * and delete the key if the component is to be deregistered
2600 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2602 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2603 if (rc != ERROR_SUCCESS)
2606 if (!comp->FullKeypath)
2609 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2611 if (comp->Attributes & msidbComponentAttributesPermanent)
2613 static const WCHAR szPermKey[] =
2614 { '0','0','0','0','0','0','0','0','0','0','0','0',
2615 '0','0','0','0','0','0','0','0','0','0','0','0',
2616 '0','0','0','0','0','0','0','0',0 };
2618 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2624 uirow = MSI_CreateRecord(3);
2625 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2626 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2627 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2628 ui_actiondata(package,szProcessComponents,uirow);
2629 msiobj_release( &uirow->hdr );
2631 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2635 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2636 if (rc != ERROR_SUCCESS)
2639 RegDeleteValueW(hkey2,squished_pc);
2641 /* if the key is empty delete it */
2642 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2644 if (res == ERROR_NO_MORE_ITEMS)
2645 RegDeleteKeyW(hkey,squished_cc);
2648 uirow = MSI_CreateRecord(2);
2649 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2650 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2651 ui_actiondata(package,szProcessComponents,uirow);
2652 msiobj_release( &uirow->hdr );
2667 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2668 LPWSTR lpszName, LONG_PTR lParam)
2671 typelib_struct *tl_struct = (typelib_struct*) lParam;
2672 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2676 if (!IS_INTRESOURCE(lpszName))
2678 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2682 sz = strlenW(tl_struct->source)+4;
2683 sz *= sizeof(WCHAR);
2685 if ((INT_PTR)lpszName == 1)
2686 tl_struct->path = strdupW(tl_struct->source);
2689 tl_struct->path = msi_alloc(sz);
2690 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2693 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2694 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2695 if (!SUCCEEDED(res))
2697 msi_free(tl_struct->path);
2698 tl_struct->path = NULL;
2703 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2704 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2706 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2710 msi_free(tl_struct->path);
2711 tl_struct->path = NULL;
2713 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2714 ITypeLib_Release(tl_struct->ptLib);
2719 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2721 MSIPACKAGE* package = (MSIPACKAGE*)param;
2725 typelib_struct tl_struct;
2727 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2729 component = MSI_RecordGetString(row,3);
2730 comp = get_loaded_component(package,component);
2732 return ERROR_SUCCESS;
2734 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2736 TRACE("Skipping typelib reg due to disabled component\n");
2738 comp->Action = comp->Installed;
2740 return ERROR_SUCCESS;
2743 comp->Action = INSTALLSTATE_LOCAL;
2745 file = get_loaded_file( package, comp->KeyPath );
2747 return ERROR_SUCCESS;
2749 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2753 guid = MSI_RecordGetString(row,1);
2754 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2755 tl_struct.source = strdupW( file->TargetPath );
2756 tl_struct.path = NULL;
2758 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2759 (LONG_PTR)&tl_struct);
2767 helpid = MSI_RecordGetString(row,6);
2770 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2771 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2774 if (!SUCCEEDED(res))
2775 ERR("Failed to register type library %s\n",
2776 debugstr_w(tl_struct.path));
2779 ui_actiondata(package,szRegisterTypeLibraries,row);
2781 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2784 ITypeLib_Release(tl_struct.ptLib);
2785 msi_free(tl_struct.path);
2788 ERR("Failed to load type library %s\n",
2789 debugstr_w(tl_struct.source));
2791 FreeLibrary(module);
2792 msi_free(tl_struct.source);
2795 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2797 return ERROR_SUCCESS;
2800 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2803 * OK this is a bit confusing.. I am given a _Component key and I believe
2804 * that the file that is being registered as a type library is the "key file
2805 * of that component" which I interpret to mean "The file in the KeyPath of
2810 static const WCHAR Query[] =
2811 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2812 '`','T','y','p','e','L','i','b','`',0};
2814 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2815 if (rc != ERROR_SUCCESS)
2816 return ERROR_SUCCESS;
2818 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2819 msiobj_release(&view->hdr);
2823 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2825 MSIPACKAGE *package = (MSIPACKAGE*)param;
2826 LPWSTR target_file, target_folder, filename;
2827 LPCWSTR buffer, extension;
2829 static const WCHAR szlnk[]={'.','l','n','k',0};
2830 IShellLinkW *sl = NULL;
2831 IPersistFile *pf = NULL;
2834 buffer = MSI_RecordGetString(row,4);
2835 comp = get_loaded_component(package,buffer);
2837 return ERROR_SUCCESS;
2839 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2841 TRACE("Skipping shortcut creation due to disabled component\n");
2843 comp->Action = comp->Installed;
2845 return ERROR_SUCCESS;
2848 comp->Action = INSTALLSTATE_LOCAL;
2850 ui_actiondata(package,szCreateShortcuts,row);
2852 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2853 &IID_IShellLinkW, (LPVOID *) &sl );
2857 ERR("CLSID_ShellLink not available\n");
2861 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2864 ERR("QueryInterface(IID_IPersistFile) failed\n");
2868 buffer = MSI_RecordGetString(row,2);
2869 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2871 /* may be needed because of a bug somehwere else */
2872 create_full_pathW(target_folder);
2874 filename = msi_dup_record_field( row, 3 );
2875 reduce_to_longfilename(filename);
2877 extension = strchrW(filename,'.');
2878 if (!extension || strcmpiW(extension,szlnk))
2880 int len = strlenW(filename);
2881 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2882 memcpy(filename + len, szlnk, sizeof(szlnk));
2884 target_file = build_directory_name(2, target_folder, filename);
2885 msi_free(target_folder);
2888 buffer = MSI_RecordGetString(row,5);
2889 if (strchrW(buffer,'['))
2892 deformat_string(package,buffer,&deformated);
2893 IShellLinkW_SetPath(sl,deformated);
2894 msi_free(deformated);
2898 FIXME("poorly handled shortcut format, advertised shortcut\n");
2899 IShellLinkW_SetPath(sl,comp->FullKeypath);
2902 if (!MSI_RecordIsNull(row,6))
2905 buffer = MSI_RecordGetString(row,6);
2906 deformat_string(package,buffer,&deformated);
2907 IShellLinkW_SetArguments(sl,deformated);
2908 msi_free(deformated);
2911 if (!MSI_RecordIsNull(row,7))
2913 buffer = MSI_RecordGetString(row,7);
2914 IShellLinkW_SetDescription(sl,buffer);
2917 if (!MSI_RecordIsNull(row,8))
2918 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2920 if (!MSI_RecordIsNull(row,9))
2925 buffer = MSI_RecordGetString(row,9);
2927 Path = build_icon_path(package,buffer);
2928 index = MSI_RecordGetInteger(row,10);
2930 IShellLinkW_SetIconLocation(sl,Path,index);
2934 if (!MSI_RecordIsNull(row,11))
2935 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2937 if (!MSI_RecordIsNull(row,12))
2940 buffer = MSI_RecordGetString(row,12);
2941 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2943 IShellLinkW_SetWorkingDirectory(sl,Path);
2947 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2948 IPersistFile_Save(pf,target_file,FALSE);
2950 msi_free(target_file);
2954 IPersistFile_Release( pf );
2956 IShellLinkW_Release( sl );
2958 return ERROR_SUCCESS;
2961 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2966 static const WCHAR Query[] =
2967 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2968 '`','S','h','o','r','t','c','u','t','`',0};
2970 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2971 if (rc != ERROR_SUCCESS)
2972 return ERROR_SUCCESS;
2974 res = CoInitialize( NULL );
2977 ERR("CoInitialize failed\n");
2978 return ERROR_FUNCTION_FAILED;
2981 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2982 msiobj_release(&view->hdr);
2989 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2991 MSIPACKAGE* package = (MSIPACKAGE*)param;
3000 FileName = MSI_RecordGetString(row,1);
3003 ERR("Unable to get FileName\n");
3004 return ERROR_SUCCESS;
3007 FilePath = build_icon_path(package,FileName);
3009 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3011 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3012 FILE_ATTRIBUTE_NORMAL, NULL);
3014 if (the_file == INVALID_HANDLE_VALUE)
3016 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3018 return ERROR_SUCCESS;
3025 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3026 if (rc != ERROR_SUCCESS)
3028 ERR("Failed to get stream\n");
3029 CloseHandle(the_file);
3030 DeleteFileW(FilePath);
3033 WriteFile(the_file,buffer,sz,&write,NULL);
3034 } while (sz == 1024);
3038 CloseHandle(the_file);
3040 uirow = MSI_CreateRecord(1);
3041 MSI_RecordSetStringW(uirow,1,FileName);
3042 ui_actiondata(package,szPublishProduct,uirow);
3043 msiobj_release( &uirow->hdr );
3045 return ERROR_SUCCESS;
3049 * 99% of the work done here is only done for
3050 * advertised installs. However this is where the
3051 * Icon table is processed and written out
3052 * so that is what I am going to do here.
3054 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3058 static const WCHAR Query[]=
3059 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3060 '`','I','c','o','n','`',0};
3061 /* for registry stuff */
3064 static const WCHAR szProductLanguage[] =
3065 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3066 static const WCHAR szARPProductIcon[] =
3067 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3068 static const WCHAR szProductVersion[] =
3069 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3073 MSIHANDLE hDb, hSumInfo;
3075 /* write out icon files */
3077 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3078 if (rc == ERROR_SUCCESS)
3080 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3081 msiobj_release(&view->hdr);
3084 /* ok there is a lot more done here but i need to figure out what */
3086 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3087 if (rc != ERROR_SUCCESS)
3090 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3091 if (rc != ERROR_SUCCESS)
3095 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3096 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3099 langid = msi_get_property_int( package, szProductLanguage, 0 );
3100 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3102 buffer = msi_dup_property( package, szARPProductIcon );
3105 LPWSTR path = build_icon_path(package,buffer);
3106 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3111 buffer = msi_dup_property( package, szProductVersion );
3114 DWORD verdword = msi_version_str_to_dword(buffer);
3115 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3119 /* FIXME: Need to write more keys to the user registry */
3121 hDb= alloc_msihandle( &package->db->hdr );
3122 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3123 MsiCloseHandle(hDb);
3124 if (rc == ERROR_SUCCESS)
3126 WCHAR guidbuffer[0x200];
3128 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3130 if (rc == ERROR_SUCCESS)
3132 WCHAR squashed[GUID_SIZE];
3133 /* for now we only care about the first guid */
3134 LPWSTR ptr = strchrW(guidbuffer,';');
3136 squash_guid(guidbuffer,squashed);
3137 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3141 ERR("Unable to query Revision_Number...\n");
3144 MsiCloseHandle(hSumInfo);
3148 ERR("Unable to open Summary Information\n");
3160 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3162 MSIPACKAGE *package = (MSIPACKAGE*)param;
3163 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3164 LPWSTR deformated_section, deformated_key, deformated_value;
3165 LPWSTR folder, fullname = NULL;
3169 static const WCHAR szWindowsFolder[] =
3170 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3172 component = MSI_RecordGetString(row, 8);
3173 comp = get_loaded_component(package,component);
3175 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3177 TRACE("Skipping ini file due to disabled component %s\n",
3178 debugstr_w(component));
3180 comp->Action = comp->Installed;
3182 return ERROR_SUCCESS;
3185 comp->Action = INSTALLSTATE_LOCAL;
3187 identifier = MSI_RecordGetString(row,1);
3188 filename = MSI_RecordGetString(row,2);
3189 dirproperty = MSI_RecordGetString(row,3);
3190 section = MSI_RecordGetString(row,4);
3191 key = MSI_RecordGetString(row,5);
3192 value = MSI_RecordGetString(row,6);
3193 action = MSI_RecordGetInteger(row,7);
3195 deformat_string(package,section,&deformated_section);
3196 deformat_string(package,key,&deformated_key);
3197 deformat_string(package,value,&deformated_value);
3201 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3203 folder = msi_dup_property( package, dirproperty );
3206 folder = msi_dup_property( package, szWindowsFolder );
3210 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3214 fullname = build_directory_name(2, folder, filename);
3218 TRACE("Adding value %s to section %s in %s\n",
3219 debugstr_w(deformated_key), debugstr_w(deformated_section),
3220 debugstr_w(fullname));
3221 WritePrivateProfileStringW(deformated_section, deformated_key,
3222 deformated_value, fullname);
3224 else if (action == 1)
3227 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3228 returned, 10, fullname);
3229 if (returned[0] == 0)
3231 TRACE("Adding value %s to section %s in %s\n",
3232 debugstr_w(deformated_key), debugstr_w(deformated_section),
3233 debugstr_w(fullname));
3235 WritePrivateProfileStringW(deformated_section, deformated_key,
3236 deformated_value, fullname);
3239 else if (action == 3)
3240 FIXME("Append to existing section not yet implemented\n");
3242 uirow = MSI_CreateRecord(4);
3243 MSI_RecordSetStringW(uirow,1,identifier);
3244 MSI_RecordSetStringW(uirow,2,deformated_section);
3245 MSI_RecordSetStringW(uirow,3,deformated_key);
3246 MSI_RecordSetStringW(uirow,4,deformated_value);
3247 ui_actiondata(package,szWriteIniValues,uirow);
3248 msiobj_release( &uirow->hdr );
3252 msi_free(deformated_key);
3253 msi_free(deformated_value);
3254 msi_free(deformated_section);
3255 return ERROR_SUCCESS;
3258 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3262 static const WCHAR ExecSeqQuery[] =
3263 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3264 '`','I','n','i','F','i','l','e','`',0};
3266 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3267 if (rc != ERROR_SUCCESS)
3269 TRACE("no IniFile table\n");
3270 return ERROR_SUCCESS;
3273 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3274 msiobj_release(&view->hdr);
3278 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3280 MSIPACKAGE *package = (MSIPACKAGE*)param;
3285 static const WCHAR ExeStr[] =
3286 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3287 static const WCHAR close[] = {'\"',0};
3289 PROCESS_INFORMATION info;
3294 memset(&si,0,sizeof(STARTUPINFOW));
3296 filename = MSI_RecordGetString(row,1);
3297 file = get_loaded_file( package, filename );
3301 ERR("Unable to find file id %s\n",debugstr_w(filename));
3302 return ERROR_SUCCESS;
3305 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3307 FullName = msi_alloc(len*sizeof(WCHAR));
3308 strcpyW(FullName,ExeStr);
3309 strcatW( FullName, file->TargetPath );
3310 strcatW(FullName,close);
3312 TRACE("Registering %s\n",debugstr_w(FullName));
3313 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3317 msi_dialog_check_messages(info.hProcess);
3322 uirow = MSI_CreateRecord( 2 );
3323 uipath = strdupW( file->TargetPath );
3324 p = strrchrW(uipath,'\\');
3327 MSI_RecordSetStringW( uirow, 1, &p[2] );
3328 MSI_RecordSetStringW( uirow, 2, uipath);
3329 ui_actiondata( package, szSelfRegModules, uirow);
3330 msiobj_release( &uirow->hdr );
3332 /* FIXME: call ui_progress? */
3334 return ERROR_SUCCESS;
3337 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3341 static const WCHAR ExecSeqQuery[] =
3342 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3343 '`','S','e','l','f','R','e','g','`',0};
3345 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3346 if (rc != ERROR_SUCCESS)
3348 TRACE("no SelfReg table\n");
3349 return ERROR_SUCCESS;
3352 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3353 msiobj_release(&view->hdr);
3355 return ERROR_SUCCESS;
3358 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3360 MSIFEATURE *feature;
3365 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3366 if (rc != ERROR_SUCCESS)
3369 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3370 if (rc != ERROR_SUCCESS)
3373 /* here the guids are base 85 encoded */
3374 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3380 BOOL absent = FALSE;
3383 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3384 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3385 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3389 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3393 if (feature->Feature_Parent)
3394 size += strlenW( feature->Feature_Parent )+2;
3396 data = msi_alloc(size * sizeof(WCHAR));
3399 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3401 MSICOMPONENT* component = cl->component;
3405 if (component->ComponentId)
3407 TRACE("From %s\n",debugstr_w(component->ComponentId));
3408 CLSIDFromString(component->ComponentId, &clsid);
3409 encode_base85_guid(&clsid,buf);
3410 TRACE("to %s\n",debugstr_w(buf));
3414 if (feature->Feature_Parent)
3416 static const WCHAR sep[] = {'\2',0};
3418 strcatW(data,feature->Feature_Parent);
3421 msi_reg_set_val_str( hkey, feature->Feature, data );
3425 if (feature->Feature_Parent)
3426 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3429 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3430 (LPBYTE)feature->Feature_Parent,size);
3434 size += 2*sizeof(WCHAR);
3435 data = msi_alloc(size);
3438 if (feature->Feature_Parent)
3439 strcpyW( &data[1], feature->Feature_Parent );
3440 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3446 uirow = MSI_CreateRecord( 1 );
3447 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3448 ui_actiondata( package, szPublishFeatures, uirow);
3449 msiobj_release( &uirow->hdr );
3450 /* FIXME: call ui_progress? */
3459 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3461 static const WCHAR installerPathFmt[] = {
3462 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3463 static const WCHAR fmt[] = {
3465 'I','n','s','t','a','l','l','e','r','\\',
3466 '%','x','.','m','s','i',0};
3467 static const WCHAR szOriginalDatabase[] =
3468 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3469 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3474 /* copy the package locally */
3475 num = GetTickCount() & 0xffff;
3479 GetWindowsDirectoryW( windir, MAX_PATH );
3480 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3483 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3484 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3485 if (handle != INVALID_HANDLE_VALUE)
3487 CloseHandle(handle);
3490 if (GetLastError() != ERROR_FILE_EXISTS &&
3491 GetLastError() != ERROR_SHARING_VIOLATION)
3493 if (!(++num & 0xffff)) num = 1;
3494 sprintfW(packagefile,fmt,num);
3495 } while (num != start);
3497 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3498 create_full_pathW(path);
3500 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3502 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3503 r = CopyFileW( msiFilePath, packagefile, FALSE);
3504 msi_free( msiFilePath );
3508 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3509 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3510 return ERROR_FUNCTION_FAILED;
3513 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3514 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3515 return ERROR_SUCCESS;
3518 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3520 LPWSTR prop, val, key;
3521 static const LPCSTR propval[] = {
3522 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3523 "ARPCONTACT", "Contact",
3524 "ARPCOMMENTS", "Comments",
3525 "ProductName", "DisplayName",
3526 "ProductVersion", "DisplayVersion",
3527 "ARPHELPLINK", "HelpLink",
3528 "ARPHELPTELEPHONE", "HelpTelephone",
3529 "ARPINSTALLLOCATION", "InstallLocation",
3530 "SourceDir", "InstallSource",
3531 "Manufacturer", "Publisher",
3532 "ARPREADME", "Readme",
3534 "ARPURLINFOABOUT", "URLInfoAbout",
3535 "ARPURLUPDATEINFO", "URLUpdateInfo",
3538 const LPCSTR *p = propval;
3542 prop = strdupAtoW( *p++ );
3543 key = strdupAtoW( *p++ );
3544 val = msi_dup_property( package, prop );
3545 msi_reg_set_val_str( hkey, key, val );
3550 return ERROR_SUCCESS;
3553 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3556 LPWSTR buffer = NULL;
3559 static const WCHAR szWindowsInstaller[] =
3560 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3561 static const WCHAR szUpgradeCode[] =
3562 {'U','p','g','r','a','d','e','C','o','d','e',0};
3563 static const WCHAR modpath_fmt[] =
3564 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3565 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3566 static const WCHAR szModifyPath[] =
3567 {'M','o','d','i','f','y','P','a','t','h',0};
3568 static const WCHAR szUninstallString[] =
3569 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3570 static const WCHAR szEstimatedSize[] =
3571 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3572 static const WCHAR szProductLanguage[] =
3573 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3574 static const WCHAR szProductVersion[] =
3575 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3578 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3579 LPWSTR upgrade_code;
3582 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3583 if (rc != ERROR_SUCCESS)
3586 /* dump all the info i can grab */
3587 /* FIXME: Flesh out more information */
3589 msi_write_uninstall_property_vals( package, hkey );
3591 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3593 msi_make_package_local( package, hkey );
3595 /* do ModifyPath and UninstallString */
3596 size = deformat_string(package,modpath_fmt,&buffer);
3597 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3598 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3601 /* FIXME: Write real Estimated Size when we have it */
3602 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3604 GetLocalTime(&systime);
3605 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3606 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3608 langid = msi_get_property_int( package, szProductLanguage, 0 );
3609 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3611 buffer = msi_dup_property( package, szProductVersion );
3614 DWORD verdword = msi_version_str_to_dword(buffer);
3616 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3617 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3618 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3622 /* Handle Upgrade Codes */
3623 upgrade_code = msi_dup_property( package, szUpgradeCode );
3628 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3629 squash_guid(package->ProductCode,squashed);
3630 msi_reg_set_val_str( hkey2, squashed, NULL );
3632 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3633 squash_guid(package->ProductCode,squashed);
3634 msi_reg_set_val_str( hkey2, squashed, NULL );
3637 msi_free(upgrade_code);
3642 /* FIXME: call ui_actiondata */
3644 return ERROR_SUCCESS;
3647 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3649 return execute_script(package,INSTALL_SCRIPT);
3652 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3656 /* turn off scheduleing */
3657 package->script->CurrentlyScripting= FALSE;
3659 /* first do the same as an InstallExecute */
3660 rc = ACTION_InstallExecute(package);
3661 if (rc != ERROR_SUCCESS)
3664 /* then handle Commit Actions */
3665 rc = execute_script(package,COMMIT_SCRIPT);
3670 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3672 static const WCHAR RunOnce[] = {
3673 'S','o','f','t','w','a','r','e','\\',
3674 'M','i','c','r','o','s','o','f','t','\\',
3675 'W','i','n','d','o','w','s','\\',
3676 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3677 'R','u','n','O','n','c','e',0};
3678 static const WCHAR InstallRunOnce[] = {
3679 'S','o','f','t','w','a','r','e','\\',
3680 'M','i','c','r','o','s','o','f','t','\\',
3681 'W','i','n','d','o','w','s','\\',
3682 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3683 'I','n','s','t','a','l','l','e','r','\\',
3684 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3686 static const WCHAR msiexec_fmt[] = {
3688 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3689 '\"','%','s','\"',0};
3690 static const WCHAR install_fmt[] = {
3691 '/','I',' ','\"','%','s','\"',' ',
3692 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3693 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3694 WCHAR buffer[256], sysdir[MAX_PATH];
3696 WCHAR squished_pc[100];
3698 squash_guid(package->ProductCode,squished_pc);
3700 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3701 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3702 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3705 msi_reg_set_val_str( hkey, squished_pc, buffer );
3708 TRACE("Reboot command %s\n",debugstr_w(buffer));
3710 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3711 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3713 msi_reg_set_val_str( hkey, squished_pc, buffer );
3716 return ERROR_INSTALL_SUSPEND;
3719 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3724 * we are currently doing what should be done here in the top level Install
3725 * however for Adminastrative and uninstalls this step will be needed
3727 if (!package->PackagePath)
3728 return ERROR_SUCCESS;
3730 attrib = GetFileAttributesW(package->PackagePath);
3731 if (attrib == INVALID_FILE_ATTRIBUTES)
3737 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3738 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3739 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3740 if (rc == ERROR_MORE_DATA)
3742 prompt = msi_alloc(size * sizeof(WCHAR));
3743 MsiSourceListGetInfoW(package->ProductCode, NULL,
3744 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3745 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3748 prompt = strdupW(package->PackagePath);
3750 msg = generate_error_string(package,1302,1,prompt);
3751 while(attrib == INVALID_FILE_ATTRIBUTES)
3753 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3756 rc = ERROR_INSTALL_USEREXIT;
3759 attrib = GetFileAttributesW(package->PackagePath);
3765 return ERROR_SUCCESS;
3770 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3777 static const WCHAR szPropKeys[][80] =
3779 {'P','r','o','d','u','c','t','I','D',0},
3780 {'U','S','E','R','N','A','M','E',0},
3781 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3785 static const WCHAR szRegKeys[][80] =
3787 {'P','r','o','d','u','c','t','I','D',0},
3788 {'R','e','g','O','w','n','e','r',0},
3789 {'R','e','g','C','o','m','p','a','n','y',0},
3793 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3795 return ERROR_SUCCESS;
3797 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3798 if (rc != ERROR_SUCCESS)
3801 for( i = 0; szPropKeys[i][0]; i++ )
3803 buffer = msi_dup_property( package, szPropKeys[i] );
3804 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3809 msi_free(productid);
3812 /* FIXME: call ui_actiondata */
3814 return ERROR_SUCCESS;
3818 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3822 package->script->InWhatSequence |= SEQUENCE_EXEC;
3823 rc = ACTION_ProcessExecSequence(package,FALSE);
3829 * Code based off of code located here
3830 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3832 * Using string index 4 (full font name) instead of 1 (family name)
3834 static LPWSTR load_ttfname_from(LPCWSTR filename)
3840 typedef struct _tagTT_OFFSET_TABLE{
3841 USHORT uMajorVersion;
3842 USHORT uMinorVersion;
3843 USHORT uNumOfTables;
3844 USHORT uSearchRange;
3845 USHORT uEntrySelector;
3849 typedef struct _tagTT_TABLE_DIRECTORY{
3850 char szTag[4]; /* table name */
3851 ULONG uCheckSum; /* Check sum */
3852 ULONG uOffset; /* Offset from beginning of file */
3853 ULONG uLength; /* length of the table in bytes */
3854 }TT_TABLE_DIRECTORY;
3856 typedef struct _tagTT_NAME_TABLE_HEADER{
3857 USHORT uFSelector; /* format selector. Always 0 */
3858 USHORT uNRCount; /* Name Records count */
3859 USHORT uStorageOffset; /* Offset for strings storage,
3860 * from start of the table */
3861 }TT_NAME_TABLE_HEADER;
3863 typedef struct _tagTT_NAME_RECORD{
3868 USHORT uStringLength;
3869 USHORT uStringOffset; /* from start of storage area */
3872 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3873 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3875 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3876 FILE_ATTRIBUTE_NORMAL, 0 );
3877 if (handle != INVALID_HANDLE_VALUE)
3879 TT_TABLE_DIRECTORY tblDir;
3880 BOOL bFound = FALSE;
3881 TT_OFFSET_TABLE ttOffsetTable;
3884 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3885 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3886 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3887 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3889 if (ttOffsetTable.uMajorVersion != 1 ||
3890 ttOffsetTable.uMinorVersion != 0)
3893 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3895 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3896 if (strncmp(tblDir.szTag,"name",4)==0)
3899 tblDir.uLength = SWAPLONG(tblDir.uLength);
3900 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3907 TT_NAME_TABLE_HEADER ttNTHeader;
3908 TT_NAME_RECORD ttRecord;
3910 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3911 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3914 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3915 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3917 for(i=0; i<ttNTHeader.uNRCount; i++)
3919 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3920 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3921 /* 4 is the Full Font Name */
3922 if(ttRecord.uNameID == 4)
3926 static LPCSTR tt = " (TrueType)";
3928 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3929 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3930 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3931 SetFilePointer(handle, tblDir.uOffset +
3932 ttRecord.uStringOffset +
3933 ttNTHeader.uStorageOffset,
3935 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3936 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3937 if (strlen(buf) > 0)
3940 ret = strdupAtoW(buf);
3946 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3950 CloseHandle(handle);
3953 ERR("Unable to open font file %s\n", debugstr_w(filename));
3955 TRACE("Returning fontname %s\n",debugstr_w(ret));
3959 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3961 MSIPACKAGE *package = (MSIPACKAGE*)param;
3965 static const WCHAR regfont1[] =
3966 {'S','o','f','t','w','a','r','e','\\',
3967 'M','i','c','r','o','s','o','f','t','\\',
3968 'W','i','n','d','o','w','s',' ','N','T','\\',
3969 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3970 'F','o','n','t','s',0};
3971 static const WCHAR regfont2[] =
3972 {'S','o','f','t','w','a','r','e','\\',
3973 'M','i','c','r','o','s','o','f','t','\\',
3974 'W','i','n','d','o','w','s','\\',
3975 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3976 'F','o','n','t','s',0};
3982 filename = MSI_RecordGetString( row, 1 );
3983 file = get_loaded_file( package, filename );
3986 ERR("Unable to load file\n");
3987 return ERROR_SUCCESS;
3990 /* check to make sure that component is installed */
3991 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3993 TRACE("Skipping: Component not scheduled for install\n");
3994 return ERROR_SUCCESS;
3997 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3998 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
4000 if (MSI_RecordIsNull(row,2))
4001 name = load_ttfname_from( file->TargetPath );
4003 name = msi_dup_record_field(row,2);
4007 msi_reg_set_val_str( hkey1, name, file->FileName );
4008 msi_reg_set_val_str( hkey2, name, file->FileName );
4016 uirow = MSI_CreateRecord( 1 );
4017 uipath = strdupW( file->TargetPath );
4018 p = strrchrW(uipath,'\\');
4021 MSI_RecordSetStringW( uirow, 1, p );
4022 ui_actiondata( package, szRegisterFonts, uirow);
4023 msiobj_release( &uirow->hdr );
4025 /* FIXME: call ui_progress? */
4027 return ERROR_SUCCESS;
4030 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4034 static const WCHAR ExecSeqQuery[] =
4035 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4036 '`','F','o','n','t','`',0};
4038 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4039 if (rc != ERROR_SUCCESS)
4041 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4042 return ERROR_SUCCESS;
4045 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4046 msiobj_release(&view->hdr);
4048 return ERROR_SUCCESS;
4051 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4053 MSIPACKAGE *package = (MSIPACKAGE*)param;
4054 LPCWSTR compgroupid=NULL;
4055 LPCWSTR feature=NULL;
4056 LPCWSTR text = NULL;
4057 LPCWSTR qualifier = NULL;
4058 LPCWSTR component = NULL;
4059 LPWSTR advertise = NULL;
4060 LPWSTR output = NULL;
4062 UINT rc = ERROR_SUCCESS;
4067 component = MSI_RecordGetString(rec,3);
4068 comp = get_loaded_component(package,component);
4070 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4071 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4072 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4074 TRACE("Skipping: Component %s not scheduled for install\n",
4075 debugstr_w(component));
4077 return ERROR_SUCCESS;
4080 compgroupid = MSI_RecordGetString(rec,1);
4081 qualifier = MSI_RecordGetString(rec,2);
4083 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4084 if (rc != ERROR_SUCCESS)
4087 text = MSI_RecordGetString(rec,4);
4088 feature = MSI_RecordGetString(rec,5);
4090 advertise = create_component_advertise_string(package, comp, feature);
4092 sz = strlenW(advertise);
4095 sz += lstrlenW(text);
4098 sz *= sizeof(WCHAR);
4100 output = msi_alloc_zero(sz);
4101 strcpyW(output,advertise);
4102 msi_free(advertise);
4105 strcatW(output,text);
4107 msi_reg_set_val_multi_str( hkey, qualifier, output );
4114 uirow = MSI_CreateRecord( 2 );
4115 MSI_RecordSetStringW( uirow, 1, compgroupid );
4116 MSI_RecordSetStringW( uirow, 2, qualifier);
4117 ui_actiondata( package, szPublishComponents, uirow);
4118 msiobj_release( &uirow->hdr );
4119 /* FIXME: call ui_progress? */
4125 * At present I am ignorning the advertised components part of this and only
4126 * focusing on the qualified component sets
4128 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4132 static const WCHAR ExecSeqQuery[] =
4133 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4134 '`','P','u','b','l','i','s','h',
4135 'C','o','m','p','o','n','e','n','t','`',0};
4137 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4138 if (rc != ERROR_SUCCESS)
4139 return ERROR_SUCCESS;
4141 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4142 msiobj_release(&view->hdr);
4147 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4148 LPCSTR action, LPCWSTR table )
4150 static const WCHAR query[] = {
4151 'S','E','L','E','C','T',' ','*',' ',
4152 'F','R','O','M',' ','`','%','s','`',0 };
4153 MSIQUERY *view = NULL;
4157 r = MSI_OpenQuery( package->db, &view, query, table );
4158 if (r == ERROR_SUCCESS)
4160 r = MSI_IterateRecords(view, &count, NULL, package);
4161 msiobj_release(&view->hdr);
4165 FIXME("%s -> %lu ignored %s table values\n",
4166 action, count, debugstr_w(table));
4168 return ERROR_SUCCESS;
4171 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4173 TRACE("%p\n", package);
4174 return ERROR_SUCCESS;
4177 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4179 static const WCHAR table[] =
4180 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4181 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4184 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4186 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4187 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4190 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4192 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4193 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4196 static UINT ACTION_BindImage( MSIPACKAGE *package )
4198 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4199 return msi_unimplemented_action_stub( package, "BindImage", table );
4202 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4204 static const WCHAR table[] = {
4205 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4206 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4209 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4211 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4212 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4215 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4217 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4218 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4221 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4223 static const WCHAR table[] = {
4224 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4225 return msi_unimplemented_action_stub( package, "InstallServices", table );
4228 static UINT ACTION_StartServices( MSIPACKAGE *package )
4230 static const WCHAR table[] = {
4231 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4232 return msi_unimplemented_action_stub( package, "StartServices", table );
4235 static UINT ACTION_StopServices( MSIPACKAGE *package )
4237 static const WCHAR table[] = {
4238 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4239 return msi_unimplemented_action_stub( package, "StopServices", table );
4242 static UINT ACTION_DeleteServices( 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, "DeleteServices", table );
4249 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4251 static const WCHAR table[] = {
4252 'E','n','v','i','r','o','n','m','e','n','t',0 };
4253 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4256 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4258 static const WCHAR table[] = {
4259 'E','n','v','i','r','o','n','m','e','n','t',0 };
4260 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4263 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4265 static const WCHAR table[] = {
4266 'M','s','i','A','s','s','e','m','b','l','y',0 };
4267 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4270 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4272 static const WCHAR table[] = {
4273 'M','s','i','A','s','s','e','m','b','l','y',0 };
4274 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4277 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4279 static const WCHAR table[] = { 'F','o','n','t',0 };
4280 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4283 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4285 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4286 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4289 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4291 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4292 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4295 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4297 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4298 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4301 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4303 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4304 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4307 static struct _actions StandardActions[] = {
4308 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4309 { szAppSearch, ACTION_AppSearch },
4310 { szBindImage, ACTION_BindImage },
4311 { szCCPSearch, ACTION_CCPSearch},
4312 { szCostFinalize, ACTION_CostFinalize },
4313 { szCostInitialize, ACTION_CostInitialize },
4314 { szCreateFolders, ACTION_CreateFolders },
4315 { szCreateShortcuts, ACTION_CreateShortcuts },
4316 { szDeleteServices, ACTION_DeleteServices },
4317 { szDisableRollback, NULL},
4318 { szDuplicateFiles, ACTION_DuplicateFiles },
4319 { szExecuteAction, ACTION_ExecuteAction },
4320 { szFileCost, ACTION_FileCost },
4321 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4322 { szForceReboot, ACTION_ForceReboot },
4323 { szInstallAdminPackage, NULL},
4324 { szInstallExecute, ACTION_InstallExecute },
4325 { szInstallExecuteAgain, ACTION_InstallExecute },
4326 { szInstallFiles, ACTION_InstallFiles},
4327 { szInstallFinalize, ACTION_InstallFinalize },
4328 { szInstallInitialize, ACTION_InstallInitialize },
4329 { szInstallSFPCatalogFile, NULL},
4330 { szInstallValidate, ACTION_InstallValidate },
4331 { szIsolateComponents, ACTION_IsolateComponents },
4332 { szLaunchConditions, ACTION_LaunchConditions },
4333 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4334 { szMoveFiles, ACTION_MoveFiles },
4335 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4336 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4337 { szInstallODBC, NULL},
4338 { szInstallServices, ACTION_InstallServices },
4339 { szPatchFiles, ACTION_PatchFiles },
4340 { szProcessComponents, ACTION_ProcessComponents },
4341 { szPublishComponents, ACTION_PublishComponents },
4342 { szPublishFeatures, ACTION_PublishFeatures },
4343 { szPublishProduct, ACTION_PublishProduct },
4344 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4345 { szRegisterComPlus, ACTION_RegisterComPlus},
4346 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4347 { szRegisterFonts, ACTION_RegisterFonts },
4348 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4349 { szRegisterProduct, ACTION_RegisterProduct },
4350 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4351 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4352 { szRegisterUser, ACTION_RegisterUser},
4353 { szRemoveDuplicateFiles, NULL},
4354 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4355 { szRemoveExistingProducts, NULL},
4356 { szRemoveFiles, ACTION_RemoveFiles},
4357 { szRemoveFolders, NULL},
4358 { szRemoveIniValues, ACTION_RemoveIniValues },
4359 { szRemoveODBC, NULL},
4360 { szRemoveRegistryValues, NULL},
4361 { szRemoveShortcuts, NULL},
4362 { szResolveSource, ACTION_ResolveSource},
4363 { szRMCCPSearch, ACTION_RMCCPSearch},
4364 { szScheduleReboot, NULL},
4365 { szSelfRegModules, ACTION_SelfRegModules },
4366 { szSelfUnregModules, ACTION_SelfUnregModules },
4367 { szSetODBCFolders, NULL},
4368 { szStartServices, ACTION_StartServices },
4369 { szStopServices, ACTION_StopServices },
4370 { szUnpublishComponents, NULL},
4371 { szUnpublishFeatures, NULL},
4372 { szUnregisterClassInfo, NULL},
4373 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4374 { szUnregisterExtensionInfo, NULL},
4375 { szUnregisterFonts, ACTION_UnregisterFonts },
4376 { szUnregisterMIMEInfo, NULL},
4377 { szUnregisterProgIdInfo, NULL},
4378 { szUnregisterTypeLibraries, NULL},
4379 { szValidateProductID, NULL},
4380 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4381 { szWriteIniValues, ACTION_WriteIniValues },
4382 { szWriteRegistryValues, ACTION_WriteRegistryValues},