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 MSICOMPONENT* load_component( MSIRECORD * row )
1102 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1106 /* fill in the data */
1107 comp->Component = msi_dup_record_field( row, 1 );
1109 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1111 comp->ComponentId = msi_dup_record_field( row, 2 );
1112 comp->Directory = msi_dup_record_field( row, 3 );
1113 comp->Attributes = MSI_RecordGetInteger(row,4);
1114 comp->Condition = msi_dup_record_field( row, 5 );
1115 comp->KeyPath = msi_dup_record_field( row, 6 );
1117 comp->Installed = INSTALLSTATE_ABSENT;
1118 comp->Action = INSTALLSTATE_UNKNOWN;
1119 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1121 comp->Enabled = TRUE;
1127 MSIPACKAGE *package;
1128 MSIFEATURE *feature;
1131 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1135 cl = msi_alloc( sizeof (*cl) );
1137 return ERROR_NOT_ENOUGH_MEMORY;
1138 cl->component = comp;
1139 list_add_tail( &feature->Components, &cl->entry );
1141 return ERROR_SUCCESS;
1144 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1146 _ilfs* ilfs= (_ilfs*)param;
1147 MSIPACKAGE *package = ilfs->package;
1148 MSIFEATURE *feature = ilfs->feature;
1151 comp = load_component( row );
1153 return ERROR_FUNCTION_FAILED;
1155 list_add_tail( &package->components, &comp->entry );
1156 add_feature_component( feature, comp );
1158 TRACE("Loaded new component %p\n", comp);
1160 return ERROR_SUCCESS;
1163 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1165 _ilfs* ilfs= (_ilfs*)param;
1170 static const WCHAR Query[] =
1171 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1172 '`','C','o','m','p','o','n','e','n','t','`',' ',
1173 'W','H','E','R','E',' ',
1174 '`','C','o','m','p','o','n','e','n','t','`',' ',
1175 '=','\'','%','s','\'',0};
1177 component = MSI_RecordGetString(row,1);
1179 /* check to see if the component is already loaded */
1180 comp = get_loaded_component( ilfs->package, component );
1183 TRACE("Component %s already loaded\n", debugstr_w(component) );
1184 add_feature_component( ilfs->feature, comp );
1185 return ERROR_SUCCESS;
1188 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1189 if (rc != ERROR_SUCCESS)
1190 return ERROR_SUCCESS;
1192 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1193 msiobj_release( &view->hdr );
1195 return ERROR_SUCCESS;
1198 static UINT load_feature(MSIRECORD * row, LPVOID param)
1200 MSIPACKAGE* package = (MSIPACKAGE*)param;
1201 MSIFEATURE* feature;
1202 static const WCHAR Query1[] =
1203 {'S','E','L','E','C','T',' ',
1204 '`','C','o','m','p','o','n','e','n','t','_','`',
1205 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1206 'C','o','m','p','o','n','e','n','t','s','`',' ',
1207 'W','H','E','R','E',' ',
1208 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1213 /* fill in the data */
1215 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1217 return ERROR_NOT_ENOUGH_MEMORY;
1219 list_init( &feature->Components );
1221 feature->Feature = msi_dup_record_field( row, 1 );
1223 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1225 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1226 feature->Title = msi_dup_record_field( row, 3 );
1227 feature->Description = msi_dup_record_field( row, 4 );
1229 if (!MSI_RecordIsNull(row,5))
1230 feature->Display = MSI_RecordGetInteger(row,5);
1232 feature->Level= MSI_RecordGetInteger(row,6);
1233 feature->Directory = msi_dup_record_field( row, 7 );
1234 feature->Attributes = MSI_RecordGetInteger(row,8);
1236 feature->Installed = INSTALLSTATE_ABSENT;
1237 feature->Action = INSTALLSTATE_UNKNOWN;
1238 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1240 list_add_tail( &package->features, &feature->entry );
1242 /* load feature components */
1244 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1245 if (rc != ERROR_SUCCESS)
1246 return ERROR_SUCCESS;
1248 ilfs.package = package;
1249 ilfs.feature = feature;
1251 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1252 msiobj_release(&view->hdr);
1254 return ERROR_SUCCESS;
1257 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1268 static UINT load_file(MSIRECORD *row, LPVOID param)
1270 MSIPACKAGE* package = (MSIPACKAGE*)param;
1274 /* fill in the data */
1276 file = msi_alloc_zero( sizeof (MSIFILE) );
1278 return ERROR_NOT_ENOUGH_MEMORY;
1280 file->File = msi_dup_record_field( row, 1 );
1282 component = MSI_RecordGetString( row, 2 );
1283 file->Component = get_loaded_component( package, component );
1285 if (!file->Component)
1286 ERR("Unfound Component %s\n",debugstr_w(component));
1288 file->FileName = msi_dup_record_field( row, 3 );
1289 reduce_to_longfilename( file->FileName );
1291 file->ShortName = msi_dup_record_field( row, 3 );
1292 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1294 file->FileSize = MSI_RecordGetInteger( row, 4 );
1295 file->Version = msi_dup_record_field( row, 5 );
1296 file->Language = msi_dup_record_field( row, 6 );
1297 file->Attributes = MSI_RecordGetInteger( row, 7 );
1298 file->Sequence = MSI_RecordGetInteger( row, 8 );
1300 file->state = msifs_invalid;
1302 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1304 list_add_tail( &package->files, &file->entry );
1306 return ERROR_SUCCESS;
1309 static UINT load_all_files(MSIPACKAGE *package)
1313 static const WCHAR Query[] =
1314 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1315 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1316 '`','S','e','q','u','e','n','c','e','`', 0};
1318 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1319 if (rc != ERROR_SUCCESS)
1320 return ERROR_SUCCESS;
1322 rc = MSI_IterateRecords(view, NULL, load_file, package);
1323 msiobj_release(&view->hdr);
1325 return ERROR_SUCCESS;
1330 * I am not doing any of the costing functionality yet.
1331 * Mostly looking at doing the Component and Feature loading
1333 * The native MSI does A LOT of modification to tables here. Mostly adding
1334 * a lot of temporary columns to the Feature and Component tables.
1336 * note: Native msi also tracks the short filename. But I am only going to
1337 * track the long ones. Also looking at this directory table
1338 * it appears that the directory table does not get the parents
1339 * resolved base on property only based on their entries in the
1342 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1346 static const WCHAR Query_all[] =
1347 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1348 '`','F','e','a','t','u','r','e','`',0};
1349 static const WCHAR szCosting[] =
1350 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1351 static const WCHAR szZero[] = { '0', 0 };
1353 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1354 return ERROR_SUCCESS;
1356 MSI_SetPropertyW(package, szCosting, szZero);
1357 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1359 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1360 if (rc != ERROR_SUCCESS)
1363 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1364 msiobj_release(&view->hdr);
1366 load_all_files(package);
1368 return ERROR_SUCCESS;
1371 static UINT execute_script(MSIPACKAGE *package, UINT script )
1374 UINT rc = ERROR_SUCCESS;
1376 TRACE("Executing Script %i\n",script);
1378 if (!package->script)
1380 ERR("no script!\n");
1381 return ERROR_FUNCTION_FAILED;
1384 for (i = 0; i < package->script->ActionCount[script]; i++)
1387 action = package->script->Actions[script][i];
1388 ui_actionstart(package, action);
1389 TRACE("Executing Action (%s)\n",debugstr_w(action));
1390 rc = ACTION_PerformAction(package, action, TRUE);
1391 msi_free(package->script->Actions[script][i]);
1392 if (rc != ERROR_SUCCESS)
1395 msi_free(package->script->Actions[script]);
1397 package->script->ActionCount[script] = 0;
1398 package->script->Actions[script] = NULL;
1402 static UINT ACTION_FileCost(MSIPACKAGE *package)
1404 return ERROR_SUCCESS;
1407 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1409 static const WCHAR Query[] =
1410 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1411 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1412 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1413 ' ','=',' ','\'','%','s','\'',
1415 static const WCHAR szDot[] = { '.',0 };
1416 static WCHAR szEmpty[] = { 0 };
1417 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1422 TRACE("Looking for dir %s\n",debugstr_w(dir));
1424 folder = get_loaded_folder( package, dir );
1428 TRACE("Working to load %s\n",debugstr_w(dir));
1430 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1434 folder->Directory = strdupW(dir);
1436 row = MSI_QueryGetRecord(package->db, Query, dir);
1440 p = msi_dup_record_field(row, 3);
1442 /* split src and target dir */
1444 src_short = folder_split_path( p, ':' );
1446 /* split the long and short paths */
1447 tgt_long = folder_split_path( tgt_short, '|' );
1448 src_long = folder_split_path( src_short, '|' );
1450 /* check for no-op dirs */
1451 if (!lstrcmpW(szDot, tgt_short))
1452 tgt_short = szEmpty;
1453 if (!lstrcmpW(szDot, src_short))
1454 src_short = szEmpty;
1457 tgt_long = tgt_short;
1460 src_short = tgt_short;
1461 src_long = tgt_long;
1465 src_long = src_short;
1467 /* FIXME: use the target short path too */
1468 folder->TargetDefault = strdupW(tgt_long);
1469 folder->SourceShortPath = strdupW(src_short);
1470 folder->SourceLongPath = strdupW(src_long);
1473 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1474 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1475 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1477 parent = MSI_RecordGetString(row, 2);
1480 folder->Parent = load_folder( package, parent );
1481 if ( folder->Parent )
1482 TRACE("loaded parent %p %s\n", folder->Parent,
1483 debugstr_w(folder->Parent->Directory));
1485 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1488 folder->Property = msi_dup_property( package, dir );
1490 msiobj_release(&row->hdr);
1492 list_add_tail( &package->folders, &folder->entry );
1494 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1499 /* scan for and update current install states */
1500 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1503 MSIFEATURE *feature;
1505 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1508 res = MsiGetComponentPathW( package->ProductCode,
1509 comp->ComponentId, NULL, NULL);
1511 res = INSTALLSTATE_ABSENT;
1512 comp->Installed = res;
1515 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1518 INSTALLSTATE res = -10;
1520 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1522 comp= cl->component;
1525 res = comp->Installed;
1528 if (res == comp->Installed)
1531 if (res != comp->Installed)
1532 res = INSTALLSTATE_INCOMPLETE;
1535 feature->Installed = res;
1539 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1542 static const WCHAR all[]={'A','L','L',0};
1544 MSIFEATURE *feature;
1546 override = msi_dup_property( package, property );
1550 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1552 if (strcmpiW(override,all)==0)
1554 feature->ActionRequest= state;
1555 feature->Action = state;
1559 LPWSTR ptr = override;
1560 LPWSTR ptr2 = strchrW(override,',');
1564 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1565 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1567 feature->ActionRequest= state;
1568 feature->Action = state;
1574 ptr2 = strchrW(ptr,',');
1586 static UINT SetFeatureStates(MSIPACKAGE *package)
1589 static const WCHAR szlevel[] =
1590 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1591 static const WCHAR szAddLocal[] =
1592 {'A','D','D','L','O','C','A','L',0};
1593 static const WCHAR szRemove[] =
1594 {'R','E','M','O','V','E',0};
1595 static const WCHAR szReinstall[] =
1596 {'R','E','I','N','S','T','A','L','L',0};
1597 BOOL override = FALSE;
1598 MSICOMPONENT* component;
1599 MSIFEATURE *feature;
1602 /* I do not know if this is where it should happen.. but */
1604 TRACE("Checking Install Level\n");
1606 install_level = msi_get_property_int( package, szlevel, 1 );
1608 /* ok hereis the _real_ rub
1609 * all these activation/deactivation things happen in order and things
1610 * later on the list override things earlier on the list.
1611 * 1) INSTALLLEVEL processing
1621 * 11) FILEADDDEFAULT
1622 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1623 * ignored for all the features. seems strange, especially since it is not
1624 * documented anywhere, but it is how it works.
1626 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1627 * REMOVE are the big ones, since we don't handle administrative installs
1630 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1631 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1632 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1636 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1638 BOOL feature_state = ((feature->Level > 0) &&
1639 (feature->Level <= install_level));
1641 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1643 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1645 feature->ActionRequest = INSTALLSTATE_SOURCE;
1646 feature->Action = INSTALLSTATE_SOURCE;
1648 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1650 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1651 feature->Action = INSTALLSTATE_ADVERTISED;
1655 feature->ActionRequest = INSTALLSTATE_LOCAL;
1656 feature->Action = INSTALLSTATE_LOCAL;
1663 /* set the Preselected Property */
1664 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1665 static const WCHAR szOne[] = { '1', 0 };
1667 MSI_SetPropertyW(package,szPreselected,szOne);
1671 * now we want to enable or disable components base on feature
1674 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1678 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1679 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1680 feature->ActionRequest);
1682 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1684 component = cl->component;
1686 if (!component->Enabled)
1688 component->Action = INSTALLSTATE_UNKNOWN;
1689 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1693 if (feature->Action == INSTALLSTATE_LOCAL)
1695 component->Action = INSTALLSTATE_LOCAL;
1696 component->ActionRequest = INSTALLSTATE_LOCAL;
1698 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1700 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1701 (component->Action == INSTALLSTATE_ABSENT) ||
1702 (component->Action == INSTALLSTATE_ADVERTISED))
1705 component->Action = INSTALLSTATE_SOURCE;
1706 component->ActionRequest = INSTALLSTATE_SOURCE;
1709 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1711 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1712 (component->Action == INSTALLSTATE_ABSENT))
1715 component->Action = INSTALLSTATE_ADVERTISED;
1716 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1719 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1721 if (component->Action == INSTALLSTATE_UNKNOWN)
1723 component->Action = INSTALLSTATE_ABSENT;
1724 component->ActionRequest = INSTALLSTATE_ABSENT;
1731 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1733 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1734 debugstr_w(component->Component), component->Installed,
1735 component->Action, component->ActionRequest);
1739 return ERROR_SUCCESS;
1742 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1744 MSIPACKAGE *package = (MSIPACKAGE*)param;
1748 name = MSI_RecordGetString(row,1);
1750 /* This helper function now does ALL the work */
1751 TRACE("Dir %s ...\n",debugstr_w(name));
1752 load_folder(package,name);
1753 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1754 TRACE("resolves to %s\n",debugstr_w(path));
1757 return ERROR_SUCCESS;
1760 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1762 MSIPACKAGE *package = (MSIPACKAGE*)param;
1764 MSIFEATURE *feature;
1766 name = MSI_RecordGetString( row, 1 );
1768 feature = get_loaded_feature( package, name );
1770 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1774 Condition = MSI_RecordGetString(row,3);
1776 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1778 int level = MSI_RecordGetInteger(row,2);
1779 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1780 feature->Level = level;
1783 return ERROR_SUCCESS;
1788 * A lot is done in this function aside from just the costing.
1789 * The costing needs to be implemented at some point but for now I am going
1790 * to focus on the directory building
1793 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1795 static const WCHAR ExecSeqQuery[] =
1796 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1797 '`','D','i','r','e','c','t','o','r','y','`',0};
1798 static const WCHAR ConditionQuery[] =
1799 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1800 '`','C','o','n','d','i','t','i','o','n','`',0};
1801 static const WCHAR szCosting[] =
1802 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1803 static const WCHAR szlevel[] =
1804 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1805 static const WCHAR szOne[] = { '1', 0 };
1812 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1813 return ERROR_SUCCESS;
1815 TRACE("Building Directory properties\n");
1817 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1818 if (rc == ERROR_SUCCESS)
1820 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1822 msiobj_release(&view->hdr);
1825 TRACE("File calculations\n");
1827 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1829 MSICOMPONENT* comp = file->Component;
1835 /* calculate target */
1836 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1838 msi_free(file->TargetPath);
1840 TRACE("file %s is named %s\n",
1841 debugstr_w(file->File),debugstr_w(file->FileName));
1843 file->TargetPath = build_directory_name(2, p, file->FileName);
1847 TRACE("file %s resolves to %s\n",
1848 debugstr_w(file->File),debugstr_w(file->TargetPath));
1850 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1852 file->state = msifs_missing;
1853 comp->Cost += file->FileSize;
1863 static WCHAR name[] = {'\\',0};
1864 static const WCHAR name_fmt[] =
1865 {'%','u','.','%','u','.','%','u','.','%','u',0};
1866 WCHAR filever[0x100];
1867 VS_FIXEDFILEINFO *lpVer;
1869 TRACE("Version comparison..\n");
1870 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1871 version = msi_alloc(versize);
1872 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1874 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1876 sprintfW(filever,name_fmt,
1877 HIWORD(lpVer->dwFileVersionMS),
1878 LOWORD(lpVer->dwFileVersionMS),
1879 HIWORD(lpVer->dwFileVersionLS),
1880 LOWORD(lpVer->dwFileVersionLS));
1882 TRACE("new %s old %s\n", debugstr_w(file->Version),
1883 debugstr_w(filever));
1884 if (strcmpiW(filever,file->Version)<0)
1886 file->state = msifs_overwrite;
1887 /* FIXME: cost should be diff in size */
1888 comp->Cost += file->FileSize;
1891 file->state = msifs_present;
1895 file->state = msifs_present;
1898 TRACE("Evaluating Condition Table\n");
1900 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1901 if (rc == ERROR_SUCCESS)
1903 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1905 msiobj_release(&view->hdr);
1908 TRACE("Enabling or Disabling Components\n");
1909 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1911 if (comp->Condition)
1913 if (MSI_EvaluateConditionW(package,
1914 comp->Condition) == MSICONDITION_FALSE)
1916 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1917 comp->Enabled = FALSE;
1922 MSI_SetPropertyW(package,szCosting,szOne);
1923 /* set default run level if not set */
1924 level = msi_dup_property( package, szlevel );
1926 MSI_SetPropertyW(package,szlevel, szOne);
1929 ACTION_UpdateInstallStates(package);
1931 return SetFeatureStates(package);
1934 /* OK this value is "interpreted" and then formatted based on the
1935 first few characters */
1936 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1940 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1946 LPWSTR deformated = NULL;
1949 deformat_string(package, &value[2], &deformated);
1951 /* binary value type */
1955 *size = (strlenW(ptr)/2)+1;
1957 *size = strlenW(ptr)/2;
1959 data = msi_alloc(*size);
1965 /* if uneven pad with a zero in front */
1971 data[count] = (BYTE)strtol(byte,NULL,0);
1973 TRACE("Uneven byte count\n");
1981 data[count] = (BYTE)strtol(byte,NULL,0);
1984 msi_free(deformated);
1986 TRACE("Data %li bytes(%i)\n",*size,count);
1993 deformat_string(package, &value[1], &deformated);
1996 *size = sizeof(DWORD);
1997 data = msi_alloc(*size);
2003 if ( (*p < '0') || (*p > '9') )
2009 if (deformated[0] == '-')
2012 TRACE("DWORD %li\n",*(LPDWORD)data);
2014 msi_free(deformated);
2019 static const WCHAR szMulti[] = {'[','~',']',0};
2028 *type=REG_EXPAND_SZ;
2036 if (strstrW(value,szMulti))
2037 *type = REG_MULTI_SZ;
2039 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2044 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2046 MSIPACKAGE *package = (MSIPACKAGE*)param;
2047 static const WCHAR szHCR[] =
2048 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2049 'R','O','O','T','\\',0};
2050 static const WCHAR szHCU[] =
2051 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2052 'U','S','E','R','\\',0};
2053 static const WCHAR szHLM[] =
2054 {'H','K','E','Y','_','L','O','C','A','L','_',
2055 'M','A','C','H','I','N','E','\\',0};
2056 static const WCHAR szHU[] =
2057 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2059 LPSTR value_data = NULL;
2060 HKEY root_key, hkey;
2063 LPCWSTR szRoot, component, name, key, value;
2068 BOOL check_first = FALSE;
2071 ui_progress(package,2,0,0,0);
2078 component = MSI_RecordGetString(row, 6);
2079 comp = get_loaded_component(package,component);
2081 return ERROR_SUCCESS;
2083 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2085 TRACE("Skipping write due to disabled component %s\n",
2086 debugstr_w(component));
2088 comp->Action = comp->Installed;
2090 return ERROR_SUCCESS;
2093 comp->Action = INSTALLSTATE_LOCAL;
2095 name = MSI_RecordGetString(row, 4);
2096 if( MSI_RecordIsNull(row,5) && name )
2098 /* null values can have special meanings */
2099 if (name[0]=='-' && name[1] == 0)
2100 return ERROR_SUCCESS;
2101 else if ((name[0]=='+' && name[1] == 0) ||
2102 (name[0] == '*' && name[1] == 0))
2107 root = MSI_RecordGetInteger(row,2);
2108 key = MSI_RecordGetString(row, 3);
2110 /* get the root key */
2115 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2116 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2117 if (all_users && all_users[0] == '1')
2119 root_key = HKEY_LOCAL_MACHINE;
2124 root_key = HKEY_CURRENT_USER;
2127 msi_free(all_users);
2130 case 0: root_key = HKEY_CLASSES_ROOT;
2133 case 1: root_key = HKEY_CURRENT_USER;
2136 case 2: root_key = HKEY_LOCAL_MACHINE;
2139 case 3: root_key = HKEY_USERS;
2143 ERR("Unknown root %i\n",root);
2149 return ERROR_SUCCESS;
2151 deformat_string(package, key , &deformated);
2152 size = strlenW(deformated) + strlenW(szRoot) + 1;
2153 uikey = msi_alloc(size*sizeof(WCHAR));
2154 strcpyW(uikey,szRoot);
2155 strcatW(uikey,deformated);
2157 if (RegCreateKeyW( root_key, deformated, &hkey))
2159 ERR("Could not create key %s\n",debugstr_w(deformated));
2160 msi_free(deformated);
2162 return ERROR_SUCCESS;
2164 msi_free(deformated);
2166 value = MSI_RecordGetString(row,5);
2168 value_data = parse_value(package, value, &type, &size);
2171 static const WCHAR szEmpty[] = {0};
2172 value_data = (LPSTR)strdupW(szEmpty);
2177 deformat_string(package, name, &deformated);
2179 /* get the double nulls to terminate SZ_MULTI */
2180 if (type == REG_MULTI_SZ)
2181 size +=sizeof(WCHAR);
2185 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2187 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2192 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2193 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2195 TRACE("value %s of %s checked already exists\n",
2196 debugstr_w(deformated), debugstr_w(uikey));
2200 TRACE("Checked and setting value %s of %s\n",
2201 debugstr_w(deformated), debugstr_w(uikey));
2202 if (deformated || size)
2203 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2208 uirow = MSI_CreateRecord(3);
2209 MSI_RecordSetStringW(uirow,2,deformated);
2210 MSI_RecordSetStringW(uirow,1,uikey);
2213 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2215 MSI_RecordSetStringW(uirow,3,value);
2217 ui_actiondata(package,szWriteRegistryValues,uirow);
2218 msiobj_release( &uirow->hdr );
2220 msi_free(value_data);
2221 msi_free(deformated);
2224 return ERROR_SUCCESS;
2227 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2231 static const WCHAR ExecSeqQuery[] =
2232 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2233 '`','R','e','g','i','s','t','r','y','`',0 };
2235 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2236 if (rc != ERROR_SUCCESS)
2237 return ERROR_SUCCESS;
2239 /* increment progress bar each time action data is sent */
2240 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2242 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2244 msiobj_release(&view->hdr);
2248 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2250 package->script->CurrentlyScripting = TRUE;
2252 return ERROR_SUCCESS;
2256 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2261 static const WCHAR q1[]=
2262 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2263 '`','R','e','g','i','s','t','r','y','`',0};
2266 MSIFEATURE *feature;
2269 TRACE("InstallValidate\n");
2271 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2272 if (rc == ERROR_SUCCESS)
2274 MSI_IterateRecords( view, &progress, NULL, package );
2275 msiobj_release( &view->hdr );
2276 total += progress * REG_PROGRESS_VALUE;
2279 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2280 total += COMPONENT_PROGRESS_VALUE;
2282 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2283 total += file->FileSize;
2285 ui_progress(package,0,total,0,0);
2287 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2289 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2290 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2291 feature->ActionRequest);
2294 return ERROR_SUCCESS;
2297 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2299 MSIPACKAGE* package = (MSIPACKAGE*)param;
2300 LPCWSTR cond = NULL;
2301 LPCWSTR message = NULL;
2302 static const WCHAR title[]=
2303 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2305 cond = MSI_RecordGetString(row,1);
2307 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2310 message = MSI_RecordGetString(row,2);
2311 deformat_string(package,message,&deformated);
2312 MessageBoxW(NULL,deformated,title,MB_OK);
2313 msi_free(deformated);
2314 return ERROR_FUNCTION_FAILED;
2317 return ERROR_SUCCESS;
2320 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2323 MSIQUERY * view = NULL;
2324 static const WCHAR ExecSeqQuery[] =
2325 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2326 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2328 TRACE("Checking launch conditions\n");
2330 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2331 if (rc != ERROR_SUCCESS)
2332 return ERROR_SUCCESS;
2334 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2335 msiobj_release(&view->hdr);
2340 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2344 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2346 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2348 MSIRECORD * row = 0;
2350 LPWSTR deformated,buffer,deformated_name;
2352 static const WCHAR ExecSeqQuery[] =
2353 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2354 '`','R','e','g','i','s','t','r','y','`',' ',
2355 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2356 ' ','=',' ' ,'\'','%','s','\'',0 };
2357 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2358 static const WCHAR fmt2[]=
2359 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2361 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2365 root = MSI_RecordGetInteger(row,2);
2366 key = MSI_RecordGetString(row, 3);
2367 name = MSI_RecordGetString(row, 4);
2368 deformat_string(package, key , &deformated);
2369 deformat_string(package, name, &deformated_name);
2371 len = strlenW(deformated) + 6;
2372 if (deformated_name)
2373 len+=strlenW(deformated_name);
2375 buffer = msi_alloc( len *sizeof(WCHAR));
2377 if (deformated_name)
2378 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2380 sprintfW(buffer,fmt,root,deformated);
2382 msi_free(deformated);
2383 msi_free(deformated_name);
2384 msiobj_release(&row->hdr);
2388 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2390 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2395 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2398 return strdupW( file->TargetPath );
2403 static HKEY openSharedDLLsKey(void)
2406 static const WCHAR path[] =
2407 {'S','o','f','t','w','a','r','e','\\',
2408 'M','i','c','r','o','s','o','f','t','\\',
2409 'W','i','n','d','o','w','s','\\',
2410 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2411 'S','h','a','r','e','d','D','L','L','s',0};
2413 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2417 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2422 DWORD sz = sizeof(count);
2425 hkey = openSharedDLLsKey();
2426 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2427 if (rc != ERROR_SUCCESS)
2433 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2437 hkey = openSharedDLLsKey();
2439 msi_reg_set_val_dword( hkey, path, count );
2441 RegDeleteValueW(hkey,path);
2447 * Return TRUE if the count should be written out and FALSE if not
2449 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2451 MSIFEATURE *feature;
2455 /* only refcount DLLs */
2456 if (comp->KeyPath == NULL ||
2457 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2458 comp->Attributes & msidbComponentAttributesODBCDataSource)
2462 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2463 write = (count > 0);
2465 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2469 /* increment counts */
2470 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2474 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2477 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2479 if ( cl->component == comp )
2484 /* decrement counts */
2485 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2489 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2492 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2494 if ( cl->component == comp )
2499 /* ref count all the files in the component */
2504 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2506 if (file->Component == comp)
2507 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2511 /* add a count for permenent */
2512 if (comp->Attributes & msidbComponentAttributesPermanent)
2515 comp->RefCount = count;
2518 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2522 * Ok further analysis makes me think that this work is
2523 * actually done in the PublishComponents and PublishFeatures
2524 * step, and not here. It appears like the keypath and all that is
2525 * resolved in this step, however actually written in the Publish steps.
2526 * But we will leave it here for now because it is unclear
2528 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2530 WCHAR squished_pc[GUID_SIZE];
2531 WCHAR squished_cc[GUID_SIZE];
2534 HKEY hkey=0,hkey2=0;
2536 /* writes the Component and Features values to the registry */
2538 rc = MSIREG_OpenComponents(&hkey);
2539 if (rc != ERROR_SUCCESS)
2542 squash_guid(package->ProductCode,squished_pc);
2543 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2545 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2549 ui_progress(package,2,0,0,0);
2550 if (!comp->ComponentId)
2553 squash_guid(comp->ComponentId,squished_cc);
2555 msi_free(comp->FullKeypath);
2556 comp->FullKeypath = resolve_keypath( package, comp );
2558 /* do the refcounting */
2559 ACTION_RefCountComponent( package, comp );
2561 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2562 debugstr_w(comp->Component),
2563 debugstr_w(squished_cc),
2564 debugstr_w(comp->FullKeypath),
2567 * Write the keypath out if the component is to be registered
2568 * and delete the key if the component is to be deregistered
2570 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2572 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2573 if (rc != ERROR_SUCCESS)
2576 if (!comp->FullKeypath)
2579 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2581 if (comp->Attributes & msidbComponentAttributesPermanent)
2583 static const WCHAR szPermKey[] =
2584 { '0','0','0','0','0','0','0','0','0','0','0','0',
2585 '0','0','0','0','0','0','0','0','0','0','0','0',
2586 '0','0','0','0','0','0','0','0',0 };
2588 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2594 uirow = MSI_CreateRecord(3);
2595 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2596 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2597 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2598 ui_actiondata(package,szProcessComponents,uirow);
2599 msiobj_release( &uirow->hdr );
2601 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2605 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2606 if (rc != ERROR_SUCCESS)
2609 RegDeleteValueW(hkey2,squished_pc);
2611 /* if the key is empty delete it */
2612 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2614 if (res == ERROR_NO_MORE_ITEMS)
2615 RegDeleteKeyW(hkey,squished_cc);
2618 uirow = MSI_CreateRecord(2);
2619 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2620 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2621 ui_actiondata(package,szProcessComponents,uirow);
2622 msiobj_release( &uirow->hdr );
2637 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2638 LPWSTR lpszName, LONG_PTR lParam)
2641 typelib_struct *tl_struct = (typelib_struct*) lParam;
2642 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2646 if (!IS_INTRESOURCE(lpszName))
2648 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2652 sz = strlenW(tl_struct->source)+4;
2653 sz *= sizeof(WCHAR);
2655 if ((INT_PTR)lpszName == 1)
2656 tl_struct->path = strdupW(tl_struct->source);
2659 tl_struct->path = msi_alloc(sz);
2660 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2663 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2664 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2665 if (!SUCCEEDED(res))
2667 msi_free(tl_struct->path);
2668 tl_struct->path = NULL;
2673 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2674 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2676 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2680 msi_free(tl_struct->path);
2681 tl_struct->path = NULL;
2683 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2684 ITypeLib_Release(tl_struct->ptLib);
2689 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2691 MSIPACKAGE* package = (MSIPACKAGE*)param;
2695 typelib_struct tl_struct;
2697 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2699 component = MSI_RecordGetString(row,3);
2700 comp = get_loaded_component(package,component);
2702 return ERROR_SUCCESS;
2704 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2706 TRACE("Skipping typelib reg due to disabled component\n");
2708 comp->Action = comp->Installed;
2710 return ERROR_SUCCESS;
2713 comp->Action = INSTALLSTATE_LOCAL;
2715 file = get_loaded_file( package, comp->KeyPath );
2717 return ERROR_SUCCESS;
2719 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2723 guid = MSI_RecordGetString(row,1);
2724 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2725 tl_struct.source = strdupW( file->TargetPath );
2726 tl_struct.path = NULL;
2728 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2729 (LONG_PTR)&tl_struct);
2737 helpid = MSI_RecordGetString(row,6);
2740 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2741 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2744 if (!SUCCEEDED(res))
2745 ERR("Failed to register type library %s\n",
2746 debugstr_w(tl_struct.path));
2749 ui_actiondata(package,szRegisterTypeLibraries,row);
2751 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2754 ITypeLib_Release(tl_struct.ptLib);
2755 msi_free(tl_struct.path);
2758 ERR("Failed to load type library %s\n",
2759 debugstr_w(tl_struct.source));
2761 FreeLibrary(module);
2762 msi_free(tl_struct.source);
2765 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2767 return ERROR_SUCCESS;
2770 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2773 * OK this is a bit confusing.. I am given a _Component key and I believe
2774 * that the file that is being registered as a type library is the "key file
2775 * of that component" which I interpret to mean "The file in the KeyPath of
2780 static const WCHAR Query[] =
2781 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2782 '`','T','y','p','e','L','i','b','`',0};
2784 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2785 if (rc != ERROR_SUCCESS)
2786 return ERROR_SUCCESS;
2788 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2789 msiobj_release(&view->hdr);
2793 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2795 MSIPACKAGE *package = (MSIPACKAGE*)param;
2796 LPWSTR target_file, target_folder, filename;
2797 LPCWSTR buffer, extension;
2799 static const WCHAR szlnk[]={'.','l','n','k',0};
2800 IShellLinkW *sl = NULL;
2801 IPersistFile *pf = NULL;
2804 buffer = MSI_RecordGetString(row,4);
2805 comp = get_loaded_component(package,buffer);
2807 return ERROR_SUCCESS;
2809 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2811 TRACE("Skipping shortcut creation due to disabled component\n");
2813 comp->Action = comp->Installed;
2815 return ERROR_SUCCESS;
2818 comp->Action = INSTALLSTATE_LOCAL;
2820 ui_actiondata(package,szCreateShortcuts,row);
2822 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2823 &IID_IShellLinkW, (LPVOID *) &sl );
2827 ERR("CLSID_ShellLink not available\n");
2831 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2834 ERR("QueryInterface(IID_IPersistFile) failed\n");
2838 buffer = MSI_RecordGetString(row,2);
2839 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2841 /* may be needed because of a bug somehwere else */
2842 create_full_pathW(target_folder);
2844 filename = msi_dup_record_field( row, 3 );
2845 reduce_to_longfilename(filename);
2847 extension = strchrW(filename,'.');
2848 if (!extension || strcmpiW(extension,szlnk))
2850 int len = strlenW(filename);
2851 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2852 memcpy(filename + len, szlnk, sizeof(szlnk));
2854 target_file = build_directory_name(2, target_folder, filename);
2855 msi_free(target_folder);
2858 buffer = MSI_RecordGetString(row,5);
2859 if (strchrW(buffer,'['))
2862 deformat_string(package,buffer,&deformated);
2863 IShellLinkW_SetPath(sl,deformated);
2864 msi_free(deformated);
2868 FIXME("poorly handled shortcut format, advertised shortcut\n");
2869 IShellLinkW_SetPath(sl,comp->FullKeypath);
2872 if (!MSI_RecordIsNull(row,6))
2875 buffer = MSI_RecordGetString(row,6);
2876 deformat_string(package,buffer,&deformated);
2877 IShellLinkW_SetArguments(sl,deformated);
2878 msi_free(deformated);
2881 if (!MSI_RecordIsNull(row,7))
2883 buffer = MSI_RecordGetString(row,7);
2884 IShellLinkW_SetDescription(sl,buffer);
2887 if (!MSI_RecordIsNull(row,8))
2888 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2890 if (!MSI_RecordIsNull(row,9))
2895 buffer = MSI_RecordGetString(row,9);
2897 Path = build_icon_path(package,buffer);
2898 index = MSI_RecordGetInteger(row,10);
2900 IShellLinkW_SetIconLocation(sl,Path,index);
2904 if (!MSI_RecordIsNull(row,11))
2905 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2907 if (!MSI_RecordIsNull(row,12))
2910 buffer = MSI_RecordGetString(row,12);
2911 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2912 IShellLinkW_SetWorkingDirectory(sl,Path);
2916 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2917 IPersistFile_Save(pf,target_file,FALSE);
2919 msi_free(target_file);
2923 IPersistFile_Release( pf );
2925 IShellLinkW_Release( sl );
2927 return ERROR_SUCCESS;
2930 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2935 static const WCHAR Query[] =
2936 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2937 '`','S','h','o','r','t','c','u','t','`',0};
2939 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2940 if (rc != ERROR_SUCCESS)
2941 return ERROR_SUCCESS;
2943 res = CoInitialize( NULL );
2946 ERR("CoInitialize failed\n");
2947 return ERROR_FUNCTION_FAILED;
2950 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2951 msiobj_release(&view->hdr);
2958 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2960 MSIPACKAGE* package = (MSIPACKAGE*)param;
2969 FileName = MSI_RecordGetString(row,1);
2972 ERR("Unable to get FileName\n");
2973 return ERROR_SUCCESS;
2976 FilePath = build_icon_path(package,FileName);
2978 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2980 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2981 FILE_ATTRIBUTE_NORMAL, NULL);
2983 if (the_file == INVALID_HANDLE_VALUE)
2985 ERR("Unable to create file %s\n",debugstr_w(FilePath));
2987 return ERROR_SUCCESS;
2994 rc = MSI_RecordReadStream(row,2,buffer,&sz);
2995 if (rc != ERROR_SUCCESS)
2997 ERR("Failed to get stream\n");
2998 CloseHandle(the_file);
2999 DeleteFileW(FilePath);
3002 WriteFile(the_file,buffer,sz,&write,NULL);
3003 } while (sz == 1024);
3007 CloseHandle(the_file);
3009 uirow = MSI_CreateRecord(1);
3010 MSI_RecordSetStringW(uirow,1,FileName);
3011 ui_actiondata(package,szPublishProduct,uirow);
3012 msiobj_release( &uirow->hdr );
3014 return ERROR_SUCCESS;
3018 * 99% of the work done here is only done for
3019 * advertised installs. However this is where the
3020 * Icon table is processed and written out
3021 * so that is what I am going to do here.
3023 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3027 static const WCHAR Query[]=
3028 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3029 '`','I','c','o','n','`',0};
3030 /* for registry stuff */
3033 static const WCHAR szProductLanguage[] =
3034 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3035 static const WCHAR szARPProductIcon[] =
3036 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3037 static const WCHAR szProductVersion[] =
3038 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3042 MSIHANDLE hDb, hSumInfo;
3044 /* write out icon files */
3046 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3047 if (rc == ERROR_SUCCESS)
3049 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3050 msiobj_release(&view->hdr);
3053 /* ok there is a lot more done here but i need to figure out what */
3055 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3056 if (rc != ERROR_SUCCESS)
3059 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3060 if (rc != ERROR_SUCCESS)
3064 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3065 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3068 langid = msi_get_property_int( package, szProductLanguage, 0 );
3069 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3071 buffer = msi_dup_property( package, szARPProductIcon );
3074 LPWSTR path = build_icon_path(package,buffer);
3075 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3080 buffer = msi_dup_property( package, szProductVersion );
3083 DWORD verdword = msi_version_str_to_dword(buffer);
3084 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3088 /* FIXME: Need to write more keys to the user registry */
3090 hDb= alloc_msihandle( &package->db->hdr );
3091 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3092 MsiCloseHandle(hDb);
3093 if (rc == ERROR_SUCCESS)
3095 WCHAR guidbuffer[0x200];
3097 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3099 if (rc == ERROR_SUCCESS)
3101 WCHAR squashed[GUID_SIZE];
3102 /* for now we only care about the first guid */
3103 LPWSTR ptr = strchrW(guidbuffer,';');
3105 squash_guid(guidbuffer,squashed);
3106 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3110 ERR("Unable to query Revision_Number...\n");
3113 MsiCloseHandle(hSumInfo);
3117 ERR("Unable to open Summary Information\n");
3129 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3131 MSIPACKAGE *package = (MSIPACKAGE*)param;
3132 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3133 LPWSTR deformated_section, deformated_key, deformated_value;
3134 LPWSTR folder, fullname = NULL;
3138 static const WCHAR szWindowsFolder[] =
3139 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3141 component = MSI_RecordGetString(row, 8);
3142 comp = get_loaded_component(package,component);
3144 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3146 TRACE("Skipping ini file due to disabled component %s\n",
3147 debugstr_w(component));
3149 comp->Action = comp->Installed;
3151 return ERROR_SUCCESS;
3154 comp->Action = INSTALLSTATE_LOCAL;
3156 identifier = MSI_RecordGetString(row,1);
3157 filename = MSI_RecordGetString(row,2);
3158 dirproperty = MSI_RecordGetString(row,3);
3159 section = MSI_RecordGetString(row,4);
3160 key = MSI_RecordGetString(row,5);
3161 value = MSI_RecordGetString(row,6);
3162 action = MSI_RecordGetInteger(row,7);
3164 deformat_string(package,section,&deformated_section);
3165 deformat_string(package,key,&deformated_key);
3166 deformat_string(package,value,&deformated_value);
3170 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3172 folder = msi_dup_property( package, dirproperty );
3175 folder = msi_dup_property( package, szWindowsFolder );
3179 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3183 fullname = build_directory_name(2, folder, filename);
3187 TRACE("Adding value %s to section %s in %s\n",
3188 debugstr_w(deformated_key), debugstr_w(deformated_section),
3189 debugstr_w(fullname));
3190 WritePrivateProfileStringW(deformated_section, deformated_key,
3191 deformated_value, fullname);
3193 else if (action == 1)
3196 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3197 returned, 10, fullname);
3198 if (returned[0] == 0)
3200 TRACE("Adding value %s to section %s in %s\n",
3201 debugstr_w(deformated_key), debugstr_w(deformated_section),
3202 debugstr_w(fullname));
3204 WritePrivateProfileStringW(deformated_section, deformated_key,
3205 deformated_value, fullname);
3208 else if (action == 3)
3209 FIXME("Append to existing section not yet implemented\n");
3211 uirow = MSI_CreateRecord(4);
3212 MSI_RecordSetStringW(uirow,1,identifier);
3213 MSI_RecordSetStringW(uirow,2,deformated_section);
3214 MSI_RecordSetStringW(uirow,3,deformated_key);
3215 MSI_RecordSetStringW(uirow,4,deformated_value);
3216 ui_actiondata(package,szWriteIniValues,uirow);
3217 msiobj_release( &uirow->hdr );
3221 msi_free(deformated_key);
3222 msi_free(deformated_value);
3223 msi_free(deformated_section);
3224 return ERROR_SUCCESS;
3227 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3231 static const WCHAR ExecSeqQuery[] =
3232 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3233 '`','I','n','i','F','i','l','e','`',0};
3235 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3236 if (rc != ERROR_SUCCESS)
3238 TRACE("no IniFile table\n");
3239 return ERROR_SUCCESS;
3242 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3243 msiobj_release(&view->hdr);
3247 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3249 MSIPACKAGE *package = (MSIPACKAGE*)param;
3254 static const WCHAR ExeStr[] =
3255 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3256 static const WCHAR close[] = {'\"',0};
3258 PROCESS_INFORMATION info;
3263 memset(&si,0,sizeof(STARTUPINFOW));
3265 filename = MSI_RecordGetString(row,1);
3266 file = get_loaded_file( package, filename );
3270 ERR("Unable to find file id %s\n",debugstr_w(filename));
3271 return ERROR_SUCCESS;
3274 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3276 FullName = msi_alloc(len*sizeof(WCHAR));
3277 strcpyW(FullName,ExeStr);
3278 strcatW( FullName, file->TargetPath );
3279 strcatW(FullName,close);
3281 TRACE("Registering %s\n",debugstr_w(FullName));
3282 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3286 msi_dialog_check_messages(info.hProcess);
3291 uirow = MSI_CreateRecord( 2 );
3292 uipath = strdupW( file->TargetPath );
3293 p = strrchrW(uipath,'\\');
3296 MSI_RecordSetStringW( uirow, 1, &p[2] );
3297 MSI_RecordSetStringW( uirow, 2, uipath);
3298 ui_actiondata( package, szSelfRegModules, uirow);
3299 msiobj_release( &uirow->hdr );
3301 /* FIXME: call ui_progress? */
3303 return ERROR_SUCCESS;
3306 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3310 static const WCHAR ExecSeqQuery[] =
3311 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3312 '`','S','e','l','f','R','e','g','`',0};
3314 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3315 if (rc != ERROR_SUCCESS)
3317 TRACE("no SelfReg table\n");
3318 return ERROR_SUCCESS;
3321 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3322 msiobj_release(&view->hdr);
3324 return ERROR_SUCCESS;
3327 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3329 MSIFEATURE *feature;
3334 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3335 if (rc != ERROR_SUCCESS)
3338 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3339 if (rc != ERROR_SUCCESS)
3342 /* here the guids are base 85 encoded */
3343 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3349 BOOL absent = FALSE;
3352 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3353 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3354 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3358 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3362 if (feature->Feature_Parent)
3363 size += strlenW( feature->Feature_Parent )+2;
3365 data = msi_alloc(size * sizeof(WCHAR));
3368 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3370 MSICOMPONENT* component = cl->component;
3374 if (component->ComponentId)
3376 TRACE("From %s\n",debugstr_w(component->ComponentId));
3377 CLSIDFromString(component->ComponentId, &clsid);
3378 encode_base85_guid(&clsid,buf);
3379 TRACE("to %s\n",debugstr_w(buf));
3383 if (feature->Feature_Parent)
3385 static const WCHAR sep[] = {'\2',0};
3387 strcatW(data,feature->Feature_Parent);
3390 msi_reg_set_val_str( hkey, feature->Feature, data );
3394 if (feature->Feature_Parent)
3395 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3398 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3399 (LPBYTE)feature->Feature_Parent,size);
3403 size += 2*sizeof(WCHAR);
3404 data = msi_alloc(size);
3407 if (feature->Feature_Parent)
3408 strcpyW( &data[1], feature->Feature_Parent );
3409 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3415 uirow = MSI_CreateRecord( 1 );
3416 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3417 ui_actiondata( package, szPublishFeatures, uirow);
3418 msiobj_release( &uirow->hdr );
3419 /* FIXME: call ui_progress? */
3428 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3430 static const WCHAR installerPathFmt[] = {
3431 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3432 static const WCHAR fmt[] = {
3434 'I','n','s','t','a','l','l','e','r','\\',
3435 '%','x','.','m','s','i',0};
3436 static const WCHAR szOriginalDatabase[] =
3437 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3438 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3443 /* copy the package locally */
3444 num = GetTickCount() & 0xffff;
3448 GetWindowsDirectoryW( windir, MAX_PATH );
3449 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3452 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3453 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3454 if (handle != INVALID_HANDLE_VALUE)
3456 CloseHandle(handle);
3459 if (GetLastError() != ERROR_FILE_EXISTS &&
3460 GetLastError() != ERROR_SHARING_VIOLATION)
3462 if (!(++num & 0xffff)) num = 1;
3463 sprintfW(packagefile,fmt,num);
3464 } while (num != start);
3466 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3467 create_full_pathW(path);
3469 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3471 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3472 r = CopyFileW( msiFilePath, packagefile, FALSE);
3473 msi_free( msiFilePath );
3477 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3478 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3479 return ERROR_FUNCTION_FAILED;
3482 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3483 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3484 return ERROR_SUCCESS;
3487 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3489 LPWSTR prop, val, key;
3490 static const LPCSTR propval[] = {
3491 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3492 "ARPCONTACT", "Contact",
3493 "ARPCOMMENTS", "Comments",
3494 "ProductName", "DisplayName",
3495 "ProductVersion", "DisplayVersion",
3496 "ARPHELPLINK", "HelpLink",
3497 "ARPHELPTELEPHONE", "HelpTelephone",
3498 "ARPINSTALLLOCATION", "InstallLocation",
3499 "SourceDir", "InstallSource",
3500 "Manufacturer", "Publisher",
3501 "ARPREADME", "Readme",
3503 "ARPURLINFOABOUT", "URLInfoAbout",
3504 "ARPURLUPDATEINFO", "URLUpdateInfo",
3507 const LPCSTR *p = propval;
3511 prop = strdupAtoW( *p++ );
3512 key = strdupAtoW( *p++ );
3513 val = msi_dup_property( package, prop );
3514 msi_reg_set_val_str( hkey, key, val );
3519 return ERROR_SUCCESS;
3522 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3525 LPWSTR buffer = NULL;
3528 static const WCHAR szWindowsInstaller[] =
3529 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3530 static const WCHAR szUpgradeCode[] =
3531 {'U','p','g','r','a','d','e','C','o','d','e',0};
3532 static const WCHAR modpath_fmt[] =
3533 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3534 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3535 static const WCHAR szModifyPath[] =
3536 {'M','o','d','i','f','y','P','a','t','h',0};
3537 static const WCHAR szUninstallString[] =
3538 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3539 static const WCHAR szEstimatedSize[] =
3540 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3541 static const WCHAR szProductLanguage[] =
3542 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3543 static const WCHAR szProductVersion[] =
3544 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3547 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3548 LPWSTR upgrade_code;
3551 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3552 if (rc != ERROR_SUCCESS)
3555 /* dump all the info i can grab */
3556 /* FIXME: Flesh out more information */
3558 msi_write_uninstall_property_vals( package, hkey );
3560 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3562 msi_make_package_local( package, hkey );
3564 /* do ModifyPath and UninstallString */
3565 size = deformat_string(package,modpath_fmt,&buffer);
3566 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3567 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3570 /* FIXME: Write real Estimated Size when we have it */
3571 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3573 GetLocalTime(&systime);
3574 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3575 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3577 langid = msi_get_property_int( package, szProductLanguage, 0 );
3578 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3580 buffer = msi_dup_property( package, szProductVersion );
3583 DWORD verdword = msi_version_str_to_dword(buffer);
3585 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3586 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3587 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3591 /* Handle Upgrade Codes */
3592 upgrade_code = msi_dup_property( package, szUpgradeCode );
3597 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3598 squash_guid(package->ProductCode,squashed);
3599 msi_reg_set_val_str( hkey2, squashed, NULL );
3601 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3602 squash_guid(package->ProductCode,squashed);
3603 msi_reg_set_val_str( hkey2, squashed, NULL );
3606 msi_free(upgrade_code);
3611 /* FIXME: call ui_actiondata */
3613 return ERROR_SUCCESS;
3616 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3618 return execute_script(package,INSTALL_SCRIPT);
3621 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3625 /* turn off scheduleing */
3626 package->script->CurrentlyScripting= FALSE;
3628 /* first do the same as an InstallExecute */
3629 rc = ACTION_InstallExecute(package);
3630 if (rc != ERROR_SUCCESS)
3633 /* then handle Commit Actions */
3634 rc = execute_script(package,COMMIT_SCRIPT);
3639 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3641 static const WCHAR RunOnce[] = {
3642 'S','o','f','t','w','a','r','e','\\',
3643 'M','i','c','r','o','s','o','f','t','\\',
3644 'W','i','n','d','o','w','s','\\',
3645 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3646 'R','u','n','O','n','c','e',0};
3647 static const WCHAR InstallRunOnce[] = {
3648 'S','o','f','t','w','a','r','e','\\',
3649 'M','i','c','r','o','s','o','f','t','\\',
3650 'W','i','n','d','o','w','s','\\',
3651 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3652 'I','n','s','t','a','l','l','e','r','\\',
3653 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3655 static const WCHAR msiexec_fmt[] = {
3657 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3658 '\"','%','s','\"',0};
3659 static const WCHAR install_fmt[] = {
3660 '/','I',' ','\"','%','s','\"',' ',
3661 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3662 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3663 WCHAR buffer[256], sysdir[MAX_PATH];
3665 WCHAR squished_pc[100];
3667 squash_guid(package->ProductCode,squished_pc);
3669 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3670 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3671 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3674 msi_reg_set_val_str( hkey, squished_pc, buffer );
3677 TRACE("Reboot command %s\n",debugstr_w(buffer));
3679 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3680 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3682 msi_reg_set_val_str( hkey, squished_pc, buffer );
3685 return ERROR_INSTALL_SUSPEND;
3688 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3693 * we are currently doing what should be done here in the top level Install
3694 * however for Adminastrative and uninstalls this step will be needed
3696 if (!package->PackagePath)
3697 return ERROR_SUCCESS;
3699 attrib = GetFileAttributesW(package->PackagePath);
3700 if (attrib == INVALID_FILE_ATTRIBUTES)
3706 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3707 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3708 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3709 if (rc == ERROR_MORE_DATA)
3711 prompt = msi_alloc(size * sizeof(WCHAR));
3712 MsiSourceListGetInfoW(package->ProductCode, NULL,
3713 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3714 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3717 prompt = strdupW(package->PackagePath);
3719 msg = generate_error_string(package,1302,1,prompt);
3720 while(attrib == INVALID_FILE_ATTRIBUTES)
3722 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3725 rc = ERROR_INSTALL_USEREXIT;
3728 attrib = GetFileAttributesW(package->PackagePath);
3734 return ERROR_SUCCESS;
3739 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3746 static const WCHAR szPropKeys[][80] =
3748 {'P','r','o','d','u','c','t','I','D',0},
3749 {'U','S','E','R','N','A','M','E',0},
3750 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3754 static const WCHAR szRegKeys[][80] =
3756 {'P','r','o','d','u','c','t','I','D',0},
3757 {'R','e','g','O','w','n','e','r',0},
3758 {'R','e','g','C','o','m','p','a','n','y',0},
3762 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3764 return ERROR_SUCCESS;
3766 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3767 if (rc != ERROR_SUCCESS)
3770 for( i = 0; szPropKeys[i][0]; i++ )
3772 buffer = msi_dup_property( package, szPropKeys[i] );
3773 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3778 msi_free(productid);
3781 /* FIXME: call ui_actiondata */
3783 return ERROR_SUCCESS;
3787 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3791 package->script->InWhatSequence |= SEQUENCE_EXEC;
3792 rc = ACTION_ProcessExecSequence(package,FALSE);
3798 * Code based off of code located here
3799 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3801 * Using string index 4 (full font name) instead of 1 (family name)
3803 static LPWSTR load_ttfname_from(LPCWSTR filename)
3809 typedef struct _tagTT_OFFSET_TABLE{
3810 USHORT uMajorVersion;
3811 USHORT uMinorVersion;
3812 USHORT uNumOfTables;
3813 USHORT uSearchRange;
3814 USHORT uEntrySelector;
3818 typedef struct _tagTT_TABLE_DIRECTORY{
3819 char szTag[4]; /* table name */
3820 ULONG uCheckSum; /* Check sum */
3821 ULONG uOffset; /* Offset from beginning of file */
3822 ULONG uLength; /* length of the table in bytes */
3823 }TT_TABLE_DIRECTORY;
3825 typedef struct _tagTT_NAME_TABLE_HEADER{
3826 USHORT uFSelector; /* format selector. Always 0 */
3827 USHORT uNRCount; /* Name Records count */
3828 USHORT uStorageOffset; /* Offset for strings storage,
3829 * from start of the table */
3830 }TT_NAME_TABLE_HEADER;
3832 typedef struct _tagTT_NAME_RECORD{
3837 USHORT uStringLength;
3838 USHORT uStringOffset; /* from start of storage area */
3841 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3842 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3844 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3845 FILE_ATTRIBUTE_NORMAL, 0 );
3846 if (handle != INVALID_HANDLE_VALUE)
3848 TT_TABLE_DIRECTORY tblDir;
3849 BOOL bFound = FALSE;
3850 TT_OFFSET_TABLE ttOffsetTable;
3853 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3854 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3855 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3856 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3858 if (ttOffsetTable.uMajorVersion != 1 ||
3859 ttOffsetTable.uMinorVersion != 0)
3862 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3864 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3865 if (strncmp(tblDir.szTag,"name",4)==0)
3868 tblDir.uLength = SWAPLONG(tblDir.uLength);
3869 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3876 TT_NAME_TABLE_HEADER ttNTHeader;
3877 TT_NAME_RECORD ttRecord;
3879 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3880 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3883 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3884 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3886 for(i=0; i<ttNTHeader.uNRCount; i++)
3888 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3889 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3890 /* 4 is the Full Font Name */
3891 if(ttRecord.uNameID == 4)
3895 static LPCSTR tt = " (TrueType)";
3897 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3898 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3899 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3900 SetFilePointer(handle, tblDir.uOffset +
3901 ttRecord.uStringOffset +
3902 ttNTHeader.uStorageOffset,
3904 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3905 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3906 if (strlen(buf) > 0)
3909 ret = strdupAtoW(buf);
3915 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3919 CloseHandle(handle);
3922 ERR("Unable to open font file %s\n", debugstr_w(filename));
3924 TRACE("Returning fontname %s\n",debugstr_w(ret));
3928 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3930 MSIPACKAGE *package = (MSIPACKAGE*)param;
3934 static const WCHAR regfont1[] =
3935 {'S','o','f','t','w','a','r','e','\\',
3936 'M','i','c','r','o','s','o','f','t','\\',
3937 'W','i','n','d','o','w','s',' ','N','T','\\',
3938 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3939 'F','o','n','t','s',0};
3940 static const WCHAR regfont2[] =
3941 {'S','o','f','t','w','a','r','e','\\',
3942 'M','i','c','r','o','s','o','f','t','\\',
3943 'W','i','n','d','o','w','s','\\',
3944 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3945 'F','o','n','t','s',0};
3951 filename = MSI_RecordGetString( row, 1 );
3952 file = get_loaded_file( package, filename );
3955 ERR("Unable to load file\n");
3956 return ERROR_SUCCESS;
3959 /* check to make sure that component is installed */
3960 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3962 TRACE("Skipping: Component not scheduled for install\n");
3963 return ERROR_SUCCESS;
3966 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3967 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3969 if (MSI_RecordIsNull(row,2))
3970 name = load_ttfname_from( file->TargetPath );
3972 name = msi_dup_record_field(row,2);
3976 msi_reg_set_val_str( hkey1, name, file->FileName );
3977 msi_reg_set_val_str( hkey2, name, file->FileName );
3985 uirow = MSI_CreateRecord( 1 );
3986 uipath = strdupW( file->TargetPath );
3987 p = strrchrW(uipath,'\\');
3990 MSI_RecordSetStringW( uirow, 1, p );
3991 ui_actiondata( package, szRegisterFonts, uirow);
3992 msiobj_release( &uirow->hdr );
3994 /* FIXME: call ui_progress? */
3996 return ERROR_SUCCESS;
3999 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4003 static const WCHAR ExecSeqQuery[] =
4004 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4005 '`','F','o','n','t','`',0};
4007 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4008 if (rc != ERROR_SUCCESS)
4010 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4011 return ERROR_SUCCESS;
4014 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4015 msiobj_release(&view->hdr);
4017 return ERROR_SUCCESS;
4020 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4022 MSIPACKAGE *package = (MSIPACKAGE*)param;
4023 LPCWSTR compgroupid=NULL;
4024 LPCWSTR feature=NULL;
4025 LPCWSTR text = NULL;
4026 LPCWSTR qualifier = NULL;
4027 LPCWSTR component = NULL;
4028 LPWSTR advertise = NULL;
4029 LPWSTR output = NULL;
4031 UINT rc = ERROR_SUCCESS;
4036 component = MSI_RecordGetString(rec,3);
4037 comp = get_loaded_component(package,component);
4039 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4040 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4041 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4043 TRACE("Skipping: Component %s not scheduled for install\n",
4044 debugstr_w(component));
4046 return ERROR_SUCCESS;
4049 compgroupid = MSI_RecordGetString(rec,1);
4050 qualifier = MSI_RecordGetString(rec,2);
4052 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4053 if (rc != ERROR_SUCCESS)
4056 text = MSI_RecordGetString(rec,4);
4057 feature = MSI_RecordGetString(rec,5);
4059 advertise = create_component_advertise_string(package, comp, feature);
4061 sz = strlenW(advertise);
4064 sz += lstrlenW(text);
4067 sz *= sizeof(WCHAR);
4069 output = msi_alloc_zero(sz);
4070 strcpyW(output,advertise);
4071 msi_free(advertise);
4074 strcatW(output,text);
4076 msi_reg_set_val_multi_str( hkey, qualifier, output );
4083 uirow = MSI_CreateRecord( 2 );
4084 MSI_RecordSetStringW( uirow, 1, compgroupid );
4085 MSI_RecordSetStringW( uirow, 2, qualifier);
4086 ui_actiondata( package, szPublishComponents, uirow);
4087 msiobj_release( &uirow->hdr );
4088 /* FIXME: call ui_progress? */
4094 * At present I am ignorning the advertised components part of this and only
4095 * focusing on the qualified component sets
4097 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4101 static const WCHAR ExecSeqQuery[] =
4102 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4103 '`','P','u','b','l','i','s','h',
4104 'C','o','m','p','o','n','e','n','t','`',0};
4106 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4107 if (rc != ERROR_SUCCESS)
4108 return ERROR_SUCCESS;
4110 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4111 msiobj_release(&view->hdr);
4116 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4117 LPCSTR action, LPCWSTR table )
4119 static const WCHAR query[] = {
4120 'S','E','L','E','C','T',' ','*',' ',
4121 'F','R','O','M',' ','`','%','s','`',0 };
4122 MSIQUERY *view = NULL;
4126 r = MSI_OpenQuery( package->db, &view, query, table );
4127 if (r == ERROR_SUCCESS)
4129 r = MSI_IterateRecords(view, &count, NULL, package);
4130 msiobj_release(&view->hdr);
4134 FIXME("%s -> %lu ignored %s table values\n",
4135 action, count, debugstr_w(table));
4137 return ERROR_SUCCESS;
4140 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4142 TRACE("%p\n", package);
4143 return ERROR_SUCCESS;
4146 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4148 static const WCHAR table[] =
4149 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4150 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4153 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4155 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4156 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4159 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4161 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4162 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4165 static UINT ACTION_BindImage( MSIPACKAGE *package )
4167 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4168 return msi_unimplemented_action_stub( package, "BindImage", table );
4171 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4173 static const WCHAR table[] = {
4174 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4175 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4178 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4180 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4181 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4184 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4186 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4187 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4190 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4192 static const WCHAR table[] = {
4193 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4194 return msi_unimplemented_action_stub( package, "InstallServices", table );
4197 static UINT ACTION_StartServices( MSIPACKAGE *package )
4199 static const WCHAR table[] = {
4200 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4201 return msi_unimplemented_action_stub( package, "StartServices", table );
4204 static UINT ACTION_StopServices( MSIPACKAGE *package )
4206 static const WCHAR table[] = {
4207 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4208 return msi_unimplemented_action_stub( package, "StopServices", table );
4211 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4213 static const WCHAR table[] = {
4214 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4215 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4218 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4220 static const WCHAR table[] = {
4221 'E','n','v','i','r','o','n','m','e','n','t',0 };
4222 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4225 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4227 static const WCHAR table[] = {
4228 'E','n','v','i','r','o','n','m','e','n','t',0 };
4229 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4232 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4234 static const WCHAR table[] = {
4235 'M','s','i','A','s','s','e','m','b','l','y',0 };
4236 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4239 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4241 static const WCHAR table[] = {
4242 'M','s','i','A','s','s','e','m','b','l','y',0 };
4243 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4246 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4248 static const WCHAR table[] = { 'F','o','n','t',0 };
4249 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4252 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4254 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4255 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4258 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4260 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4261 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4264 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4266 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4267 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4270 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4272 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4273 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4276 static struct _actions StandardActions[] = {
4277 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4278 { szAppSearch, ACTION_AppSearch },
4279 { szBindImage, ACTION_BindImage },
4280 { szCCPSearch, ACTION_CCPSearch},
4281 { szCostFinalize, ACTION_CostFinalize },
4282 { szCostInitialize, ACTION_CostInitialize },
4283 { szCreateFolders, ACTION_CreateFolders },
4284 { szCreateShortcuts, ACTION_CreateShortcuts },
4285 { szDeleteServices, ACTION_DeleteServices },
4286 { szDisableRollback, NULL},
4287 { szDuplicateFiles, ACTION_DuplicateFiles },
4288 { szExecuteAction, ACTION_ExecuteAction },
4289 { szFileCost, ACTION_FileCost },
4290 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4291 { szForceReboot, ACTION_ForceReboot },
4292 { szInstallAdminPackage, NULL},
4293 { szInstallExecute, ACTION_InstallExecute },
4294 { szInstallExecuteAgain, ACTION_InstallExecute },
4295 { szInstallFiles, ACTION_InstallFiles},
4296 { szInstallFinalize, ACTION_InstallFinalize },
4297 { szInstallInitialize, ACTION_InstallInitialize },
4298 { szInstallSFPCatalogFile, NULL},
4299 { szInstallValidate, ACTION_InstallValidate },
4300 { szIsolateComponents, ACTION_IsolateComponents },
4301 { szLaunchConditions, ACTION_LaunchConditions },
4302 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4303 { szMoveFiles, ACTION_MoveFiles },
4304 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4305 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4306 { szInstallODBC, NULL},
4307 { szInstallServices, ACTION_InstallServices },
4308 { szPatchFiles, ACTION_PatchFiles },
4309 { szProcessComponents, ACTION_ProcessComponents },
4310 { szPublishComponents, ACTION_PublishComponents },
4311 { szPublishFeatures, ACTION_PublishFeatures },
4312 { szPublishProduct, ACTION_PublishProduct },
4313 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4314 { szRegisterComPlus, ACTION_RegisterComPlus},
4315 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4316 { szRegisterFonts, ACTION_RegisterFonts },
4317 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4318 { szRegisterProduct, ACTION_RegisterProduct },
4319 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4320 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4321 { szRegisterUser, ACTION_RegisterUser},
4322 { szRemoveDuplicateFiles, NULL},
4323 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4324 { szRemoveExistingProducts, NULL},
4325 { szRemoveFiles, ACTION_RemoveFiles},
4326 { szRemoveFolders, NULL},
4327 { szRemoveIniValues, ACTION_RemoveIniValues },
4328 { szRemoveODBC, NULL},
4329 { szRemoveRegistryValues, NULL},
4330 { szRemoveShortcuts, NULL},
4331 { szResolveSource, ACTION_ResolveSource},
4332 { szRMCCPSearch, ACTION_RMCCPSearch},
4333 { szScheduleReboot, NULL},
4334 { szSelfRegModules, ACTION_SelfRegModules },
4335 { szSelfUnregModules, ACTION_SelfUnregModules },
4336 { szSetODBCFolders, NULL},
4337 { szStartServices, ACTION_StartServices },
4338 { szStopServices, ACTION_StopServices },
4339 { szUnpublishComponents, NULL},
4340 { szUnpublishFeatures, NULL},
4341 { szUnregisterClassInfo, NULL},
4342 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4343 { szUnregisterExtensionInfo, NULL},
4344 { szUnregisterFonts, ACTION_UnregisterFonts },
4345 { szUnregisterMIMEInfo, NULL},
4346 { szUnregisterProgIdInfo, NULL},
4347 { szUnregisterTypeLibraries, NULL},
4348 { szValidateProductID, NULL},
4349 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4350 { szWriteIniValues, ACTION_WriteIniValues },
4351 { szWriteRegistryValues, ACTION_WriteRegistryValues},