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 case msidbComponentAttributesOptional:
1126 comp->Action = INSTALLSTATE_LOCAL;
1127 comp->ActionRequest = INSTALLSTATE_LOCAL;
1129 case msidbComponentAttributesSourceOnly:
1130 comp->Action = INSTALLSTATE_SOURCE;
1131 comp->ActionRequest = INSTALLSTATE_SOURCE;
1134 comp->Action = INSTALLSTATE_UNKNOWN;
1135 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1138 return ERROR_SUCCESS;
1141 static UINT load_all_components( MSIPACKAGE *package )
1143 static const WCHAR query[] = {
1144 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1145 '`','C','o','m','p','o','n','e','n','t','`',0 };
1149 if (!list_empty(&package->components))
1150 return ERROR_SUCCESS;
1152 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1153 if (r != ERROR_SUCCESS)
1156 r = MSI_IterateRecords(view, NULL, load_component, package);
1157 msiobj_release(&view->hdr);
1162 MSIPACKAGE *package;
1163 MSIFEATURE *feature;
1166 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1170 cl = msi_alloc( sizeof (*cl) );
1172 return ERROR_NOT_ENOUGH_MEMORY;
1173 cl->component = comp;
1174 list_add_tail( &feature->Components, &cl->entry );
1176 return ERROR_SUCCESS;
1179 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1181 _ilfs* ilfs= (_ilfs*)param;
1185 component = MSI_RecordGetString(row,1);
1187 /* check to see if the component is already loaded */
1188 comp = get_loaded_component( ilfs->package, component );
1191 ERR("unknown component %s\n", debugstr_w(component));
1192 return ERROR_FUNCTION_FAILED;
1195 add_feature_component( ilfs->feature, comp );
1196 comp->Enabled = TRUE;
1198 return ERROR_SUCCESS;
1201 static UINT load_feature(MSIRECORD * row, LPVOID param)
1203 MSIPACKAGE* package = (MSIPACKAGE*)param;
1204 MSIFEATURE* feature;
1205 static const WCHAR Query1[] =
1206 {'S','E','L','E','C','T',' ',
1207 '`','C','o','m','p','o','n','e','n','t','_','`',
1208 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1209 'C','o','m','p','o','n','e','n','t','s','`',' ',
1210 'W','H','E','R','E',' ',
1211 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1216 /* fill in the data */
1218 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1220 return ERROR_NOT_ENOUGH_MEMORY;
1222 list_init( &feature->Components );
1224 feature->Feature = msi_dup_record_field( row, 1 );
1226 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1228 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1229 feature->Title = msi_dup_record_field( row, 3 );
1230 feature->Description = msi_dup_record_field( row, 4 );
1232 if (!MSI_RecordIsNull(row,5))
1233 feature->Display = MSI_RecordGetInteger(row,5);
1235 feature->Level= MSI_RecordGetInteger(row,6);
1236 feature->Directory = msi_dup_record_field( row, 7 );
1237 feature->Attributes = MSI_RecordGetInteger(row,8);
1239 feature->Installed = INSTALLSTATE_ABSENT;
1240 feature->Action = INSTALLSTATE_UNKNOWN;
1241 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1243 list_add_tail( &package->features, &feature->entry );
1245 /* load feature components */
1247 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1248 if (rc != ERROR_SUCCESS)
1249 return ERROR_SUCCESS;
1251 ilfs.package = package;
1252 ilfs.feature = feature;
1254 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1255 msiobj_release(&view->hdr);
1257 return ERROR_SUCCESS;
1260 static UINT load_all_features( MSIPACKAGE *package )
1262 static const WCHAR query[] = {
1263 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1264 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1265 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1269 if (!list_empty(&package->features))
1270 return ERROR_SUCCESS;
1272 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1273 if (r != ERROR_SUCCESS)
1276 r = MSI_IterateRecords( view, NULL, load_feature, package );
1277 msiobj_release( &view->hdr );
1281 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1292 static UINT load_file(MSIRECORD *row, LPVOID param)
1294 MSIPACKAGE* package = (MSIPACKAGE*)param;
1298 /* fill in the data */
1300 file = msi_alloc_zero( sizeof (MSIFILE) );
1302 return ERROR_NOT_ENOUGH_MEMORY;
1304 file->File = msi_dup_record_field( row, 1 );
1306 component = MSI_RecordGetString( row, 2 );
1307 file->Component = get_loaded_component( package, component );
1309 if (!file->Component)
1310 ERR("Unfound Component %s\n",debugstr_w(component));
1312 file->FileName = msi_dup_record_field( row, 3 );
1313 reduce_to_longfilename( file->FileName );
1315 file->ShortName = msi_dup_record_field( row, 3 );
1316 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1318 file->FileSize = MSI_RecordGetInteger( row, 4 );
1319 file->Version = msi_dup_record_field( row, 5 );
1320 file->Language = msi_dup_record_field( row, 6 );
1321 file->Attributes = MSI_RecordGetInteger( row, 7 );
1322 file->Sequence = MSI_RecordGetInteger( row, 8 );
1324 file->state = msifs_invalid;
1326 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1328 list_add_tail( &package->files, &file->entry );
1330 return ERROR_SUCCESS;
1333 static UINT load_all_files(MSIPACKAGE *package)
1337 static const WCHAR Query[] =
1338 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1339 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1340 '`','S','e','q','u','e','n','c','e','`', 0};
1342 if (!list_empty(&package->files))
1343 return ERROR_SUCCESS;
1345 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1346 if (rc != ERROR_SUCCESS)
1347 return ERROR_SUCCESS;
1349 rc = MSI_IterateRecords(view, NULL, load_file, package);
1350 msiobj_release(&view->hdr);
1352 return ERROR_SUCCESS;
1357 * I am not doing any of the costing functionality yet.
1358 * Mostly looking at doing the Component and Feature loading
1360 * The native MSI does A LOT of modification to tables here. Mostly adding
1361 * a lot of temporary columns to the Feature and Component tables.
1363 * note: Native msi also tracks the short filename. But I am only going to
1364 * track the long ones. Also looking at this directory table
1365 * it appears that the directory table does not get the parents
1366 * resolved base on property only based on their entries in the
1369 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1371 static const WCHAR szCosting[] =
1372 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1373 static const WCHAR szZero[] = { '0', 0 };
1375 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1376 return ERROR_SUCCESS;
1378 MSI_SetPropertyW(package, szCosting, szZero);
1379 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1381 load_all_components( package );
1382 load_all_features( package );
1383 load_all_files( package );
1385 return ERROR_SUCCESS;
1388 static UINT execute_script(MSIPACKAGE *package, UINT script )
1391 UINT rc = ERROR_SUCCESS;
1393 TRACE("Executing Script %i\n",script);
1395 if (!package->script)
1397 ERR("no script!\n");
1398 return ERROR_FUNCTION_FAILED;
1401 for (i = 0; i < package->script->ActionCount[script]; i++)
1404 action = package->script->Actions[script][i];
1405 ui_actionstart(package, action);
1406 TRACE("Executing Action (%s)\n",debugstr_w(action));
1407 rc = ACTION_PerformAction(package, action, TRUE);
1408 msi_free(package->script->Actions[script][i]);
1409 if (rc != ERROR_SUCCESS)
1412 msi_free(package->script->Actions[script]);
1414 package->script->ActionCount[script] = 0;
1415 package->script->Actions[script] = NULL;
1419 static UINT ACTION_FileCost(MSIPACKAGE *package)
1421 return ERROR_SUCCESS;
1424 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1426 static const WCHAR Query[] =
1427 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1428 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1429 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1430 ' ','=',' ','\'','%','s','\'',
1432 static const WCHAR szDot[] = { '.',0 };
1433 static WCHAR szEmpty[] = { 0 };
1434 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1439 TRACE("Looking for dir %s\n",debugstr_w(dir));
1441 folder = get_loaded_folder( package, dir );
1445 TRACE("Working to load %s\n",debugstr_w(dir));
1447 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1451 folder->Directory = strdupW(dir);
1453 row = MSI_QueryGetRecord(package->db, Query, dir);
1457 p = msi_dup_record_field(row, 3);
1459 /* split src and target dir */
1461 src_short = folder_split_path( p, ':' );
1463 /* split the long and short paths */
1464 tgt_long = folder_split_path( tgt_short, '|' );
1465 src_long = folder_split_path( src_short, '|' );
1467 /* check for no-op dirs */
1468 if (!lstrcmpW(szDot, tgt_short))
1469 tgt_short = szEmpty;
1470 if (!lstrcmpW(szDot, src_short))
1471 src_short = szEmpty;
1474 tgt_long = tgt_short;
1477 src_short = tgt_short;
1478 src_long = tgt_long;
1482 src_long = src_short;
1484 /* FIXME: use the target short path too */
1485 folder->TargetDefault = strdupW(tgt_long);
1486 folder->SourceShortPath = strdupW(src_short);
1487 folder->SourceLongPath = strdupW(src_long);
1490 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1491 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1492 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1494 parent = MSI_RecordGetString(row, 2);
1497 folder->Parent = load_folder( package, parent );
1498 if ( folder->Parent )
1499 TRACE("loaded parent %p %s\n", folder->Parent,
1500 debugstr_w(folder->Parent->Directory));
1502 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1505 folder->Property = msi_dup_property( package, dir );
1507 msiobj_release(&row->hdr);
1509 list_add_tail( &package->folders, &folder->entry );
1511 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1516 /* scan for and update current install states */
1517 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1520 MSIFEATURE *feature;
1522 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1525 res = MsiGetComponentPathW( package->ProductCode,
1526 comp->ComponentId, NULL, NULL);
1528 res = INSTALLSTATE_ABSENT;
1529 comp->Installed = res;
1532 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1535 INSTALLSTATE res = -10;
1537 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1539 comp= cl->component;
1542 res = comp->Installed;
1545 if (res == comp->Installed)
1548 if (res != comp->Installed)
1549 res = INSTALLSTATE_INCOMPLETE;
1552 feature->Installed = res;
1556 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1559 static const WCHAR all[]={'A','L','L',0};
1561 MSIFEATURE *feature;
1563 override = msi_dup_property( package, property );
1567 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1569 if (strcmpiW(override,all)==0)
1571 feature->ActionRequest= state;
1572 feature->Action = state;
1576 LPWSTR ptr = override;
1577 LPWSTR ptr2 = strchrW(override,',');
1581 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1582 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1584 feature->ActionRequest= state;
1585 feature->Action = state;
1591 ptr2 = strchrW(ptr,',');
1603 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1606 static const WCHAR szlevel[] =
1607 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1608 static const WCHAR szAddLocal[] =
1609 {'A','D','D','L','O','C','A','L',0};
1610 static const WCHAR szRemove[] =
1611 {'R','E','M','O','V','E',0};
1612 static const WCHAR szReinstall[] =
1613 {'R','E','I','N','S','T','A','L','L',0};
1614 BOOL override = FALSE;
1615 MSICOMPONENT* component;
1616 MSIFEATURE *feature;
1619 /* I do not know if this is where it should happen.. but */
1621 TRACE("Checking Install Level\n");
1623 install_level = msi_get_property_int( package, szlevel, 1 );
1625 /* ok hereis the _real_ rub
1626 * all these activation/deactivation things happen in order and things
1627 * later on the list override things earlier on the list.
1628 * 1) INSTALLLEVEL processing
1638 * 11) FILEADDDEFAULT
1639 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1640 * ignored for all the features. seems strange, especially since it is not
1641 * documented anywhere, but it is how it works.
1643 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1644 * REMOVE are the big ones, since we don't handle administrative installs
1647 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1648 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1649 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1655 BOOL feature_state = ((feature->Level > 0) &&
1656 (feature->Level <= install_level));
1658 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1660 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1662 feature->ActionRequest = INSTALLSTATE_SOURCE;
1663 feature->Action = INSTALLSTATE_SOURCE;
1665 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1667 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1668 feature->Action = INSTALLSTATE_ADVERTISED;
1672 feature->ActionRequest = INSTALLSTATE_LOCAL;
1673 feature->Action = INSTALLSTATE_LOCAL;
1680 /* set the Preselected Property */
1681 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1682 static const WCHAR szOne[] = { '1', 0 };
1684 MSI_SetPropertyW(package,szPreselected,szOne);
1688 * now we want to enable or disable components base on feature
1691 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1695 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1696 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1697 feature->ActionRequest);
1699 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1701 component = cl->component;
1703 if (!component->Enabled)
1705 component->Action = INSTALLSTATE_UNKNOWN;
1706 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1710 if (feature->Action == INSTALLSTATE_LOCAL)
1712 component->Action = INSTALLSTATE_LOCAL;
1713 component->ActionRequest = INSTALLSTATE_LOCAL;
1715 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1717 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1718 (component->Action == INSTALLSTATE_ABSENT) ||
1719 (component->Action == INSTALLSTATE_ADVERTISED))
1722 component->Action = INSTALLSTATE_SOURCE;
1723 component->ActionRequest = INSTALLSTATE_SOURCE;
1726 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1728 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1729 (component->Action == INSTALLSTATE_ABSENT))
1732 component->Action = INSTALLSTATE_ADVERTISED;
1733 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1736 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1738 if (component->Action == INSTALLSTATE_UNKNOWN)
1740 component->Action = INSTALLSTATE_ABSENT;
1741 component->ActionRequest = INSTALLSTATE_ABSENT;
1748 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1750 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1751 debugstr_w(component->Component), component->Installed,
1752 component->Action, component->ActionRequest);
1756 return ERROR_SUCCESS;
1759 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1761 MSIPACKAGE *package = (MSIPACKAGE*)param;
1765 name = MSI_RecordGetString(row,1);
1767 /* This helper function now does ALL the work */
1768 TRACE("Dir %s ...\n",debugstr_w(name));
1769 load_folder(package,name);
1770 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1771 TRACE("resolves to %s\n",debugstr_w(path));
1774 return ERROR_SUCCESS;
1777 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1779 MSIPACKAGE *package = (MSIPACKAGE*)param;
1781 MSIFEATURE *feature;
1783 name = MSI_RecordGetString( row, 1 );
1785 feature = get_loaded_feature( package, name );
1787 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1791 Condition = MSI_RecordGetString(row,3);
1793 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1795 int level = MSI_RecordGetInteger(row,2);
1796 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1797 feature->Level = level;
1800 return ERROR_SUCCESS;
1805 * A lot is done in this function aside from just the costing.
1806 * The costing needs to be implemented at some point but for now I am going
1807 * to focus on the directory building
1810 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1812 static const WCHAR ExecSeqQuery[] =
1813 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1814 '`','D','i','r','e','c','t','o','r','y','`',0};
1815 static const WCHAR ConditionQuery[] =
1816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1817 '`','C','o','n','d','i','t','i','o','n','`',0};
1818 static const WCHAR szCosting[] =
1819 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1820 static const WCHAR szlevel[] =
1821 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1822 static const WCHAR szOne[] = { '1', 0 };
1829 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1830 return ERROR_SUCCESS;
1832 TRACE("Building Directory properties\n");
1834 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1835 if (rc == ERROR_SUCCESS)
1837 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1839 msiobj_release(&view->hdr);
1842 TRACE("File calculations\n");
1844 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1846 MSICOMPONENT* comp = file->Component;
1852 /* calculate target */
1853 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1855 msi_free(file->TargetPath);
1857 TRACE("file %s is named %s\n",
1858 debugstr_w(file->File),debugstr_w(file->FileName));
1860 file->TargetPath = build_directory_name(2, p, file->FileName);
1864 TRACE("file %s resolves to %s\n",
1865 debugstr_w(file->File),debugstr_w(file->TargetPath));
1867 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1869 file->state = msifs_missing;
1870 comp->Cost += file->FileSize;
1880 static WCHAR name[] = {'\\',0};
1881 static const WCHAR name_fmt[] =
1882 {'%','u','.','%','u','.','%','u','.','%','u',0};
1883 WCHAR filever[0x100];
1884 VS_FIXEDFILEINFO *lpVer;
1886 TRACE("Version comparison..\n");
1887 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1888 version = msi_alloc(versize);
1889 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1891 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1893 sprintfW(filever,name_fmt,
1894 HIWORD(lpVer->dwFileVersionMS),
1895 LOWORD(lpVer->dwFileVersionMS),
1896 HIWORD(lpVer->dwFileVersionLS),
1897 LOWORD(lpVer->dwFileVersionLS));
1899 TRACE("new %s old %s\n", debugstr_w(file->Version),
1900 debugstr_w(filever));
1901 if (strcmpiW(filever,file->Version)<0)
1903 file->state = msifs_overwrite;
1904 /* FIXME: cost should be diff in size */
1905 comp->Cost += file->FileSize;
1908 file->state = msifs_present;
1912 file->state = msifs_present;
1915 TRACE("Evaluating Condition Table\n");
1917 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1918 if (rc == ERROR_SUCCESS)
1920 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1922 msiobj_release(&view->hdr);
1925 TRACE("Enabling or Disabling Components\n");
1926 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1928 if (comp->Condition)
1930 if (MSI_EvaluateConditionW(package,
1931 comp->Condition) == MSICONDITION_FALSE)
1933 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1934 comp->Enabled = FALSE;
1939 MSI_SetPropertyW(package,szCosting,szOne);
1940 /* set default run level if not set */
1941 level = msi_dup_property( package, szlevel );
1943 MSI_SetPropertyW(package,szlevel, szOne);
1946 ACTION_UpdateInstallStates(package);
1948 return MSI_SetFeatureStates(package);
1951 /* OK this value is "interpreted" and then formatted based on the
1952 first few characters */
1953 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1957 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1963 LPWSTR deformated = NULL;
1966 deformat_string(package, &value[2], &deformated);
1968 /* binary value type */
1972 *size = (strlenW(ptr)/2)+1;
1974 *size = strlenW(ptr)/2;
1976 data = msi_alloc(*size);
1982 /* if uneven pad with a zero in front */
1988 data[count] = (BYTE)strtol(byte,NULL,0);
1990 TRACE("Uneven byte count\n");
1998 data[count] = (BYTE)strtol(byte,NULL,0);
2001 msi_free(deformated);
2003 TRACE("Data %li bytes(%i)\n",*size,count);
2010 deformat_string(package, &value[1], &deformated);
2013 *size = sizeof(DWORD);
2014 data = msi_alloc(*size);
2020 if ( (*p < '0') || (*p > '9') )
2026 if (deformated[0] == '-')
2029 TRACE("DWORD %li\n",*(LPDWORD)data);
2031 msi_free(deformated);
2036 static const WCHAR szMulti[] = {'[','~',']',0};
2045 *type=REG_EXPAND_SZ;
2053 if (strstrW(value,szMulti))
2054 *type = REG_MULTI_SZ;
2056 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2061 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2063 MSIPACKAGE *package = (MSIPACKAGE*)param;
2064 static const WCHAR szHCR[] =
2065 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2066 'R','O','O','T','\\',0};
2067 static const WCHAR szHCU[] =
2068 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2069 'U','S','E','R','\\',0};
2070 static const WCHAR szHLM[] =
2071 {'H','K','E','Y','_','L','O','C','A','L','_',
2072 'M','A','C','H','I','N','E','\\',0};
2073 static const WCHAR szHU[] =
2074 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2076 LPSTR value_data = NULL;
2077 HKEY root_key, hkey;
2080 LPCWSTR szRoot, component, name, key, value;
2085 BOOL check_first = FALSE;
2088 ui_progress(package,2,0,0,0);
2095 component = MSI_RecordGetString(row, 6);
2096 comp = get_loaded_component(package,component);
2098 return ERROR_SUCCESS;
2100 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2102 TRACE("Skipping write due to disabled component %s\n",
2103 debugstr_w(component));
2105 comp->Action = comp->Installed;
2107 return ERROR_SUCCESS;
2110 comp->Action = INSTALLSTATE_LOCAL;
2112 name = MSI_RecordGetString(row, 4);
2113 if( MSI_RecordIsNull(row,5) && name )
2115 /* null values can have special meanings */
2116 if (name[0]=='-' && name[1] == 0)
2117 return ERROR_SUCCESS;
2118 else if ((name[0]=='+' && name[1] == 0) ||
2119 (name[0] == '*' && name[1] == 0))
2124 root = MSI_RecordGetInteger(row,2);
2125 key = MSI_RecordGetString(row, 3);
2127 /* get the root key */
2132 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2133 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2134 if (all_users && all_users[0] == '1')
2136 root_key = HKEY_LOCAL_MACHINE;
2141 root_key = HKEY_CURRENT_USER;
2144 msi_free(all_users);
2147 case 0: root_key = HKEY_CLASSES_ROOT;
2150 case 1: root_key = HKEY_CURRENT_USER;
2153 case 2: root_key = HKEY_LOCAL_MACHINE;
2156 case 3: root_key = HKEY_USERS;
2160 ERR("Unknown root %i\n",root);
2166 return ERROR_SUCCESS;
2168 deformat_string(package, key , &deformated);
2169 size = strlenW(deformated) + strlenW(szRoot) + 1;
2170 uikey = msi_alloc(size*sizeof(WCHAR));
2171 strcpyW(uikey,szRoot);
2172 strcatW(uikey,deformated);
2174 if (RegCreateKeyW( root_key, deformated, &hkey))
2176 ERR("Could not create key %s\n",debugstr_w(deformated));
2177 msi_free(deformated);
2179 return ERROR_SUCCESS;
2181 msi_free(deformated);
2183 value = MSI_RecordGetString(row,5);
2185 value_data = parse_value(package, value, &type, &size);
2188 static const WCHAR szEmpty[] = {0};
2189 value_data = (LPSTR)strdupW(szEmpty);
2194 deformat_string(package, name, &deformated);
2196 /* get the double nulls to terminate SZ_MULTI */
2197 if (type == REG_MULTI_SZ)
2198 size +=sizeof(WCHAR);
2202 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2204 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2209 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2210 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2212 TRACE("value %s of %s checked already exists\n",
2213 debugstr_w(deformated), debugstr_w(uikey));
2217 TRACE("Checked and setting value %s of %s\n",
2218 debugstr_w(deformated), debugstr_w(uikey));
2219 if (deformated || size)
2220 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2225 uirow = MSI_CreateRecord(3);
2226 MSI_RecordSetStringW(uirow,2,deformated);
2227 MSI_RecordSetStringW(uirow,1,uikey);
2230 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2232 MSI_RecordSetStringW(uirow,3,value);
2234 ui_actiondata(package,szWriteRegistryValues,uirow);
2235 msiobj_release( &uirow->hdr );
2237 msi_free(value_data);
2238 msi_free(deformated);
2241 return ERROR_SUCCESS;
2244 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2248 static const WCHAR ExecSeqQuery[] =
2249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2250 '`','R','e','g','i','s','t','r','y','`',0 };
2252 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2253 if (rc != ERROR_SUCCESS)
2254 return ERROR_SUCCESS;
2256 /* increment progress bar each time action data is sent */
2257 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2259 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2261 msiobj_release(&view->hdr);
2265 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2267 package->script->CurrentlyScripting = TRUE;
2269 return ERROR_SUCCESS;
2273 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2278 static const WCHAR q1[]=
2279 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2280 '`','R','e','g','i','s','t','r','y','`',0};
2283 MSIFEATURE *feature;
2286 TRACE("InstallValidate\n");
2288 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2289 if (rc == ERROR_SUCCESS)
2291 MSI_IterateRecords( view, &progress, NULL, package );
2292 msiobj_release( &view->hdr );
2293 total += progress * REG_PROGRESS_VALUE;
2296 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2297 total += COMPONENT_PROGRESS_VALUE;
2299 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2300 total += file->FileSize;
2302 ui_progress(package,0,total,0,0);
2304 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2306 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2307 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2308 feature->ActionRequest);
2311 return ERROR_SUCCESS;
2314 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2316 MSIPACKAGE* package = (MSIPACKAGE*)param;
2317 LPCWSTR cond = NULL;
2318 LPCWSTR message = NULL;
2319 static const WCHAR title[]=
2320 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2322 cond = MSI_RecordGetString(row,1);
2324 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2327 message = MSI_RecordGetString(row,2);
2328 deformat_string(package,message,&deformated);
2329 MessageBoxW(NULL,deformated,title,MB_OK);
2330 msi_free(deformated);
2331 return ERROR_FUNCTION_FAILED;
2334 return ERROR_SUCCESS;
2337 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2340 MSIQUERY * view = NULL;
2341 static const WCHAR ExecSeqQuery[] =
2342 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2343 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2345 TRACE("Checking launch conditions\n");
2347 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2348 if (rc != ERROR_SUCCESS)
2349 return ERROR_SUCCESS;
2351 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2352 msiobj_release(&view->hdr);
2357 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2361 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2363 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2365 MSIRECORD * row = 0;
2367 LPWSTR deformated,buffer,deformated_name;
2369 static const WCHAR ExecSeqQuery[] =
2370 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2371 '`','R','e','g','i','s','t','r','y','`',' ',
2372 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2373 ' ','=',' ' ,'\'','%','s','\'',0 };
2374 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2375 static const WCHAR fmt2[]=
2376 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2378 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2382 root = MSI_RecordGetInteger(row,2);
2383 key = MSI_RecordGetString(row, 3);
2384 name = MSI_RecordGetString(row, 4);
2385 deformat_string(package, key , &deformated);
2386 deformat_string(package, name, &deformated_name);
2388 len = strlenW(deformated) + 6;
2389 if (deformated_name)
2390 len+=strlenW(deformated_name);
2392 buffer = msi_alloc( len *sizeof(WCHAR));
2394 if (deformated_name)
2395 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2397 sprintfW(buffer,fmt,root,deformated);
2399 msi_free(deformated);
2400 msi_free(deformated_name);
2401 msiobj_release(&row->hdr);
2405 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2407 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2412 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2415 return strdupW( file->TargetPath );
2420 static HKEY openSharedDLLsKey(void)
2423 static const WCHAR path[] =
2424 {'S','o','f','t','w','a','r','e','\\',
2425 'M','i','c','r','o','s','o','f','t','\\',
2426 'W','i','n','d','o','w','s','\\',
2427 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2428 'S','h','a','r','e','d','D','L','L','s',0};
2430 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2434 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2439 DWORD sz = sizeof(count);
2442 hkey = openSharedDLLsKey();
2443 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2444 if (rc != ERROR_SUCCESS)
2450 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2454 hkey = openSharedDLLsKey();
2456 msi_reg_set_val_dword( hkey, path, count );
2458 RegDeleteValueW(hkey,path);
2464 * Return TRUE if the count should be written out and FALSE if not
2466 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2468 MSIFEATURE *feature;
2472 /* only refcount DLLs */
2473 if (comp->KeyPath == NULL ||
2474 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2475 comp->Attributes & msidbComponentAttributesODBCDataSource)
2479 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2480 write = (count > 0);
2482 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2486 /* increment counts */
2487 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2491 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2494 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2496 if ( cl->component == comp )
2501 /* decrement counts */
2502 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2506 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2509 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2511 if ( cl->component == comp )
2516 /* ref count all the files in the component */
2521 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2523 if (file->Component == comp)
2524 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2528 /* add a count for permenent */
2529 if (comp->Attributes & msidbComponentAttributesPermanent)
2532 comp->RefCount = count;
2535 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2539 * Ok further analysis makes me think that this work is
2540 * actually done in the PublishComponents and PublishFeatures
2541 * step, and not here. It appears like the keypath and all that is
2542 * resolved in this step, however actually written in the Publish steps.
2543 * But we will leave it here for now because it is unclear
2545 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2547 WCHAR squished_pc[GUID_SIZE];
2548 WCHAR squished_cc[GUID_SIZE];
2551 HKEY hkey=0,hkey2=0;
2553 /* writes the Component and Features values to the registry */
2555 rc = MSIREG_OpenComponents(&hkey);
2556 if (rc != ERROR_SUCCESS)
2559 squash_guid(package->ProductCode,squished_pc);
2560 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2562 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2566 ui_progress(package,2,0,0,0);
2567 if (!comp->ComponentId)
2570 squash_guid(comp->ComponentId,squished_cc);
2572 msi_free(comp->FullKeypath);
2573 comp->FullKeypath = resolve_keypath( package, comp );
2575 /* do the refcounting */
2576 ACTION_RefCountComponent( package, comp );
2578 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2579 debugstr_w(comp->Component),
2580 debugstr_w(squished_cc),
2581 debugstr_w(comp->FullKeypath),
2584 * Write the keypath out if the component is to be registered
2585 * and delete the key if the component is to be deregistered
2587 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2589 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2590 if (rc != ERROR_SUCCESS)
2593 if (!comp->FullKeypath)
2596 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2598 if (comp->Attributes & msidbComponentAttributesPermanent)
2600 static const WCHAR szPermKey[] =
2601 { '0','0','0','0','0','0','0','0','0','0','0','0',
2602 '0','0','0','0','0','0','0','0','0','0','0','0',
2603 '0','0','0','0','0','0','0','0',0 };
2605 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2611 uirow = MSI_CreateRecord(3);
2612 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2613 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2614 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2615 ui_actiondata(package,szProcessComponents,uirow);
2616 msiobj_release( &uirow->hdr );
2618 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2622 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2623 if (rc != ERROR_SUCCESS)
2626 RegDeleteValueW(hkey2,squished_pc);
2628 /* if the key is empty delete it */
2629 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2631 if (res == ERROR_NO_MORE_ITEMS)
2632 RegDeleteKeyW(hkey,squished_cc);
2635 uirow = MSI_CreateRecord(2);
2636 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2637 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2638 ui_actiondata(package,szProcessComponents,uirow);
2639 msiobj_release( &uirow->hdr );
2654 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2655 LPWSTR lpszName, LONG_PTR lParam)
2658 typelib_struct *tl_struct = (typelib_struct*) lParam;
2659 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2663 if (!IS_INTRESOURCE(lpszName))
2665 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2669 sz = strlenW(tl_struct->source)+4;
2670 sz *= sizeof(WCHAR);
2672 if ((INT_PTR)lpszName == 1)
2673 tl_struct->path = strdupW(tl_struct->source);
2676 tl_struct->path = msi_alloc(sz);
2677 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2680 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2681 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2682 if (!SUCCEEDED(res))
2684 msi_free(tl_struct->path);
2685 tl_struct->path = NULL;
2690 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2691 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2693 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2697 msi_free(tl_struct->path);
2698 tl_struct->path = NULL;
2700 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2701 ITypeLib_Release(tl_struct->ptLib);
2706 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2708 MSIPACKAGE* package = (MSIPACKAGE*)param;
2712 typelib_struct tl_struct;
2714 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2716 component = MSI_RecordGetString(row,3);
2717 comp = get_loaded_component(package,component);
2719 return ERROR_SUCCESS;
2721 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2723 TRACE("Skipping typelib reg due to disabled component\n");
2725 comp->Action = comp->Installed;
2727 return ERROR_SUCCESS;
2730 comp->Action = INSTALLSTATE_LOCAL;
2732 file = get_loaded_file( package, comp->KeyPath );
2734 return ERROR_SUCCESS;
2736 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2740 guid = MSI_RecordGetString(row,1);
2741 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2742 tl_struct.source = strdupW( file->TargetPath );
2743 tl_struct.path = NULL;
2745 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2746 (LONG_PTR)&tl_struct);
2754 helpid = MSI_RecordGetString(row,6);
2757 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2758 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2761 if (!SUCCEEDED(res))
2762 ERR("Failed to register type library %s\n",
2763 debugstr_w(tl_struct.path));
2766 ui_actiondata(package,szRegisterTypeLibraries,row);
2768 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2771 ITypeLib_Release(tl_struct.ptLib);
2772 msi_free(tl_struct.path);
2775 ERR("Failed to load type library %s\n",
2776 debugstr_w(tl_struct.source));
2778 FreeLibrary(module);
2779 msi_free(tl_struct.source);
2782 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2784 return ERROR_SUCCESS;
2787 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2790 * OK this is a bit confusing.. I am given a _Component key and I believe
2791 * that the file that is being registered as a type library is the "key file
2792 * of that component" which I interpret to mean "The file in the KeyPath of
2797 static const WCHAR Query[] =
2798 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2799 '`','T','y','p','e','L','i','b','`',0};
2801 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2802 if (rc != ERROR_SUCCESS)
2803 return ERROR_SUCCESS;
2805 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2806 msiobj_release(&view->hdr);
2810 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2812 MSIPACKAGE *package = (MSIPACKAGE*)param;
2813 LPWSTR target_file, target_folder, filename;
2814 LPCWSTR buffer, extension;
2816 static const WCHAR szlnk[]={'.','l','n','k',0};
2817 IShellLinkW *sl = NULL;
2818 IPersistFile *pf = NULL;
2821 buffer = MSI_RecordGetString(row,4);
2822 comp = get_loaded_component(package,buffer);
2824 return ERROR_SUCCESS;
2826 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2828 TRACE("Skipping shortcut creation due to disabled component\n");
2830 comp->Action = comp->Installed;
2832 return ERROR_SUCCESS;
2835 comp->Action = INSTALLSTATE_LOCAL;
2837 ui_actiondata(package,szCreateShortcuts,row);
2839 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2840 &IID_IShellLinkW, (LPVOID *) &sl );
2844 ERR("CLSID_ShellLink not available\n");
2848 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2851 ERR("QueryInterface(IID_IPersistFile) failed\n");
2855 buffer = MSI_RecordGetString(row,2);
2856 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2858 /* may be needed because of a bug somehwere else */
2859 create_full_pathW(target_folder);
2861 filename = msi_dup_record_field( row, 3 );
2862 reduce_to_longfilename(filename);
2864 extension = strchrW(filename,'.');
2865 if (!extension || strcmpiW(extension,szlnk))
2867 int len = strlenW(filename);
2868 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2869 memcpy(filename + len, szlnk, sizeof(szlnk));
2871 target_file = build_directory_name(2, target_folder, filename);
2872 msi_free(target_folder);
2875 buffer = MSI_RecordGetString(row,5);
2876 if (strchrW(buffer,'['))
2879 deformat_string(package,buffer,&deformated);
2880 IShellLinkW_SetPath(sl,deformated);
2881 msi_free(deformated);
2885 FIXME("poorly handled shortcut format, advertised shortcut\n");
2886 IShellLinkW_SetPath(sl,comp->FullKeypath);
2889 if (!MSI_RecordIsNull(row,6))
2892 buffer = MSI_RecordGetString(row,6);
2893 deformat_string(package,buffer,&deformated);
2894 IShellLinkW_SetArguments(sl,deformated);
2895 msi_free(deformated);
2898 if (!MSI_RecordIsNull(row,7))
2900 buffer = MSI_RecordGetString(row,7);
2901 IShellLinkW_SetDescription(sl,buffer);
2904 if (!MSI_RecordIsNull(row,8))
2905 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2907 if (!MSI_RecordIsNull(row,9))
2912 buffer = MSI_RecordGetString(row,9);
2914 Path = build_icon_path(package,buffer);
2915 index = MSI_RecordGetInteger(row,10);
2917 IShellLinkW_SetIconLocation(sl,Path,index);
2921 if (!MSI_RecordIsNull(row,11))
2922 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2924 if (!MSI_RecordIsNull(row,12))
2927 buffer = MSI_RecordGetString(row,12);
2928 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2929 IShellLinkW_SetWorkingDirectory(sl,Path);
2933 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2934 IPersistFile_Save(pf,target_file,FALSE);
2936 msi_free(target_file);
2940 IPersistFile_Release( pf );
2942 IShellLinkW_Release( sl );
2944 return ERROR_SUCCESS;
2947 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2952 static const WCHAR Query[] =
2953 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2954 '`','S','h','o','r','t','c','u','t','`',0};
2956 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2957 if (rc != ERROR_SUCCESS)
2958 return ERROR_SUCCESS;
2960 res = CoInitialize( NULL );
2963 ERR("CoInitialize failed\n");
2964 return ERROR_FUNCTION_FAILED;
2967 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2968 msiobj_release(&view->hdr);
2975 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2977 MSIPACKAGE* package = (MSIPACKAGE*)param;
2986 FileName = MSI_RecordGetString(row,1);
2989 ERR("Unable to get FileName\n");
2990 return ERROR_SUCCESS;
2993 FilePath = build_icon_path(package,FileName);
2995 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2997 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2998 FILE_ATTRIBUTE_NORMAL, NULL);
3000 if (the_file == INVALID_HANDLE_VALUE)
3002 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3004 return ERROR_SUCCESS;
3011 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3012 if (rc != ERROR_SUCCESS)
3014 ERR("Failed to get stream\n");
3015 CloseHandle(the_file);
3016 DeleteFileW(FilePath);
3019 WriteFile(the_file,buffer,sz,&write,NULL);
3020 } while (sz == 1024);
3024 CloseHandle(the_file);
3026 uirow = MSI_CreateRecord(1);
3027 MSI_RecordSetStringW(uirow,1,FileName);
3028 ui_actiondata(package,szPublishProduct,uirow);
3029 msiobj_release( &uirow->hdr );
3031 return ERROR_SUCCESS;
3035 * 99% of the work done here is only done for
3036 * advertised installs. However this is where the
3037 * Icon table is processed and written out
3038 * so that is what I am going to do here.
3040 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3044 static const WCHAR Query[]=
3045 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3046 '`','I','c','o','n','`',0};
3047 /* for registry stuff */
3050 static const WCHAR szProductLanguage[] =
3051 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3052 static const WCHAR szARPProductIcon[] =
3053 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3054 static const WCHAR szProductVersion[] =
3055 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3059 MSIHANDLE hDb, hSumInfo;
3061 /* write out icon files */
3063 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3064 if (rc == ERROR_SUCCESS)
3066 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3067 msiobj_release(&view->hdr);
3070 /* ok there is a lot more done here but i need to figure out what */
3072 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3073 if (rc != ERROR_SUCCESS)
3076 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3077 if (rc != ERROR_SUCCESS)
3081 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3082 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3085 langid = msi_get_property_int( package, szProductLanguage, 0 );
3086 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3088 buffer = msi_dup_property( package, szARPProductIcon );
3091 LPWSTR path = build_icon_path(package,buffer);
3092 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3097 buffer = msi_dup_property( package, szProductVersion );
3100 DWORD verdword = msi_version_str_to_dword(buffer);
3101 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3105 /* FIXME: Need to write more keys to the user registry */
3107 hDb= alloc_msihandle( &package->db->hdr );
3108 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3109 MsiCloseHandle(hDb);
3110 if (rc == ERROR_SUCCESS)
3112 WCHAR guidbuffer[0x200];
3114 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3116 if (rc == ERROR_SUCCESS)
3118 WCHAR squashed[GUID_SIZE];
3119 /* for now we only care about the first guid */
3120 LPWSTR ptr = strchrW(guidbuffer,';');
3122 squash_guid(guidbuffer,squashed);
3123 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3127 ERR("Unable to query Revision_Number...\n");
3130 MsiCloseHandle(hSumInfo);
3134 ERR("Unable to open Summary Information\n");
3146 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3148 MSIPACKAGE *package = (MSIPACKAGE*)param;
3149 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3150 LPWSTR deformated_section, deformated_key, deformated_value;
3151 LPWSTR folder, fullname = NULL;
3155 static const WCHAR szWindowsFolder[] =
3156 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3158 component = MSI_RecordGetString(row, 8);
3159 comp = get_loaded_component(package,component);
3161 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3163 TRACE("Skipping ini file due to disabled component %s\n",
3164 debugstr_w(component));
3166 comp->Action = comp->Installed;
3168 return ERROR_SUCCESS;
3171 comp->Action = INSTALLSTATE_LOCAL;
3173 identifier = MSI_RecordGetString(row,1);
3174 filename = MSI_RecordGetString(row,2);
3175 dirproperty = MSI_RecordGetString(row,3);
3176 section = MSI_RecordGetString(row,4);
3177 key = MSI_RecordGetString(row,5);
3178 value = MSI_RecordGetString(row,6);
3179 action = MSI_RecordGetInteger(row,7);
3181 deformat_string(package,section,&deformated_section);
3182 deformat_string(package,key,&deformated_key);
3183 deformat_string(package,value,&deformated_value);
3187 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3189 folder = msi_dup_property( package, dirproperty );
3192 folder = msi_dup_property( package, szWindowsFolder );
3196 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3200 fullname = build_directory_name(2, folder, filename);
3204 TRACE("Adding value %s to section %s in %s\n",
3205 debugstr_w(deformated_key), debugstr_w(deformated_section),
3206 debugstr_w(fullname));
3207 WritePrivateProfileStringW(deformated_section, deformated_key,
3208 deformated_value, fullname);
3210 else if (action == 1)
3213 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3214 returned, 10, fullname);
3215 if (returned[0] == 0)
3217 TRACE("Adding value %s to section %s in %s\n",
3218 debugstr_w(deformated_key), debugstr_w(deformated_section),
3219 debugstr_w(fullname));
3221 WritePrivateProfileStringW(deformated_section, deformated_key,
3222 deformated_value, fullname);
3225 else if (action == 3)
3226 FIXME("Append to existing section not yet implemented\n");
3228 uirow = MSI_CreateRecord(4);
3229 MSI_RecordSetStringW(uirow,1,identifier);
3230 MSI_RecordSetStringW(uirow,2,deformated_section);
3231 MSI_RecordSetStringW(uirow,3,deformated_key);
3232 MSI_RecordSetStringW(uirow,4,deformated_value);
3233 ui_actiondata(package,szWriteIniValues,uirow);
3234 msiobj_release( &uirow->hdr );
3238 msi_free(deformated_key);
3239 msi_free(deformated_value);
3240 msi_free(deformated_section);
3241 return ERROR_SUCCESS;
3244 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3248 static const WCHAR ExecSeqQuery[] =
3249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3250 '`','I','n','i','F','i','l','e','`',0};
3252 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3253 if (rc != ERROR_SUCCESS)
3255 TRACE("no IniFile table\n");
3256 return ERROR_SUCCESS;
3259 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3260 msiobj_release(&view->hdr);
3264 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3266 MSIPACKAGE *package = (MSIPACKAGE*)param;
3271 static const WCHAR ExeStr[] =
3272 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3273 static const WCHAR close[] = {'\"',0};
3275 PROCESS_INFORMATION info;
3280 memset(&si,0,sizeof(STARTUPINFOW));
3282 filename = MSI_RecordGetString(row,1);
3283 file = get_loaded_file( package, filename );
3287 ERR("Unable to find file id %s\n",debugstr_w(filename));
3288 return ERROR_SUCCESS;
3291 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3293 FullName = msi_alloc(len*sizeof(WCHAR));
3294 strcpyW(FullName,ExeStr);
3295 strcatW( FullName, file->TargetPath );
3296 strcatW(FullName,close);
3298 TRACE("Registering %s\n",debugstr_w(FullName));
3299 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3303 msi_dialog_check_messages(info.hProcess);
3308 uirow = MSI_CreateRecord( 2 );
3309 uipath = strdupW( file->TargetPath );
3310 p = strrchrW(uipath,'\\');
3313 MSI_RecordSetStringW( uirow, 1, &p[2] );
3314 MSI_RecordSetStringW( uirow, 2, uipath);
3315 ui_actiondata( package, szSelfRegModules, uirow);
3316 msiobj_release( &uirow->hdr );
3318 /* FIXME: call ui_progress? */
3320 return ERROR_SUCCESS;
3323 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3327 static const WCHAR ExecSeqQuery[] =
3328 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3329 '`','S','e','l','f','R','e','g','`',0};
3331 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3332 if (rc != ERROR_SUCCESS)
3334 TRACE("no SelfReg table\n");
3335 return ERROR_SUCCESS;
3338 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3339 msiobj_release(&view->hdr);
3341 return ERROR_SUCCESS;
3344 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3346 MSIFEATURE *feature;
3351 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3352 if (rc != ERROR_SUCCESS)
3355 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3356 if (rc != ERROR_SUCCESS)
3359 /* here the guids are base 85 encoded */
3360 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3366 BOOL absent = FALSE;
3369 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3370 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3371 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3375 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3379 if (feature->Feature_Parent)
3380 size += strlenW( feature->Feature_Parent )+2;
3382 data = msi_alloc(size * sizeof(WCHAR));
3385 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3387 MSICOMPONENT* component = cl->component;
3391 if (component->ComponentId)
3393 TRACE("From %s\n",debugstr_w(component->ComponentId));
3394 CLSIDFromString(component->ComponentId, &clsid);
3395 encode_base85_guid(&clsid,buf);
3396 TRACE("to %s\n",debugstr_w(buf));
3400 if (feature->Feature_Parent)
3402 static const WCHAR sep[] = {'\2',0};
3404 strcatW(data,feature->Feature_Parent);
3407 msi_reg_set_val_str( hkey, feature->Feature, data );
3411 if (feature->Feature_Parent)
3412 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3415 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3416 (LPBYTE)feature->Feature_Parent,size);
3420 size += 2*sizeof(WCHAR);
3421 data = msi_alloc(size);
3424 if (feature->Feature_Parent)
3425 strcpyW( &data[1], feature->Feature_Parent );
3426 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3432 uirow = MSI_CreateRecord( 1 );
3433 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3434 ui_actiondata( package, szPublishFeatures, uirow);
3435 msiobj_release( &uirow->hdr );
3436 /* FIXME: call ui_progress? */
3445 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3447 static const WCHAR installerPathFmt[] = {
3448 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3449 static const WCHAR fmt[] = {
3451 'I','n','s','t','a','l','l','e','r','\\',
3452 '%','x','.','m','s','i',0};
3453 static const WCHAR szOriginalDatabase[] =
3454 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3455 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3460 /* copy the package locally */
3461 num = GetTickCount() & 0xffff;
3465 GetWindowsDirectoryW( windir, MAX_PATH );
3466 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3469 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3470 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3471 if (handle != INVALID_HANDLE_VALUE)
3473 CloseHandle(handle);
3476 if (GetLastError() != ERROR_FILE_EXISTS &&
3477 GetLastError() != ERROR_SHARING_VIOLATION)
3479 if (!(++num & 0xffff)) num = 1;
3480 sprintfW(packagefile,fmt,num);
3481 } while (num != start);
3483 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3484 create_full_pathW(path);
3486 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3488 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3489 r = CopyFileW( msiFilePath, packagefile, FALSE);
3490 msi_free( msiFilePath );
3494 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3495 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3496 return ERROR_FUNCTION_FAILED;
3499 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3500 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3501 return ERROR_SUCCESS;
3504 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3506 LPWSTR prop, val, key;
3507 static const LPCSTR propval[] = {
3508 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3509 "ARPCONTACT", "Contact",
3510 "ARPCOMMENTS", "Comments",
3511 "ProductName", "DisplayName",
3512 "ProductVersion", "DisplayVersion",
3513 "ARPHELPLINK", "HelpLink",
3514 "ARPHELPTELEPHONE", "HelpTelephone",
3515 "ARPINSTALLLOCATION", "InstallLocation",
3516 "SourceDir", "InstallSource",
3517 "Manufacturer", "Publisher",
3518 "ARPREADME", "Readme",
3520 "ARPURLINFOABOUT", "URLInfoAbout",
3521 "ARPURLUPDATEINFO", "URLUpdateInfo",
3524 const LPCSTR *p = propval;
3528 prop = strdupAtoW( *p++ );
3529 key = strdupAtoW( *p++ );
3530 val = msi_dup_property( package, prop );
3531 msi_reg_set_val_str( hkey, key, val );
3536 return ERROR_SUCCESS;
3539 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3542 LPWSTR buffer = NULL;
3545 static const WCHAR szWindowsInstaller[] =
3546 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3547 static const WCHAR szUpgradeCode[] =
3548 {'U','p','g','r','a','d','e','C','o','d','e',0};
3549 static const WCHAR modpath_fmt[] =
3550 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3551 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3552 static const WCHAR szModifyPath[] =
3553 {'M','o','d','i','f','y','P','a','t','h',0};
3554 static const WCHAR szUninstallString[] =
3555 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3556 static const WCHAR szEstimatedSize[] =
3557 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3558 static const WCHAR szProductLanguage[] =
3559 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3560 static const WCHAR szProductVersion[] =
3561 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3564 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3565 LPWSTR upgrade_code;
3568 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3569 if (rc != ERROR_SUCCESS)
3572 /* dump all the info i can grab */
3573 /* FIXME: Flesh out more information */
3575 msi_write_uninstall_property_vals( package, hkey );
3577 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3579 msi_make_package_local( package, hkey );
3581 /* do ModifyPath and UninstallString */
3582 size = deformat_string(package,modpath_fmt,&buffer);
3583 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3584 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3587 /* FIXME: Write real Estimated Size when we have it */
3588 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3590 GetLocalTime(&systime);
3591 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3592 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3594 langid = msi_get_property_int( package, szProductLanguage, 0 );
3595 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3597 buffer = msi_dup_property( package, szProductVersion );
3600 DWORD verdword = msi_version_str_to_dword(buffer);
3602 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3603 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3604 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3608 /* Handle Upgrade Codes */
3609 upgrade_code = msi_dup_property( package, szUpgradeCode );
3614 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3615 squash_guid(package->ProductCode,squashed);
3616 msi_reg_set_val_str( hkey2, squashed, NULL );
3618 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3619 squash_guid(package->ProductCode,squashed);
3620 msi_reg_set_val_str( hkey2, squashed, NULL );
3623 msi_free(upgrade_code);
3628 /* FIXME: call ui_actiondata */
3630 return ERROR_SUCCESS;
3633 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3635 return execute_script(package,INSTALL_SCRIPT);
3638 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3642 /* turn off scheduleing */
3643 package->script->CurrentlyScripting= FALSE;
3645 /* first do the same as an InstallExecute */
3646 rc = ACTION_InstallExecute(package);
3647 if (rc != ERROR_SUCCESS)
3650 /* then handle Commit Actions */
3651 rc = execute_script(package,COMMIT_SCRIPT);
3656 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3658 static const WCHAR RunOnce[] = {
3659 'S','o','f','t','w','a','r','e','\\',
3660 'M','i','c','r','o','s','o','f','t','\\',
3661 'W','i','n','d','o','w','s','\\',
3662 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3663 'R','u','n','O','n','c','e',0};
3664 static const WCHAR InstallRunOnce[] = {
3665 'S','o','f','t','w','a','r','e','\\',
3666 'M','i','c','r','o','s','o','f','t','\\',
3667 'W','i','n','d','o','w','s','\\',
3668 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3669 'I','n','s','t','a','l','l','e','r','\\',
3670 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3672 static const WCHAR msiexec_fmt[] = {
3674 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3675 '\"','%','s','\"',0};
3676 static const WCHAR install_fmt[] = {
3677 '/','I',' ','\"','%','s','\"',' ',
3678 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3679 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3680 WCHAR buffer[256], sysdir[MAX_PATH];
3682 WCHAR squished_pc[100];
3684 squash_guid(package->ProductCode,squished_pc);
3686 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3687 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3688 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3691 msi_reg_set_val_str( hkey, squished_pc, buffer );
3694 TRACE("Reboot command %s\n",debugstr_w(buffer));
3696 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3697 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3699 msi_reg_set_val_str( hkey, squished_pc, buffer );
3702 return ERROR_INSTALL_SUSPEND;
3705 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3710 * we are currently doing what should be done here in the top level Install
3711 * however for Adminastrative and uninstalls this step will be needed
3713 if (!package->PackagePath)
3714 return ERROR_SUCCESS;
3716 attrib = GetFileAttributesW(package->PackagePath);
3717 if (attrib == INVALID_FILE_ATTRIBUTES)
3723 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3724 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3725 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3726 if (rc == ERROR_MORE_DATA)
3728 prompt = msi_alloc(size * sizeof(WCHAR));
3729 MsiSourceListGetInfoW(package->ProductCode, NULL,
3730 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3731 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3734 prompt = strdupW(package->PackagePath);
3736 msg = generate_error_string(package,1302,1,prompt);
3737 while(attrib == INVALID_FILE_ATTRIBUTES)
3739 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3742 rc = ERROR_INSTALL_USEREXIT;
3745 attrib = GetFileAttributesW(package->PackagePath);
3751 return ERROR_SUCCESS;
3756 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3763 static const WCHAR szPropKeys[][80] =
3765 {'P','r','o','d','u','c','t','I','D',0},
3766 {'U','S','E','R','N','A','M','E',0},
3767 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3771 static const WCHAR szRegKeys[][80] =
3773 {'P','r','o','d','u','c','t','I','D',0},
3774 {'R','e','g','O','w','n','e','r',0},
3775 {'R','e','g','C','o','m','p','a','n','y',0},
3779 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3781 return ERROR_SUCCESS;
3783 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3784 if (rc != ERROR_SUCCESS)
3787 for( i = 0; szPropKeys[i][0]; i++ )
3789 buffer = msi_dup_property( package, szPropKeys[i] );
3790 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3795 msi_free(productid);
3798 /* FIXME: call ui_actiondata */
3800 return ERROR_SUCCESS;
3804 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3808 package->script->InWhatSequence |= SEQUENCE_EXEC;
3809 rc = ACTION_ProcessExecSequence(package,FALSE);
3815 * Code based off of code located here
3816 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3818 * Using string index 4 (full font name) instead of 1 (family name)
3820 static LPWSTR load_ttfname_from(LPCWSTR filename)
3826 typedef struct _tagTT_OFFSET_TABLE{
3827 USHORT uMajorVersion;
3828 USHORT uMinorVersion;
3829 USHORT uNumOfTables;
3830 USHORT uSearchRange;
3831 USHORT uEntrySelector;
3835 typedef struct _tagTT_TABLE_DIRECTORY{
3836 char szTag[4]; /* table name */
3837 ULONG uCheckSum; /* Check sum */
3838 ULONG uOffset; /* Offset from beginning of file */
3839 ULONG uLength; /* length of the table in bytes */
3840 }TT_TABLE_DIRECTORY;
3842 typedef struct _tagTT_NAME_TABLE_HEADER{
3843 USHORT uFSelector; /* format selector. Always 0 */
3844 USHORT uNRCount; /* Name Records count */
3845 USHORT uStorageOffset; /* Offset for strings storage,
3846 * from start of the table */
3847 }TT_NAME_TABLE_HEADER;
3849 typedef struct _tagTT_NAME_RECORD{
3854 USHORT uStringLength;
3855 USHORT uStringOffset; /* from start of storage area */
3858 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3859 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3861 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3862 FILE_ATTRIBUTE_NORMAL, 0 );
3863 if (handle != INVALID_HANDLE_VALUE)
3865 TT_TABLE_DIRECTORY tblDir;
3866 BOOL bFound = FALSE;
3867 TT_OFFSET_TABLE ttOffsetTable;
3870 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3871 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3872 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3873 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3875 if (ttOffsetTable.uMajorVersion != 1 ||
3876 ttOffsetTable.uMinorVersion != 0)
3879 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3881 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3882 if (strncmp(tblDir.szTag,"name",4)==0)
3885 tblDir.uLength = SWAPLONG(tblDir.uLength);
3886 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3893 TT_NAME_TABLE_HEADER ttNTHeader;
3894 TT_NAME_RECORD ttRecord;
3896 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3897 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3900 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3901 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3903 for(i=0; i<ttNTHeader.uNRCount; i++)
3905 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3906 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3907 /* 4 is the Full Font Name */
3908 if(ttRecord.uNameID == 4)
3912 static LPCSTR tt = " (TrueType)";
3914 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3915 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3916 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3917 SetFilePointer(handle, tblDir.uOffset +
3918 ttRecord.uStringOffset +
3919 ttNTHeader.uStorageOffset,
3921 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3922 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3923 if (strlen(buf) > 0)
3926 ret = strdupAtoW(buf);
3932 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3936 CloseHandle(handle);
3939 ERR("Unable to open font file %s\n", debugstr_w(filename));
3941 TRACE("Returning fontname %s\n",debugstr_w(ret));
3945 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3947 MSIPACKAGE *package = (MSIPACKAGE*)param;
3951 static const WCHAR regfont1[] =
3952 {'S','o','f','t','w','a','r','e','\\',
3953 'M','i','c','r','o','s','o','f','t','\\',
3954 'W','i','n','d','o','w','s',' ','N','T','\\',
3955 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3956 'F','o','n','t','s',0};
3957 static const WCHAR regfont2[] =
3958 {'S','o','f','t','w','a','r','e','\\',
3959 'M','i','c','r','o','s','o','f','t','\\',
3960 'W','i','n','d','o','w','s','\\',
3961 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3962 'F','o','n','t','s',0};
3968 filename = MSI_RecordGetString( row, 1 );
3969 file = get_loaded_file( package, filename );
3972 ERR("Unable to load file\n");
3973 return ERROR_SUCCESS;
3976 /* check to make sure that component is installed */
3977 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3979 TRACE("Skipping: Component not scheduled for install\n");
3980 return ERROR_SUCCESS;
3983 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3984 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3986 if (MSI_RecordIsNull(row,2))
3987 name = load_ttfname_from( file->TargetPath );
3989 name = msi_dup_record_field(row,2);
3993 msi_reg_set_val_str( hkey1, name, file->FileName );
3994 msi_reg_set_val_str( hkey2, name, file->FileName );
4002 uirow = MSI_CreateRecord( 1 );
4003 uipath = strdupW( file->TargetPath );
4004 p = strrchrW(uipath,'\\');
4007 MSI_RecordSetStringW( uirow, 1, p );
4008 ui_actiondata( package, szRegisterFonts, uirow);
4009 msiobj_release( &uirow->hdr );
4011 /* FIXME: call ui_progress? */
4013 return ERROR_SUCCESS;
4016 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4020 static const WCHAR ExecSeqQuery[] =
4021 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4022 '`','F','o','n','t','`',0};
4024 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4025 if (rc != ERROR_SUCCESS)
4027 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4028 return ERROR_SUCCESS;
4031 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4032 msiobj_release(&view->hdr);
4034 return ERROR_SUCCESS;
4037 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4039 MSIPACKAGE *package = (MSIPACKAGE*)param;
4040 LPCWSTR compgroupid=NULL;
4041 LPCWSTR feature=NULL;
4042 LPCWSTR text = NULL;
4043 LPCWSTR qualifier = NULL;
4044 LPCWSTR component = NULL;
4045 LPWSTR advertise = NULL;
4046 LPWSTR output = NULL;
4048 UINT rc = ERROR_SUCCESS;
4053 component = MSI_RecordGetString(rec,3);
4054 comp = get_loaded_component(package,component);
4056 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4057 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4058 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4060 TRACE("Skipping: Component %s not scheduled for install\n",
4061 debugstr_w(component));
4063 return ERROR_SUCCESS;
4066 compgroupid = MSI_RecordGetString(rec,1);
4067 qualifier = MSI_RecordGetString(rec,2);
4069 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4070 if (rc != ERROR_SUCCESS)
4073 text = MSI_RecordGetString(rec,4);
4074 feature = MSI_RecordGetString(rec,5);
4076 advertise = create_component_advertise_string(package, comp, feature);
4078 sz = strlenW(advertise);
4081 sz += lstrlenW(text);
4084 sz *= sizeof(WCHAR);
4086 output = msi_alloc_zero(sz);
4087 strcpyW(output,advertise);
4088 msi_free(advertise);
4091 strcatW(output,text);
4093 msi_reg_set_val_multi_str( hkey, qualifier, output );
4100 uirow = MSI_CreateRecord( 2 );
4101 MSI_RecordSetStringW( uirow, 1, compgroupid );
4102 MSI_RecordSetStringW( uirow, 2, qualifier);
4103 ui_actiondata( package, szPublishComponents, uirow);
4104 msiobj_release( &uirow->hdr );
4105 /* FIXME: call ui_progress? */
4111 * At present I am ignorning the advertised components part of this and only
4112 * focusing on the qualified component sets
4114 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4118 static const WCHAR ExecSeqQuery[] =
4119 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4120 '`','P','u','b','l','i','s','h',
4121 'C','o','m','p','o','n','e','n','t','`',0};
4123 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4124 if (rc != ERROR_SUCCESS)
4125 return ERROR_SUCCESS;
4127 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4128 msiobj_release(&view->hdr);
4133 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4134 LPCSTR action, LPCWSTR table )
4136 static const WCHAR query[] = {
4137 'S','E','L','E','C','T',' ','*',' ',
4138 'F','R','O','M',' ','`','%','s','`',0 };
4139 MSIQUERY *view = NULL;
4143 r = MSI_OpenQuery( package->db, &view, query, table );
4144 if (r == ERROR_SUCCESS)
4146 r = MSI_IterateRecords(view, &count, NULL, package);
4147 msiobj_release(&view->hdr);
4151 FIXME("%s -> %lu ignored %s table values\n",
4152 action, count, debugstr_w(table));
4154 return ERROR_SUCCESS;
4157 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4159 TRACE("%p\n", package);
4160 return ERROR_SUCCESS;
4163 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4165 static const WCHAR table[] =
4166 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4167 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4170 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4172 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4173 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4176 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4178 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4179 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4182 static UINT ACTION_BindImage( MSIPACKAGE *package )
4184 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4185 return msi_unimplemented_action_stub( package, "BindImage", table );
4188 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4190 static const WCHAR table[] = {
4191 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4192 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4195 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4197 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4198 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4201 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4203 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4204 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4207 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4209 static const WCHAR table[] = {
4210 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4211 return msi_unimplemented_action_stub( package, "InstallServices", table );
4214 static UINT ACTION_StartServices( MSIPACKAGE *package )
4216 static const WCHAR table[] = {
4217 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4218 return msi_unimplemented_action_stub( package, "StartServices", table );
4221 static UINT ACTION_StopServices( MSIPACKAGE *package )
4223 static const WCHAR table[] = {
4224 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4225 return msi_unimplemented_action_stub( package, "StopServices", table );
4228 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4230 static const WCHAR table[] = {
4231 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4232 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4235 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4237 static const WCHAR table[] = {
4238 'E','n','v','i','r','o','n','m','e','n','t',0 };
4239 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4242 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4244 static const WCHAR table[] = {
4245 'E','n','v','i','r','o','n','m','e','n','t',0 };
4246 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4249 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4251 static const WCHAR table[] = {
4252 'M','s','i','A','s','s','e','m','b','l','y',0 };
4253 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4256 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4258 static const WCHAR table[] = {
4259 'M','s','i','A','s','s','e','m','b','l','y',0 };
4260 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4263 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4265 static const WCHAR table[] = { 'F','o','n','t',0 };
4266 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4269 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4271 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4272 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4275 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4277 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4278 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4281 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4283 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4284 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4287 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4289 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4290 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4293 static struct _actions StandardActions[] = {
4294 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4295 { szAppSearch, ACTION_AppSearch },
4296 { szBindImage, ACTION_BindImage },
4297 { szCCPSearch, ACTION_CCPSearch},
4298 { szCostFinalize, ACTION_CostFinalize },
4299 { szCostInitialize, ACTION_CostInitialize },
4300 { szCreateFolders, ACTION_CreateFolders },
4301 { szCreateShortcuts, ACTION_CreateShortcuts },
4302 { szDeleteServices, ACTION_DeleteServices },
4303 { szDisableRollback, NULL},
4304 { szDuplicateFiles, ACTION_DuplicateFiles },
4305 { szExecuteAction, ACTION_ExecuteAction },
4306 { szFileCost, ACTION_FileCost },
4307 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4308 { szForceReboot, ACTION_ForceReboot },
4309 { szInstallAdminPackage, NULL},
4310 { szInstallExecute, ACTION_InstallExecute },
4311 { szInstallExecuteAgain, ACTION_InstallExecute },
4312 { szInstallFiles, ACTION_InstallFiles},
4313 { szInstallFinalize, ACTION_InstallFinalize },
4314 { szInstallInitialize, ACTION_InstallInitialize },
4315 { szInstallSFPCatalogFile, NULL},
4316 { szInstallValidate, ACTION_InstallValidate },
4317 { szIsolateComponents, ACTION_IsolateComponents },
4318 { szLaunchConditions, ACTION_LaunchConditions },
4319 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4320 { szMoveFiles, ACTION_MoveFiles },
4321 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4322 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4323 { szInstallODBC, NULL},
4324 { szInstallServices, ACTION_InstallServices },
4325 { szPatchFiles, ACTION_PatchFiles },
4326 { szProcessComponents, ACTION_ProcessComponents },
4327 { szPublishComponents, ACTION_PublishComponents },
4328 { szPublishFeatures, ACTION_PublishFeatures },
4329 { szPublishProduct, ACTION_PublishProduct },
4330 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4331 { szRegisterComPlus, ACTION_RegisterComPlus},
4332 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4333 { szRegisterFonts, ACTION_RegisterFonts },
4334 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4335 { szRegisterProduct, ACTION_RegisterProduct },
4336 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4337 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4338 { szRegisterUser, ACTION_RegisterUser},
4339 { szRemoveDuplicateFiles, NULL},
4340 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4341 { szRemoveExistingProducts, NULL},
4342 { szRemoveFiles, ACTION_RemoveFiles},
4343 { szRemoveFolders, NULL},
4344 { szRemoveIniValues, ACTION_RemoveIniValues },
4345 { szRemoveODBC, NULL},
4346 { szRemoveRegistryValues, NULL},
4347 { szRemoveShortcuts, NULL},
4348 { szResolveSource, ACTION_ResolveSource},
4349 { szRMCCPSearch, ACTION_RMCCPSearch},
4350 { szScheduleReboot, NULL},
4351 { szSelfRegModules, ACTION_SelfRegModules },
4352 { szSelfUnregModules, ACTION_SelfUnregModules },
4353 { szSetODBCFolders, NULL},
4354 { szStartServices, ACTION_StartServices },
4355 { szStopServices, ACTION_StopServices },
4356 { szUnpublishComponents, NULL},
4357 { szUnpublishFeatures, NULL},
4358 { szUnregisterClassInfo, NULL},
4359 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4360 { szUnregisterExtensionInfo, NULL},
4361 { szUnregisterFonts, ACTION_UnregisterFonts },
4362 { szUnregisterMIMEInfo, NULL},
4363 { szUnregisterProgIdInfo, NULL},
4364 { szUnregisterTypeLibraries, NULL},
4365 { szValidateProductID, NULL},
4366 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4367 { szWriteIniValues, ACTION_WriteIniValues },
4368 { szWriteRegistryValues, ACTION_WriteRegistryValues},