2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
37 #include "wine/debug.h"
42 #include "wine/unicode.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 sprintfW(message,template_s,timet,action);
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
300 LPWSTR prop = NULL, val = NULL;
303 return ERROR_SUCCESS;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367 LPWSTR p, *ret = NULL;
373 /* count the number of substrings */
374 for ( p = (LPWSTR)str, count = 0; p; count++ )
376 p = strchrW( p, sep );
381 /* allocate space for an array of substring pointers and the substrings */
382 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
383 (lstrlenW(str)+1) * sizeof(WCHAR) );
387 /* copy the string and set the pointers */
388 p = (LPWSTR) &ret[count+1];
390 for( count = 0; (ret[count] = p); count++ )
392 p = strchrW( p, sep );
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
407 TRACE("%p %s\n", package, debugstr_w(name) );
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
418 ret = msi_table_apply_transform( package->db, stg );
419 IStorage_Release( stg );
423 ERR("failed to open substorage %s\n", debugstr_w(name));
428 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
430 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
431 LPWSTR guid_list, *guids, product_id;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_id = msi_dup_property( package, szProdID );
437 /* FIXME: the property ProductID should be written into the DB somewhere */
438 ERR("no product ID to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_id ))
450 msi_free( guid_list );
451 msi_free( product_id );
456 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
459 LPWSTR str, *substorage;
460 UINT i, r = ERROR_SUCCESS;
462 si = MSI_GetSummaryInformationW( patch_db, 0 );
464 return ERROR_FUNCTION_FAILED;
466 msi_check_patch_applicable( package, si );
468 /* enumerate the substorage */
469 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
470 substorage = msi_split_string( str, ';' );
471 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
472 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
473 msi_free( substorage );
476 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
478 msiobj_release( &si->hdr );
483 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
485 MSIDATABASE *patch_db = NULL;
488 TRACE("%p %s\n", package, debugstr_w( file ) );
491 * We probably want to make sure we only open a patch collection here.
492 * Patch collections (.msp) and databases (.msi) have different GUIDs
493 * but currently MSI_OpenDatabaseW will accept both.
495 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
496 if ( r != ERROR_SUCCESS )
498 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
502 msi_parse_patch_summary( package, patch_db );
503 msiobj_release( &patch_db->hdr );
505 return ERROR_SUCCESS;
508 /* get the PATCH property, and apply all the patches it specifies */
509 static UINT msi_apply_patches( MSIPACKAGE *package )
511 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
512 LPWSTR patch_list, *patches;
513 UINT i, r = ERROR_SUCCESS;
515 patch_list = msi_dup_property( package, szPatch );
517 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
519 patches = msi_split_string( patch_list, ';' );
520 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_patch_package( package, patches[i] );
524 msi_free( patch_list );
529 static UINT msi_apply_transforms( MSIPACKAGE *package )
531 static const WCHAR szTransforms[] = {
532 'T','R','A','N','S','F','O','R','M','S',0 };
533 LPWSTR xform_list, *xforms;
534 UINT i, r = ERROR_SUCCESS;
536 xform_list = msi_dup_property( package, szTransforms );
537 xforms = msi_split_string( xform_list, ';' );
539 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
541 if (xforms[i][0] == ':')
542 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
544 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
548 msi_free( xform_list );
553 /****************************************************
554 * TOP level entry points
555 *****************************************************/
557 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
558 LPCWSTR szCommandLine )
562 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
563 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
564 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
566 MSI_SetPropertyW(package, szAction, szInstall);
568 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
570 package->script->InWhatSequence = SEQUENCE_INSTALL;
574 LPWSTR p, check, path;
576 package->PackagePath = strdupW(szPackagePath);
577 path = strdupW(szPackagePath);
578 p = strrchrW(path,'\\');
587 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
588 GetCurrentDirectoryW(MAX_PATH,path);
592 check = msi_dup_property( package, cszSourceDir );
594 MSI_SetPropertyW(package, cszSourceDir, path);
599 msi_parse_command_line( package, szCommandLine );
601 msi_apply_transforms( package );
602 msi_apply_patches( package );
604 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
606 package->script->InWhatSequence |= SEQUENCE_UI;
607 rc = ACTION_ProcessUISequence(package);
609 if (rc == ERROR_SUCCESS)
611 package->script->InWhatSequence |= SEQUENCE_EXEC;
612 rc = ACTION_ProcessExecSequence(package,TRUE);
616 rc = ACTION_ProcessExecSequence(package,FALSE);
620 /* install was halted but should be considered a success */
624 package->script->CurrentlyScripting= FALSE;
626 /* process the ending type action */
627 if (rc == ERROR_SUCCESS)
628 ACTION_PerformActionSequence(package,-1,ui);
629 else if (rc == ERROR_INSTALL_USEREXIT)
630 ACTION_PerformActionSequence(package,-2,ui);
631 else if (rc == ERROR_INSTALL_SUSPEND)
632 ACTION_PerformActionSequence(package,-4,ui);
634 ACTION_PerformActionSequence(package,-3,ui);
636 /* finish up running custom actions */
637 ACTION_FinishCustomActions(package);
642 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
644 UINT rc = ERROR_SUCCESS;
646 static const WCHAR ExecSeqQuery[] =
647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
648 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
649 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
650 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
652 static const WCHAR UISeqQuery[] =
653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
654 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
655 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
656 ' ', '=',' ','%','i',0};
659 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
661 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
665 LPCWSTR action, cond;
667 TRACE("Running the actions\n");
669 /* check conditions */
670 cond = MSI_RecordGetString(row,2);
673 /* this is a hack to skip errors in the condition code */
674 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
678 action = MSI_RecordGetString(row,1);
681 ERR("failed to fetch action\n");
682 rc = ERROR_FUNCTION_FAILED;
687 rc = ACTION_PerformUIAction(package,action);
689 rc = ACTION_PerformAction(package,action,FALSE);
691 msiobj_release(&row->hdr);
702 } iterate_action_param;
704 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
706 iterate_action_param *iap= (iterate_action_param*)param;
708 LPCWSTR cond, action;
710 action = MSI_RecordGetString(row,1);
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED;
717 /* check conditions */
718 cond = MSI_RecordGetString(row,2);
721 /* this is a hack to skip errors in the condition code */
722 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
724 TRACE("Skipping action: %s (condition is false)\n",
726 return ERROR_SUCCESS;
731 rc = ACTION_PerformUIAction(iap->package,action);
733 rc = ACTION_PerformAction(iap->package,action,FALSE);
735 msi_dialog_check_messages( NULL );
737 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
738 rc = iap->package->CurrentInstallState;
740 if (rc == ERROR_FUNCTION_NOT_CALLED)
743 if (rc != ERROR_SUCCESS)
744 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
749 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
753 static const WCHAR query[] =
754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
756 ' ','W','H','E','R','E',' ',
757 '`','S','e','q','u','e','n','c','e','`',' ',
758 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
759 '`','S','e','q','u','e','n','c','e','`',0};
760 iterate_action_param iap;
763 * FIXME: probably should be checking UILevel in the
764 * ACTION_PerformUIAction/ACTION_PerformAction
765 * rather than saving the UI level here. Those
766 * two functions can be merged too.
768 iap.package = package;
771 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
773 r = MSI_OpenQuery( package->db, &view, query, szTable );
774 if (r == ERROR_SUCCESS)
776 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
777 msiobj_release(&view->hdr);
783 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
787 static const WCHAR ExecSeqQuery[] =
788 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
789 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
790 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
792 'O','R','D','E','R',' ', 'B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0 };
795 static const WCHAR IVQuery[] =
796 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
797 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
798 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
799 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
800 ' ','\'', 'I','n','s','t','a','l','l',
801 'V','a','l','i','d','a','t','e','\'', 0};
803 iterate_action_param iap;
805 iap.package = package;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
819 row = MSI_QueryGetRecord(package->db, IVQuery);
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
832 msiobj_release(&view->hdr);
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
850 iterate_action_param iap;
852 iap.package = package;
855 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
857 if (rc == ERROR_SUCCESS)
859 TRACE("Running the actions\n");
861 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
862 msiobj_release(&view->hdr);
868 /********************************************************
869 * ACTION helper functions and functions that perform the actions
870 *******************************************************/
871 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
872 UINT* rc, BOOL force )
878 if (!run && !package->script->CurrentlyScripting)
883 if (strcmpW(action,szInstallFinalize) == 0 ||
884 strcmpW(action,szInstallExecute) == 0 ||
885 strcmpW(action,szInstallExecuteAgain) == 0)
890 while (StandardActions[i].action != NULL)
892 if (strcmpW(StandardActions[i].action, action)==0)
896 ui_actioninfo(package, action, TRUE, 0);
897 *rc = schedule_action(package,INSTALL_SCRIPT,action);
898 ui_actioninfo(package, action, FALSE, *rc);
902 ui_actionstart(package, action);
903 if (StandardActions[i].handler)
905 *rc = StandardActions[i].handler(package);
909 FIXME("unhandled standard action %s\n",debugstr_w(action));
921 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
922 UINT* rc, BOOL force )
927 arc = ACTION_CustomAction(package,action, force);
929 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
938 * A lot of actions are really important even if they don't do anything
939 * explicit... Lots of properties are set at the beginning of the installation
940 * CostFinalize does a bunch of work to translate the directories and such
942 * But until I get write access to the database that is hard, so I am going to
943 * hack it to see if I can get something to run.
945 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
947 UINT rc = ERROR_SUCCESS;
950 TRACE("Performing action (%s)\n",debugstr_w(action));
952 handled = ACTION_HandleStandardAction(package, action, &rc, force);
955 handled = ACTION_HandleCustomAction(package, action, &rc, force);
959 FIXME("unhandled msi action %s\n",debugstr_w(action));
960 rc = ERROR_FUNCTION_NOT_CALLED;
966 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
968 UINT rc = ERROR_SUCCESS;
969 BOOL handled = FALSE;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
976 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
978 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
983 FIXME("unhandled msi action %s\n",debugstr_w(action));
984 rc = ERROR_FUNCTION_NOT_CALLED;
992 * Actual Action Handlers
995 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
997 MSIPACKAGE *package = (MSIPACKAGE*)param;
1003 dir = MSI_RecordGetString(row,1);
1006 ERR("Unable to get folder id\n");
1007 return ERROR_SUCCESS;
1010 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1013 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1014 return ERROR_SUCCESS;
1017 TRACE("Folder is %s\n",debugstr_w(full_path));
1020 uirow = MSI_CreateRecord(1);
1021 MSI_RecordSetStringW(uirow,1,full_path);
1022 ui_actiondata(package,szCreateFolders,uirow);
1023 msiobj_release( &uirow->hdr );
1025 if (folder->State == 0)
1026 create_full_pathW(full_path);
1030 msi_free(full_path);
1031 return ERROR_SUCCESS;
1034 /* FIXME: probably should merge this with the above function */
1035 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1037 UINT rc = ERROR_SUCCESS;
1039 LPWSTR install_path;
1041 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1043 return ERROR_FUNCTION_FAILED;
1045 /* create the path */
1046 if (folder->State == 0)
1048 create_full_pathW(install_path);
1051 msi_free(install_path);
1056 UINT msi_create_component_directories( MSIPACKAGE *package )
1060 /* create all the folders required by the components are going to install */
1061 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1063 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1065 msi_create_directory( package, comp->Directory );
1068 return ERROR_SUCCESS;
1072 * Also we cannot enable/disable components either, so for now I am just going
1073 * to do all the directories for all the components.
1075 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1077 static const WCHAR ExecSeqQuery[] =
1078 {'S','E','L','E','C','T',' ',
1079 '`','D','i','r','e','c','t','o','r','y','_','`',
1080 ' ','F','R','O','M',' ',
1081 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1085 /* create all the empty folders specified in the CreateFolder table */
1086 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1087 if (rc != ERROR_SUCCESS)
1088 return ERROR_SUCCESS;
1090 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1091 msiobj_release(&view->hdr);
1093 msi_create_component_directories( package );
1098 static UINT load_component( MSIRECORD *row, LPVOID param )
1100 MSIPACKAGE *package = param;
1103 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1105 return ERROR_FUNCTION_FAILED;
1107 list_add_tail( &package->components, &comp->entry );
1109 /* fill in the data */
1110 comp->Component = msi_dup_record_field( row, 1 );
1112 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1114 comp->ComponentId = msi_dup_record_field( row, 2 );
1115 comp->Directory = msi_dup_record_field( row, 3 );
1116 comp->Attributes = MSI_RecordGetInteger(row,4);
1117 comp->Condition = msi_dup_record_field( row, 5 );
1118 comp->KeyPath = msi_dup_record_field( row, 6 );
1120 comp->Installed = INSTALLSTATE_ABSENT;
1122 switch (comp->Attributes)
1124 case msidbComponentAttributesLocalOnly:
1125 comp->Action = INSTALLSTATE_LOCAL;
1126 comp->ActionRequest = INSTALLSTATE_LOCAL;
1128 case msidbComponentAttributesSourceOnly:
1129 comp->Action = INSTALLSTATE_SOURCE;
1130 comp->ActionRequest = INSTALLSTATE_SOURCE;
1132 case msidbComponentAttributesOptional:
1133 comp->Action = INSTALLSTATE_DEFAULT;
1134 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1137 comp->Action = INSTALLSTATE_UNKNOWN;
1138 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1141 return ERROR_SUCCESS;
1144 static UINT load_all_components( MSIPACKAGE *package )
1146 static const WCHAR query[] = {
1147 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1148 '`','C','o','m','p','o','n','e','n','t','`',0 };
1152 if (!list_empty(&package->components))
1153 return ERROR_SUCCESS;
1155 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1156 if (r != ERROR_SUCCESS)
1159 r = MSI_IterateRecords(view, NULL, load_component, package);
1160 msiobj_release(&view->hdr);
1165 MSIPACKAGE *package;
1166 MSIFEATURE *feature;
1169 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1173 cl = msi_alloc( sizeof (*cl) );
1175 return ERROR_NOT_ENOUGH_MEMORY;
1176 cl->component = comp;
1177 list_add_tail( &feature->Components, &cl->entry );
1179 return ERROR_SUCCESS;
1182 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1184 _ilfs* ilfs= (_ilfs*)param;
1188 component = MSI_RecordGetString(row,1);
1190 /* check to see if the component is already loaded */
1191 comp = get_loaded_component( ilfs->package, component );
1194 ERR("unknown component %s\n", debugstr_w(component));
1195 return ERROR_FUNCTION_FAILED;
1198 add_feature_component( ilfs->feature, comp );
1199 comp->Enabled = TRUE;
1201 return ERROR_SUCCESS;
1204 static UINT load_feature(MSIRECORD * row, LPVOID param)
1206 MSIPACKAGE* package = (MSIPACKAGE*)param;
1207 MSIFEATURE* feature;
1208 static const WCHAR Query1[] =
1209 {'S','E','L','E','C','T',' ',
1210 '`','C','o','m','p','o','n','e','n','t','_','`',
1211 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1212 'C','o','m','p','o','n','e','n','t','s','`',' ',
1213 'W','H','E','R','E',' ',
1214 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1219 /* fill in the data */
1221 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1223 return ERROR_NOT_ENOUGH_MEMORY;
1225 list_init( &feature->Components );
1227 feature->Feature = msi_dup_record_field( row, 1 );
1229 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1231 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1232 feature->Title = msi_dup_record_field( row, 3 );
1233 feature->Description = msi_dup_record_field( row, 4 );
1235 if (!MSI_RecordIsNull(row,5))
1236 feature->Display = MSI_RecordGetInteger(row,5);
1238 feature->Level= MSI_RecordGetInteger(row,6);
1239 feature->Directory = msi_dup_record_field( row, 7 );
1240 feature->Attributes = MSI_RecordGetInteger(row,8);
1242 feature->Installed = INSTALLSTATE_ABSENT;
1243 feature->Action = INSTALLSTATE_UNKNOWN;
1244 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1246 list_add_tail( &package->features, &feature->entry );
1248 /* load feature components */
1250 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1251 if (rc != ERROR_SUCCESS)
1252 return ERROR_SUCCESS;
1254 ilfs.package = package;
1255 ilfs.feature = feature;
1257 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1258 msiobj_release(&view->hdr);
1260 return ERROR_SUCCESS;
1263 static UINT load_all_features( MSIPACKAGE *package )
1265 static const WCHAR query[] = {
1266 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1267 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1268 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1272 if (!list_empty(&package->features))
1273 return ERROR_SUCCESS;
1275 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1276 if (r != ERROR_SUCCESS)
1279 r = MSI_IterateRecords( view, NULL, load_feature, package );
1280 msiobj_release( &view->hdr );
1284 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1295 static UINT load_file(MSIRECORD *row, LPVOID param)
1297 MSIPACKAGE* package = (MSIPACKAGE*)param;
1301 /* fill in the data */
1303 file = msi_alloc_zero( sizeof (MSIFILE) );
1305 return ERROR_NOT_ENOUGH_MEMORY;
1307 file->File = msi_dup_record_field( row, 1 );
1309 component = MSI_RecordGetString( row, 2 );
1310 file->Component = get_loaded_component( package, component );
1312 if (!file->Component)
1313 ERR("Unfound Component %s\n",debugstr_w(component));
1315 file->FileName = msi_dup_record_field( row, 3 );
1316 reduce_to_longfilename( file->FileName );
1318 file->ShortName = msi_dup_record_field( row, 3 );
1319 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1321 file->FileSize = MSI_RecordGetInteger( row, 4 );
1322 file->Version = msi_dup_record_field( row, 5 );
1323 file->Language = msi_dup_record_field( row, 6 );
1324 file->Attributes = MSI_RecordGetInteger( row, 7 );
1325 file->Sequence = MSI_RecordGetInteger( row, 8 );
1327 file->state = msifs_invalid;
1329 if (file->Attributes & msidbFileAttributesCompressed)
1331 file->Component->ForceLocalState = TRUE;
1332 file->Component->Action = INSTALLSTATE_LOCAL;
1333 file->Component->ActionRequest = INSTALLSTATE_LOCAL;
1336 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1338 list_add_tail( &package->files, &file->entry );
1340 return ERROR_SUCCESS;
1343 static UINT load_all_files(MSIPACKAGE *package)
1347 static const WCHAR Query[] =
1348 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1349 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1350 '`','S','e','q','u','e','n','c','e','`', 0};
1352 if (!list_empty(&package->files))
1353 return ERROR_SUCCESS;
1355 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1356 if (rc != ERROR_SUCCESS)
1357 return ERROR_SUCCESS;
1359 rc = MSI_IterateRecords(view, NULL, load_file, package);
1360 msiobj_release(&view->hdr);
1362 return ERROR_SUCCESS;
1367 * I am not doing any of the costing functionality yet.
1368 * Mostly looking at doing the Component and Feature loading
1370 * The native MSI does A LOT of modification to tables here. Mostly adding
1371 * a lot of temporary columns to the Feature and Component tables.
1373 * note: Native msi also tracks the short filename. But I am only going to
1374 * track the long ones. Also looking at this directory table
1375 * it appears that the directory table does not get the parents
1376 * resolved base on property only based on their entries in the
1379 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1381 static const WCHAR szCosting[] =
1382 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1383 static const WCHAR szZero[] = { '0', 0 };
1385 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1386 return ERROR_SUCCESS;
1388 MSI_SetPropertyW(package, szCosting, szZero);
1389 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1391 load_all_components( package );
1392 load_all_features( package );
1393 load_all_files( package );
1395 return ERROR_SUCCESS;
1398 static UINT execute_script(MSIPACKAGE *package, UINT script )
1401 UINT rc = ERROR_SUCCESS;
1403 TRACE("Executing Script %i\n",script);
1405 if (!package->script)
1407 ERR("no script!\n");
1408 return ERROR_FUNCTION_FAILED;
1411 for (i = 0; i < package->script->ActionCount[script]; i++)
1414 action = package->script->Actions[script][i];
1415 ui_actionstart(package, action);
1416 TRACE("Executing Action (%s)\n",debugstr_w(action));
1417 rc = ACTION_PerformAction(package, action, TRUE);
1418 msi_free(package->script->Actions[script][i]);
1419 if (rc != ERROR_SUCCESS)
1422 msi_free(package->script->Actions[script]);
1424 package->script->ActionCount[script] = 0;
1425 package->script->Actions[script] = NULL;
1429 static UINT ACTION_FileCost(MSIPACKAGE *package)
1431 return ERROR_SUCCESS;
1434 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1436 static const WCHAR Query[] =
1437 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1438 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1439 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1440 ' ','=',' ','\'','%','s','\'',
1442 static const WCHAR szDot[] = { '.',0 };
1443 static WCHAR szEmpty[] = { 0 };
1444 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1449 TRACE("Looking for dir %s\n",debugstr_w(dir));
1451 folder = get_loaded_folder( package, dir );
1455 TRACE("Working to load %s\n",debugstr_w(dir));
1457 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1461 folder->Directory = strdupW(dir);
1463 row = MSI_QueryGetRecord(package->db, Query, dir);
1467 p = msi_dup_record_field(row, 3);
1469 /* split src and target dir */
1471 src_short = folder_split_path( p, ':' );
1473 /* split the long and short paths */
1474 tgt_long = folder_split_path( tgt_short, '|' );
1475 src_long = folder_split_path( src_short, '|' );
1477 /* check for no-op dirs */
1478 if (!lstrcmpW(szDot, tgt_short))
1479 tgt_short = szEmpty;
1480 if (!lstrcmpW(szDot, src_short))
1481 src_short = szEmpty;
1484 tgt_long = tgt_short;
1487 src_short = tgt_short;
1488 src_long = tgt_long;
1492 src_long = src_short;
1494 /* FIXME: use the target short path too */
1495 folder->TargetDefault = strdupW(tgt_long);
1496 folder->SourceShortPath = strdupW(src_short);
1497 folder->SourceLongPath = strdupW(src_long);
1500 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1501 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1502 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1504 parent = MSI_RecordGetString(row, 2);
1507 folder->Parent = load_folder( package, parent );
1508 if ( folder->Parent )
1509 TRACE("loaded parent %p %s\n", folder->Parent,
1510 debugstr_w(folder->Parent->Directory));
1512 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1515 folder->Property = msi_dup_property( package, dir );
1517 msiobj_release(&row->hdr);
1519 list_add_tail( &package->folders, &folder->entry );
1521 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1526 /* scan for and update current install states */
1527 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1530 MSIFEATURE *feature;
1532 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1535 res = MsiGetComponentPathW( package->ProductCode,
1536 comp->ComponentId, NULL, NULL);
1538 res = INSTALLSTATE_ABSENT;
1539 comp->Installed = res;
1542 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1545 INSTALLSTATE res = -10;
1547 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1549 comp= cl->component;
1552 res = comp->Installed;
1555 if (res == comp->Installed)
1558 if (res != comp->Installed)
1559 res = INSTALLSTATE_INCOMPLETE;
1562 feature->Installed = res;
1566 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1569 static const WCHAR all[]={'A','L','L',0};
1571 MSIFEATURE *feature;
1573 override = msi_dup_property( package, property );
1577 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1579 if (strcmpiW(override,all)==0)
1581 feature->ActionRequest= state;
1582 feature->Action = state;
1586 LPWSTR ptr = override;
1587 LPWSTR ptr2 = strchrW(override,',');
1591 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1592 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1594 feature->ActionRequest= state;
1595 feature->Action = state;
1601 ptr2 = strchrW(ptr,',');
1613 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1616 static const WCHAR szlevel[] =
1617 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1618 static const WCHAR szAddLocal[] =
1619 {'A','D','D','L','O','C','A','L',0};
1620 static const WCHAR szRemove[] =
1621 {'R','E','M','O','V','E',0};
1622 static const WCHAR szReinstall[] =
1623 {'R','E','I','N','S','T','A','L','L',0};
1624 BOOL override = FALSE;
1625 MSICOMPONENT* component;
1626 MSIFEATURE *feature;
1629 /* I do not know if this is where it should happen.. but */
1631 TRACE("Checking Install Level\n");
1633 install_level = msi_get_property_int( package, szlevel, 1 );
1635 /* ok hereis the _real_ rub
1636 * all these activation/deactivation things happen in order and things
1637 * later on the list override things earlier on the list.
1638 * 1) INSTALLLEVEL processing
1648 * 11) FILEADDDEFAULT
1649 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1650 * ignored for all the features. seems strange, especially since it is not
1651 * documented anywhere, but it is how it works.
1653 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1654 * REMOVE are the big ones, since we don't handle administrative installs
1657 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1658 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1659 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1665 BOOL feature_state = ((feature->Level > 0) &&
1666 (feature->Level <= install_level));
1668 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1670 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1672 feature->ActionRequest = INSTALLSTATE_SOURCE;
1673 feature->Action = INSTALLSTATE_SOURCE;
1675 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1677 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1678 feature->Action = INSTALLSTATE_ADVERTISED;
1682 feature->ActionRequest = INSTALLSTATE_LOCAL;
1683 feature->Action = INSTALLSTATE_LOCAL;
1690 /* set the Preselected Property */
1691 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1692 static const WCHAR szOne[] = { '1', 0 };
1694 MSI_SetPropertyW(package,szPreselected,szOne);
1698 * now we want to enable or disable components base on feature
1701 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1705 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1706 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1707 feature->ActionRequest);
1709 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1711 component = cl->component;
1713 if (!component->Enabled)
1715 component->Action = INSTALLSTATE_UNKNOWN;
1716 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1720 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1722 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1724 component->Action = INSTALLSTATE_LOCAL;
1725 component->ActionRequest = INSTALLSTATE_LOCAL;
1728 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1730 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1731 (component->Action == INSTALLSTATE_ABSENT) ||
1732 (component->Action == INSTALLSTATE_ADVERTISED) ||
1733 (component->Action == INSTALLSTATE_DEFAULT))
1736 component->Action = INSTALLSTATE_SOURCE;
1737 component->ActionRequest = INSTALLSTATE_SOURCE;
1740 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1742 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1743 (component->Action == INSTALLSTATE_ABSENT))
1746 component->Action = INSTALLSTATE_ADVERTISED;
1747 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1750 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1752 if (component->Action == INSTALLSTATE_UNKNOWN)
1754 component->Action = INSTALLSTATE_ABSENT;
1755 component->ActionRequest = INSTALLSTATE_ABSENT;
1760 if (component->ForceLocalState)
1762 feature->Action = INSTALLSTATE_LOCAL;
1763 feature->ActionRequest = INSTALLSTATE_LOCAL;
1768 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1770 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1771 debugstr_w(component->Component), component->Installed,
1772 component->Action, component->ActionRequest);
1776 return ERROR_SUCCESS;
1779 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1781 MSIPACKAGE *package = (MSIPACKAGE*)param;
1785 name = MSI_RecordGetString(row,1);
1787 /* This helper function now does ALL the work */
1788 TRACE("Dir %s ...\n",debugstr_w(name));
1789 load_folder(package,name);
1790 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1791 TRACE("resolves to %s\n",debugstr_w(path));
1794 return ERROR_SUCCESS;
1797 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1799 MSIPACKAGE *package = (MSIPACKAGE*)param;
1801 MSIFEATURE *feature;
1803 name = MSI_RecordGetString( row, 1 );
1805 feature = get_loaded_feature( package, name );
1807 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1811 Condition = MSI_RecordGetString(row,3);
1813 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1815 int level = MSI_RecordGetInteger(row,2);
1816 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1817 feature->Level = level;
1820 return ERROR_SUCCESS;
1825 * A lot is done in this function aside from just the costing.
1826 * The costing needs to be implemented at some point but for now I am going
1827 * to focus on the directory building
1830 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1832 static const WCHAR ExecSeqQuery[] =
1833 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1834 '`','D','i','r','e','c','t','o','r','y','`',0};
1835 static const WCHAR ConditionQuery[] =
1836 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1837 '`','C','o','n','d','i','t','i','o','n','`',0};
1838 static const WCHAR szCosting[] =
1839 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1840 static const WCHAR szlevel[] =
1841 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1842 static const WCHAR szOne[] = { '1', 0 };
1849 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1850 return ERROR_SUCCESS;
1852 TRACE("Building Directory properties\n");
1854 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1855 if (rc == ERROR_SUCCESS)
1857 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1859 msiobj_release(&view->hdr);
1862 TRACE("File calculations\n");
1864 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1866 MSICOMPONENT* comp = file->Component;
1872 /* calculate target */
1873 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1875 msi_free(file->TargetPath);
1877 TRACE("file %s is named %s\n",
1878 debugstr_w(file->File),debugstr_w(file->FileName));
1880 file->TargetPath = build_directory_name(2, p, file->FileName);
1884 TRACE("file %s resolves to %s\n",
1885 debugstr_w(file->File),debugstr_w(file->TargetPath));
1887 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1889 file->state = msifs_missing;
1890 comp->Cost += file->FileSize;
1900 static WCHAR name[] = {'\\',0};
1901 static const WCHAR name_fmt[] =
1902 {'%','u','.','%','u','.','%','u','.','%','u',0};
1903 WCHAR filever[0x100];
1904 VS_FIXEDFILEINFO *lpVer;
1906 TRACE("Version comparison..\n");
1907 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1908 version = msi_alloc(versize);
1909 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1911 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1913 sprintfW(filever,name_fmt,
1914 HIWORD(lpVer->dwFileVersionMS),
1915 LOWORD(lpVer->dwFileVersionMS),
1916 HIWORD(lpVer->dwFileVersionLS),
1917 LOWORD(lpVer->dwFileVersionLS));
1919 TRACE("new %s old %s\n", debugstr_w(file->Version),
1920 debugstr_w(filever));
1921 if (strcmpiW(filever,file->Version)<0)
1923 file->state = msifs_overwrite;
1924 /* FIXME: cost should be diff in size */
1925 comp->Cost += file->FileSize;
1928 file->state = msifs_present;
1932 file->state = msifs_present;
1935 TRACE("Evaluating Condition Table\n");
1937 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1938 if (rc == ERROR_SUCCESS)
1940 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1942 msiobj_release(&view->hdr);
1945 TRACE("Enabling or Disabling Components\n");
1946 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1948 if (comp->Condition)
1950 if (MSI_EvaluateConditionW(package,
1951 comp->Condition) == MSICONDITION_FALSE)
1953 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1954 comp->Enabled = FALSE;
1959 MSI_SetPropertyW(package,szCosting,szOne);
1960 /* set default run level if not set */
1961 level = msi_dup_property( package, szlevel );
1963 MSI_SetPropertyW(package,szlevel, szOne);
1966 ACTION_UpdateInstallStates(package);
1968 return MSI_SetFeatureStates(package);
1971 /* OK this value is "interpreted" and then formatted based on the
1972 first few characters */
1973 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1977 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1983 LPWSTR deformated = NULL;
1986 deformat_string(package, &value[2], &deformated);
1988 /* binary value type */
1992 *size = (strlenW(ptr)/2)+1;
1994 *size = strlenW(ptr)/2;
1996 data = msi_alloc(*size);
2002 /* if uneven pad with a zero in front */
2008 data[count] = (BYTE)strtol(byte,NULL,0);
2010 TRACE("Uneven byte count\n");
2018 data[count] = (BYTE)strtol(byte,NULL,0);
2021 msi_free(deformated);
2023 TRACE("Data %li bytes(%i)\n",*size,count);
2030 deformat_string(package, &value[1], &deformated);
2033 *size = sizeof(DWORD);
2034 data = msi_alloc(*size);
2040 if ( (*p < '0') || (*p > '9') )
2046 if (deformated[0] == '-')
2049 TRACE("DWORD %li\n",*(LPDWORD)data);
2051 msi_free(deformated);
2056 static const WCHAR szMulti[] = {'[','~',']',0};
2065 *type=REG_EXPAND_SZ;
2073 if (strstrW(value,szMulti))
2074 *type = REG_MULTI_SZ;
2076 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2081 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2083 MSIPACKAGE *package = (MSIPACKAGE*)param;
2084 static const WCHAR szHCR[] =
2085 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2086 'R','O','O','T','\\',0};
2087 static const WCHAR szHCU[] =
2088 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2089 'U','S','E','R','\\',0};
2090 static const WCHAR szHLM[] =
2091 {'H','K','E','Y','_','L','O','C','A','L','_',
2092 'M','A','C','H','I','N','E','\\',0};
2093 static const WCHAR szHU[] =
2094 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2096 LPSTR value_data = NULL;
2097 HKEY root_key, hkey;
2100 LPCWSTR szRoot, component, name, key, value;
2105 BOOL check_first = FALSE;
2108 ui_progress(package,2,0,0,0);
2115 component = MSI_RecordGetString(row, 6);
2116 comp = get_loaded_component(package,component);
2118 return ERROR_SUCCESS;
2120 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2122 TRACE("Skipping write due to disabled component %s\n",
2123 debugstr_w(component));
2125 comp->Action = comp->Installed;
2127 return ERROR_SUCCESS;
2130 comp->Action = INSTALLSTATE_LOCAL;
2132 name = MSI_RecordGetString(row, 4);
2133 if( MSI_RecordIsNull(row,5) && name )
2135 /* null values can have special meanings */
2136 if (name[0]=='-' && name[1] == 0)
2137 return ERROR_SUCCESS;
2138 else if ((name[0]=='+' && name[1] == 0) ||
2139 (name[0] == '*' && name[1] == 0))
2144 root = MSI_RecordGetInteger(row,2);
2145 key = MSI_RecordGetString(row, 3);
2147 /* get the root key */
2152 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2153 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2154 if (all_users && all_users[0] == '1')
2156 root_key = HKEY_LOCAL_MACHINE;
2161 root_key = HKEY_CURRENT_USER;
2164 msi_free(all_users);
2167 case 0: root_key = HKEY_CLASSES_ROOT;
2170 case 1: root_key = HKEY_CURRENT_USER;
2173 case 2: root_key = HKEY_LOCAL_MACHINE;
2176 case 3: root_key = HKEY_USERS;
2180 ERR("Unknown root %i\n",root);
2186 return ERROR_SUCCESS;
2188 deformat_string(package, key , &deformated);
2189 size = strlenW(deformated) + strlenW(szRoot) + 1;
2190 uikey = msi_alloc(size*sizeof(WCHAR));
2191 strcpyW(uikey,szRoot);
2192 strcatW(uikey,deformated);
2194 if (RegCreateKeyW( root_key, deformated, &hkey))
2196 ERR("Could not create key %s\n",debugstr_w(deformated));
2197 msi_free(deformated);
2199 return ERROR_SUCCESS;
2201 msi_free(deformated);
2203 value = MSI_RecordGetString(row,5);
2205 value_data = parse_value(package, value, &type, &size);
2208 static const WCHAR szEmpty[] = {0};
2209 value_data = (LPSTR)strdupW(szEmpty);
2214 deformat_string(package, name, &deformated);
2216 /* get the double nulls to terminate SZ_MULTI */
2217 if (type == REG_MULTI_SZ)
2218 size +=sizeof(WCHAR);
2222 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2224 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2229 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2230 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2232 TRACE("value %s of %s checked already exists\n",
2233 debugstr_w(deformated), debugstr_w(uikey));
2237 TRACE("Checked and setting value %s of %s\n",
2238 debugstr_w(deformated), debugstr_w(uikey));
2239 if (deformated || size)
2240 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2245 uirow = MSI_CreateRecord(3);
2246 MSI_RecordSetStringW(uirow,2,deformated);
2247 MSI_RecordSetStringW(uirow,1,uikey);
2250 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2252 MSI_RecordSetStringW(uirow,3,value);
2254 ui_actiondata(package,szWriteRegistryValues,uirow);
2255 msiobj_release( &uirow->hdr );
2257 msi_free(value_data);
2258 msi_free(deformated);
2261 return ERROR_SUCCESS;
2264 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2268 static const WCHAR ExecSeqQuery[] =
2269 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2270 '`','R','e','g','i','s','t','r','y','`',0 };
2272 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2273 if (rc != ERROR_SUCCESS)
2274 return ERROR_SUCCESS;
2276 /* increment progress bar each time action data is sent */
2277 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2279 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2281 msiobj_release(&view->hdr);
2285 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2287 package->script->CurrentlyScripting = TRUE;
2289 return ERROR_SUCCESS;
2293 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2298 static const WCHAR q1[]=
2299 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2300 '`','R','e','g','i','s','t','r','y','`',0};
2303 MSIFEATURE *feature;
2306 TRACE("InstallValidate\n");
2308 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2309 if (rc == ERROR_SUCCESS)
2311 MSI_IterateRecords( view, &progress, NULL, package );
2312 msiobj_release( &view->hdr );
2313 total += progress * REG_PROGRESS_VALUE;
2316 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2317 total += COMPONENT_PROGRESS_VALUE;
2319 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2320 total += file->FileSize;
2322 ui_progress(package,0,total,0,0);
2324 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2326 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2327 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2328 feature->ActionRequest);
2331 return ERROR_SUCCESS;
2334 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2336 MSIPACKAGE* package = (MSIPACKAGE*)param;
2337 LPCWSTR cond = NULL;
2338 LPCWSTR message = NULL;
2339 static const WCHAR title[]=
2340 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2342 cond = MSI_RecordGetString(row,1);
2344 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2347 message = MSI_RecordGetString(row,2);
2348 deformat_string(package,message,&deformated);
2349 MessageBoxW(NULL,deformated,title,MB_OK);
2350 msi_free(deformated);
2351 return ERROR_FUNCTION_FAILED;
2354 return ERROR_SUCCESS;
2357 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2360 MSIQUERY * view = NULL;
2361 static const WCHAR ExecSeqQuery[] =
2362 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2363 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2365 TRACE("Checking launch conditions\n");
2367 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2368 if (rc != ERROR_SUCCESS)
2369 return ERROR_SUCCESS;
2371 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2372 msiobj_release(&view->hdr);
2377 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2381 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2383 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2385 MSIRECORD * row = 0;
2387 LPWSTR deformated,buffer,deformated_name;
2389 static const WCHAR ExecSeqQuery[] =
2390 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2391 '`','R','e','g','i','s','t','r','y','`',' ',
2392 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2393 ' ','=',' ' ,'\'','%','s','\'',0 };
2394 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2395 static const WCHAR fmt2[]=
2396 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2398 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2402 root = MSI_RecordGetInteger(row,2);
2403 key = MSI_RecordGetString(row, 3);
2404 name = MSI_RecordGetString(row, 4);
2405 deformat_string(package, key , &deformated);
2406 deformat_string(package, name, &deformated_name);
2408 len = strlenW(deformated) + 6;
2409 if (deformated_name)
2410 len+=strlenW(deformated_name);
2412 buffer = msi_alloc( len *sizeof(WCHAR));
2414 if (deformated_name)
2415 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2417 sprintfW(buffer,fmt,root,deformated);
2419 msi_free(deformated);
2420 msi_free(deformated_name);
2421 msiobj_release(&row->hdr);
2425 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2427 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2432 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2435 return strdupW( file->TargetPath );
2440 static HKEY openSharedDLLsKey(void)
2443 static const WCHAR path[] =
2444 {'S','o','f','t','w','a','r','e','\\',
2445 'M','i','c','r','o','s','o','f','t','\\',
2446 'W','i','n','d','o','w','s','\\',
2447 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2448 'S','h','a','r','e','d','D','L','L','s',0};
2450 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2454 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2459 DWORD sz = sizeof(count);
2462 hkey = openSharedDLLsKey();
2463 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2464 if (rc != ERROR_SUCCESS)
2470 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2474 hkey = openSharedDLLsKey();
2476 msi_reg_set_val_dword( hkey, path, count );
2478 RegDeleteValueW(hkey,path);
2484 * Return TRUE if the count should be written out and FALSE if not
2486 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2488 MSIFEATURE *feature;
2492 /* only refcount DLLs */
2493 if (comp->KeyPath == NULL ||
2494 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2495 comp->Attributes & msidbComponentAttributesODBCDataSource)
2499 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2500 write = (count > 0);
2502 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2506 /* increment counts */
2507 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2511 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2514 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2516 if ( cl->component == comp )
2521 /* decrement counts */
2522 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2526 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2529 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2531 if ( cl->component == comp )
2536 /* ref count all the files in the component */
2541 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2543 if (file->Component == comp)
2544 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2548 /* add a count for permenent */
2549 if (comp->Attributes & msidbComponentAttributesPermanent)
2552 comp->RefCount = count;
2555 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2559 * Ok further analysis makes me think that this work is
2560 * actually done in the PublishComponents and PublishFeatures
2561 * step, and not here. It appears like the keypath and all that is
2562 * resolved in this step, however actually written in the Publish steps.
2563 * But we will leave it here for now because it is unclear
2565 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2567 WCHAR squished_pc[GUID_SIZE];
2568 WCHAR squished_cc[GUID_SIZE];
2571 HKEY hkey=0,hkey2=0;
2573 /* writes the Component and Features values to the registry */
2575 rc = MSIREG_OpenComponents(&hkey);
2576 if (rc != ERROR_SUCCESS)
2579 squash_guid(package->ProductCode,squished_pc);
2580 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2582 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2586 ui_progress(package,2,0,0,0);
2587 if (!comp->ComponentId)
2590 squash_guid(comp->ComponentId,squished_cc);
2592 msi_free(comp->FullKeypath);
2593 comp->FullKeypath = resolve_keypath( package, comp );
2595 /* do the refcounting */
2596 ACTION_RefCountComponent( package, comp );
2598 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2599 debugstr_w(comp->Component),
2600 debugstr_w(squished_cc),
2601 debugstr_w(comp->FullKeypath),
2604 * Write the keypath out if the component is to be registered
2605 * and delete the key if the component is to be deregistered
2607 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2609 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2610 if (rc != ERROR_SUCCESS)
2613 if (!comp->FullKeypath)
2616 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2618 if (comp->Attributes & msidbComponentAttributesPermanent)
2620 static const WCHAR szPermKey[] =
2621 { '0','0','0','0','0','0','0','0','0','0','0','0',
2622 '0','0','0','0','0','0','0','0','0','0','0','0',
2623 '0','0','0','0','0','0','0','0',0 };
2625 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2631 uirow = MSI_CreateRecord(3);
2632 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2633 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2634 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2635 ui_actiondata(package,szProcessComponents,uirow);
2636 msiobj_release( &uirow->hdr );
2638 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2642 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2643 if (rc != ERROR_SUCCESS)
2646 RegDeleteValueW(hkey2,squished_pc);
2648 /* if the key is empty delete it */
2649 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2651 if (res == ERROR_NO_MORE_ITEMS)
2652 RegDeleteKeyW(hkey,squished_cc);
2655 uirow = MSI_CreateRecord(2);
2656 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2657 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2658 ui_actiondata(package,szProcessComponents,uirow);
2659 msiobj_release( &uirow->hdr );
2674 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2675 LPWSTR lpszName, LONG_PTR lParam)
2678 typelib_struct *tl_struct = (typelib_struct*) lParam;
2679 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2683 if (!IS_INTRESOURCE(lpszName))
2685 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2689 sz = strlenW(tl_struct->source)+4;
2690 sz *= sizeof(WCHAR);
2692 if ((INT_PTR)lpszName == 1)
2693 tl_struct->path = strdupW(tl_struct->source);
2696 tl_struct->path = msi_alloc(sz);
2697 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2700 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2701 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2702 if (!SUCCEEDED(res))
2704 msi_free(tl_struct->path);
2705 tl_struct->path = NULL;
2710 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2711 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2713 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2717 msi_free(tl_struct->path);
2718 tl_struct->path = NULL;
2720 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2721 ITypeLib_Release(tl_struct->ptLib);
2726 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2728 MSIPACKAGE* package = (MSIPACKAGE*)param;
2732 typelib_struct tl_struct;
2734 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2736 component = MSI_RecordGetString(row,3);
2737 comp = get_loaded_component(package,component);
2739 return ERROR_SUCCESS;
2741 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2743 TRACE("Skipping typelib reg due to disabled component\n");
2745 comp->Action = comp->Installed;
2747 return ERROR_SUCCESS;
2750 comp->Action = INSTALLSTATE_LOCAL;
2752 file = get_loaded_file( package, comp->KeyPath );
2754 return ERROR_SUCCESS;
2756 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2760 guid = MSI_RecordGetString(row,1);
2761 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2762 tl_struct.source = strdupW( file->TargetPath );
2763 tl_struct.path = NULL;
2765 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2766 (LONG_PTR)&tl_struct);
2774 helpid = MSI_RecordGetString(row,6);
2777 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2778 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2781 if (!SUCCEEDED(res))
2782 ERR("Failed to register type library %s\n",
2783 debugstr_w(tl_struct.path));
2786 ui_actiondata(package,szRegisterTypeLibraries,row);
2788 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2791 ITypeLib_Release(tl_struct.ptLib);
2792 msi_free(tl_struct.path);
2795 ERR("Failed to load type library %s\n",
2796 debugstr_w(tl_struct.source));
2798 FreeLibrary(module);
2799 msi_free(tl_struct.source);
2802 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2804 return ERROR_SUCCESS;
2807 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2810 * OK this is a bit confusing.. I am given a _Component key and I believe
2811 * that the file that is being registered as a type library is the "key file
2812 * of that component" which I interpret to mean "The file in the KeyPath of
2817 static const WCHAR Query[] =
2818 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2819 '`','T','y','p','e','L','i','b','`',0};
2821 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2822 if (rc != ERROR_SUCCESS)
2823 return ERROR_SUCCESS;
2825 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2826 msiobj_release(&view->hdr);
2830 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2832 MSIPACKAGE *package = (MSIPACKAGE*)param;
2833 LPWSTR target_file, target_folder, filename;
2834 LPCWSTR buffer, extension;
2836 static const WCHAR szlnk[]={'.','l','n','k',0};
2837 IShellLinkW *sl = NULL;
2838 IPersistFile *pf = NULL;
2841 buffer = MSI_RecordGetString(row,4);
2842 comp = get_loaded_component(package,buffer);
2844 return ERROR_SUCCESS;
2846 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2848 TRACE("Skipping shortcut creation due to disabled component\n");
2850 comp->Action = comp->Installed;
2852 return ERROR_SUCCESS;
2855 comp->Action = INSTALLSTATE_LOCAL;
2857 ui_actiondata(package,szCreateShortcuts,row);
2859 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2860 &IID_IShellLinkW, (LPVOID *) &sl );
2864 ERR("CLSID_ShellLink not available\n");
2868 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2871 ERR("QueryInterface(IID_IPersistFile) failed\n");
2875 buffer = MSI_RecordGetString(row,2);
2876 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2878 /* may be needed because of a bug somehwere else */
2879 create_full_pathW(target_folder);
2881 filename = msi_dup_record_field( row, 3 );
2882 reduce_to_longfilename(filename);
2884 extension = strchrW(filename,'.');
2885 if (!extension || strcmpiW(extension,szlnk))
2887 int len = strlenW(filename);
2888 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2889 memcpy(filename + len, szlnk, sizeof(szlnk));
2891 target_file = build_directory_name(2, target_folder, filename);
2892 msi_free(target_folder);
2895 buffer = MSI_RecordGetString(row,5);
2896 if (strchrW(buffer,'['))
2899 deformat_string(package,buffer,&deformated);
2900 IShellLinkW_SetPath(sl,deformated);
2901 msi_free(deformated);
2905 FIXME("poorly handled shortcut format, advertised shortcut\n");
2906 IShellLinkW_SetPath(sl,comp->FullKeypath);
2909 if (!MSI_RecordIsNull(row,6))
2912 buffer = MSI_RecordGetString(row,6);
2913 deformat_string(package,buffer,&deformated);
2914 IShellLinkW_SetArguments(sl,deformated);
2915 msi_free(deformated);
2918 if (!MSI_RecordIsNull(row,7))
2920 buffer = MSI_RecordGetString(row,7);
2921 IShellLinkW_SetDescription(sl,buffer);
2924 if (!MSI_RecordIsNull(row,8))
2925 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2927 if (!MSI_RecordIsNull(row,9))
2932 buffer = MSI_RecordGetString(row,9);
2934 Path = build_icon_path(package,buffer);
2935 index = MSI_RecordGetInteger(row,10);
2937 /* no value means 0 */
2938 if (index == MSI_NULL_INTEGER)
2941 IShellLinkW_SetIconLocation(sl,Path,index);
2945 if (!MSI_RecordIsNull(row,11))
2946 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2948 if (!MSI_RecordIsNull(row,12))
2951 buffer = MSI_RecordGetString(row,12);
2952 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2954 IShellLinkW_SetWorkingDirectory(sl,Path);
2958 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2959 IPersistFile_Save(pf,target_file,FALSE);
2961 msi_free(target_file);
2965 IPersistFile_Release( pf );
2967 IShellLinkW_Release( sl );
2969 return ERROR_SUCCESS;
2972 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2977 static const WCHAR Query[] =
2978 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2979 '`','S','h','o','r','t','c','u','t','`',0};
2981 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2982 if (rc != ERROR_SUCCESS)
2983 return ERROR_SUCCESS;
2985 res = CoInitialize( NULL );
2988 ERR("CoInitialize failed\n");
2989 return ERROR_FUNCTION_FAILED;
2992 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2993 msiobj_release(&view->hdr);
3000 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3002 MSIPACKAGE* package = (MSIPACKAGE*)param;
3011 FileName = MSI_RecordGetString(row,1);
3014 ERR("Unable to get FileName\n");
3015 return ERROR_SUCCESS;
3018 FilePath = build_icon_path(package,FileName);
3020 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3022 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3023 FILE_ATTRIBUTE_NORMAL, NULL);
3025 if (the_file == INVALID_HANDLE_VALUE)
3027 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3029 return ERROR_SUCCESS;
3036 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3037 if (rc != ERROR_SUCCESS)
3039 ERR("Failed to get stream\n");
3040 CloseHandle(the_file);
3041 DeleteFileW(FilePath);
3044 WriteFile(the_file,buffer,sz,&write,NULL);
3045 } while (sz == 1024);
3049 CloseHandle(the_file);
3051 uirow = MSI_CreateRecord(1);
3052 MSI_RecordSetStringW(uirow,1,FileName);
3053 ui_actiondata(package,szPublishProduct,uirow);
3054 msiobj_release( &uirow->hdr );
3056 return ERROR_SUCCESS;
3060 * 99% of the work done here is only done for
3061 * advertised installs. However this is where the
3062 * Icon table is processed and written out
3063 * so that is what I am going to do here.
3065 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3069 static const WCHAR Query[]=
3070 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3071 '`','I','c','o','n','`',0};
3072 /* for registry stuff */
3075 static const WCHAR szProductLanguage[] =
3076 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3077 static const WCHAR szARPProductIcon[] =
3078 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3079 static const WCHAR szProductVersion[] =
3080 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3084 MSIHANDLE hDb, hSumInfo;
3086 /* write out icon files */
3088 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3089 if (rc == ERROR_SUCCESS)
3091 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3092 msiobj_release(&view->hdr);
3095 /* ok there is a lot more done here but i need to figure out what */
3097 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3098 if (rc != ERROR_SUCCESS)
3101 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3102 if (rc != ERROR_SUCCESS)
3106 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3107 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3110 langid = msi_get_property_int( package, szProductLanguage, 0 );
3111 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3113 buffer = msi_dup_property( package, szARPProductIcon );
3116 LPWSTR path = build_icon_path(package,buffer);
3117 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3122 buffer = msi_dup_property( package, szProductVersion );
3125 DWORD verdword = msi_version_str_to_dword(buffer);
3126 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3130 /* FIXME: Need to write more keys to the user registry */
3132 hDb= alloc_msihandle( &package->db->hdr );
3133 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3134 MsiCloseHandle(hDb);
3135 if (rc == ERROR_SUCCESS)
3137 WCHAR guidbuffer[0x200];
3139 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3141 if (rc == ERROR_SUCCESS)
3143 WCHAR squashed[GUID_SIZE];
3144 /* for now we only care about the first guid */
3145 LPWSTR ptr = strchrW(guidbuffer,';');
3147 squash_guid(guidbuffer,squashed);
3148 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3152 ERR("Unable to query Revision_Number...\n");
3155 MsiCloseHandle(hSumInfo);
3159 ERR("Unable to open Summary Information\n");
3171 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3173 MSIPACKAGE *package = (MSIPACKAGE*)param;
3174 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3175 LPWSTR deformated_section, deformated_key, deformated_value;
3176 LPWSTR folder, fullname = NULL;
3180 static const WCHAR szWindowsFolder[] =
3181 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3183 component = MSI_RecordGetString(row, 8);
3184 comp = get_loaded_component(package,component);
3186 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3188 TRACE("Skipping ini file due to disabled component %s\n",
3189 debugstr_w(component));
3191 comp->Action = comp->Installed;
3193 return ERROR_SUCCESS;
3196 comp->Action = INSTALLSTATE_LOCAL;
3198 identifier = MSI_RecordGetString(row,1);
3199 filename = MSI_RecordGetString(row,2);
3200 dirproperty = MSI_RecordGetString(row,3);
3201 section = MSI_RecordGetString(row,4);
3202 key = MSI_RecordGetString(row,5);
3203 value = MSI_RecordGetString(row,6);
3204 action = MSI_RecordGetInteger(row,7);
3206 deformat_string(package,section,&deformated_section);
3207 deformat_string(package,key,&deformated_key);
3208 deformat_string(package,value,&deformated_value);
3212 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3214 folder = msi_dup_property( package, dirproperty );
3217 folder = msi_dup_property( package, szWindowsFolder );
3221 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3225 fullname = build_directory_name(2, folder, filename);
3229 TRACE("Adding value %s to section %s in %s\n",
3230 debugstr_w(deformated_key), debugstr_w(deformated_section),
3231 debugstr_w(fullname));
3232 WritePrivateProfileStringW(deformated_section, deformated_key,
3233 deformated_value, fullname);
3235 else if (action == 1)
3238 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3239 returned, 10, fullname);
3240 if (returned[0] == 0)
3242 TRACE("Adding value %s to section %s in %s\n",
3243 debugstr_w(deformated_key), debugstr_w(deformated_section),
3244 debugstr_w(fullname));
3246 WritePrivateProfileStringW(deformated_section, deformated_key,
3247 deformated_value, fullname);
3250 else if (action == 3)
3251 FIXME("Append to existing section not yet implemented\n");
3253 uirow = MSI_CreateRecord(4);
3254 MSI_RecordSetStringW(uirow,1,identifier);
3255 MSI_RecordSetStringW(uirow,2,deformated_section);
3256 MSI_RecordSetStringW(uirow,3,deformated_key);
3257 MSI_RecordSetStringW(uirow,4,deformated_value);
3258 ui_actiondata(package,szWriteIniValues,uirow);
3259 msiobj_release( &uirow->hdr );
3263 msi_free(deformated_key);
3264 msi_free(deformated_value);
3265 msi_free(deformated_section);
3266 return ERROR_SUCCESS;
3269 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3273 static const WCHAR ExecSeqQuery[] =
3274 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3275 '`','I','n','i','F','i','l','e','`',0};
3277 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3278 if (rc != ERROR_SUCCESS)
3280 TRACE("no IniFile table\n");
3281 return ERROR_SUCCESS;
3284 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3285 msiobj_release(&view->hdr);
3289 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3291 MSIPACKAGE *package = (MSIPACKAGE*)param;
3296 static const WCHAR ExeStr[] =
3297 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3298 static const WCHAR close[] = {'\"',0};
3300 PROCESS_INFORMATION info;
3305 memset(&si,0,sizeof(STARTUPINFOW));
3307 filename = MSI_RecordGetString(row,1);
3308 file = get_loaded_file( package, filename );
3312 ERR("Unable to find file id %s\n",debugstr_w(filename));
3313 return ERROR_SUCCESS;
3316 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3318 FullName = msi_alloc(len*sizeof(WCHAR));
3319 strcpyW(FullName,ExeStr);
3320 strcatW( FullName, file->TargetPath );
3321 strcatW(FullName,close);
3323 TRACE("Registering %s\n",debugstr_w(FullName));
3324 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3328 msi_dialog_check_messages(info.hProcess);
3333 uirow = MSI_CreateRecord( 2 );
3334 uipath = strdupW( file->TargetPath );
3335 p = strrchrW(uipath,'\\');
3338 MSI_RecordSetStringW( uirow, 1, &p[2] );
3339 MSI_RecordSetStringW( uirow, 2, uipath);
3340 ui_actiondata( package, szSelfRegModules, uirow);
3341 msiobj_release( &uirow->hdr );
3343 /* FIXME: call ui_progress? */
3345 return ERROR_SUCCESS;
3348 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3352 static const WCHAR ExecSeqQuery[] =
3353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3354 '`','S','e','l','f','R','e','g','`',0};
3356 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3357 if (rc != ERROR_SUCCESS)
3359 TRACE("no SelfReg table\n");
3360 return ERROR_SUCCESS;
3363 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3364 msiobj_release(&view->hdr);
3366 return ERROR_SUCCESS;
3369 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3371 MSIFEATURE *feature;
3376 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3377 if (rc != ERROR_SUCCESS)
3380 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3381 if (rc != ERROR_SUCCESS)
3384 /* here the guids are base 85 encoded */
3385 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3391 BOOL absent = FALSE;
3394 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3395 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3396 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3400 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3404 if (feature->Feature_Parent)
3405 size += strlenW( feature->Feature_Parent )+2;
3407 data = msi_alloc(size * sizeof(WCHAR));
3410 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3412 MSICOMPONENT* component = cl->component;
3416 if (component->ComponentId)
3418 TRACE("From %s\n",debugstr_w(component->ComponentId));
3419 CLSIDFromString(component->ComponentId, &clsid);
3420 encode_base85_guid(&clsid,buf);
3421 TRACE("to %s\n",debugstr_w(buf));
3425 if (feature->Feature_Parent)
3427 static const WCHAR sep[] = {'\2',0};
3429 strcatW(data,feature->Feature_Parent);
3432 msi_reg_set_val_str( hkey, feature->Feature, data );
3436 if (feature->Feature_Parent)
3437 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3440 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3441 (LPBYTE)feature->Feature_Parent,size);
3445 size += 2*sizeof(WCHAR);
3446 data = msi_alloc(size);
3449 if (feature->Feature_Parent)
3450 strcpyW( &data[1], feature->Feature_Parent );
3451 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3457 uirow = MSI_CreateRecord( 1 );
3458 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3459 ui_actiondata( package, szPublishFeatures, uirow);
3460 msiobj_release( &uirow->hdr );
3461 /* FIXME: call ui_progress? */
3470 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3472 static const WCHAR installerPathFmt[] = {
3473 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3474 static const WCHAR fmt[] = {
3476 'I','n','s','t','a','l','l','e','r','\\',
3477 '%','x','.','m','s','i',0};
3478 static const WCHAR szOriginalDatabase[] =
3479 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3480 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3485 /* copy the package locally */
3486 num = GetTickCount() & 0xffff;
3490 GetWindowsDirectoryW( windir, MAX_PATH );
3491 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3494 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3495 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3496 if (handle != INVALID_HANDLE_VALUE)
3498 CloseHandle(handle);
3501 if (GetLastError() != ERROR_FILE_EXISTS &&
3502 GetLastError() != ERROR_SHARING_VIOLATION)
3504 if (!(++num & 0xffff)) num = 1;
3505 sprintfW(packagefile,fmt,num);
3506 } while (num != start);
3508 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3509 create_full_pathW(path);
3511 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3513 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3514 r = CopyFileW( msiFilePath, packagefile, FALSE);
3515 msi_free( msiFilePath );
3519 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3520 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3521 return ERROR_FUNCTION_FAILED;
3524 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3525 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3526 return ERROR_SUCCESS;
3529 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3531 LPWSTR prop, val, key;
3532 static const LPCSTR propval[] = {
3533 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3534 "ARPCONTACT", "Contact",
3535 "ARPCOMMENTS", "Comments",
3536 "ProductName", "DisplayName",
3537 "ProductVersion", "DisplayVersion",
3538 "ARPHELPLINK", "HelpLink",
3539 "ARPHELPTELEPHONE", "HelpTelephone",
3540 "ARPINSTALLLOCATION", "InstallLocation",
3541 "SourceDir", "InstallSource",
3542 "Manufacturer", "Publisher",
3543 "ARPREADME", "Readme",
3545 "ARPURLINFOABOUT", "URLInfoAbout",
3546 "ARPURLUPDATEINFO", "URLUpdateInfo",
3549 const LPCSTR *p = propval;
3553 prop = strdupAtoW( *p++ );
3554 key = strdupAtoW( *p++ );
3555 val = msi_dup_property( package, prop );
3556 msi_reg_set_val_str( hkey, key, val );
3561 return ERROR_SUCCESS;
3564 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3567 LPWSTR buffer = NULL;
3570 static const WCHAR szWindowsInstaller[] =
3571 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3572 static const WCHAR szUpgradeCode[] =
3573 {'U','p','g','r','a','d','e','C','o','d','e',0};
3574 static const WCHAR modpath_fmt[] =
3575 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3576 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3577 static const WCHAR szModifyPath[] =
3578 {'M','o','d','i','f','y','P','a','t','h',0};
3579 static const WCHAR szUninstallString[] =
3580 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3581 static const WCHAR szEstimatedSize[] =
3582 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3583 static const WCHAR szProductLanguage[] =
3584 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3585 static const WCHAR szProductVersion[] =
3586 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3589 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3590 LPWSTR upgrade_code;
3593 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3594 if (rc != ERROR_SUCCESS)
3597 /* dump all the info i can grab */
3598 /* FIXME: Flesh out more information */
3600 msi_write_uninstall_property_vals( package, hkey );
3602 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3604 msi_make_package_local( package, hkey );
3606 /* do ModifyPath and UninstallString */
3607 size = deformat_string(package,modpath_fmt,&buffer);
3608 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3609 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3612 /* FIXME: Write real Estimated Size when we have it */
3613 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3615 GetLocalTime(&systime);
3616 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3617 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3619 langid = msi_get_property_int( package, szProductLanguage, 0 );
3620 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3622 buffer = msi_dup_property( package, szProductVersion );
3625 DWORD verdword = msi_version_str_to_dword(buffer);
3627 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3628 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3629 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3633 /* Handle Upgrade Codes */
3634 upgrade_code = msi_dup_property( package, szUpgradeCode );
3639 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3640 squash_guid(package->ProductCode,squashed);
3641 msi_reg_set_val_str( hkey2, squashed, NULL );
3643 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3644 squash_guid(package->ProductCode,squashed);
3645 msi_reg_set_val_str( hkey2, squashed, NULL );
3648 msi_free(upgrade_code);
3653 /* FIXME: call ui_actiondata */
3655 return ERROR_SUCCESS;
3658 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3660 return execute_script(package,INSTALL_SCRIPT);
3663 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3667 /* turn off scheduleing */
3668 package->script->CurrentlyScripting= FALSE;
3670 /* first do the same as an InstallExecute */
3671 rc = ACTION_InstallExecute(package);
3672 if (rc != ERROR_SUCCESS)
3675 /* then handle Commit Actions */
3676 rc = execute_script(package,COMMIT_SCRIPT);
3681 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3683 static const WCHAR RunOnce[] = {
3684 'S','o','f','t','w','a','r','e','\\',
3685 'M','i','c','r','o','s','o','f','t','\\',
3686 'W','i','n','d','o','w','s','\\',
3687 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3688 'R','u','n','O','n','c','e',0};
3689 static const WCHAR InstallRunOnce[] = {
3690 'S','o','f','t','w','a','r','e','\\',
3691 'M','i','c','r','o','s','o','f','t','\\',
3692 'W','i','n','d','o','w','s','\\',
3693 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3694 'I','n','s','t','a','l','l','e','r','\\',
3695 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3697 static const WCHAR msiexec_fmt[] = {
3699 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3700 '\"','%','s','\"',0};
3701 static const WCHAR install_fmt[] = {
3702 '/','I',' ','\"','%','s','\"',' ',
3703 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3704 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3705 WCHAR buffer[256], sysdir[MAX_PATH];
3707 WCHAR squished_pc[100];
3709 squash_guid(package->ProductCode,squished_pc);
3711 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3712 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3713 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3716 msi_reg_set_val_str( hkey, squished_pc, buffer );
3719 TRACE("Reboot command %s\n",debugstr_w(buffer));
3721 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3722 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3724 msi_reg_set_val_str( hkey, squished_pc, buffer );
3727 return ERROR_INSTALL_SUSPEND;
3730 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3735 * we are currently doing what should be done here in the top level Install
3736 * however for Adminastrative and uninstalls this step will be needed
3738 if (!package->PackagePath)
3739 return ERROR_SUCCESS;
3741 attrib = GetFileAttributesW(package->PackagePath);
3742 if (attrib == INVALID_FILE_ATTRIBUTES)
3748 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3749 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3750 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3751 if (rc == ERROR_MORE_DATA)
3753 prompt = msi_alloc(size * sizeof(WCHAR));
3754 MsiSourceListGetInfoW(package->ProductCode, NULL,
3755 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3756 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3759 prompt = strdupW(package->PackagePath);
3761 msg = generate_error_string(package,1302,1,prompt);
3762 while(attrib == INVALID_FILE_ATTRIBUTES)
3764 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3767 rc = ERROR_INSTALL_USEREXIT;
3770 attrib = GetFileAttributesW(package->PackagePath);
3776 return ERROR_SUCCESS;
3781 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3788 static const WCHAR szPropKeys[][80] =
3790 {'P','r','o','d','u','c','t','I','D',0},
3791 {'U','S','E','R','N','A','M','E',0},
3792 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3796 static const WCHAR szRegKeys[][80] =
3798 {'P','r','o','d','u','c','t','I','D',0},
3799 {'R','e','g','O','w','n','e','r',0},
3800 {'R','e','g','C','o','m','p','a','n','y',0},
3804 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3806 return ERROR_SUCCESS;
3808 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3809 if (rc != ERROR_SUCCESS)
3812 for( i = 0; szPropKeys[i][0]; i++ )
3814 buffer = msi_dup_property( package, szPropKeys[i] );
3815 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3820 msi_free(productid);
3823 /* FIXME: call ui_actiondata */
3825 return ERROR_SUCCESS;
3829 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3833 package->script->InWhatSequence |= SEQUENCE_EXEC;
3834 rc = ACTION_ProcessExecSequence(package,FALSE);
3840 * Code based off of code located here
3841 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3843 * Using string index 4 (full font name) instead of 1 (family name)
3845 static LPWSTR load_ttfname_from(LPCWSTR filename)
3851 typedef struct _tagTT_OFFSET_TABLE{
3852 USHORT uMajorVersion;
3853 USHORT uMinorVersion;
3854 USHORT uNumOfTables;
3855 USHORT uSearchRange;
3856 USHORT uEntrySelector;
3860 typedef struct _tagTT_TABLE_DIRECTORY{
3861 char szTag[4]; /* table name */
3862 ULONG uCheckSum; /* Check sum */
3863 ULONG uOffset; /* Offset from beginning of file */
3864 ULONG uLength; /* length of the table in bytes */
3865 }TT_TABLE_DIRECTORY;
3867 typedef struct _tagTT_NAME_TABLE_HEADER{
3868 USHORT uFSelector; /* format selector. Always 0 */
3869 USHORT uNRCount; /* Name Records count */
3870 USHORT uStorageOffset; /* Offset for strings storage,
3871 * from start of the table */
3872 }TT_NAME_TABLE_HEADER;
3874 typedef struct _tagTT_NAME_RECORD{
3879 USHORT uStringLength;
3880 USHORT uStringOffset; /* from start of storage area */
3883 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3884 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3886 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3887 FILE_ATTRIBUTE_NORMAL, 0 );
3888 if (handle != INVALID_HANDLE_VALUE)
3890 TT_TABLE_DIRECTORY tblDir;
3891 BOOL bFound = FALSE;
3892 TT_OFFSET_TABLE ttOffsetTable;
3895 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3896 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3897 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3898 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3900 if (ttOffsetTable.uMajorVersion != 1 ||
3901 ttOffsetTable.uMinorVersion != 0)
3904 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3906 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3907 if (strncmp(tblDir.szTag,"name",4)==0)
3910 tblDir.uLength = SWAPLONG(tblDir.uLength);
3911 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3918 TT_NAME_TABLE_HEADER ttNTHeader;
3919 TT_NAME_RECORD ttRecord;
3921 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3922 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3925 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3926 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3928 for(i=0; i<ttNTHeader.uNRCount; i++)
3930 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3931 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3932 /* 4 is the Full Font Name */
3933 if(ttRecord.uNameID == 4)
3937 static LPCSTR tt = " (TrueType)";
3939 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3940 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3941 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3942 SetFilePointer(handle, tblDir.uOffset +
3943 ttRecord.uStringOffset +
3944 ttNTHeader.uStorageOffset,
3946 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3947 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3948 if (strlen(buf) > 0)
3951 ret = strdupAtoW(buf);
3957 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3961 CloseHandle(handle);
3964 ERR("Unable to open font file %s\n", debugstr_w(filename));
3966 TRACE("Returning fontname %s\n",debugstr_w(ret));
3970 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3972 MSIPACKAGE *package = (MSIPACKAGE*)param;
3976 static const WCHAR regfont1[] =
3977 {'S','o','f','t','w','a','r','e','\\',
3978 'M','i','c','r','o','s','o','f','t','\\',
3979 'W','i','n','d','o','w','s',' ','N','T','\\',
3980 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3981 'F','o','n','t','s',0};
3982 static const WCHAR regfont2[] =
3983 {'S','o','f','t','w','a','r','e','\\',
3984 'M','i','c','r','o','s','o','f','t','\\',
3985 'W','i','n','d','o','w','s','\\',
3986 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3987 'F','o','n','t','s',0};
3993 filename = MSI_RecordGetString( row, 1 );
3994 file = get_loaded_file( package, filename );
3997 ERR("Unable to load file\n");
3998 return ERROR_SUCCESS;
4001 /* check to make sure that component is installed */
4002 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
4004 TRACE("Skipping: Component not scheduled for install\n");
4005 return ERROR_SUCCESS;
4008 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
4009 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
4011 if (MSI_RecordIsNull(row,2))
4012 name = load_ttfname_from( file->TargetPath );
4014 name = msi_dup_record_field(row,2);
4018 msi_reg_set_val_str( hkey1, name, file->FileName );
4019 msi_reg_set_val_str( hkey2, name, file->FileName );
4027 uirow = MSI_CreateRecord( 1 );
4028 uipath = strdupW( file->TargetPath );
4029 p = strrchrW(uipath,'\\');
4032 MSI_RecordSetStringW( uirow, 1, p );
4033 ui_actiondata( package, szRegisterFonts, uirow);
4034 msiobj_release( &uirow->hdr );
4036 /* FIXME: call ui_progress? */
4038 return ERROR_SUCCESS;
4041 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4045 static const WCHAR ExecSeqQuery[] =
4046 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4047 '`','F','o','n','t','`',0};
4049 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4050 if (rc != ERROR_SUCCESS)
4052 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4053 return ERROR_SUCCESS;
4056 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4057 msiobj_release(&view->hdr);
4059 return ERROR_SUCCESS;
4062 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4064 MSIPACKAGE *package = (MSIPACKAGE*)param;
4065 LPCWSTR compgroupid=NULL;
4066 LPCWSTR feature=NULL;
4067 LPCWSTR text = NULL;
4068 LPCWSTR qualifier = NULL;
4069 LPCWSTR component = NULL;
4070 LPWSTR advertise = NULL;
4071 LPWSTR output = NULL;
4073 UINT rc = ERROR_SUCCESS;
4078 component = MSI_RecordGetString(rec,3);
4079 comp = get_loaded_component(package,component);
4081 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4082 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4083 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4085 TRACE("Skipping: Component %s not scheduled for install\n",
4086 debugstr_w(component));
4088 return ERROR_SUCCESS;
4091 compgroupid = MSI_RecordGetString(rec,1);
4092 qualifier = MSI_RecordGetString(rec,2);
4094 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4095 if (rc != ERROR_SUCCESS)
4098 text = MSI_RecordGetString(rec,4);
4099 feature = MSI_RecordGetString(rec,5);
4101 advertise = create_component_advertise_string(package, comp, feature);
4103 sz = strlenW(advertise);
4106 sz += lstrlenW(text);
4109 sz *= sizeof(WCHAR);
4111 output = msi_alloc_zero(sz);
4112 strcpyW(output,advertise);
4113 msi_free(advertise);
4116 strcatW(output,text);
4118 msi_reg_set_val_multi_str( hkey, qualifier, output );
4125 uirow = MSI_CreateRecord( 2 );
4126 MSI_RecordSetStringW( uirow, 1, compgroupid );
4127 MSI_RecordSetStringW( uirow, 2, qualifier);
4128 ui_actiondata( package, szPublishComponents, uirow);
4129 msiobj_release( &uirow->hdr );
4130 /* FIXME: call ui_progress? */
4136 * At present I am ignorning the advertised components part of this and only
4137 * focusing on the qualified component sets
4139 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4143 static const WCHAR ExecSeqQuery[] =
4144 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4145 '`','P','u','b','l','i','s','h',
4146 'C','o','m','p','o','n','e','n','t','`',0};
4148 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4149 if (rc != ERROR_SUCCESS)
4150 return ERROR_SUCCESS;
4152 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4153 msiobj_release(&view->hdr);
4158 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4159 LPCSTR action, LPCWSTR table )
4161 static const WCHAR query[] = {
4162 'S','E','L','E','C','T',' ','*',' ',
4163 'F','R','O','M',' ','`','%','s','`',0 };
4164 MSIQUERY *view = NULL;
4168 r = MSI_OpenQuery( package->db, &view, query, table );
4169 if (r == ERROR_SUCCESS)
4171 r = MSI_IterateRecords(view, &count, NULL, package);
4172 msiobj_release(&view->hdr);
4176 FIXME("%s -> %lu ignored %s table values\n",
4177 action, count, debugstr_w(table));
4179 return ERROR_SUCCESS;
4182 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4184 TRACE("%p\n", package);
4185 return ERROR_SUCCESS;
4188 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4190 static const WCHAR table[] =
4191 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4192 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4195 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4197 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4198 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4201 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4203 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4204 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4207 static UINT ACTION_BindImage( MSIPACKAGE *package )
4209 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4210 return msi_unimplemented_action_stub( package, "BindImage", table );
4213 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4215 static const WCHAR table[] = {
4216 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4217 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4220 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4222 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4223 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4226 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4228 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4229 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4232 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4234 static const WCHAR table[] = {
4235 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4236 return msi_unimplemented_action_stub( package, "InstallServices", table );
4239 static UINT ACTION_StartServices( MSIPACKAGE *package )
4241 static const WCHAR table[] = {
4242 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4243 return msi_unimplemented_action_stub( package, "StartServices", table );
4246 static UINT ACTION_StopServices( MSIPACKAGE *package )
4248 static const WCHAR table[] = {
4249 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4250 return msi_unimplemented_action_stub( package, "StopServices", table );
4253 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4255 static const WCHAR table[] = {
4256 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4257 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4260 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4262 static const WCHAR table[] = {
4263 'E','n','v','i','r','o','n','m','e','n','t',0 };
4264 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4267 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4269 static const WCHAR table[] = {
4270 'E','n','v','i','r','o','n','m','e','n','t',0 };
4271 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4274 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4276 static const WCHAR table[] = {
4277 'M','s','i','A','s','s','e','m','b','l','y',0 };
4278 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4281 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4283 static const WCHAR table[] = {
4284 'M','s','i','A','s','s','e','m','b','l','y',0 };
4285 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4288 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4290 static const WCHAR table[] = { 'F','o','n','t',0 };
4291 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4294 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4296 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4297 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4300 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4302 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4303 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4306 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4308 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4309 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4312 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4314 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4315 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4318 static struct _actions StandardActions[] = {
4319 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4320 { szAppSearch, ACTION_AppSearch },
4321 { szBindImage, ACTION_BindImage },
4322 { szCCPSearch, ACTION_CCPSearch},
4323 { szCostFinalize, ACTION_CostFinalize },
4324 { szCostInitialize, ACTION_CostInitialize },
4325 { szCreateFolders, ACTION_CreateFolders },
4326 { szCreateShortcuts, ACTION_CreateShortcuts },
4327 { szDeleteServices, ACTION_DeleteServices },
4328 { szDisableRollback, NULL},
4329 { szDuplicateFiles, ACTION_DuplicateFiles },
4330 { szExecuteAction, ACTION_ExecuteAction },
4331 { szFileCost, ACTION_FileCost },
4332 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4333 { szForceReboot, ACTION_ForceReboot },
4334 { szInstallAdminPackage, NULL},
4335 { szInstallExecute, ACTION_InstallExecute },
4336 { szInstallExecuteAgain, ACTION_InstallExecute },
4337 { szInstallFiles, ACTION_InstallFiles},
4338 { szInstallFinalize, ACTION_InstallFinalize },
4339 { szInstallInitialize, ACTION_InstallInitialize },
4340 { szInstallSFPCatalogFile, NULL},
4341 { szInstallValidate, ACTION_InstallValidate },
4342 { szIsolateComponents, ACTION_IsolateComponents },
4343 { szLaunchConditions, ACTION_LaunchConditions },
4344 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4345 { szMoveFiles, ACTION_MoveFiles },
4346 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4347 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4348 { szInstallODBC, NULL},
4349 { szInstallServices, ACTION_InstallServices },
4350 { szPatchFiles, ACTION_PatchFiles },
4351 { szProcessComponents, ACTION_ProcessComponents },
4352 { szPublishComponents, ACTION_PublishComponents },
4353 { szPublishFeatures, ACTION_PublishFeatures },
4354 { szPublishProduct, ACTION_PublishProduct },
4355 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4356 { szRegisterComPlus, ACTION_RegisterComPlus},
4357 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4358 { szRegisterFonts, ACTION_RegisterFonts },
4359 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4360 { szRegisterProduct, ACTION_RegisterProduct },
4361 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4362 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4363 { szRegisterUser, ACTION_RegisterUser},
4364 { szRemoveDuplicateFiles, NULL},
4365 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4366 { szRemoveExistingProducts, NULL},
4367 { szRemoveFiles, ACTION_RemoveFiles},
4368 { szRemoveFolders, NULL},
4369 { szRemoveIniValues, ACTION_RemoveIniValues },
4370 { szRemoveODBC, NULL},
4371 { szRemoveRegistryValues, NULL},
4372 { szRemoveShortcuts, NULL},
4373 { szResolveSource, ACTION_ResolveSource},
4374 { szRMCCPSearch, ACTION_RMCCPSearch},
4375 { szScheduleReboot, NULL},
4376 { szSelfRegModules, ACTION_SelfRegModules },
4377 { szSelfUnregModules, ACTION_SelfUnregModules },
4378 { szSetODBCFolders, NULL},
4379 { szStartServices, ACTION_StartServices },
4380 { szStopServices, ACTION_StopServices },
4381 { szUnpublishComponents, NULL},
4382 { szUnpublishFeatures, NULL},
4383 { szUnregisterClassInfo, NULL},
4384 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4385 { szUnregisterExtensionInfo, NULL},
4386 { szUnregisterFonts, ACTION_UnregisterFonts },
4387 { szUnregisterMIMEInfo, NULL},
4388 { szUnregisterProgIdInfo, NULL},
4389 { szUnregisterTypeLibraries, NULL},
4390 { szValidateProductID, NULL},
4391 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4392 { szWriteIniValues, ACTION_WriteIniValues },
4393 { szWriteRegistryValues, ACTION_WriteRegistryValues},