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_LOCAL;
1138 comp->ActionRequest = INSTALLSTATE_LOCAL;
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 the compressed bits are not set in the file attributes,
1330 * then read the information from the package word count property
1332 if (file->Attributes & msidbFileAttributesCompressed)
1334 file->IsCompressed = TRUE;
1336 else if (file->Attributes & msidbFileAttributesNoncompressed)
1338 file->IsCompressed = FALSE;
1342 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1345 if (file->IsCompressed)
1347 file->Component->ForceLocalState = TRUE;
1348 file->Component->Action = INSTALLSTATE_LOCAL;
1349 file->Component->ActionRequest = INSTALLSTATE_LOCAL;
1352 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1354 list_add_tail( &package->files, &file->entry );
1356 return ERROR_SUCCESS;
1359 static UINT load_all_files(MSIPACKAGE *package)
1363 static const WCHAR Query[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1366 '`','S','e','q','u','e','n','c','e','`', 0};
1368 if (!list_empty(&package->files))
1369 return ERROR_SUCCESS;
1371 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1372 if (rc != ERROR_SUCCESS)
1373 return ERROR_SUCCESS;
1375 rc = MSI_IterateRecords(view, NULL, load_file, package);
1376 msiobj_release(&view->hdr);
1378 return ERROR_SUCCESS;
1383 * I am not doing any of the costing functionality yet.
1384 * Mostly looking at doing the Component and Feature loading
1386 * The native MSI does A LOT of modification to tables here. Mostly adding
1387 * a lot of temporary columns to the Feature and Component tables.
1389 * note: Native msi also tracks the short filename. But I am only going to
1390 * track the long ones. Also looking at this directory table
1391 * it appears that the directory table does not get the parents
1392 * resolved base on property only based on their entries in the
1395 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1397 static const WCHAR szCosting[] =
1398 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1399 static const WCHAR szZero[] = { '0', 0 };
1401 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1402 return ERROR_SUCCESS;
1404 MSI_SetPropertyW(package, szCosting, szZero);
1405 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1407 load_all_components( package );
1408 load_all_features( package );
1409 load_all_files( package );
1411 return ERROR_SUCCESS;
1414 static UINT execute_script(MSIPACKAGE *package, UINT script )
1417 UINT rc = ERROR_SUCCESS;
1419 TRACE("Executing Script %i\n",script);
1421 if (!package->script)
1423 ERR("no script!\n");
1424 return ERROR_FUNCTION_FAILED;
1427 for (i = 0; i < package->script->ActionCount[script]; i++)
1430 action = package->script->Actions[script][i];
1431 ui_actionstart(package, action);
1432 TRACE("Executing Action (%s)\n",debugstr_w(action));
1433 rc = ACTION_PerformAction(package, action, TRUE);
1434 msi_free(package->script->Actions[script][i]);
1435 if (rc != ERROR_SUCCESS)
1438 msi_free(package->script->Actions[script]);
1440 package->script->ActionCount[script] = 0;
1441 package->script->Actions[script] = NULL;
1445 static UINT ACTION_FileCost(MSIPACKAGE *package)
1447 return ERROR_SUCCESS;
1450 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1452 static const WCHAR Query[] =
1453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1454 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1455 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1456 ' ','=',' ','\'','%','s','\'',
1458 static const WCHAR szDot[] = { '.',0 };
1459 static WCHAR szEmpty[] = { 0 };
1460 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1465 TRACE("Looking for dir %s\n",debugstr_w(dir));
1467 folder = get_loaded_folder( package, dir );
1471 TRACE("Working to load %s\n",debugstr_w(dir));
1473 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1477 folder->Directory = strdupW(dir);
1479 row = MSI_QueryGetRecord(package->db, Query, dir);
1483 p = msi_dup_record_field(row, 3);
1485 /* split src and target dir */
1487 src_short = folder_split_path( p, ':' );
1489 /* split the long and short paths */
1490 tgt_long = folder_split_path( tgt_short, '|' );
1491 src_long = folder_split_path( src_short, '|' );
1493 /* check for no-op dirs */
1494 if (!lstrcmpW(szDot, tgt_short))
1495 tgt_short = szEmpty;
1496 if (!lstrcmpW(szDot, src_short))
1497 src_short = szEmpty;
1500 tgt_long = tgt_short;
1503 src_short = tgt_short;
1504 src_long = tgt_long;
1508 src_long = src_short;
1510 /* FIXME: use the target short path too */
1511 folder->TargetDefault = strdupW(tgt_long);
1512 folder->SourceShortPath = strdupW(src_short);
1513 folder->SourceLongPath = strdupW(src_long);
1516 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1517 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1518 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1520 parent = MSI_RecordGetString(row, 2);
1523 folder->Parent = load_folder( package, parent );
1524 if ( folder->Parent )
1525 TRACE("loaded parent %p %s\n", folder->Parent,
1526 debugstr_w(folder->Parent->Directory));
1528 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1531 folder->Property = msi_dup_property( package, dir );
1533 msiobj_release(&row->hdr);
1535 list_add_tail( &package->folders, &folder->entry );
1537 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1542 /* scan for and update current install states */
1543 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1546 MSIFEATURE *feature;
1548 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1551 res = MsiGetComponentPathW( package->ProductCode,
1552 comp->ComponentId, NULL, NULL);
1554 res = INSTALLSTATE_ABSENT;
1555 comp->Installed = res;
1558 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1561 INSTALLSTATE res = -10;
1563 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1565 comp= cl->component;
1568 res = comp->Installed;
1571 if (res == comp->Installed)
1574 if (res != comp->Installed)
1575 res = INSTALLSTATE_INCOMPLETE;
1578 feature->Installed = res;
1582 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1585 static const WCHAR all[]={'A','L','L',0};
1587 MSIFEATURE *feature;
1589 override = msi_dup_property( package, property );
1593 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1595 if (strcmpiW(override,all)==0)
1597 feature->ActionRequest= state;
1598 feature->Action = state;
1602 LPWSTR ptr = override;
1603 LPWSTR ptr2 = strchrW(override,',');
1607 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1608 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1610 feature->ActionRequest= state;
1611 feature->Action = state;
1617 ptr2 = strchrW(ptr,',');
1629 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1632 static const WCHAR szlevel[] =
1633 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1634 static const WCHAR szAddLocal[] =
1635 {'A','D','D','L','O','C','A','L',0};
1636 static const WCHAR szRemove[] =
1637 {'R','E','M','O','V','E',0};
1638 static const WCHAR szReinstall[] =
1639 {'R','E','I','N','S','T','A','L','L',0};
1640 BOOL override = FALSE;
1641 MSICOMPONENT* component;
1642 MSIFEATURE *feature;
1645 /* I do not know if this is where it should happen.. but */
1647 TRACE("Checking Install Level\n");
1649 install_level = msi_get_property_int( package, szlevel, 1 );
1651 /* ok hereis the _real_ rub
1652 * all these activation/deactivation things happen in order and things
1653 * later on the list override things earlier on the list.
1654 * 1) INSTALLLEVEL processing
1664 * 11) FILEADDDEFAULT
1665 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1666 * ignored for all the features. seems strange, especially since it is not
1667 * documented anywhere, but it is how it works.
1669 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1670 * REMOVE are the big ones, since we don't handle administrative installs
1673 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1674 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1675 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1679 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1681 BOOL feature_state = ((feature->Level > 0) &&
1682 (feature->Level <= install_level));
1684 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1686 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1688 feature->ActionRequest = INSTALLSTATE_SOURCE;
1689 feature->Action = INSTALLSTATE_SOURCE;
1691 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1693 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1694 feature->Action = INSTALLSTATE_ADVERTISED;
1698 feature->ActionRequest = INSTALLSTATE_LOCAL;
1699 feature->Action = INSTALLSTATE_LOCAL;
1706 /* set the Preselected Property */
1707 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1708 static const WCHAR szOne[] = { '1', 0 };
1710 MSI_SetPropertyW(package,szPreselected,szOne);
1714 * now we want to enable or disable components base on feature
1717 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1721 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1722 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1723 feature->ActionRequest);
1725 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1727 component = cl->component;
1729 if (!component->Enabled)
1731 component->Action = INSTALLSTATE_UNKNOWN;
1732 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1736 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1738 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1740 component->Action = INSTALLSTATE_LOCAL;
1741 component->ActionRequest = INSTALLSTATE_LOCAL;
1744 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1746 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1747 (component->Action == INSTALLSTATE_ABSENT) ||
1748 (component->Action == INSTALLSTATE_ADVERTISED) ||
1749 (component->Action == INSTALLSTATE_DEFAULT))
1752 component->Action = INSTALLSTATE_SOURCE;
1753 component->ActionRequest = INSTALLSTATE_SOURCE;
1756 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1758 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1759 (component->Action == INSTALLSTATE_ABSENT))
1762 component->Action = INSTALLSTATE_ADVERTISED;
1763 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1766 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1768 if (component->Action == INSTALLSTATE_UNKNOWN)
1770 component->Action = INSTALLSTATE_ABSENT;
1771 component->ActionRequest = INSTALLSTATE_ABSENT;
1776 if (component->ForceLocalState)
1778 feature->Action = INSTALLSTATE_LOCAL;
1779 feature->ActionRequest = INSTALLSTATE_LOCAL;
1784 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1786 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1787 debugstr_w(component->Component), component->Installed,
1788 component->Action, component->ActionRequest);
1792 return ERROR_SUCCESS;
1795 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1797 MSIPACKAGE *package = (MSIPACKAGE*)param;
1801 name = MSI_RecordGetString(row,1);
1803 /* This helper function now does ALL the work */
1804 TRACE("Dir %s ...\n",debugstr_w(name));
1805 load_folder(package,name);
1806 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1807 TRACE("resolves to %s\n",debugstr_w(path));
1810 return ERROR_SUCCESS;
1813 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1815 MSIPACKAGE *package = (MSIPACKAGE*)param;
1817 MSIFEATURE *feature;
1819 name = MSI_RecordGetString( row, 1 );
1821 feature = get_loaded_feature( package, name );
1823 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1827 Condition = MSI_RecordGetString(row,3);
1829 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1831 int level = MSI_RecordGetInteger(row,2);
1832 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1833 feature->Level = level;
1836 return ERROR_SUCCESS;
1841 * A lot is done in this function aside from just the costing.
1842 * The costing needs to be implemented at some point but for now I am going
1843 * to focus on the directory building
1846 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1848 static const WCHAR ExecSeqQuery[] =
1849 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1850 '`','D','i','r','e','c','t','o','r','y','`',0};
1851 static const WCHAR ConditionQuery[] =
1852 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1853 '`','C','o','n','d','i','t','i','o','n','`',0};
1854 static const WCHAR szCosting[] =
1855 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1856 static const WCHAR szlevel[] =
1857 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1858 static const WCHAR szOne[] = { '1', 0 };
1865 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1866 return ERROR_SUCCESS;
1868 TRACE("Building Directory properties\n");
1870 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1871 if (rc == ERROR_SUCCESS)
1873 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1875 msiobj_release(&view->hdr);
1878 TRACE("File calculations\n");
1880 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1882 MSICOMPONENT* comp = file->Component;
1888 /* calculate target */
1889 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1891 msi_free(file->TargetPath);
1893 TRACE("file %s is named %s\n",
1894 debugstr_w(file->File),debugstr_w(file->FileName));
1896 file->TargetPath = build_directory_name(2, p, file->FileName);
1900 TRACE("file %s resolves to %s\n",
1901 debugstr_w(file->File),debugstr_w(file->TargetPath));
1903 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1905 file->state = msifs_missing;
1906 comp->Cost += file->FileSize;
1916 static WCHAR name[] = {'\\',0};
1917 static const WCHAR name_fmt[] =
1918 {'%','u','.','%','u','.','%','u','.','%','u',0};
1919 WCHAR filever[0x100];
1920 VS_FIXEDFILEINFO *lpVer;
1922 TRACE("Version comparison..\n");
1923 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1924 version = msi_alloc(versize);
1925 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1927 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1929 sprintfW(filever,name_fmt,
1930 HIWORD(lpVer->dwFileVersionMS),
1931 LOWORD(lpVer->dwFileVersionMS),
1932 HIWORD(lpVer->dwFileVersionLS),
1933 LOWORD(lpVer->dwFileVersionLS));
1935 TRACE("new %s old %s\n", debugstr_w(file->Version),
1936 debugstr_w(filever));
1937 if (strcmpiW(filever,file->Version)<0)
1939 file->state = msifs_overwrite;
1940 /* FIXME: cost should be diff in size */
1941 comp->Cost += file->FileSize;
1944 file->state = msifs_present;
1948 file->state = msifs_present;
1951 TRACE("Evaluating Condition Table\n");
1953 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1954 if (rc == ERROR_SUCCESS)
1956 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1958 msiobj_release(&view->hdr);
1961 TRACE("Enabling or Disabling Components\n");
1962 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1964 if (comp->Condition)
1966 if (MSI_EvaluateConditionW(package,
1967 comp->Condition) == MSICONDITION_FALSE)
1969 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1970 comp->Enabled = FALSE;
1975 MSI_SetPropertyW(package,szCosting,szOne);
1976 /* set default run level if not set */
1977 level = msi_dup_property( package, szlevel );
1979 MSI_SetPropertyW(package,szlevel, szOne);
1982 ACTION_UpdateInstallStates(package);
1984 return MSI_SetFeatureStates(package);
1987 /* OK this value is "interpreted" and then formatted based on the
1988 first few characters */
1989 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1993 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1999 LPWSTR deformated = NULL;
2002 deformat_string(package, &value[2], &deformated);
2004 /* binary value type */
2008 *size = (strlenW(ptr)/2)+1;
2010 *size = strlenW(ptr)/2;
2012 data = msi_alloc(*size);
2018 /* if uneven pad with a zero in front */
2024 data[count] = (BYTE)strtol(byte,NULL,0);
2026 TRACE("Uneven byte count\n");
2034 data[count] = (BYTE)strtol(byte,NULL,0);
2037 msi_free(deformated);
2039 TRACE("Data %li bytes(%i)\n",*size,count);
2046 deformat_string(package, &value[1], &deformated);
2049 *size = sizeof(DWORD);
2050 data = msi_alloc(*size);
2056 if ( (*p < '0') || (*p > '9') )
2062 if (deformated[0] == '-')
2065 TRACE("DWORD %li\n",*(LPDWORD)data);
2067 msi_free(deformated);
2072 static const WCHAR szMulti[] = {'[','~',']',0};
2081 *type=REG_EXPAND_SZ;
2089 if (strstrW(value,szMulti))
2090 *type = REG_MULTI_SZ;
2092 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2097 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2099 MSIPACKAGE *package = (MSIPACKAGE*)param;
2100 static const WCHAR szHCR[] =
2101 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2102 'R','O','O','T','\\',0};
2103 static const WCHAR szHCU[] =
2104 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2105 'U','S','E','R','\\',0};
2106 static const WCHAR szHLM[] =
2107 {'H','K','E','Y','_','L','O','C','A','L','_',
2108 'M','A','C','H','I','N','E','\\',0};
2109 static const WCHAR szHU[] =
2110 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2112 LPSTR value_data = NULL;
2113 HKEY root_key, hkey;
2116 LPCWSTR szRoot, component, name, key, value;
2121 BOOL check_first = FALSE;
2124 ui_progress(package,2,0,0,0);
2131 component = MSI_RecordGetString(row, 6);
2132 comp = get_loaded_component(package,component);
2134 return ERROR_SUCCESS;
2136 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2138 TRACE("Skipping write due to disabled component %s\n",
2139 debugstr_w(component));
2141 comp->Action = comp->Installed;
2143 return ERROR_SUCCESS;
2146 comp->Action = INSTALLSTATE_LOCAL;
2148 name = MSI_RecordGetString(row, 4);
2149 if( MSI_RecordIsNull(row,5) && name )
2151 /* null values can have special meanings */
2152 if (name[0]=='-' && name[1] == 0)
2153 return ERROR_SUCCESS;
2154 else if ((name[0]=='+' && name[1] == 0) ||
2155 (name[0] == '*' && name[1] == 0))
2160 root = MSI_RecordGetInteger(row,2);
2161 key = MSI_RecordGetString(row, 3);
2163 /* get the root key */
2168 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2169 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2170 if (all_users && all_users[0] == '1')
2172 root_key = HKEY_LOCAL_MACHINE;
2177 root_key = HKEY_CURRENT_USER;
2180 msi_free(all_users);
2183 case 0: root_key = HKEY_CLASSES_ROOT;
2186 case 1: root_key = HKEY_CURRENT_USER;
2189 case 2: root_key = HKEY_LOCAL_MACHINE;
2192 case 3: root_key = HKEY_USERS;
2196 ERR("Unknown root %i\n",root);
2202 return ERROR_SUCCESS;
2204 deformat_string(package, key , &deformated);
2205 size = strlenW(deformated) + strlenW(szRoot) + 1;
2206 uikey = msi_alloc(size*sizeof(WCHAR));
2207 strcpyW(uikey,szRoot);
2208 strcatW(uikey,deformated);
2210 if (RegCreateKeyW( root_key, deformated, &hkey))
2212 ERR("Could not create key %s\n",debugstr_w(deformated));
2213 msi_free(deformated);
2215 return ERROR_SUCCESS;
2217 msi_free(deformated);
2219 value = MSI_RecordGetString(row,5);
2221 value_data = parse_value(package, value, &type, &size);
2224 static const WCHAR szEmpty[] = {0};
2225 value_data = (LPSTR)strdupW(szEmpty);
2230 deformat_string(package, name, &deformated);
2232 /* get the double nulls to terminate SZ_MULTI */
2233 if (type == REG_MULTI_SZ)
2234 size +=sizeof(WCHAR);
2238 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2240 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2245 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2246 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2248 TRACE("value %s of %s checked already exists\n",
2249 debugstr_w(deformated), debugstr_w(uikey));
2253 TRACE("Checked and setting value %s of %s\n",
2254 debugstr_w(deformated), debugstr_w(uikey));
2255 if (deformated || size)
2256 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2261 uirow = MSI_CreateRecord(3);
2262 MSI_RecordSetStringW(uirow,2,deformated);
2263 MSI_RecordSetStringW(uirow,1,uikey);
2266 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2268 MSI_RecordSetStringW(uirow,3,value);
2270 ui_actiondata(package,szWriteRegistryValues,uirow);
2271 msiobj_release( &uirow->hdr );
2273 msi_free(value_data);
2274 msi_free(deformated);
2277 return ERROR_SUCCESS;
2280 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2284 static const WCHAR ExecSeqQuery[] =
2285 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2286 '`','R','e','g','i','s','t','r','y','`',0 };
2288 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2289 if (rc != ERROR_SUCCESS)
2290 return ERROR_SUCCESS;
2292 /* increment progress bar each time action data is sent */
2293 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2295 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2297 msiobj_release(&view->hdr);
2301 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2303 package->script->CurrentlyScripting = TRUE;
2305 return ERROR_SUCCESS;
2309 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2314 static const WCHAR q1[]=
2315 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2316 '`','R','e','g','i','s','t','r','y','`',0};
2319 MSIFEATURE *feature;
2322 TRACE("InstallValidate\n");
2324 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2325 if (rc == ERROR_SUCCESS)
2327 MSI_IterateRecords( view, &progress, NULL, package );
2328 msiobj_release( &view->hdr );
2329 total += progress * REG_PROGRESS_VALUE;
2332 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2333 total += COMPONENT_PROGRESS_VALUE;
2335 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2336 total += file->FileSize;
2338 ui_progress(package,0,total,0,0);
2340 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2342 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2343 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2344 feature->ActionRequest);
2347 return ERROR_SUCCESS;
2350 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2352 MSIPACKAGE* package = (MSIPACKAGE*)param;
2353 LPCWSTR cond = NULL;
2354 LPCWSTR message = NULL;
2355 static const WCHAR title[]=
2356 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2358 cond = MSI_RecordGetString(row,1);
2360 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2363 message = MSI_RecordGetString(row,2);
2364 deformat_string(package,message,&deformated);
2365 MessageBoxW(NULL,deformated,title,MB_OK);
2366 msi_free(deformated);
2367 return ERROR_FUNCTION_FAILED;
2370 return ERROR_SUCCESS;
2373 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2376 MSIQUERY * view = NULL;
2377 static const WCHAR ExecSeqQuery[] =
2378 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2379 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2381 TRACE("Checking launch conditions\n");
2383 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2384 if (rc != ERROR_SUCCESS)
2385 return ERROR_SUCCESS;
2387 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2388 msiobj_release(&view->hdr);
2393 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2397 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2399 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2401 MSIRECORD * row = 0;
2403 LPWSTR deformated,buffer,deformated_name;
2405 static const WCHAR ExecSeqQuery[] =
2406 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2407 '`','R','e','g','i','s','t','r','y','`',' ',
2408 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2409 ' ','=',' ' ,'\'','%','s','\'',0 };
2410 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2411 static const WCHAR fmt2[]=
2412 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2414 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2418 root = MSI_RecordGetInteger(row,2);
2419 key = MSI_RecordGetString(row, 3);
2420 name = MSI_RecordGetString(row, 4);
2421 deformat_string(package, key , &deformated);
2422 deformat_string(package, name, &deformated_name);
2424 len = strlenW(deformated) + 6;
2425 if (deformated_name)
2426 len+=strlenW(deformated_name);
2428 buffer = msi_alloc( len *sizeof(WCHAR));
2430 if (deformated_name)
2431 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2433 sprintfW(buffer,fmt,root,deformated);
2435 msi_free(deformated);
2436 msi_free(deformated_name);
2437 msiobj_release(&row->hdr);
2441 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2443 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2448 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2451 return strdupW( file->TargetPath );
2456 static HKEY openSharedDLLsKey(void)
2459 static const WCHAR path[] =
2460 {'S','o','f','t','w','a','r','e','\\',
2461 'M','i','c','r','o','s','o','f','t','\\',
2462 'W','i','n','d','o','w','s','\\',
2463 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2464 'S','h','a','r','e','d','D','L','L','s',0};
2466 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2470 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2475 DWORD sz = sizeof(count);
2478 hkey = openSharedDLLsKey();
2479 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2480 if (rc != ERROR_SUCCESS)
2486 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2490 hkey = openSharedDLLsKey();
2492 msi_reg_set_val_dword( hkey, path, count );
2494 RegDeleteValueW(hkey,path);
2500 * Return TRUE if the count should be written out and FALSE if not
2502 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2504 MSIFEATURE *feature;
2508 /* only refcount DLLs */
2509 if (comp->KeyPath == NULL ||
2510 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2511 comp->Attributes & msidbComponentAttributesODBCDataSource)
2515 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2516 write = (count > 0);
2518 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2522 /* increment counts */
2523 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2527 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2530 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2532 if ( cl->component == comp )
2537 /* decrement counts */
2538 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2542 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2545 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2547 if ( cl->component == comp )
2552 /* ref count all the files in the component */
2557 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2559 if (file->Component == comp)
2560 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2564 /* add a count for permenent */
2565 if (comp->Attributes & msidbComponentAttributesPermanent)
2568 comp->RefCount = count;
2571 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2575 * Ok further analysis makes me think that this work is
2576 * actually done in the PublishComponents and PublishFeatures
2577 * step, and not here. It appears like the keypath and all that is
2578 * resolved in this step, however actually written in the Publish steps.
2579 * But we will leave it here for now because it is unclear
2581 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2583 WCHAR squished_pc[GUID_SIZE];
2584 WCHAR squished_cc[GUID_SIZE];
2587 HKEY hkey=0,hkey2=0;
2589 /* writes the Component and Features values to the registry */
2591 rc = MSIREG_OpenComponents(&hkey);
2592 if (rc != ERROR_SUCCESS)
2595 squash_guid(package->ProductCode,squished_pc);
2596 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2598 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2602 ui_progress(package,2,0,0,0);
2603 if (!comp->ComponentId)
2606 squash_guid(comp->ComponentId,squished_cc);
2608 msi_free(comp->FullKeypath);
2609 comp->FullKeypath = resolve_keypath( package, comp );
2611 /* do the refcounting */
2612 ACTION_RefCountComponent( package, comp );
2614 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2615 debugstr_w(comp->Component),
2616 debugstr_w(squished_cc),
2617 debugstr_w(comp->FullKeypath),
2620 * Write the keypath out if the component is to be registered
2621 * and delete the key if the component is to be deregistered
2623 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2625 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2626 if (rc != ERROR_SUCCESS)
2629 if (!comp->FullKeypath)
2632 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2634 if (comp->Attributes & msidbComponentAttributesPermanent)
2636 static const WCHAR szPermKey[] =
2637 { '0','0','0','0','0','0','0','0','0','0','0','0',
2638 '0','0','0','0','0','0','0','0','0','0','0','0',
2639 '0','0','0','0','0','0','0','0',0 };
2641 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2647 uirow = MSI_CreateRecord(3);
2648 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2649 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2650 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2651 ui_actiondata(package,szProcessComponents,uirow);
2652 msiobj_release( &uirow->hdr );
2654 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2658 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2659 if (rc != ERROR_SUCCESS)
2662 RegDeleteValueW(hkey2,squished_pc);
2664 /* if the key is empty delete it */
2665 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2667 if (res == ERROR_NO_MORE_ITEMS)
2668 RegDeleteKeyW(hkey,squished_cc);
2671 uirow = MSI_CreateRecord(2);
2672 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2673 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2674 ui_actiondata(package,szProcessComponents,uirow);
2675 msiobj_release( &uirow->hdr );
2690 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2691 LPWSTR lpszName, LONG_PTR lParam)
2694 typelib_struct *tl_struct = (typelib_struct*) lParam;
2695 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2699 if (!IS_INTRESOURCE(lpszName))
2701 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2705 sz = strlenW(tl_struct->source)+4;
2706 sz *= sizeof(WCHAR);
2708 if ((INT_PTR)lpszName == 1)
2709 tl_struct->path = strdupW(tl_struct->source);
2712 tl_struct->path = msi_alloc(sz);
2713 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2716 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2717 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2718 if (!SUCCEEDED(res))
2720 msi_free(tl_struct->path);
2721 tl_struct->path = NULL;
2726 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2727 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2729 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2733 msi_free(tl_struct->path);
2734 tl_struct->path = NULL;
2736 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2737 ITypeLib_Release(tl_struct->ptLib);
2742 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2744 MSIPACKAGE* package = (MSIPACKAGE*)param;
2748 typelib_struct tl_struct;
2750 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2752 component = MSI_RecordGetString(row,3);
2753 comp = get_loaded_component(package,component);
2755 return ERROR_SUCCESS;
2757 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2759 TRACE("Skipping typelib reg due to disabled component\n");
2761 comp->Action = comp->Installed;
2763 return ERROR_SUCCESS;
2766 comp->Action = INSTALLSTATE_LOCAL;
2768 file = get_loaded_file( package, comp->KeyPath );
2770 return ERROR_SUCCESS;
2772 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2776 guid = MSI_RecordGetString(row,1);
2777 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2778 tl_struct.source = strdupW( file->TargetPath );
2779 tl_struct.path = NULL;
2781 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2782 (LONG_PTR)&tl_struct);
2790 helpid = MSI_RecordGetString(row,6);
2793 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2794 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2797 if (!SUCCEEDED(res))
2798 ERR("Failed to register type library %s\n",
2799 debugstr_w(tl_struct.path));
2802 ui_actiondata(package,szRegisterTypeLibraries,row);
2804 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2807 ITypeLib_Release(tl_struct.ptLib);
2808 msi_free(tl_struct.path);
2811 ERR("Failed to load type library %s\n",
2812 debugstr_w(tl_struct.source));
2814 FreeLibrary(module);
2815 msi_free(tl_struct.source);
2818 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2820 return ERROR_SUCCESS;
2823 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2826 * OK this is a bit confusing.. I am given a _Component key and I believe
2827 * that the file that is being registered as a type library is the "key file
2828 * of that component" which I interpret to mean "The file in the KeyPath of
2833 static const WCHAR Query[] =
2834 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2835 '`','T','y','p','e','L','i','b','`',0};
2837 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2838 if (rc != ERROR_SUCCESS)
2839 return ERROR_SUCCESS;
2841 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2842 msiobj_release(&view->hdr);
2846 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2848 MSIPACKAGE *package = (MSIPACKAGE*)param;
2849 LPWSTR target_file, target_folder, filename;
2850 LPCWSTR buffer, extension;
2852 static const WCHAR szlnk[]={'.','l','n','k',0};
2853 IShellLinkW *sl = NULL;
2854 IPersistFile *pf = NULL;
2857 buffer = MSI_RecordGetString(row,4);
2858 comp = get_loaded_component(package,buffer);
2860 return ERROR_SUCCESS;
2862 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2864 TRACE("Skipping shortcut creation due to disabled component\n");
2866 comp->Action = comp->Installed;
2868 return ERROR_SUCCESS;
2871 comp->Action = INSTALLSTATE_LOCAL;
2873 ui_actiondata(package,szCreateShortcuts,row);
2875 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2876 &IID_IShellLinkW, (LPVOID *) &sl );
2880 ERR("CLSID_ShellLink not available\n");
2884 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2887 ERR("QueryInterface(IID_IPersistFile) failed\n");
2891 buffer = MSI_RecordGetString(row,2);
2892 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2894 /* may be needed because of a bug somehwere else */
2895 create_full_pathW(target_folder);
2897 filename = msi_dup_record_field( row, 3 );
2898 reduce_to_longfilename(filename);
2900 extension = strchrW(filename,'.');
2901 if (!extension || strcmpiW(extension,szlnk))
2903 int len = strlenW(filename);
2904 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2905 memcpy(filename + len, szlnk, sizeof(szlnk));
2907 target_file = build_directory_name(2, target_folder, filename);
2908 msi_free(target_folder);
2911 buffer = MSI_RecordGetString(row,5);
2912 if (strchrW(buffer,'['))
2915 deformat_string(package,buffer,&deformated);
2916 IShellLinkW_SetPath(sl,deformated);
2917 msi_free(deformated);
2921 FIXME("poorly handled shortcut format, advertised shortcut\n");
2922 IShellLinkW_SetPath(sl,comp->FullKeypath);
2925 if (!MSI_RecordIsNull(row,6))
2928 buffer = MSI_RecordGetString(row,6);
2929 deformat_string(package,buffer,&deformated);
2930 IShellLinkW_SetArguments(sl,deformated);
2931 msi_free(deformated);
2934 if (!MSI_RecordIsNull(row,7))
2936 buffer = MSI_RecordGetString(row,7);
2937 IShellLinkW_SetDescription(sl,buffer);
2940 if (!MSI_RecordIsNull(row,8))
2941 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2943 if (!MSI_RecordIsNull(row,9))
2948 buffer = MSI_RecordGetString(row,9);
2950 Path = build_icon_path(package,buffer);
2951 index = MSI_RecordGetInteger(row,10);
2953 /* no value means 0 */
2954 if (index == MSI_NULL_INTEGER)
2957 IShellLinkW_SetIconLocation(sl,Path,index);
2961 if (!MSI_RecordIsNull(row,11))
2962 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2964 if (!MSI_RecordIsNull(row,12))
2967 buffer = MSI_RecordGetString(row,12);
2968 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2970 IShellLinkW_SetWorkingDirectory(sl,Path);
2974 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2975 IPersistFile_Save(pf,target_file,FALSE);
2977 msi_free(target_file);
2981 IPersistFile_Release( pf );
2983 IShellLinkW_Release( sl );
2985 return ERROR_SUCCESS;
2988 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2993 static const WCHAR Query[] =
2994 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2995 '`','S','h','o','r','t','c','u','t','`',0};
2997 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2998 if (rc != ERROR_SUCCESS)
2999 return ERROR_SUCCESS;
3001 res = CoInitialize( NULL );
3004 ERR("CoInitialize failed\n");
3005 return ERROR_FUNCTION_FAILED;
3008 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3009 msiobj_release(&view->hdr);
3016 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3018 MSIPACKAGE* package = (MSIPACKAGE*)param;
3027 FileName = MSI_RecordGetString(row,1);
3030 ERR("Unable to get FileName\n");
3031 return ERROR_SUCCESS;
3034 FilePath = build_icon_path(package,FileName);
3036 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3038 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3039 FILE_ATTRIBUTE_NORMAL, NULL);
3041 if (the_file == INVALID_HANDLE_VALUE)
3043 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3045 return ERROR_SUCCESS;
3052 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3053 if (rc != ERROR_SUCCESS)
3055 ERR("Failed to get stream\n");
3056 CloseHandle(the_file);
3057 DeleteFileW(FilePath);
3060 WriteFile(the_file,buffer,sz,&write,NULL);
3061 } while (sz == 1024);
3065 CloseHandle(the_file);
3067 uirow = MSI_CreateRecord(1);
3068 MSI_RecordSetStringW(uirow,1,FileName);
3069 ui_actiondata(package,szPublishProduct,uirow);
3070 msiobj_release( &uirow->hdr );
3072 return ERROR_SUCCESS;
3076 * 99% of the work done here is only done for
3077 * advertised installs. However this is where the
3078 * Icon table is processed and written out
3079 * so that is what I am going to do here.
3081 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3085 static const WCHAR Query[]=
3086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3087 '`','I','c','o','n','`',0};
3088 /* for registry stuff */
3091 static const WCHAR szProductLanguage[] =
3092 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3093 static const WCHAR szARPProductIcon[] =
3094 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3095 static const WCHAR szProductVersion[] =
3096 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3100 MSIHANDLE hDb, hSumInfo;
3102 /* write out icon files */
3104 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3105 if (rc == ERROR_SUCCESS)
3107 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3108 msiobj_release(&view->hdr);
3111 /* ok there is a lot more done here but i need to figure out what */
3113 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3114 if (rc != ERROR_SUCCESS)
3117 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3118 if (rc != ERROR_SUCCESS)
3122 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3123 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3126 langid = msi_get_property_int( package, szProductLanguage, 0 );
3127 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3129 buffer = msi_dup_property( package, szARPProductIcon );
3132 LPWSTR path = build_icon_path(package,buffer);
3133 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3138 buffer = msi_dup_property( package, szProductVersion );
3141 DWORD verdword = msi_version_str_to_dword(buffer);
3142 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3146 /* FIXME: Need to write more keys to the user registry */
3148 hDb= alloc_msihandle( &package->db->hdr );
3150 rc = ERROR_NOT_ENOUGH_MEMORY;
3153 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3154 MsiCloseHandle(hDb);
3155 if (rc == ERROR_SUCCESS)
3157 WCHAR guidbuffer[0x200];
3159 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3161 if (rc == ERROR_SUCCESS)
3163 WCHAR squashed[GUID_SIZE];
3164 /* for now we only care about the first guid */
3165 LPWSTR ptr = strchrW(guidbuffer,';');
3167 squash_guid(guidbuffer,squashed);
3168 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3172 ERR("Unable to query Revision_Number...\n");
3175 MsiCloseHandle(hSumInfo);
3179 ERR("Unable to open Summary Information\n");
3191 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3193 MSIPACKAGE *package = (MSIPACKAGE*)param;
3194 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3195 LPWSTR deformated_section, deformated_key, deformated_value;
3196 LPWSTR folder, fullname = NULL;
3200 static const WCHAR szWindowsFolder[] =
3201 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3203 component = MSI_RecordGetString(row, 8);
3204 comp = get_loaded_component(package,component);
3206 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3208 TRACE("Skipping ini file due to disabled component %s\n",
3209 debugstr_w(component));
3211 comp->Action = comp->Installed;
3213 return ERROR_SUCCESS;
3216 comp->Action = INSTALLSTATE_LOCAL;
3218 identifier = MSI_RecordGetString(row,1);
3219 filename = MSI_RecordGetString(row,2);
3220 dirproperty = MSI_RecordGetString(row,3);
3221 section = MSI_RecordGetString(row,4);
3222 key = MSI_RecordGetString(row,5);
3223 value = MSI_RecordGetString(row,6);
3224 action = MSI_RecordGetInteger(row,7);
3226 deformat_string(package,section,&deformated_section);
3227 deformat_string(package,key,&deformated_key);
3228 deformat_string(package,value,&deformated_value);
3232 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3234 folder = msi_dup_property( package, dirproperty );
3237 folder = msi_dup_property( package, szWindowsFolder );
3241 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3245 fullname = build_directory_name(2, folder, filename);
3249 TRACE("Adding value %s to section %s in %s\n",
3250 debugstr_w(deformated_key), debugstr_w(deformated_section),
3251 debugstr_w(fullname));
3252 WritePrivateProfileStringW(deformated_section, deformated_key,
3253 deformated_value, fullname);
3255 else if (action == 1)
3258 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3259 returned, 10, fullname);
3260 if (returned[0] == 0)
3262 TRACE("Adding value %s to section %s in %s\n",
3263 debugstr_w(deformated_key), debugstr_w(deformated_section),
3264 debugstr_w(fullname));
3266 WritePrivateProfileStringW(deformated_section, deformated_key,
3267 deformated_value, fullname);
3270 else if (action == 3)
3271 FIXME("Append to existing section not yet implemented\n");
3273 uirow = MSI_CreateRecord(4);
3274 MSI_RecordSetStringW(uirow,1,identifier);
3275 MSI_RecordSetStringW(uirow,2,deformated_section);
3276 MSI_RecordSetStringW(uirow,3,deformated_key);
3277 MSI_RecordSetStringW(uirow,4,deformated_value);
3278 ui_actiondata(package,szWriteIniValues,uirow);
3279 msiobj_release( &uirow->hdr );
3283 msi_free(deformated_key);
3284 msi_free(deformated_value);
3285 msi_free(deformated_section);
3286 return ERROR_SUCCESS;
3289 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3293 static const WCHAR ExecSeqQuery[] =
3294 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3295 '`','I','n','i','F','i','l','e','`',0};
3297 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3298 if (rc != ERROR_SUCCESS)
3300 TRACE("no IniFile table\n");
3301 return ERROR_SUCCESS;
3304 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3305 msiobj_release(&view->hdr);
3309 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3311 MSIPACKAGE *package = (MSIPACKAGE*)param;
3316 static const WCHAR ExeStr[] =
3317 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3318 static const WCHAR close[] = {'\"',0};
3320 PROCESS_INFORMATION info;
3325 memset(&si,0,sizeof(STARTUPINFOW));
3327 filename = MSI_RecordGetString(row,1);
3328 file = get_loaded_file( package, filename );
3332 ERR("Unable to find file id %s\n",debugstr_w(filename));
3333 return ERROR_SUCCESS;
3336 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3338 FullName = msi_alloc(len*sizeof(WCHAR));
3339 strcpyW(FullName,ExeStr);
3340 strcatW( FullName, file->TargetPath );
3341 strcatW(FullName,close);
3343 TRACE("Registering %s\n",debugstr_w(FullName));
3344 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3348 msi_dialog_check_messages(info.hProcess);
3353 uirow = MSI_CreateRecord( 2 );
3354 uipath = strdupW( file->TargetPath );
3355 p = strrchrW(uipath,'\\');
3358 MSI_RecordSetStringW( uirow, 1, &p[2] );
3359 MSI_RecordSetStringW( uirow, 2, uipath);
3360 ui_actiondata( package, szSelfRegModules, uirow);
3361 msiobj_release( &uirow->hdr );
3363 /* FIXME: call ui_progress? */
3365 return ERROR_SUCCESS;
3368 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3372 static const WCHAR ExecSeqQuery[] =
3373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3374 '`','S','e','l','f','R','e','g','`',0};
3376 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3377 if (rc != ERROR_SUCCESS)
3379 TRACE("no SelfReg table\n");
3380 return ERROR_SUCCESS;
3383 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3384 msiobj_release(&view->hdr);
3386 return ERROR_SUCCESS;
3389 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3391 MSIFEATURE *feature;
3396 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3397 if (rc != ERROR_SUCCESS)
3400 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3401 if (rc != ERROR_SUCCESS)
3404 /* here the guids are base 85 encoded */
3405 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3411 BOOL absent = FALSE;
3414 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3415 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3416 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3420 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3424 if (feature->Feature_Parent)
3425 size += strlenW( feature->Feature_Parent )+2;
3427 data = msi_alloc(size * sizeof(WCHAR));
3430 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3432 MSICOMPONENT* component = cl->component;
3436 if (component->ComponentId)
3438 TRACE("From %s\n",debugstr_w(component->ComponentId));
3439 CLSIDFromString(component->ComponentId, &clsid);
3440 encode_base85_guid(&clsid,buf);
3441 TRACE("to %s\n",debugstr_w(buf));
3445 if (feature->Feature_Parent)
3447 static const WCHAR sep[] = {'\2',0};
3449 strcatW(data,feature->Feature_Parent);
3452 msi_reg_set_val_str( hkey, feature->Feature, data );
3456 if (feature->Feature_Parent)
3457 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3460 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3461 (LPBYTE)feature->Feature_Parent,size);
3465 size += 2*sizeof(WCHAR);
3466 data = msi_alloc(size);
3469 if (feature->Feature_Parent)
3470 strcpyW( &data[1], feature->Feature_Parent );
3471 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3477 uirow = MSI_CreateRecord( 1 );
3478 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3479 ui_actiondata( package, szPublishFeatures, uirow);
3480 msiobj_release( &uirow->hdr );
3481 /* FIXME: call ui_progress? */
3490 static UINT msi_get_local_package_name( LPWSTR path )
3492 static const WCHAR szInstaller[] = {
3493 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3494 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3498 time = GetTickCount();
3499 GetWindowsDirectoryW( path, MAX_PATH );
3500 lstrcatW( path, szInstaller );
3501 CreateDirectoryW( path, NULL );
3503 len = lstrlenW(path);
3504 for (i=0; i<0x10000; i++)
3506 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3507 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3508 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3509 if (handle != INVALID_HANDLE_VALUE)
3511 CloseHandle(handle);
3514 if (GetLastError() != ERROR_FILE_EXISTS &&
3515 GetLastError() != ERROR_SHARING_VIOLATION)
3516 return ERROR_FUNCTION_FAILED;
3519 return ERROR_SUCCESS;
3522 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3524 static const WCHAR szOriginalDatabase[] =
3525 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3526 WCHAR packagefile[MAX_PATH];
3530 r = msi_get_local_package_name( packagefile );
3531 if (r != ERROR_SUCCESS)
3534 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3536 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3537 r = CopyFileW( msiFilePath, packagefile, FALSE);
3538 msi_free( msiFilePath );
3542 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3543 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3544 return ERROR_FUNCTION_FAILED;
3547 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3548 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3549 return ERROR_SUCCESS;
3552 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3554 LPWSTR prop, val, key;
3555 static const LPCSTR propval[] = {
3556 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3557 "ARPCONTACT", "Contact",
3558 "ARPCOMMENTS", "Comments",
3559 "ProductName", "DisplayName",
3560 "ProductVersion", "DisplayVersion",
3561 "ARPHELPLINK", "HelpLink",
3562 "ARPHELPTELEPHONE", "HelpTelephone",
3563 "ARPINSTALLLOCATION", "InstallLocation",
3564 "SourceDir", "InstallSource",
3565 "Manufacturer", "Publisher",
3566 "ARPREADME", "Readme",
3568 "ARPURLINFOABOUT", "URLInfoAbout",
3569 "ARPURLUPDATEINFO", "URLUpdateInfo",
3572 const LPCSTR *p = propval;
3576 prop = strdupAtoW( *p++ );
3577 key = strdupAtoW( *p++ );
3578 val = msi_dup_property( package, prop );
3579 msi_reg_set_val_str( hkey, key, val );
3584 return ERROR_SUCCESS;
3587 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3590 LPWSTR buffer = NULL;
3593 static const WCHAR szWindowsInstaller[] =
3594 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3595 static const WCHAR szUpgradeCode[] =
3596 {'U','p','g','r','a','d','e','C','o','d','e',0};
3597 static const WCHAR modpath_fmt[] =
3598 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3599 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3600 static const WCHAR szModifyPath[] =
3601 {'M','o','d','i','f','y','P','a','t','h',0};
3602 static const WCHAR szUninstallString[] =
3603 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3604 static const WCHAR szEstimatedSize[] =
3605 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3606 static const WCHAR szProductLanguage[] =
3607 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3608 static const WCHAR szProductVersion[] =
3609 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3612 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3613 LPWSTR upgrade_code;
3616 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3617 if (rc != ERROR_SUCCESS)
3620 /* dump all the info i can grab */
3621 /* FIXME: Flesh out more information */
3623 msi_write_uninstall_property_vals( package, hkey );
3625 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3627 msi_make_package_local( package, hkey );
3629 /* do ModifyPath and UninstallString */
3630 size = deformat_string(package,modpath_fmt,&buffer);
3631 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3632 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3635 /* FIXME: Write real Estimated Size when we have it */
3636 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3638 GetLocalTime(&systime);
3639 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3640 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3642 langid = msi_get_property_int( package, szProductLanguage, 0 );
3643 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3645 buffer = msi_dup_property( package, szProductVersion );
3648 DWORD verdword = msi_version_str_to_dword(buffer);
3650 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3651 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3652 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3656 /* Handle Upgrade Codes */
3657 upgrade_code = msi_dup_property( package, szUpgradeCode );
3662 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3663 squash_guid(package->ProductCode,squashed);
3664 msi_reg_set_val_str( hkey2, squashed, NULL );
3666 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3667 squash_guid(package->ProductCode,squashed);
3668 msi_reg_set_val_str( hkey2, squashed, NULL );
3671 msi_free(upgrade_code);
3676 /* FIXME: call ui_actiondata */
3678 return ERROR_SUCCESS;
3681 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3683 return execute_script(package,INSTALL_SCRIPT);
3686 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3690 /* turn off scheduleing */
3691 package->script->CurrentlyScripting= FALSE;
3693 /* first do the same as an InstallExecute */
3694 rc = ACTION_InstallExecute(package);
3695 if (rc != ERROR_SUCCESS)
3698 /* then handle Commit Actions */
3699 rc = execute_script(package,COMMIT_SCRIPT);
3704 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3706 static const WCHAR RunOnce[] = {
3707 'S','o','f','t','w','a','r','e','\\',
3708 'M','i','c','r','o','s','o','f','t','\\',
3709 'W','i','n','d','o','w','s','\\',
3710 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3711 'R','u','n','O','n','c','e',0};
3712 static const WCHAR InstallRunOnce[] = {
3713 'S','o','f','t','w','a','r','e','\\',
3714 'M','i','c','r','o','s','o','f','t','\\',
3715 'W','i','n','d','o','w','s','\\',
3716 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3717 'I','n','s','t','a','l','l','e','r','\\',
3718 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3720 static const WCHAR msiexec_fmt[] = {
3722 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3723 '\"','%','s','\"',0};
3724 static const WCHAR install_fmt[] = {
3725 '/','I',' ','\"','%','s','\"',' ',
3726 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3727 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3728 WCHAR buffer[256], sysdir[MAX_PATH];
3730 WCHAR squished_pc[100];
3732 squash_guid(package->ProductCode,squished_pc);
3734 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3735 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3736 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3739 msi_reg_set_val_str( hkey, squished_pc, buffer );
3742 TRACE("Reboot command %s\n",debugstr_w(buffer));
3744 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3745 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3747 msi_reg_set_val_str( hkey, squished_pc, buffer );
3750 return ERROR_INSTALL_SUSPEND;
3753 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3758 * we are currently doing what should be done here in the top level Install
3759 * however for Adminastrative and uninstalls this step will be needed
3761 if (!package->PackagePath)
3762 return ERROR_SUCCESS;
3764 attrib = GetFileAttributesW(package->PackagePath);
3765 if (attrib == INVALID_FILE_ATTRIBUTES)
3771 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3772 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3773 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3774 if (rc == ERROR_MORE_DATA)
3776 prompt = msi_alloc(size * sizeof(WCHAR));
3777 MsiSourceListGetInfoW(package->ProductCode, NULL,
3778 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3779 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3782 prompt = strdupW(package->PackagePath);
3784 msg = generate_error_string(package,1302,1,prompt);
3785 while(attrib == INVALID_FILE_ATTRIBUTES)
3787 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3790 rc = ERROR_INSTALL_USEREXIT;
3793 attrib = GetFileAttributesW(package->PackagePath);
3799 return ERROR_SUCCESS;
3804 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3811 static const WCHAR szPropKeys[][80] =
3813 {'P','r','o','d','u','c','t','I','D',0},
3814 {'U','S','E','R','N','A','M','E',0},
3815 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3819 static const WCHAR szRegKeys[][80] =
3821 {'P','r','o','d','u','c','t','I','D',0},
3822 {'R','e','g','O','w','n','e','r',0},
3823 {'R','e','g','C','o','m','p','a','n','y',0},
3827 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3829 return ERROR_SUCCESS;
3831 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3832 if (rc != ERROR_SUCCESS)
3835 for( i = 0; szPropKeys[i][0]; i++ )
3837 buffer = msi_dup_property( package, szPropKeys[i] );
3838 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3843 msi_free(productid);
3846 /* FIXME: call ui_actiondata */
3848 return ERROR_SUCCESS;
3852 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3856 package->script->InWhatSequence |= SEQUENCE_EXEC;
3857 rc = ACTION_ProcessExecSequence(package,FALSE);
3863 * Code based off of code located here
3864 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3866 * Using string index 4 (full font name) instead of 1 (family name)
3868 static LPWSTR load_ttfname_from(LPCWSTR filename)
3874 typedef struct _tagTT_OFFSET_TABLE{
3875 USHORT uMajorVersion;
3876 USHORT uMinorVersion;
3877 USHORT uNumOfTables;
3878 USHORT uSearchRange;
3879 USHORT uEntrySelector;
3883 typedef struct _tagTT_TABLE_DIRECTORY{
3884 char szTag[4]; /* table name */
3885 ULONG uCheckSum; /* Check sum */
3886 ULONG uOffset; /* Offset from beginning of file */
3887 ULONG uLength; /* length of the table in bytes */
3888 }TT_TABLE_DIRECTORY;
3890 typedef struct _tagTT_NAME_TABLE_HEADER{
3891 USHORT uFSelector; /* format selector. Always 0 */
3892 USHORT uNRCount; /* Name Records count */
3893 USHORT uStorageOffset; /* Offset for strings storage,
3894 * from start of the table */
3895 }TT_NAME_TABLE_HEADER;
3897 typedef struct _tagTT_NAME_RECORD{
3902 USHORT uStringLength;
3903 USHORT uStringOffset; /* from start of storage area */
3906 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3907 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3909 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3910 FILE_ATTRIBUTE_NORMAL, 0 );
3911 if (handle != INVALID_HANDLE_VALUE)
3913 TT_TABLE_DIRECTORY tblDir;
3914 BOOL bFound = FALSE;
3915 TT_OFFSET_TABLE ttOffsetTable;
3918 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3919 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3920 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3921 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3923 if (ttOffsetTable.uMajorVersion != 1 ||
3924 ttOffsetTable.uMinorVersion != 0)
3927 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3929 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3930 if (strncmp(tblDir.szTag,"name",4)==0)
3933 tblDir.uLength = SWAPLONG(tblDir.uLength);
3934 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3941 TT_NAME_TABLE_HEADER ttNTHeader;
3942 TT_NAME_RECORD ttRecord;
3944 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3945 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3948 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3949 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3951 for(i=0; i<ttNTHeader.uNRCount; i++)
3953 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3954 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3955 /* 4 is the Full Font Name */
3956 if(ttRecord.uNameID == 4)
3960 static LPCSTR tt = " (TrueType)";
3962 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3963 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3964 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3965 SetFilePointer(handle, tblDir.uOffset +
3966 ttRecord.uStringOffset +
3967 ttNTHeader.uStorageOffset,
3969 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3970 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3971 if (strlen(buf) > 0)
3974 ret = strdupAtoW(buf);
3980 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3984 CloseHandle(handle);
3987 ERR("Unable to open font file %s\n", debugstr_w(filename));
3989 TRACE("Returning fontname %s\n",debugstr_w(ret));
3993 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3995 MSIPACKAGE *package = (MSIPACKAGE*)param;
3999 static const WCHAR regfont1[] =
4000 {'S','o','f','t','w','a','r','e','\\',
4001 'M','i','c','r','o','s','o','f','t','\\',
4002 'W','i','n','d','o','w','s',' ','N','T','\\',
4003 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4004 'F','o','n','t','s',0};
4005 static const WCHAR regfont2[] =
4006 {'S','o','f','t','w','a','r','e','\\',
4007 'M','i','c','r','o','s','o','f','t','\\',
4008 'W','i','n','d','o','w','s','\\',
4009 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4010 'F','o','n','t','s',0};
4016 filename = MSI_RecordGetString( row, 1 );
4017 file = get_loaded_file( package, filename );
4020 ERR("Unable to load file\n");
4021 return ERROR_SUCCESS;
4024 /* check to make sure that component is installed */
4025 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
4027 TRACE("Skipping: Component not scheduled for install\n");
4028 return ERROR_SUCCESS;
4031 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
4032 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
4034 if (MSI_RecordIsNull(row,2))
4035 name = load_ttfname_from( file->TargetPath );
4037 name = msi_dup_record_field(row,2);
4041 msi_reg_set_val_str( hkey1, name, file->FileName );
4042 msi_reg_set_val_str( hkey2, name, file->FileName );
4050 uirow = MSI_CreateRecord( 1 );
4051 uipath = strdupW( file->TargetPath );
4052 p = strrchrW(uipath,'\\');
4055 MSI_RecordSetStringW( uirow, 1, p );
4056 ui_actiondata( package, szRegisterFonts, uirow);
4057 msiobj_release( &uirow->hdr );
4059 /* FIXME: call ui_progress? */
4061 return ERROR_SUCCESS;
4064 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4068 static const WCHAR ExecSeqQuery[] =
4069 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4070 '`','F','o','n','t','`',0};
4072 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4073 if (rc != ERROR_SUCCESS)
4075 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4076 return ERROR_SUCCESS;
4079 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4080 msiobj_release(&view->hdr);
4082 return ERROR_SUCCESS;
4085 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4087 MSIPACKAGE *package = (MSIPACKAGE*)param;
4088 LPCWSTR compgroupid=NULL;
4089 LPCWSTR feature=NULL;
4090 LPCWSTR text = NULL;
4091 LPCWSTR qualifier = NULL;
4092 LPCWSTR component = NULL;
4093 LPWSTR advertise = NULL;
4094 LPWSTR output = NULL;
4096 UINT rc = ERROR_SUCCESS;
4101 component = MSI_RecordGetString(rec,3);
4102 comp = get_loaded_component(package,component);
4104 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4105 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4106 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4108 TRACE("Skipping: Component %s not scheduled for install\n",
4109 debugstr_w(component));
4111 return ERROR_SUCCESS;
4114 compgroupid = MSI_RecordGetString(rec,1);
4115 qualifier = MSI_RecordGetString(rec,2);
4117 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4118 if (rc != ERROR_SUCCESS)
4121 text = MSI_RecordGetString(rec,4);
4122 feature = MSI_RecordGetString(rec,5);
4124 advertise = create_component_advertise_string(package, comp, feature);
4126 sz = strlenW(advertise);
4129 sz += lstrlenW(text);
4132 sz *= sizeof(WCHAR);
4134 output = msi_alloc_zero(sz);
4135 strcpyW(output,advertise);
4136 msi_free(advertise);
4139 strcatW(output,text);
4141 msi_reg_set_val_multi_str( hkey, qualifier, output );
4148 uirow = MSI_CreateRecord( 2 );
4149 MSI_RecordSetStringW( uirow, 1, compgroupid );
4150 MSI_RecordSetStringW( uirow, 2, qualifier);
4151 ui_actiondata( package, szPublishComponents, uirow);
4152 msiobj_release( &uirow->hdr );
4153 /* FIXME: call ui_progress? */
4159 * At present I am ignorning the advertised components part of this and only
4160 * focusing on the qualified component sets
4162 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4166 static const WCHAR ExecSeqQuery[] =
4167 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4168 '`','P','u','b','l','i','s','h',
4169 'C','o','m','p','o','n','e','n','t','`',0};
4171 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4172 if (rc != ERROR_SUCCESS)
4173 return ERROR_SUCCESS;
4175 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4176 msiobj_release(&view->hdr);
4181 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4182 LPCSTR action, LPCWSTR table )
4184 static const WCHAR query[] = {
4185 'S','E','L','E','C','T',' ','*',' ',
4186 'F','R','O','M',' ','`','%','s','`',0 };
4187 MSIQUERY *view = NULL;
4191 r = MSI_OpenQuery( package->db, &view, query, table );
4192 if (r == ERROR_SUCCESS)
4194 r = MSI_IterateRecords(view, &count, NULL, package);
4195 msiobj_release(&view->hdr);
4199 FIXME("%s -> %lu ignored %s table values\n",
4200 action, count, debugstr_w(table));
4202 return ERROR_SUCCESS;
4205 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4207 TRACE("%p\n", package);
4208 return ERROR_SUCCESS;
4211 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4213 static const WCHAR table[] =
4214 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4215 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4218 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4220 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4221 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4224 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4226 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4227 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4230 static UINT ACTION_BindImage( MSIPACKAGE *package )
4232 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4233 return msi_unimplemented_action_stub( package, "BindImage", table );
4236 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4238 static const WCHAR table[] = {
4239 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4240 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4243 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4245 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4246 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4249 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4251 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4252 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4255 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4257 static const WCHAR table[] = {
4258 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4259 return msi_unimplemented_action_stub( package, "InstallServices", table );
4262 static UINT ACTION_StartServices( MSIPACKAGE *package )
4264 static const WCHAR table[] = {
4265 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4266 return msi_unimplemented_action_stub( package, "StartServices", table );
4269 static UINT ACTION_StopServices( MSIPACKAGE *package )
4271 static const WCHAR table[] = {
4272 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4273 return msi_unimplemented_action_stub( package, "StopServices", table );
4276 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4278 static const WCHAR table[] = {
4279 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4280 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4283 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4285 static const WCHAR table[] = {
4286 'E','n','v','i','r','o','n','m','e','n','t',0 };
4287 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4290 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4292 static const WCHAR table[] = {
4293 'E','n','v','i','r','o','n','m','e','n','t',0 };
4294 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4297 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4299 static const WCHAR table[] = {
4300 'M','s','i','A','s','s','e','m','b','l','y',0 };
4301 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4304 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4306 static const WCHAR table[] = {
4307 'M','s','i','A','s','s','e','m','b','l','y',0 };
4308 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4311 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4313 static const WCHAR table[] = { 'F','o','n','t',0 };
4314 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4317 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4319 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4320 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4323 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4325 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4326 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4329 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4331 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4332 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4335 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4337 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4338 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4341 static struct _actions StandardActions[] = {
4342 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4343 { szAppSearch, ACTION_AppSearch },
4344 { szBindImage, ACTION_BindImage },
4345 { szCCPSearch, ACTION_CCPSearch},
4346 { szCostFinalize, ACTION_CostFinalize },
4347 { szCostInitialize, ACTION_CostInitialize },
4348 { szCreateFolders, ACTION_CreateFolders },
4349 { szCreateShortcuts, ACTION_CreateShortcuts },
4350 { szDeleteServices, ACTION_DeleteServices },
4351 { szDisableRollback, NULL},
4352 { szDuplicateFiles, ACTION_DuplicateFiles },
4353 { szExecuteAction, ACTION_ExecuteAction },
4354 { szFileCost, ACTION_FileCost },
4355 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4356 { szForceReboot, ACTION_ForceReboot },
4357 { szInstallAdminPackage, NULL},
4358 { szInstallExecute, ACTION_InstallExecute },
4359 { szInstallExecuteAgain, ACTION_InstallExecute },
4360 { szInstallFiles, ACTION_InstallFiles},
4361 { szInstallFinalize, ACTION_InstallFinalize },
4362 { szInstallInitialize, ACTION_InstallInitialize },
4363 { szInstallSFPCatalogFile, NULL},
4364 { szInstallValidate, ACTION_InstallValidate },
4365 { szIsolateComponents, ACTION_IsolateComponents },
4366 { szLaunchConditions, ACTION_LaunchConditions },
4367 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4368 { szMoveFiles, ACTION_MoveFiles },
4369 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4370 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4371 { szInstallODBC, NULL},
4372 { szInstallServices, ACTION_InstallServices },
4373 { szPatchFiles, ACTION_PatchFiles },
4374 { szProcessComponents, ACTION_ProcessComponents },
4375 { szPublishComponents, ACTION_PublishComponents },
4376 { szPublishFeatures, ACTION_PublishFeatures },
4377 { szPublishProduct, ACTION_PublishProduct },
4378 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4379 { szRegisterComPlus, ACTION_RegisterComPlus},
4380 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4381 { szRegisterFonts, ACTION_RegisterFonts },
4382 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4383 { szRegisterProduct, ACTION_RegisterProduct },
4384 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4385 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4386 { szRegisterUser, ACTION_RegisterUser},
4387 { szRemoveDuplicateFiles, NULL},
4388 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4389 { szRemoveExistingProducts, NULL},
4390 { szRemoveFiles, ACTION_RemoveFiles},
4391 { szRemoveFolders, NULL},
4392 { szRemoveIniValues, ACTION_RemoveIniValues },
4393 { szRemoveODBC, NULL},
4394 { szRemoveRegistryValues, NULL},
4395 { szRemoveShortcuts, NULL},
4396 { szResolveSource, ACTION_ResolveSource},
4397 { szRMCCPSearch, ACTION_RMCCPSearch},
4398 { szScheduleReboot, NULL},
4399 { szSelfRegModules, ACTION_SelfRegModules },
4400 { szSelfUnregModules, ACTION_SelfUnregModules },
4401 { szSetODBCFolders, NULL},
4402 { szStartServices, ACTION_StartServices },
4403 { szStopServices, ACTION_StopServices },
4404 { szUnpublishComponents, NULL},
4405 { szUnpublishFeatures, NULL},
4406 { szUnregisterClassInfo, NULL},
4407 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4408 { szUnregisterExtensionInfo, NULL},
4409 { szUnregisterFonts, ACTION_UnregisterFonts },
4410 { szUnregisterMIMEInfo, NULL},
4411 { szUnregisterProgIdInfo, NULL},
4412 { szUnregisterTypeLibraries, NULL},
4413 { szValidateProductID, NULL},
4414 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4415 { szWriteIniValues, ACTION_WriteIniValues },
4416 { szWriteRegistryValues, ACTION_WriteRegistryValues},