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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 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 int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
297 LPWSTR str = msi_dup_property( package, prop );
298 int val = str ? atoiW( str ) : def;
303 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
308 LPWSTR prop = NULL, val = NULL;
311 return ERROR_SUCCESS;
323 TRACE("Looking at %s\n",debugstr_w(ptr));
325 ptr2 = strchrW(ptr,'=');
328 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
335 prop = msi_alloc((len+1)*sizeof(WCHAR));
336 memcpy(prop,ptr,len*sizeof(WCHAR));
342 while (*ptr && (quote || (!quote && *ptr!=' ')))
355 val = msi_alloc((len+1)*sizeof(WCHAR));
356 memcpy(val,ptr2,len*sizeof(WCHAR));
359 if (lstrlenW(prop) > 0)
361 TRACE("Found commandline property (%s) = (%s)\n",
362 debugstr_w(prop), debugstr_w(val));
363 MSI_SetPropertyW(package,prop,val);
369 return ERROR_SUCCESS;
373 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
375 LPWSTR p, *ret = NULL;
381 /* count the number of substrings */
382 for ( p = (LPWSTR)str, count = 0; p; count++ )
384 p = strchrW( p, sep );
389 /* allocate space for an array of substring pointers and the substrings */
390 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
391 (lstrlenW(str)+1) * sizeof(WCHAR) );
395 /* copy the string and set the pointers */
396 p = (LPWSTR) &ret[count+1];
398 for( count = 0; (ret[count] = p); count++ )
400 p = strchrW( p, sep );
408 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
415 TRACE("%p %s\n", package, debugstr_w(name) );
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
426 ret = msi_table_apply_transform( package->db, stg );
427 IStorage_Release( stg );
431 ERR("failed to open substorage %s\n", debugstr_w(name));
436 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
438 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
439 LPWSTR guid_list, *guids, product_id;
440 UINT i, ret = ERROR_FUNCTION_FAILED;
442 product_id = msi_dup_property( package, szProdID );
445 /* FIXME: the property ProductID should be written into the DB somewhere */
446 ERR("no product ID to check\n");
447 return ERROR_SUCCESS;
450 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
451 guids = msi_split_string( guid_list, ';' );
452 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
454 if (!lstrcmpW( guids[i], product_id ))
458 msi_free( guid_list );
459 msi_free( product_id );
464 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
467 LPWSTR str, *substorage;
468 UINT i, r = ERROR_SUCCESS;
470 si = MSI_GetSummaryInformationW( patch_db, 0 );
472 return ERROR_FUNCTION_FAILED;
474 msi_check_patch_applicable( package, si );
476 /* enumerate the substorage */
477 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
478 substorage = msi_split_string( str, ';' );
479 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
480 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
481 msi_free( substorage );
484 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
486 msiobj_release( &si->hdr );
491 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
493 MSIDATABASE *patch_db = NULL;
496 TRACE("%p %s\n", package, debugstr_w( file ) );
499 * We probably want to make sure we only open a patch collection here.
500 * Patch collections (.msp) and databases (.msi) have different GUIDs
501 * but currently MSI_OpenDatabaseW will accept both.
503 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
504 if ( r != ERROR_SUCCESS )
506 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
510 msi_parse_patch_summary( package, patch_db );
511 msiobj_release( &patch_db->hdr );
513 return ERROR_SUCCESS;
516 /* get the PATCH property, and apply all the patches it specifies */
517 static UINT msi_apply_patches( MSIPACKAGE *package )
519 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
520 LPWSTR patch_list, *patches;
521 UINT i, r = ERROR_SUCCESS;
523 patch_list = msi_dup_property( package, szPatch );
525 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
527 patches = msi_split_string( patch_list, ';' );
528 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
529 r = msi_apply_patch_package( package, patches[i] );
532 msi_free( patch_list );
537 static UINT msi_apply_transforms( MSIPACKAGE *package )
539 static const WCHAR szTransforms[] = {
540 'T','R','A','N','S','F','O','R','M','S',0 };
541 LPWSTR xform_list, *xforms;
542 UINT i, r = ERROR_SUCCESS;
544 xform_list = msi_dup_property( package, szTransforms );
545 xforms = msi_split_string( xform_list, ';' );
547 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
549 if (xforms[i][0] == ':')
550 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
552 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
556 msi_free( xform_list );
561 /****************************************************
562 * TOP level entry points
563 *****************************************************/
565 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
566 LPCWSTR szCommandLine )
570 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
571 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
572 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
574 MSI_SetPropertyW(package, szAction, szInstall);
576 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
578 package->script->InWhatSequence = SEQUENCE_INSTALL;
582 LPWSTR p, check, path;
584 package->PackagePath = strdupW(szPackagePath);
585 path = strdupW(szPackagePath);
586 p = strrchrW(path,'\\');
595 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
596 GetCurrentDirectoryW(MAX_PATH,path);
600 check = msi_dup_property( package, cszSourceDir );
602 MSI_SetPropertyW(package, cszSourceDir, path);
607 msi_parse_command_line( package, szCommandLine );
609 msi_apply_transforms( package );
610 msi_apply_patches( package );
612 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
614 package->script->InWhatSequence |= SEQUENCE_UI;
615 rc = ACTION_ProcessUISequence(package);
617 if (rc == ERROR_SUCCESS)
619 package->script->InWhatSequence |= SEQUENCE_EXEC;
620 rc = ACTION_ProcessExecSequence(package,TRUE);
624 rc = ACTION_ProcessExecSequence(package,FALSE);
628 /* install was halted but should be considered a success */
632 package->script->CurrentlyScripting= FALSE;
634 /* process the ending type action */
635 if (rc == ERROR_SUCCESS)
636 ACTION_PerformActionSequence(package,-1,ui);
637 else if (rc == ERROR_INSTALL_USEREXIT)
638 ACTION_PerformActionSequence(package,-2,ui);
639 else if (rc == ERROR_INSTALL_SUSPEND)
640 ACTION_PerformActionSequence(package,-4,ui);
642 ACTION_PerformActionSequence(package,-3,ui);
644 /* finish up running custom actions */
645 ACTION_FinishCustomActions(package);
650 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
652 UINT rc = ERROR_SUCCESS;
654 static const WCHAR ExecSeqQuery[] =
655 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
656 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
657 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
658 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
660 static const WCHAR UISeqQuery[] =
661 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
662 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
663 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
664 ' ', '=',' ','%','i',0};
667 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
669 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
673 LPCWSTR action, cond;
675 TRACE("Running the actions\n");
677 /* check conditions */
678 cond = MSI_RecordGetString(row,2);
681 /* this is a hack to skip errors in the condition code */
682 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
686 action = MSI_RecordGetString(row,1);
689 ERR("failed to fetch action\n");
690 rc = ERROR_FUNCTION_FAILED;
695 rc = ACTION_PerformUIAction(package,action);
697 rc = ACTION_PerformAction(package,action,FALSE);
699 msiobj_release(&row->hdr);
710 } iterate_action_param;
712 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
714 iterate_action_param *iap= (iterate_action_param*)param;
716 LPCWSTR cond, action;
718 action = MSI_RecordGetString(row,1);
721 ERR("Error is retrieving action name\n");
722 return ERROR_FUNCTION_FAILED;
725 /* check conditions */
726 cond = MSI_RecordGetString(row,2);
729 /* this is a hack to skip errors in the condition code */
730 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
732 TRACE("Skipping action: %s (condition is false)\n",
734 return ERROR_SUCCESS;
739 rc = ACTION_PerformUIAction(iap->package,action);
741 rc = ACTION_PerformAction(iap->package,action,FALSE);
743 msi_dialog_check_messages( NULL );
745 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
746 rc = iap->package->CurrentInstallState;
748 if (rc == ERROR_FUNCTION_NOT_CALLED)
751 if (rc != ERROR_SUCCESS)
752 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
757 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
761 static const WCHAR query[] =
762 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
764 ' ','W','H','E','R','E',' ',
765 '`','S','e','q','u','e','n','c','e','`',' ',
766 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
767 '`','S','e','q','u','e','n','c','e','`',0};
768 iterate_action_param iap;
771 * FIXME: probably should be checking UILevel in the
772 * ACTION_PerformUIAction/ACTION_PerformAction
773 * rather than saving the UI level here. Those
774 * two functions can be merged too.
776 iap.package = package;
779 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
781 r = MSI_OpenQuery( package->db, &view, query, szTable );
782 if (r == ERROR_SUCCESS)
784 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
785 msiobj_release(&view->hdr);
791 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
795 static const WCHAR ExecSeqQuery[] =
796 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
797 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
798 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
799 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
800 'O','R','D','E','R',' ', 'B','Y',' ',
801 '`','S','e','q','u','e','n','c','e','`',0 };
803 static const WCHAR IVQuery[] =
804 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
805 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
806 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
807 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
808 ' ','\'', 'I','n','s','t','a','l','l',
809 'V','a','l','i','d','a','t','e','\'', 0};
811 iterate_action_param iap;
813 iap.package = package;
816 if (package->script->ExecuteSequenceRun)
818 TRACE("Execute Sequence already Run\n");
819 return ERROR_SUCCESS;
822 package->script->ExecuteSequenceRun = TRUE;
824 /* get the sequence number */
827 row = MSI_QueryGetRecord(package->db, IVQuery);
829 return ERROR_FUNCTION_FAILED;
830 seq = MSI_RecordGetInteger(row,1);
831 msiobj_release(&row->hdr);
834 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
835 if (rc == ERROR_SUCCESS)
837 TRACE("Running the actions\n");
839 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
840 msiobj_release(&view->hdr);
846 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
850 static const WCHAR ExecSeqQuery [] =
851 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
852 '`','I','n','s','t','a','l','l',
853 'U','I','S','e','q','u','e','n','c','e','`',
854 ' ','W','H','E','R','E',' ',
855 '`','S','e','q','u','e','n','c','e','`',' ',
856 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
857 '`','S','e','q','u','e','n','c','e','`',0};
858 iterate_action_param iap;
860 iap.package = package;
863 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
865 if (rc == ERROR_SUCCESS)
867 TRACE("Running the actions\n");
869 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
870 msiobj_release(&view->hdr);
876 /********************************************************
877 * ACTION helper functions and functions that perform the actions
878 *******************************************************/
879 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
880 UINT* rc, BOOL force )
888 ERR("package was null!\n");
892 if (!run && !package->script->CurrentlyScripting)
897 if (strcmpW(action,szInstallFinalize) == 0 ||
898 strcmpW(action,szInstallExecute) == 0 ||
899 strcmpW(action,szInstallExecuteAgain) == 0)
904 while (StandardActions[i].action != NULL)
906 if (strcmpW(StandardActions[i].action, action)==0)
910 ui_actioninfo(package, action, TRUE, 0);
911 *rc = schedule_action(package,INSTALL_SCRIPT,action);
912 ui_actioninfo(package, action, FALSE, *rc);
916 ui_actionstart(package, action);
917 if (StandardActions[i].handler)
919 *rc = StandardActions[i].handler(package);
923 FIXME("unhandled standard action %s\n",debugstr_w(action));
935 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
936 UINT* rc, BOOL force )
941 arc = ACTION_CustomAction(package,action, force);
943 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
952 * A lot of actions are really important even if they don't do anything
953 * explicit... Lots of properties are set at the beginning of the installation
954 * CostFinalize does a bunch of work to translate the directories and such
956 * But until I get write access to the database that is hard, so I am going to
957 * hack it to see if I can get something to run.
959 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
961 UINT rc = ERROR_SUCCESS;
964 TRACE("Performing action (%s)\n",debugstr_w(action));
966 handled = ACTION_HandleStandardAction(package, action, &rc, force);
969 handled = ACTION_HandleCustomAction(package, action, &rc, force);
973 FIXME("unhandled msi action %s\n",debugstr_w(action));
974 rc = ERROR_FUNCTION_NOT_CALLED;
980 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
982 UINT rc = ERROR_SUCCESS;
983 BOOL handled = FALSE;
985 TRACE("Performing action (%s)\n",debugstr_w(action));
987 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
990 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
992 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
997 FIXME("unhandled msi action %s\n",debugstr_w(action));
998 rc = ERROR_FUNCTION_NOT_CALLED;
1006 * Actual Action Handlers
1009 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1011 MSIPACKAGE *package = (MSIPACKAGE*)param;
1017 dir = MSI_RecordGetString(row,1);
1020 ERR("Unable to get folder id\n");
1021 return ERROR_SUCCESS;
1024 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1027 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1028 return ERROR_SUCCESS;
1031 TRACE("Folder is %s\n",debugstr_w(full_path));
1034 uirow = MSI_CreateRecord(1);
1035 MSI_RecordSetStringW(uirow,1,full_path);
1036 ui_actiondata(package,szCreateFolders,uirow);
1037 msiobj_release( &uirow->hdr );
1039 if (folder->State == 0)
1040 create_full_pathW(full_path);
1044 msi_free(full_path);
1045 return ERROR_SUCCESS;
1048 /* FIXME: probably should merge this with the above function */
1049 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1051 UINT rc = ERROR_SUCCESS;
1053 LPWSTR install_path;
1055 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1057 return ERROR_FUNCTION_FAILED;
1059 /* create the path */
1060 if (folder->State == 0)
1062 create_full_pathW(install_path);
1065 msi_free(install_path);
1070 UINT msi_create_component_directories( MSIPACKAGE *package )
1074 /* create all the folders required by the components are going to install */
1075 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1077 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1079 msi_create_directory( package, comp->Directory );
1082 return ERROR_SUCCESS;
1086 * Also we cannot enable/disable components either, so for now I am just going
1087 * to do all the directories for all the components.
1089 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1091 static const WCHAR ExecSeqQuery[] =
1092 {'S','E','L','E','C','T',' ',
1093 '`','D','i','r','e','c','t','o','r','y','_','`',
1094 ' ','F','R','O','M',' ',
1095 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1099 /* create all the empty folders specified in the CreateFolder table */
1100 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1101 if (rc != ERROR_SUCCESS)
1102 return ERROR_SUCCESS;
1104 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1105 msiobj_release(&view->hdr);
1107 msi_create_component_directories( package );
1112 static MSICOMPONENT* load_component( MSIRECORD * row )
1116 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1120 /* fill in the data */
1121 comp->Component = msi_dup_record_field( row, 1 );
1123 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1125 comp->ComponentId = msi_dup_record_field( row, 2 );
1126 comp->Directory = msi_dup_record_field( row, 3 );
1127 comp->Attributes = MSI_RecordGetInteger(row,4);
1128 comp->Condition = msi_dup_record_field( row, 5 );
1129 comp->KeyPath = msi_dup_record_field( row, 6 );
1131 comp->Installed = INSTALLSTATE_ABSENT;
1132 comp->Action = INSTALLSTATE_UNKNOWN;
1133 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1135 comp->Enabled = TRUE;
1141 MSIPACKAGE *package;
1142 MSIFEATURE *feature;
1145 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1149 cl = msi_alloc( sizeof (*cl) );
1151 return ERROR_NOT_ENOUGH_MEMORY;
1152 cl->component = comp;
1153 list_add_tail( &feature->Components, &cl->entry );
1155 return ERROR_SUCCESS;
1158 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1160 _ilfs* ilfs= (_ilfs*)param;
1161 MSIPACKAGE *package = ilfs->package;
1162 MSIFEATURE *feature = ilfs->feature;
1165 comp = load_component( row );
1167 return ERROR_FUNCTION_FAILED;
1169 list_add_tail( &package->components, &comp->entry );
1170 add_feature_component( feature, comp );
1172 TRACE("Loaded new component %p\n", comp);
1174 return ERROR_SUCCESS;
1177 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1179 _ilfs* ilfs= (_ilfs*)param;
1184 static const WCHAR Query[] =
1185 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1186 '`','C','o','m','p','o','n','e','n','t','`',' ',
1187 'W','H','E','R','E',' ',
1188 '`','C','o','m','p','o','n','e','n','t','`',' ',
1189 '=','\'','%','s','\'',0};
1191 component = MSI_RecordGetString(row,1);
1193 /* check to see if the component is already loaded */
1194 comp = get_loaded_component( ilfs->package, component );
1197 TRACE("Component %s already loaded\n", debugstr_w(component) );
1198 add_feature_component( ilfs->feature, comp );
1199 return ERROR_SUCCESS;
1202 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1203 if (rc != ERROR_SUCCESS)
1204 return ERROR_SUCCESS;
1206 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1207 msiobj_release( &view->hdr );
1209 return ERROR_SUCCESS;
1212 static UINT load_feature(MSIRECORD * row, LPVOID param)
1214 MSIPACKAGE* package = (MSIPACKAGE*)param;
1215 MSIFEATURE* feature;
1216 static const WCHAR Query1[] =
1217 {'S','E','L','E','C','T',' ',
1218 '`','C','o','m','p','o','n','e','n','t','_','`',
1219 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1220 'C','o','m','p','o','n','e','n','t','s','`',' ',
1221 'W','H','E','R','E',' ',
1222 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1227 /* fill in the data */
1229 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1231 return ERROR_NOT_ENOUGH_MEMORY;
1233 list_init( &feature->Components );
1235 feature->Feature = msi_dup_record_field( row, 1 );
1237 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1239 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1240 feature->Title = msi_dup_record_field( row, 3 );
1241 feature->Description = msi_dup_record_field( row, 4 );
1243 if (!MSI_RecordIsNull(row,5))
1244 feature->Display = MSI_RecordGetInteger(row,5);
1246 feature->Level= MSI_RecordGetInteger(row,6);
1247 feature->Directory = msi_dup_record_field( row, 7 );
1248 feature->Attributes = MSI_RecordGetInteger(row,8);
1250 feature->Installed = INSTALLSTATE_ABSENT;
1251 feature->Action = INSTALLSTATE_UNKNOWN;
1252 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1254 list_add_tail( &package->features, &feature->entry );
1256 /* load feature components */
1258 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1259 if (rc != ERROR_SUCCESS)
1260 return ERROR_SUCCESS;
1262 ilfs.package = package;
1263 ilfs.feature = feature;
1265 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1266 msiobj_release(&view->hdr);
1268 return ERROR_SUCCESS;
1271 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1282 static UINT load_file(MSIRECORD *row, LPVOID param)
1284 MSIPACKAGE* package = (MSIPACKAGE*)param;
1288 /* fill in the data */
1290 file = msi_alloc_zero( sizeof (MSIFILE) );
1292 return ERROR_NOT_ENOUGH_MEMORY;
1294 file->File = msi_dup_record_field( row, 1 );
1296 component = MSI_RecordGetString( row, 2 );
1297 file->Component = get_loaded_component( package, component );
1299 if (!file->Component)
1300 ERR("Unfound Component %s\n",debugstr_w(component));
1302 file->FileName = msi_dup_record_field( row, 3 );
1303 reduce_to_longfilename( file->FileName );
1305 file->ShortName = msi_dup_record_field( row, 3 );
1306 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1308 file->FileSize = MSI_RecordGetInteger( row, 4 );
1309 file->Version = msi_dup_record_field( row, 5 );
1310 file->Language = msi_dup_record_field( row, 6 );
1311 file->Attributes = MSI_RecordGetInteger( row, 7 );
1312 file->Sequence = MSI_RecordGetInteger( row, 8 );
1314 file->state = msifs_invalid;
1316 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1318 list_add_tail( &package->files, &file->entry );
1320 return ERROR_SUCCESS;
1323 static UINT load_all_files(MSIPACKAGE *package)
1327 static const WCHAR Query[] =
1328 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1330 '`','S','e','q','u','e','n','c','e','`', 0};
1333 return ERROR_INVALID_HANDLE;
1335 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1336 if (rc != ERROR_SUCCESS)
1337 return ERROR_SUCCESS;
1339 rc = MSI_IterateRecords(view, NULL, load_file, package);
1340 msiobj_release(&view->hdr);
1342 return ERROR_SUCCESS;
1347 * I am not doing any of the costing functionality yet.
1348 * Mostly looking at doing the Component and Feature loading
1350 * The native MSI does A LOT of modification to tables here. Mostly adding
1351 * a lot of temporary columns to the Feature and Component tables.
1353 * note: Native msi also tracks the short filename. But I am only going to
1354 * track the long ones. Also looking at this directory table
1355 * it appears that the directory table does not get the parents
1356 * resolved base on property only based on their entries in the
1359 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1363 static const WCHAR Query_all[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','e','a','t','u','r','e','`',0};
1366 static const WCHAR szCosting[] =
1367 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1368 static const WCHAR szZero[] = { '0', 0 };
1370 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1371 return ERROR_SUCCESS;
1373 MSI_SetPropertyW(package, szCosting, szZero);
1374 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1376 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1377 if (rc != ERROR_SUCCESS)
1380 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1381 msiobj_release(&view->hdr);
1383 load_all_files(package);
1385 return ERROR_SUCCESS;
1388 static UINT execute_script(MSIPACKAGE *package, UINT script )
1391 UINT rc = ERROR_SUCCESS;
1393 TRACE("Executing Script %i\n",script);
1395 if (!package->script)
1397 ERR("no script!\n");
1398 return ERROR_FUNCTION_FAILED;
1401 for (i = 0; i < package->script->ActionCount[script]; i++)
1404 action = package->script->Actions[script][i];
1405 ui_actionstart(package, action);
1406 TRACE("Executing Action (%s)\n",debugstr_w(action));
1407 rc = ACTION_PerformAction(package, action, TRUE);
1408 msi_free(package->script->Actions[script][i]);
1409 if (rc != ERROR_SUCCESS)
1412 msi_free(package->script->Actions[script]);
1414 package->script->ActionCount[script] = 0;
1415 package->script->Actions[script] = NULL;
1419 static UINT ACTION_FileCost(MSIPACKAGE *package)
1421 return ERROR_SUCCESS;
1424 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1426 static const WCHAR Query[] =
1427 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1428 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1429 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1430 ' ','=',' ','\'','%','s','\'',
1432 static const WCHAR szDot[] = { '.',0 };
1433 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1438 TRACE("Looking for dir %s\n",debugstr_w(dir));
1440 folder = get_loaded_folder( package, dir );
1444 TRACE("Working to load %s\n",debugstr_w(dir));
1446 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1450 folder->Directory = strdupW(dir);
1452 row = MSI_QueryGetRecord(package->db, Query, dir);
1456 p = msi_dup_record_field(row, 3);
1458 /* split src and target dir */
1460 src_short = folder_split_path( p, ':' );
1462 /* split the long and short pathes */
1463 tgt_long = folder_split_path( tgt_short, '|' );
1464 src_long = folder_split_path( src_short, '|' );
1466 /* check for root dirs */
1467 if (!lstrcmpW(szDot, tgt_short))
1469 if (!lstrcmpW(szDot, tgt_long))
1473 tgt_long = tgt_short;
1475 src_short = tgt_long;
1477 src_long = src_short;
1479 /* FIXME: use the target short path too */
1480 folder->TargetDefault = strdupW(tgt_long);
1481 folder->SourceShortPath = strdupW(src_long);
1482 folder->SourceLongPath = strdupW(src_long);
1485 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1486 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1487 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1489 parent = MSI_RecordGetString(row, 2);
1492 folder->Parent = load_folder( package, parent );
1493 if ( folder->Parent )
1494 TRACE("loaded parent %p %s\n", folder->Parent,
1495 debugstr_w(folder->Parent->Directory));
1497 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1500 folder->Property = msi_dup_property( package, dir );
1502 msiobj_release(&row->hdr);
1504 list_add_tail( &package->folders, &folder->entry );
1506 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1511 /* scan for and update current install states */
1512 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1515 MSIFEATURE *feature;
1517 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1520 res = MsiGetComponentPathW( package->ProductCode,
1521 comp->ComponentId, NULL, NULL);
1523 res = INSTALLSTATE_ABSENT;
1524 comp->Installed = res;
1527 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1530 INSTALLSTATE res = -10;
1532 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1534 comp= cl->component;
1537 res = comp->Installed;
1540 if (res == comp->Installed)
1543 if (res != comp->Installed)
1544 res = INSTALLSTATE_INCOMPLETE;
1547 feature->Installed = res;
1551 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1554 static const WCHAR all[]={'A','L','L',0};
1556 MSIFEATURE *feature;
1558 override = msi_dup_property( package, property );
1562 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1564 if (strcmpiW(override,all)==0)
1566 feature->ActionRequest= state;
1567 feature->Action = state;
1571 LPWSTR ptr = override;
1572 LPWSTR ptr2 = strchrW(override,',');
1576 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1577 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1579 feature->ActionRequest= state;
1580 feature->Action = state;
1586 ptr2 = strchrW(ptr,',');
1598 static UINT SetFeatureStates(MSIPACKAGE *package)
1601 static const WCHAR szlevel[] =
1602 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1603 static const WCHAR szAddLocal[] =
1604 {'A','D','D','L','O','C','A','L',0};
1605 static const WCHAR szRemove[] =
1606 {'R','E','M','O','V','E',0};
1607 static const WCHAR szReinstall[] =
1608 {'R','E','I','N','S','T','A','L','L',0};
1609 BOOL override = FALSE;
1610 MSICOMPONENT* component;
1611 MSIFEATURE *feature;
1614 /* I do not know if this is where it should happen.. but */
1616 TRACE("Checking Install Level\n");
1618 install_level = msi_get_property_int( package, szlevel, 1 );
1620 /* ok hereis the _real_ rub
1621 * all these activation/deactivation things happen in order and things
1622 * later on the list override things earlier on the list.
1623 * 1) INSTALLLEVEL processing
1633 * 11) FILEADDDEFAULT
1634 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1635 * ignored for all the features. seems strange, especially since it is not
1636 * documented anywhere, but it is how it works.
1638 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1639 * REMOVE are the big ones, since we don't handle administrative installs
1642 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1643 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1644 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1648 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1650 BOOL feature_state = ((feature->Level > 0) &&
1651 (feature->Level <= install_level));
1653 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1655 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1657 feature->ActionRequest = INSTALLSTATE_SOURCE;
1658 feature->Action = INSTALLSTATE_SOURCE;
1660 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1662 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1663 feature->Action = INSTALLSTATE_ADVERTISED;
1667 feature->ActionRequest = INSTALLSTATE_LOCAL;
1668 feature->Action = INSTALLSTATE_LOCAL;
1675 /* set the Preselected Property */
1676 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1677 static const WCHAR szOne[] = { '1', 0 };
1679 MSI_SetPropertyW(package,szPreselected,szOne);
1683 * now we want to enable or disable components base on feature
1686 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1690 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1691 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1692 feature->ActionRequest);
1694 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1696 component = cl->component;
1698 if (!component->Enabled)
1700 component->Action = INSTALLSTATE_UNKNOWN;
1701 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1705 if (feature->Action == INSTALLSTATE_LOCAL)
1707 component->Action = INSTALLSTATE_LOCAL;
1708 component->ActionRequest = INSTALLSTATE_LOCAL;
1710 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1712 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1713 (component->Action == INSTALLSTATE_ABSENT) ||
1714 (component->Action == INSTALLSTATE_ADVERTISED))
1717 component->Action = INSTALLSTATE_SOURCE;
1718 component->ActionRequest = INSTALLSTATE_SOURCE;
1721 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1723 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1724 (component->Action == INSTALLSTATE_ABSENT))
1727 component->Action = INSTALLSTATE_ADVERTISED;
1728 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1731 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1733 if (component->Action == INSTALLSTATE_UNKNOWN)
1735 component->Action = INSTALLSTATE_ABSENT;
1736 component->ActionRequest = INSTALLSTATE_ABSENT;
1743 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1745 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1746 debugstr_w(component->Component), component->Installed,
1747 component->Action, component->ActionRequest);
1751 return ERROR_SUCCESS;
1754 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1756 MSIPACKAGE *package = (MSIPACKAGE*)param;
1760 name = MSI_RecordGetString(row,1);
1762 /* This helper function now does ALL the work */
1763 TRACE("Dir %s ...\n",debugstr_w(name));
1764 load_folder(package,name);
1765 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1766 TRACE("resolves to %s\n",debugstr_w(path));
1769 return ERROR_SUCCESS;
1772 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1774 MSIPACKAGE *package = (MSIPACKAGE*)param;
1776 MSIFEATURE *feature;
1778 name = MSI_RecordGetString( row, 1 );
1780 feature = get_loaded_feature( package, name );
1782 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1786 Condition = MSI_RecordGetString(row,3);
1788 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1790 int level = MSI_RecordGetInteger(row,2);
1791 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1792 feature->Level = level;
1795 return ERROR_SUCCESS;
1800 * A lot is done in this function aside from just the costing.
1801 * The costing needs to be implemented at some point but for now I am going
1802 * to focus on the directory building
1805 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1807 static const WCHAR ExecSeqQuery[] =
1808 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1809 '`','D','i','r','e','c','t','o','r','y','`',0};
1810 static const WCHAR ConditionQuery[] =
1811 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1812 '`','C','o','n','d','i','t','i','o','n','`',0};
1813 static const WCHAR szCosting[] =
1814 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1815 static const WCHAR szlevel[] =
1816 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1817 static const WCHAR szOne[] = { '1', 0 };
1824 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1825 return ERROR_SUCCESS;
1827 TRACE("Building Directory properties\n");
1829 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1830 if (rc == ERROR_SUCCESS)
1832 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1834 msiobj_release(&view->hdr);
1837 TRACE("File calculations\n");
1839 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1841 MSICOMPONENT* comp = file->Component;
1847 /* calculate target */
1848 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1850 msi_free(file->TargetPath);
1852 TRACE("file %s is named %s\n",
1853 debugstr_w(file->File),debugstr_w(file->FileName));
1855 file->TargetPath = build_directory_name(2, p, file->FileName);
1859 TRACE("file %s resolves to %s\n",
1860 debugstr_w(file->File),debugstr_w(file->TargetPath));
1862 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1864 file->state = msifs_missing;
1865 comp->Cost += file->FileSize;
1875 static WCHAR name[] = {'\\',0};
1876 static const WCHAR name_fmt[] =
1877 {'%','u','.','%','u','.','%','u','.','%','u',0};
1878 WCHAR filever[0x100];
1879 VS_FIXEDFILEINFO *lpVer;
1881 TRACE("Version comparison..\n");
1882 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1883 version = msi_alloc(versize);
1884 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1886 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1888 sprintfW(filever,name_fmt,
1889 HIWORD(lpVer->dwFileVersionMS),
1890 LOWORD(lpVer->dwFileVersionMS),
1891 HIWORD(lpVer->dwFileVersionLS),
1892 LOWORD(lpVer->dwFileVersionLS));
1894 TRACE("new %s old %s\n", debugstr_w(file->Version),
1895 debugstr_w(filever));
1896 if (strcmpiW(filever,file->Version)<0)
1898 file->state = msifs_overwrite;
1899 /* FIXME: cost should be diff in size */
1900 comp->Cost += file->FileSize;
1903 file->state = msifs_present;
1907 file->state = msifs_present;
1910 TRACE("Evaluating Condition Table\n");
1912 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1913 if (rc == ERROR_SUCCESS)
1915 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1917 msiobj_release(&view->hdr);
1920 TRACE("Enabling or Disabling Components\n");
1921 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1923 if (comp->Condition)
1925 if (MSI_EvaluateConditionW(package,
1926 comp->Condition) == MSICONDITION_FALSE)
1928 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1929 comp->Enabled = FALSE;
1934 MSI_SetPropertyW(package,szCosting,szOne);
1935 /* set default run level if not set */
1936 level = msi_dup_property( package, szlevel );
1938 MSI_SetPropertyW(package,szlevel, szOne);
1941 ACTION_UpdateInstallStates(package);
1943 return SetFeatureStates(package);
1946 /* OK this value is "interpreted" and then formatted based on the
1947 first few characters */
1948 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1952 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1958 LPWSTR deformated = NULL;
1961 deformat_string(package, &value[2], &deformated);
1963 /* binary value type */
1967 *size = (strlenW(ptr)/2)+1;
1969 *size = strlenW(ptr)/2;
1971 data = msi_alloc(*size);
1977 /* if uneven pad with a zero in front */
1983 data[count] = (BYTE)strtol(byte,NULL,0);
1985 TRACE("Uneven byte count\n");
1993 data[count] = (BYTE)strtol(byte,NULL,0);
1996 msi_free(deformated);
1998 TRACE("Data %li bytes(%i)\n",*size,count);
2005 deformat_string(package, &value[1], &deformated);
2008 *size = sizeof(DWORD);
2009 data = msi_alloc(*size);
2015 if ( (*p < '0') || (*p > '9') )
2021 if (deformated[0] == '-')
2024 TRACE("DWORD %li\n",*(LPDWORD)data);
2026 msi_free(deformated);
2031 static const WCHAR szMulti[] = {'[','~',']',0};
2040 *type=REG_EXPAND_SZ;
2048 if (strstrW(value,szMulti))
2049 *type = REG_MULTI_SZ;
2051 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2056 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2058 MSIPACKAGE *package = (MSIPACKAGE*)param;
2059 static const WCHAR szHCR[] =
2060 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2061 'R','O','O','T','\\',0};
2062 static const WCHAR szHCU[] =
2063 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2064 'U','S','E','R','\\',0};
2065 static const WCHAR szHLM[] =
2066 {'H','K','E','Y','_','L','O','C','A','L','_',
2067 'M','A','C','H','I','N','E','\\',0};
2068 static const WCHAR szHU[] =
2069 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2071 LPSTR value_data = NULL;
2072 HKEY root_key, hkey;
2075 LPCWSTR szRoot, component, name, key, value;
2080 BOOL check_first = FALSE;
2083 ui_progress(package,2,0,0,0);
2090 component = MSI_RecordGetString(row, 6);
2091 comp = get_loaded_component(package,component);
2093 return ERROR_SUCCESS;
2095 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2097 TRACE("Skipping write due to disabled component %s\n",
2098 debugstr_w(component));
2100 comp->Action = comp->Installed;
2102 return ERROR_SUCCESS;
2105 comp->Action = INSTALLSTATE_LOCAL;
2107 name = MSI_RecordGetString(row, 4);
2108 if( MSI_RecordIsNull(row,5) && name )
2110 /* null values can have special meanings */
2111 if (name[0]=='-' && name[1] == 0)
2112 return ERROR_SUCCESS;
2113 else if ((name[0]=='+' && name[1] == 0) ||
2114 (name[0] == '*' && name[1] == 0))
2119 root = MSI_RecordGetInteger(row,2);
2120 key = MSI_RecordGetString(row, 3);
2122 /* get the root key */
2127 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2128 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2129 if (all_users && all_users[0] == '1')
2131 root_key = HKEY_LOCAL_MACHINE;
2136 root_key = HKEY_CURRENT_USER;
2139 msi_free(all_users);
2142 case 0: root_key = HKEY_CLASSES_ROOT;
2145 case 1: root_key = HKEY_CURRENT_USER;
2148 case 2: root_key = HKEY_LOCAL_MACHINE;
2151 case 3: root_key = HKEY_USERS;
2155 ERR("Unknown root %i\n",root);
2161 return ERROR_SUCCESS;
2163 deformat_string(package, key , &deformated);
2164 size = strlenW(deformated) + strlenW(szRoot) + 1;
2165 uikey = msi_alloc(size*sizeof(WCHAR));
2166 strcpyW(uikey,szRoot);
2167 strcatW(uikey,deformated);
2169 if (RegCreateKeyW( root_key, deformated, &hkey))
2171 ERR("Could not create key %s\n",debugstr_w(deformated));
2172 msi_free(deformated);
2174 return ERROR_SUCCESS;
2176 msi_free(deformated);
2178 value = MSI_RecordGetString(row,5);
2180 value_data = parse_value(package, value, &type, &size);
2183 static const WCHAR szEmpty[] = {0};
2184 value_data = (LPSTR)strdupW(szEmpty);
2189 deformat_string(package, name, &deformated);
2191 /* get the double nulls to terminate SZ_MULTI */
2192 if (type == REG_MULTI_SZ)
2193 size +=sizeof(WCHAR);
2197 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2199 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2204 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2205 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2207 TRACE("value %s of %s checked already exists\n",
2208 debugstr_w(deformated), debugstr_w(uikey));
2212 TRACE("Checked and setting value %s of %s\n",
2213 debugstr_w(deformated), debugstr_w(uikey));
2214 if (deformated || size)
2215 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2220 uirow = MSI_CreateRecord(3);
2221 MSI_RecordSetStringW(uirow,2,deformated);
2222 MSI_RecordSetStringW(uirow,1,uikey);
2225 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2227 MSI_RecordSetStringW(uirow,3,value);
2229 ui_actiondata(package,szWriteRegistryValues,uirow);
2230 msiobj_release( &uirow->hdr );
2232 msi_free(value_data);
2233 msi_free(deformated);
2236 return ERROR_SUCCESS;
2239 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2243 static const WCHAR ExecSeqQuery[] =
2244 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2245 '`','R','e','g','i','s','t','r','y','`',0 };
2248 return ERROR_INVALID_HANDLE;
2250 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2251 if (rc != ERROR_SUCCESS)
2252 return ERROR_SUCCESS;
2254 /* increment progress bar each time action data is sent */
2255 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2257 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2259 msiobj_release(&view->hdr);
2263 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2265 package->script->CurrentlyScripting = TRUE;
2267 return ERROR_SUCCESS;
2271 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2276 static const WCHAR q1[]=
2277 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2278 '`','R','e','g','i','s','t','r','y','`',0};
2281 MSIFEATURE *feature;
2284 TRACE("InstallValidate\n");
2286 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2287 if (rc == ERROR_SUCCESS)
2289 MSI_IterateRecords( view, &progress, NULL, package );
2290 msiobj_release( &view->hdr );
2291 total += progress * REG_PROGRESS_VALUE;
2294 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2295 total += COMPONENT_PROGRESS_VALUE;
2297 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2298 total += file->FileSize;
2300 ui_progress(package,0,total,0,0);
2302 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2304 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2305 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2306 feature->ActionRequest);
2309 return ERROR_SUCCESS;
2312 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2314 MSIPACKAGE* package = (MSIPACKAGE*)param;
2315 LPCWSTR cond = NULL;
2316 LPCWSTR message = NULL;
2317 static const WCHAR title[]=
2318 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2320 cond = MSI_RecordGetString(row,1);
2322 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2325 message = MSI_RecordGetString(row,2);
2326 deformat_string(package,message,&deformated);
2327 MessageBoxW(NULL,deformated,title,MB_OK);
2328 msi_free(deformated);
2329 return ERROR_FUNCTION_FAILED;
2332 return ERROR_SUCCESS;
2335 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2338 MSIQUERY * view = NULL;
2339 static const WCHAR ExecSeqQuery[] =
2340 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2341 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2343 TRACE("Checking launch conditions\n");
2345 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2346 if (rc != ERROR_SUCCESS)
2347 return ERROR_SUCCESS;
2349 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2350 msiobj_release(&view->hdr);
2355 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2359 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2361 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2363 MSIRECORD * row = 0;
2365 LPWSTR deformated,buffer,deformated_name;
2367 static const WCHAR ExecSeqQuery[] =
2368 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2369 '`','R','e','g','i','s','t','r','y','`',' ',
2370 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2371 ' ','=',' ' ,'\'','%','s','\'',0 };
2372 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2373 static const WCHAR fmt2[]=
2374 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2376 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2380 root = MSI_RecordGetInteger(row,2);
2381 key = MSI_RecordGetString(row, 3);
2382 name = MSI_RecordGetString(row, 4);
2383 deformat_string(package, key , &deformated);
2384 deformat_string(package, name, &deformated_name);
2386 len = strlenW(deformated) + 6;
2387 if (deformated_name)
2388 len+=strlenW(deformated_name);
2390 buffer = msi_alloc( len *sizeof(WCHAR));
2392 if (deformated_name)
2393 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2395 sprintfW(buffer,fmt,root,deformated);
2397 msi_free(deformated);
2398 msi_free(deformated_name);
2399 msiobj_release(&row->hdr);
2403 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2405 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2410 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2413 return strdupW( file->TargetPath );
2418 static HKEY openSharedDLLsKey(void)
2421 static const WCHAR path[] =
2422 {'S','o','f','t','w','a','r','e','\\',
2423 'M','i','c','r','o','s','o','f','t','\\',
2424 'W','i','n','d','o','w','s','\\',
2425 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2426 'S','h','a','r','e','d','D','L','L','s',0};
2428 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2432 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2437 DWORD sz = sizeof(count);
2440 hkey = openSharedDLLsKey();
2441 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2442 if (rc != ERROR_SUCCESS)
2448 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2452 hkey = openSharedDLLsKey();
2454 msi_reg_set_val_dword( hkey, path, count );
2456 RegDeleteValueW(hkey,path);
2462 * Return TRUE if the count should be written out and FALSE if not
2464 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2466 MSIFEATURE *feature;
2470 /* only refcount DLLs */
2471 if (comp->KeyPath == NULL ||
2472 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2473 comp->Attributes & msidbComponentAttributesODBCDataSource)
2477 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2478 write = (count > 0);
2480 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2484 /* increment counts */
2485 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2489 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2492 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2494 if ( cl->component == comp )
2499 /* decrement counts */
2500 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2504 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2507 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2509 if ( cl->component == comp )
2514 /* ref count all the files in the component */
2519 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2521 if (file->Component == comp)
2522 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2526 /* add a count for permenent */
2527 if (comp->Attributes & msidbComponentAttributesPermanent)
2530 comp->RefCount = count;
2533 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2537 * Ok further analysis makes me think that this work is
2538 * actually done in the PublishComponents and PublishFeatures
2539 * step, and not here. It appears like the keypath and all that is
2540 * resolved in this step, however actually written in the Publish steps.
2541 * But we will leave it here for now because it is unclear
2543 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2545 WCHAR squished_pc[GUID_SIZE];
2546 WCHAR squished_cc[GUID_SIZE];
2549 HKEY hkey=0,hkey2=0;
2551 /* writes the Component and Features values to the registry */
2553 rc = MSIREG_OpenComponents(&hkey);
2554 if (rc != ERROR_SUCCESS)
2557 squash_guid(package->ProductCode,squished_pc);
2558 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2560 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2564 ui_progress(package,2,0,0,0);
2565 if (!comp->ComponentId)
2568 squash_guid(comp->ComponentId,squished_cc);
2570 msi_free(comp->FullKeypath);
2571 comp->FullKeypath = resolve_keypath( package, comp );
2573 /* do the refcounting */
2574 ACTION_RefCountComponent( package, comp );
2576 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2577 debugstr_w(comp->Component),
2578 debugstr_w(squished_cc),
2579 debugstr_w(comp->FullKeypath),
2582 * Write the keypath out if the component is to be registered
2583 * and delete the key if the component is to be deregistered
2585 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2587 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2588 if (rc != ERROR_SUCCESS)
2591 if (!comp->FullKeypath)
2594 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2596 if (comp->Attributes & msidbComponentAttributesPermanent)
2598 static const WCHAR szPermKey[] =
2599 { '0','0','0','0','0','0','0','0','0','0','0','0',
2600 '0','0','0','0','0','0','0','0','0','0','0','0',
2601 '0','0','0','0','0','0','0','0',0 };
2603 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2609 uirow = MSI_CreateRecord(3);
2610 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2611 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2612 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2613 ui_actiondata(package,szProcessComponents,uirow);
2614 msiobj_release( &uirow->hdr );
2616 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2620 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2621 if (rc != ERROR_SUCCESS)
2624 RegDeleteValueW(hkey2,squished_pc);
2626 /* if the key is empty delete it */
2627 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2629 if (res == ERROR_NO_MORE_ITEMS)
2630 RegDeleteKeyW(hkey,squished_cc);
2633 uirow = MSI_CreateRecord(2);
2634 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2635 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2636 ui_actiondata(package,szProcessComponents,uirow);
2637 msiobj_release( &uirow->hdr );
2652 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2653 LPWSTR lpszName, LONG_PTR lParam)
2656 typelib_struct *tl_struct = (typelib_struct*) lParam;
2657 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2661 if (!IS_INTRESOURCE(lpszName))
2663 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2667 sz = strlenW(tl_struct->source)+4;
2668 sz *= sizeof(WCHAR);
2670 if ((INT)lpszName == 1)
2671 tl_struct->path = strdupW(tl_struct->source);
2674 tl_struct->path = msi_alloc(sz);
2675 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2678 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2679 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2680 if (!SUCCEEDED(res))
2682 msi_free(tl_struct->path);
2683 tl_struct->path = NULL;
2688 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2689 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2691 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2695 msi_free(tl_struct->path);
2696 tl_struct->path = NULL;
2698 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2699 ITypeLib_Release(tl_struct->ptLib);
2704 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2706 MSIPACKAGE* package = (MSIPACKAGE*)param;
2710 typelib_struct tl_struct;
2712 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2714 component = MSI_RecordGetString(row,3);
2715 comp = get_loaded_component(package,component);
2717 return ERROR_SUCCESS;
2719 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2721 TRACE("Skipping typelib reg due to disabled component\n");
2723 comp->Action = comp->Installed;
2725 return ERROR_SUCCESS;
2728 comp->Action = INSTALLSTATE_LOCAL;
2730 file = get_loaded_file( package, comp->KeyPath );
2732 return ERROR_SUCCESS;
2734 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2738 guid = MSI_RecordGetString(row,1);
2739 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2740 tl_struct.source = strdupW( file->TargetPath );
2741 tl_struct.path = NULL;
2743 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2744 (LONG_PTR)&tl_struct);
2752 helpid = MSI_RecordGetString(row,6);
2755 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2756 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2759 if (!SUCCEEDED(res))
2760 ERR("Failed to register type library %s\n",
2761 debugstr_w(tl_struct.path));
2764 ui_actiondata(package,szRegisterTypeLibraries,row);
2766 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2769 ITypeLib_Release(tl_struct.ptLib);
2770 msi_free(tl_struct.path);
2773 ERR("Failed to load type library %s\n",
2774 debugstr_w(tl_struct.source));
2776 FreeLibrary(module);
2777 msi_free(tl_struct.source);
2780 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2782 return ERROR_SUCCESS;
2785 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2788 * OK this is a bit confusing.. I am given a _Component key and I believe
2789 * that the file that is being registered as a type library is the "key file
2790 * of that component" which I interpret to mean "The file in the KeyPath of
2795 static const WCHAR Query[] =
2796 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2797 '`','T','y','p','e','L','i','b','`',0};
2799 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2800 if (rc != ERROR_SUCCESS)
2801 return ERROR_SUCCESS;
2803 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2804 msiobj_release(&view->hdr);
2808 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2810 MSIPACKAGE *package = (MSIPACKAGE*)param;
2811 LPWSTR target_file, target_folder, filename;
2812 LPCWSTR buffer, extension;
2814 static const WCHAR szlnk[]={'.','l','n','k',0};
2819 buffer = MSI_RecordGetString(row,4);
2820 comp = get_loaded_component(package,buffer);
2822 return ERROR_SUCCESS;
2824 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2826 TRACE("Skipping shortcut creation due to disabled component\n");
2828 comp->Action = comp->Installed;
2830 return ERROR_SUCCESS;
2833 comp->Action = INSTALLSTATE_LOCAL;
2835 ui_actiondata(package,szCreateShortcuts,row);
2837 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2838 &IID_IShellLinkW, (LPVOID *) &sl );
2842 ERR("Is IID_IShellLink\n");
2843 return ERROR_SUCCESS;
2846 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2849 ERR("Is IID_IPersistFile\n");
2850 return ERROR_SUCCESS;
2853 buffer = MSI_RecordGetString(row,2);
2854 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2856 /* may be needed because of a bug somehwere else */
2857 create_full_pathW(target_folder);
2859 filename = msi_dup_record_field( row, 3 );
2860 reduce_to_longfilename(filename);
2862 extension = strchrW(filename,'.');
2863 if (!extension || strcmpiW(extension,szlnk))
2865 int len = strlenW(filename);
2866 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2867 memcpy(filename + len, szlnk, sizeof(szlnk));
2869 target_file = build_directory_name(2, target_folder, filename);
2870 msi_free(target_folder);
2873 buffer = MSI_RecordGetString(row,5);
2874 if (strchrW(buffer,'['))
2877 deformat_string(package,buffer,&deformated);
2878 IShellLinkW_SetPath(sl,deformated);
2879 msi_free(deformated);
2883 FIXME("poorly handled shortcut format, advertised shortcut\n");
2884 IShellLinkW_SetPath(sl,comp->FullKeypath);
2887 if (!MSI_RecordIsNull(row,6))
2890 buffer = MSI_RecordGetString(row,6);
2891 deformat_string(package,buffer,&deformated);
2892 IShellLinkW_SetArguments(sl,deformated);
2893 msi_free(deformated);
2896 if (!MSI_RecordIsNull(row,7))
2898 buffer = MSI_RecordGetString(row,7);
2899 IShellLinkW_SetDescription(sl,buffer);
2902 if (!MSI_RecordIsNull(row,8))
2903 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2905 if (!MSI_RecordIsNull(row,9))
2910 buffer = MSI_RecordGetString(row,9);
2912 Path = build_icon_path(package,buffer);
2913 index = MSI_RecordGetInteger(row,10);
2915 IShellLinkW_SetIconLocation(sl,Path,index);
2919 if (!MSI_RecordIsNull(row,11))
2920 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2922 if (!MSI_RecordIsNull(row,12))
2925 buffer = MSI_RecordGetString(row,12);
2926 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2927 IShellLinkW_SetWorkingDirectory(sl,Path);
2931 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2932 IPersistFile_Save(pf,target_file,FALSE);
2934 msi_free(target_file);
2936 IPersistFile_Release( pf );
2937 IShellLinkW_Release( sl );
2939 return ERROR_SUCCESS;
2942 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2947 static const WCHAR Query[] =
2948 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2949 '`','S','h','o','r','t','c','u','t','`',0};
2951 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2952 if (rc != ERROR_SUCCESS)
2953 return ERROR_SUCCESS;
2955 res = CoInitialize( NULL );
2958 ERR("CoInitialize failed\n");
2959 return ERROR_FUNCTION_FAILED;
2962 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2963 msiobj_release(&view->hdr);
2970 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2972 MSIPACKAGE* package = (MSIPACKAGE*)param;
2981 FileName = MSI_RecordGetString(row,1);
2984 ERR("Unable to get FileName\n");
2985 return ERROR_SUCCESS;
2988 FilePath = build_icon_path(package,FileName);
2990 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2992 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2993 FILE_ATTRIBUTE_NORMAL, NULL);
2995 if (the_file == INVALID_HANDLE_VALUE)
2997 ERR("Unable to create file %s\n",debugstr_w(FilePath));
2999 return ERROR_SUCCESS;
3006 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3007 if (rc != ERROR_SUCCESS)
3009 ERR("Failed to get stream\n");
3010 CloseHandle(the_file);
3011 DeleteFileW(FilePath);
3014 WriteFile(the_file,buffer,sz,&write,NULL);
3015 } while (sz == 1024);
3019 CloseHandle(the_file);
3021 uirow = MSI_CreateRecord(1);
3022 MSI_RecordSetStringW(uirow,1,FileName);
3023 ui_actiondata(package,szPublishProduct,uirow);
3024 msiobj_release( &uirow->hdr );
3026 return ERROR_SUCCESS;
3030 * 99% of the work done here is only done for
3031 * advertised installs. However this is where the
3032 * Icon table is processed and written out
3033 * so that is what I am going to do here.
3035 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3039 static const WCHAR Query[]=
3040 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3041 '`','I','c','o','n','`',0};
3042 /* for registry stuff */
3045 static const WCHAR szProductLanguage[] =
3046 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3047 static const WCHAR szARPProductIcon[] =
3048 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3049 static const WCHAR szProductVersion[] =
3050 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3054 MSIHANDLE hDb, hSumInfo;
3056 /* write out icon files */
3058 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3059 if (rc == ERROR_SUCCESS)
3061 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3062 msiobj_release(&view->hdr);
3065 /* ok there is a lot more done here but i need to figure out what */
3067 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3068 if (rc != ERROR_SUCCESS)
3071 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3072 if (rc != ERROR_SUCCESS)
3076 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3077 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3080 langid = msi_get_property_int( package, szProductLanguage, 0 );
3081 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3083 buffer = msi_dup_property( package, szARPProductIcon );
3086 LPWSTR path = build_icon_path(package,buffer);
3087 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3092 buffer = msi_dup_property( package, szProductVersion );
3095 DWORD verdword = build_version_dword(buffer);
3096 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3100 /* FIXME: Need to write more keys to the user registry */
3102 hDb= alloc_msihandle( &package->db->hdr );
3103 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3104 MsiCloseHandle(hDb);
3105 if (rc == ERROR_SUCCESS)
3107 WCHAR guidbuffer[0x200];
3109 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3111 if (rc == ERROR_SUCCESS)
3113 WCHAR squashed[GUID_SIZE];
3114 /* for now we only care about the first guid */
3115 LPWSTR ptr = strchrW(guidbuffer,';');
3117 squash_guid(guidbuffer,squashed);
3118 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3122 ERR("Unable to query Revision_Number...\n");
3125 MsiCloseHandle(hSumInfo);
3129 ERR("Unable to open Summary Information\n");
3141 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3143 MSIPACKAGE *package = (MSIPACKAGE*)param;
3144 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3145 LPWSTR deformated_section, deformated_key, deformated_value;
3146 LPWSTR folder, fullname = NULL;
3150 static const WCHAR szWindowsFolder[] =
3151 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3153 component = MSI_RecordGetString(row, 8);
3154 comp = get_loaded_component(package,component);
3156 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3158 TRACE("Skipping ini file due to disabled component %s\n",
3159 debugstr_w(component));
3161 comp->Action = comp->Installed;
3163 return ERROR_SUCCESS;
3166 comp->Action = INSTALLSTATE_LOCAL;
3168 identifier = MSI_RecordGetString(row,1);
3169 filename = MSI_RecordGetString(row,2);
3170 dirproperty = MSI_RecordGetString(row,3);
3171 section = MSI_RecordGetString(row,4);
3172 key = MSI_RecordGetString(row,5);
3173 value = MSI_RecordGetString(row,6);
3174 action = MSI_RecordGetInteger(row,7);
3176 deformat_string(package,section,&deformated_section);
3177 deformat_string(package,key,&deformated_key);
3178 deformat_string(package,value,&deformated_value);
3182 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3184 folder = msi_dup_property( package, dirproperty );
3187 folder = msi_dup_property( package, szWindowsFolder );
3191 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3195 fullname = build_directory_name(2, folder, filename);
3199 TRACE("Adding value %s to section %s in %s\n",
3200 debugstr_w(deformated_key), debugstr_w(deformated_section),
3201 debugstr_w(fullname));
3202 WritePrivateProfileStringW(deformated_section, deformated_key,
3203 deformated_value, fullname);
3205 else if (action == 1)
3208 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3209 returned, 10, fullname);
3210 if (returned[0] == 0)
3212 TRACE("Adding value %s to section %s in %s\n",
3213 debugstr_w(deformated_key), debugstr_w(deformated_section),
3214 debugstr_w(fullname));
3216 WritePrivateProfileStringW(deformated_section, deformated_key,
3217 deformated_value, fullname);
3220 else if (action == 3)
3221 FIXME("Append to existing section not yet implemented\n");
3223 uirow = MSI_CreateRecord(4);
3224 MSI_RecordSetStringW(uirow,1,identifier);
3225 MSI_RecordSetStringW(uirow,2,deformated_section);
3226 MSI_RecordSetStringW(uirow,3,deformated_key);
3227 MSI_RecordSetStringW(uirow,4,deformated_value);
3228 ui_actiondata(package,szWriteIniValues,uirow);
3229 msiobj_release( &uirow->hdr );
3233 msi_free(deformated_key);
3234 msi_free(deformated_value);
3235 msi_free(deformated_section);
3236 return ERROR_SUCCESS;
3239 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3243 static const WCHAR ExecSeqQuery[] =
3244 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3245 '`','I','n','i','F','i','l','e','`',0};
3247 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3248 if (rc != ERROR_SUCCESS)
3250 TRACE("no IniFile table\n");
3251 return ERROR_SUCCESS;
3254 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3255 msiobj_release(&view->hdr);
3259 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3261 MSIPACKAGE *package = (MSIPACKAGE*)param;
3266 static const WCHAR ExeStr[] =
3267 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3268 static const WCHAR close[] = {'\"',0};
3270 PROCESS_INFORMATION info;
3275 memset(&si,0,sizeof(STARTUPINFOW));
3277 filename = MSI_RecordGetString(row,1);
3278 file = get_loaded_file( package, filename );
3282 ERR("Unable to find file id %s\n",debugstr_w(filename));
3283 return ERROR_SUCCESS;
3286 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3288 FullName = msi_alloc(len*sizeof(WCHAR));
3289 strcpyW(FullName,ExeStr);
3290 strcatW( FullName, file->TargetPath );
3291 strcatW(FullName,close);
3293 TRACE("Registering %s\n",debugstr_w(FullName));
3294 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3298 msi_dialog_check_messages(info.hProcess);
3303 uirow = MSI_CreateRecord( 2 );
3304 uipath = strdupW( file->TargetPath );
3305 p = strrchrW(uipath,'\\');
3308 MSI_RecordSetStringW( uirow, 1, &p[2] );
3309 MSI_RecordSetStringW( uirow, 2, uipath);
3310 ui_actiondata( package, szSelfRegModules, uirow);
3311 msiobj_release( &uirow->hdr );
3313 /* FIXME: call ui_progress? */
3315 return ERROR_SUCCESS;
3318 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3322 static const WCHAR ExecSeqQuery[] =
3323 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3324 '`','S','e','l','f','R','e','g','`',0};
3326 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3327 if (rc != ERROR_SUCCESS)
3329 TRACE("no SelfReg table\n");
3330 return ERROR_SUCCESS;
3333 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3334 msiobj_release(&view->hdr);
3336 return ERROR_SUCCESS;
3339 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3341 MSIFEATURE *feature;
3346 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3347 if (rc != ERROR_SUCCESS)
3350 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3351 if (rc != ERROR_SUCCESS)
3354 /* here the guids are base 85 encoded */
3355 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3361 BOOL absent = FALSE;
3364 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3365 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3366 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3370 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3374 if (feature->Feature_Parent)
3375 size += strlenW( feature->Feature_Parent )+2;
3377 data = msi_alloc(size * sizeof(WCHAR));
3380 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3382 MSICOMPONENT* component = cl->component;
3386 if (component->ComponentId)
3388 TRACE("From %s\n",debugstr_w(component->ComponentId));
3389 CLSIDFromString(component->ComponentId, &clsid);
3390 encode_base85_guid(&clsid,buf);
3391 TRACE("to %s\n",debugstr_w(buf));
3395 if (feature->Feature_Parent)
3397 static const WCHAR sep[] = {'\2',0};
3399 strcatW(data,feature->Feature_Parent);
3402 msi_reg_set_val_str( hkey, feature->Feature, data );
3406 if (feature->Feature_Parent)
3407 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3410 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3411 (LPBYTE)feature->Feature_Parent,size);
3415 size += 2*sizeof(WCHAR);
3416 data = msi_alloc(size);
3419 if (feature->Feature_Parent)
3420 strcpyW( &data[1], feature->Feature_Parent );
3421 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3427 uirow = MSI_CreateRecord( 1 );
3428 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3429 ui_actiondata( package, szPublishFeatures, uirow);
3430 msiobj_release( &uirow->hdr );
3431 /* FIXME: call ui_progress? */
3440 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3442 static const WCHAR installerPathFmt[] = {
3443 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3444 static const WCHAR fmt[] = {
3446 'I','n','s','t','a','l','l','e','r','\\',
3447 '%','x','.','m','s','i',0};
3448 static const WCHAR szOriginalDatabase[] =
3449 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3450 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3455 /* copy the package locally */
3456 num = GetTickCount() & 0xffff;
3460 GetWindowsDirectoryW( windir, MAX_PATH );
3461 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3464 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3465 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3466 if (handle != INVALID_HANDLE_VALUE)
3468 CloseHandle(handle);
3471 if (GetLastError() != ERROR_FILE_EXISTS &&
3472 GetLastError() != ERROR_SHARING_VIOLATION)
3474 if (!(++num & 0xffff)) num = 1;
3475 sprintfW(packagefile,fmt,num);
3476 } while (num != start);
3478 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3479 create_full_pathW(path);
3481 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3483 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3484 r = CopyFileW( msiFilePath, packagefile, FALSE);
3485 msi_free( msiFilePath );
3489 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3490 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3491 return ERROR_FUNCTION_FAILED;
3494 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3495 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3496 return ERROR_SUCCESS;
3499 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3501 LPWSTR prop, val, key;
3502 static const LPCSTR propval[] = {
3503 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3504 "ARPCONTACT", "Contact",
3505 "ARPCOMMENTS", "Comments",
3506 "ProductName", "DisplayName",
3507 "ProductVersion", "DisplayVersion",
3508 "ARPHELPLINK", "HelpLink",
3509 "ARPHELPTELEPHONE", "HelpTelephone",
3510 "ARPINSTALLLOCATION", "InstallLocation",
3511 "SourceDir", "InstallSource",
3512 "Manufacturer", "Publisher",
3513 "ARPREADME", "Readme",
3515 "ARPURLINFOABOUT", "URLInfoAbout",
3516 "ARPURLUPDATEINFO", "URLUpdateInfo",
3519 const LPCSTR *p = propval;
3523 prop = strdupAtoW( *p++ );
3524 key = strdupAtoW( *p++ );
3525 val = msi_dup_property( package, prop );
3526 msi_reg_set_val_str( hkey, key, val );
3531 return ERROR_SUCCESS;
3534 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3537 LPWSTR buffer = NULL;
3540 static const WCHAR szWindowsInstaller[] =
3541 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3542 static const WCHAR szUpgradeCode[] =
3543 {'U','p','g','r','a','d','e','C','o','d','e',0};
3544 static const WCHAR modpath_fmt[] =
3545 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3546 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3547 static const WCHAR szModifyPath[] =
3548 {'M','o','d','i','f','y','P','a','t','h',0};
3549 static const WCHAR szUninstallString[] =
3550 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3551 static const WCHAR szEstimatedSize[] =
3552 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3553 static const WCHAR szProductLanguage[] =
3554 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3555 static const WCHAR szProductVersion[] =
3556 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3559 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3560 LPWSTR upgrade_code;
3563 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3564 if (rc != ERROR_SUCCESS)
3567 /* dump all the info i can grab */
3568 /* FIXME: Flesh out more information */
3570 msi_write_uninstall_property_vals( package, hkey );
3572 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3574 msi_make_package_local( package, hkey );
3576 /* do ModifyPath and UninstallString */
3577 size = deformat_string(package,modpath_fmt,&buffer);
3578 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3579 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3582 /* FIXME: Write real Estimated Size when we have it */
3583 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3585 GetLocalTime(&systime);
3586 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3587 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3589 langid = msi_get_property_int( package, szProductLanguage, 0 );
3590 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3592 buffer = msi_dup_property( package, szProductVersion );
3595 DWORD verdword = build_version_dword(buffer);
3597 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3598 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3599 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3603 /* Handle Upgrade Codes */
3604 upgrade_code = msi_dup_property( package, szUpgradeCode );
3609 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3610 squash_guid(package->ProductCode,squashed);
3611 msi_reg_set_val_str( hkey2, squashed, NULL );
3613 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3614 squash_guid(package->ProductCode,squashed);
3615 msi_reg_set_val_str( hkey2, squashed, NULL );
3618 msi_free(upgrade_code);
3623 /* FIXME: call ui_actiondata */
3625 return ERROR_SUCCESS;
3628 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3630 return execute_script(package,INSTALL_SCRIPT);
3633 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3637 /* turn off scheduleing */
3638 package->script->CurrentlyScripting= FALSE;
3640 /* first do the same as an InstallExecute */
3641 rc = ACTION_InstallExecute(package);
3642 if (rc != ERROR_SUCCESS)
3645 /* then handle Commit Actions */
3646 rc = execute_script(package,COMMIT_SCRIPT);
3651 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3653 static const WCHAR RunOnce[] = {
3654 'S','o','f','t','w','a','r','e','\\',
3655 'M','i','c','r','o','s','o','f','t','\\',
3656 'W','i','n','d','o','w','s','\\',
3657 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3658 'R','u','n','O','n','c','e',0};
3659 static const WCHAR InstallRunOnce[] = {
3660 'S','o','f','t','w','a','r','e','\\',
3661 'M','i','c','r','o','s','o','f','t','\\',
3662 'W','i','n','d','o','w','s','\\',
3663 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3664 'I','n','s','t','a','l','l','e','r','\\',
3665 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3667 static const WCHAR msiexec_fmt[] = {
3669 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3670 '\"','%','s','\"',0};
3671 static const WCHAR install_fmt[] = {
3672 '/','I',' ','\"','%','s','\"',' ',
3673 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3674 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3675 WCHAR buffer[256], sysdir[MAX_PATH];
3677 WCHAR squished_pc[100];
3679 squash_guid(package->ProductCode,squished_pc);
3681 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3682 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3683 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3686 msi_reg_set_val_str( hkey, squished_pc, buffer );
3689 TRACE("Reboot command %s\n",debugstr_w(buffer));
3691 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3692 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3694 msi_reg_set_val_str( hkey, squished_pc, buffer );
3697 return ERROR_INSTALL_SUSPEND;
3700 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3705 * we are currently doing what should be done here in the top level Install
3706 * however for Adminastrative and uninstalls this step will be needed
3708 if (!package->PackagePath)
3709 return ERROR_SUCCESS;
3711 attrib = GetFileAttributesW(package->PackagePath);
3712 if (attrib == INVALID_FILE_ATTRIBUTES)
3718 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3719 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3720 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3721 if (rc == ERROR_MORE_DATA)
3723 prompt = msi_alloc(size * sizeof(WCHAR));
3724 MsiSourceListGetInfoW(package->ProductCode, NULL,
3725 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3726 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3729 prompt = strdupW(package->PackagePath);
3731 msg = generate_error_string(package,1302,1,prompt);
3732 while(attrib == INVALID_FILE_ATTRIBUTES)
3734 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3737 rc = ERROR_INSTALL_USEREXIT;
3740 attrib = GetFileAttributesW(package->PackagePath);
3746 return ERROR_SUCCESS;
3751 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3758 static const WCHAR szPropKeys[][80] =
3760 {'P','r','o','d','u','c','t','I','D',0},
3761 {'U','S','E','R','N','A','M','E',0},
3762 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3766 static const WCHAR szRegKeys[][80] =
3768 {'P','r','o','d','u','c','t','I','D',0},
3769 {'R','e','g','O','w','n','e','r',0},
3770 {'R','e','g','C','o','m','p','a','n','y',0},
3774 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3776 return ERROR_SUCCESS;
3778 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3779 if (rc != ERROR_SUCCESS)
3782 for( i = 0; szPropKeys[i][0]; i++ )
3784 buffer = msi_dup_property( package, szPropKeys[i] );
3785 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3790 msi_free(productid);
3793 /* FIXME: call ui_actiondata */
3795 return ERROR_SUCCESS;
3799 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3803 package->script->InWhatSequence |= SEQUENCE_EXEC;
3804 rc = ACTION_ProcessExecSequence(package,FALSE);
3810 * Code based off of code located here
3811 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3813 * Using string index 4 (full font name) instead of 1 (family name)
3815 static LPWSTR load_ttfname_from(LPCWSTR filename)
3821 typedef struct _tagTT_OFFSET_TABLE{
3822 USHORT uMajorVersion;
3823 USHORT uMinorVersion;
3824 USHORT uNumOfTables;
3825 USHORT uSearchRange;
3826 USHORT uEntrySelector;
3830 typedef struct _tagTT_TABLE_DIRECTORY{
3831 char szTag[4]; /* table name */
3832 ULONG uCheckSum; /* Check sum */
3833 ULONG uOffset; /* Offset from beginning of file */
3834 ULONG uLength; /* length of the table in bytes */
3835 }TT_TABLE_DIRECTORY;
3837 typedef struct _tagTT_NAME_TABLE_HEADER{
3838 USHORT uFSelector; /* format selector. Always 0 */
3839 USHORT uNRCount; /* Name Records count */
3840 USHORT uStorageOffset; /* Offset for strings storage,
3841 * from start of the table */
3842 }TT_NAME_TABLE_HEADER;
3844 typedef struct _tagTT_NAME_RECORD{
3849 USHORT uStringLength;
3850 USHORT uStringOffset; /* from start of storage area */
3853 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3854 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3856 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3857 FILE_ATTRIBUTE_NORMAL, 0 );
3858 if (handle != INVALID_HANDLE_VALUE)
3860 TT_TABLE_DIRECTORY tblDir;
3861 BOOL bFound = FALSE;
3862 TT_OFFSET_TABLE ttOffsetTable;
3865 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3866 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3867 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3868 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3870 if (ttOffsetTable.uMajorVersion != 1 ||
3871 ttOffsetTable.uMinorVersion != 0)
3874 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3876 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3877 if (strncmp(tblDir.szTag,"name",4)==0)
3880 tblDir.uLength = SWAPLONG(tblDir.uLength);
3881 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3888 TT_NAME_TABLE_HEADER ttNTHeader;
3889 TT_NAME_RECORD ttRecord;
3891 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3892 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3895 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3896 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3898 for(i=0; i<ttNTHeader.uNRCount; i++)
3900 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3901 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3902 /* 4 is the Full Font Name */
3903 if(ttRecord.uNameID == 4)
3907 static LPCSTR tt = " (TrueType)";
3909 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3910 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3911 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3912 SetFilePointer(handle, tblDir.uOffset +
3913 ttRecord.uStringOffset +
3914 ttNTHeader.uStorageOffset,
3916 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3917 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3918 if (strlen(buf) > 0)
3921 ret = strdupAtoW(buf);
3927 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3931 CloseHandle(handle);
3934 ERR("Unable to open font file %s\n", debugstr_w(filename));
3936 TRACE("Returning fontname %s\n",debugstr_w(ret));
3940 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3942 MSIPACKAGE *package = (MSIPACKAGE*)param;
3946 static const WCHAR regfont1[] =
3947 {'S','o','f','t','w','a','r','e','\\',
3948 'M','i','c','r','o','s','o','f','t','\\',
3949 'W','i','n','d','o','w','s',' ','N','T','\\',
3950 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3951 'F','o','n','t','s',0};
3952 static const WCHAR regfont2[] =
3953 {'S','o','f','t','w','a','r','e','\\',
3954 'M','i','c','r','o','s','o','f','t','\\',
3955 'W','i','n','d','o','w','s','\\',
3956 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3957 'F','o','n','t','s',0};
3963 filename = MSI_RecordGetString( row, 1 );
3964 file = get_loaded_file( package, filename );
3967 ERR("Unable to load file\n");
3968 return ERROR_SUCCESS;
3971 /* check to make sure that component is installed */
3972 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3974 TRACE("Skipping: Component not scheduled for install\n");
3975 return ERROR_SUCCESS;
3978 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3979 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3981 if (MSI_RecordIsNull(row,2))
3982 name = load_ttfname_from( file->TargetPath );
3984 name = msi_dup_record_field(row,2);
3988 msi_reg_set_val_str( hkey1, name, file->FileName );
3989 msi_reg_set_val_str( hkey2, name, file->FileName );
3997 uirow = MSI_CreateRecord( 1 );
3998 uipath = strdupW( file->TargetPath );
3999 p = strrchrW(uipath,'\\');
4002 MSI_RecordSetStringW( uirow, 1, p );
4003 ui_actiondata( package, szRegisterFonts, uirow);
4004 msiobj_release( &uirow->hdr );
4006 /* FIXME: call ui_progress? */
4008 return ERROR_SUCCESS;
4011 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4015 static const WCHAR ExecSeqQuery[] =
4016 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4017 '`','F','o','n','t','`',0};
4019 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4020 if (rc != ERROR_SUCCESS)
4022 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4023 return ERROR_SUCCESS;
4026 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4027 msiobj_release(&view->hdr);
4029 return ERROR_SUCCESS;
4032 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4034 MSIPACKAGE *package = (MSIPACKAGE*)param;
4035 LPCWSTR compgroupid=NULL;
4036 LPCWSTR feature=NULL;
4037 LPCWSTR text = NULL;
4038 LPCWSTR qualifier = NULL;
4039 LPCWSTR component = NULL;
4040 LPWSTR advertise = NULL;
4041 LPWSTR output = NULL;
4043 UINT rc = ERROR_SUCCESS;
4048 component = MSI_RecordGetString(rec,3);
4049 comp = get_loaded_component(package,component);
4051 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4052 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4053 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4055 TRACE("Skipping: Component %s not scheduled for install\n",
4056 debugstr_w(component));
4058 return ERROR_SUCCESS;
4061 compgroupid = MSI_RecordGetString(rec,1);
4062 qualifier = MSI_RecordGetString(rec,2);
4064 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4065 if (rc != ERROR_SUCCESS)
4068 text = MSI_RecordGetString(rec,4);
4069 feature = MSI_RecordGetString(rec,5);
4071 advertise = create_component_advertise_string(package, comp, feature);
4073 sz = strlenW(advertise);
4076 sz += lstrlenW(text);
4079 sz *= sizeof(WCHAR);
4081 output = msi_alloc_zero(sz);
4082 strcpyW(output,advertise);
4083 msi_free(advertise);
4086 strcatW(output,text);
4088 msi_reg_set_val_multi_str( hkey, qualifier, output );
4095 uirow = MSI_CreateRecord( 2 );
4096 MSI_RecordSetStringW( uirow, 1, compgroupid );
4097 MSI_RecordSetStringW( uirow, 2, qualifier);
4098 ui_actiondata( package, szPublishComponents, uirow);
4099 msiobj_release( &uirow->hdr );
4100 /* FIXME: call ui_progress? */
4106 * At present I am ignorning the advertised components part of this and only
4107 * focusing on the qualified component sets
4109 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4113 static const WCHAR ExecSeqQuery[] =
4114 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4115 '`','P','u','b','l','i','s','h',
4116 'C','o','m','p','o','n','e','n','t','`',0};
4118 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4119 if (rc != ERROR_SUCCESS)
4120 return ERROR_SUCCESS;
4122 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4123 msiobj_release(&view->hdr);
4128 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4129 LPCSTR action, LPCWSTR table )
4131 static const WCHAR query[] = {
4132 'S','E','L','E','C','T',' ','*',' ',
4133 'F','R','O','M',' ','`','%','s','`',0 };
4134 MSIQUERY *view = NULL;
4138 r = MSI_OpenQuery( package->db, &view, query, table );
4139 if (r == ERROR_SUCCESS)
4141 r = MSI_IterateRecords(view, &count, NULL, package);
4142 msiobj_release(&view->hdr);
4146 FIXME("%s -> %lu ignored %s table values\n",
4147 action, count, debugstr_w(table));
4149 return ERROR_SUCCESS;
4152 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4154 TRACE("%p\n", package);
4155 return ERROR_SUCCESS;
4158 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4160 static const WCHAR table[] =
4161 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4162 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4165 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4167 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4168 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4171 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4173 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4174 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4177 static UINT ACTION_BindImage( MSIPACKAGE *package )
4179 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4180 return msi_unimplemented_action_stub( package, "BindImage", table );
4183 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4185 static const WCHAR table[] = {
4186 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4187 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4190 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4192 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4193 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4196 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4198 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4199 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4202 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4204 static const WCHAR table[] = {
4205 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4206 return msi_unimplemented_action_stub( package, "InstallServices", table );
4209 static UINT ACTION_StartServices( MSIPACKAGE *package )
4211 static const WCHAR table[] = {
4212 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4213 return msi_unimplemented_action_stub( package, "StartServices", table );
4216 static UINT ACTION_StopServices( MSIPACKAGE *package )
4218 static const WCHAR table[] = {
4219 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4220 return msi_unimplemented_action_stub( package, "StopServices", table );
4223 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4225 static const WCHAR table[] = {
4226 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4227 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4230 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4232 static const WCHAR table[] = {
4233 'E','n','v','i','r','o','n','m','e','n','t',0 };
4234 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4237 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4239 static const WCHAR table[] = {
4240 'E','n','v','i','r','o','n','m','e','n','t',0 };
4241 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4244 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4246 static const WCHAR table[] = {
4247 'M','s','i','A','s','s','e','m','b','l','y',0 };
4248 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4251 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4253 static const WCHAR table[] = {
4254 'M','s','i','A','s','s','e','m','b','l','y',0 };
4255 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4258 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4260 static const WCHAR table[] = { 'F','o','n','t',0 };
4261 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4264 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4266 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4267 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4270 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4272 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4273 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4276 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4278 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4279 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4282 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4284 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4285 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4288 static struct _actions StandardActions[] = {
4289 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4290 { szAppSearch, ACTION_AppSearch },
4291 { szBindImage, ACTION_BindImage },
4292 { szCCPSearch, ACTION_CCPSearch},
4293 { szCostFinalize, ACTION_CostFinalize },
4294 { szCostInitialize, ACTION_CostInitialize },
4295 { szCreateFolders, ACTION_CreateFolders },
4296 { szCreateShortcuts, ACTION_CreateShortcuts },
4297 { szDeleteServices, ACTION_DeleteServices },
4298 { szDisableRollback, NULL},
4299 { szDuplicateFiles, ACTION_DuplicateFiles },
4300 { szExecuteAction, ACTION_ExecuteAction },
4301 { szFileCost, ACTION_FileCost },
4302 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4303 { szForceReboot, ACTION_ForceReboot },
4304 { szInstallAdminPackage, NULL},
4305 { szInstallExecute, ACTION_InstallExecute },
4306 { szInstallExecuteAgain, ACTION_InstallExecute },
4307 { szInstallFiles, ACTION_InstallFiles},
4308 { szInstallFinalize, ACTION_InstallFinalize },
4309 { szInstallInitialize, ACTION_InstallInitialize },
4310 { szInstallSFPCatalogFile, NULL},
4311 { szInstallValidate, ACTION_InstallValidate },
4312 { szIsolateComponents, ACTION_IsolateComponents },
4313 { szLaunchConditions, ACTION_LaunchConditions },
4314 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4315 { szMoveFiles, ACTION_MoveFiles },
4316 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4317 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4318 { szInstallODBC, NULL},
4319 { szInstallServices, ACTION_InstallServices },
4320 { szPatchFiles, ACTION_PatchFiles },
4321 { szProcessComponents, ACTION_ProcessComponents },
4322 { szPublishComponents, ACTION_PublishComponents },
4323 { szPublishFeatures, ACTION_PublishFeatures },
4324 { szPublishProduct, ACTION_PublishProduct },
4325 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4326 { szRegisterComPlus, ACTION_RegisterComPlus},
4327 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4328 { szRegisterFonts, ACTION_RegisterFonts },
4329 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4330 { szRegisterProduct, ACTION_RegisterProduct },
4331 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4332 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4333 { szRegisterUser, ACTION_RegisterUser},
4334 { szRemoveDuplicateFiles, NULL},
4335 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4336 { szRemoveExistingProducts, NULL},
4337 { szRemoveFiles, ACTION_RemoveFiles},
4338 { szRemoveFolders, NULL},
4339 { szRemoveIniValues, ACTION_RemoveIniValues },
4340 { szRemoveODBC, NULL},
4341 { szRemoveRegistryValues, NULL},
4342 { szRemoveShortcuts, NULL},
4343 { szResolveSource, ACTION_ResolveSource},
4344 { szRMCCPSearch, ACTION_RMCCPSearch},
4345 { szScheduleReboot, NULL},
4346 { szSelfRegModules, ACTION_SelfRegModules },
4347 { szSelfUnregModules, ACTION_SelfUnregModules },
4348 { szSetODBCFolders, NULL},
4349 { szStartServices, ACTION_StartServices },
4350 { szStopServices, ACTION_StopServices },
4351 { szUnpublishComponents, NULL},
4352 { szUnpublishFeatures, NULL},
4353 { szUnregisterClassInfo, NULL},
4354 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4355 { szUnregisterExtensionInfo, NULL},
4356 { szUnregisterFonts, ACTION_UnregisterFonts },
4357 { szUnregisterMIMEInfo, NULL},
4358 { szUnregisterProgIdInfo, NULL},
4359 { szUnregisterTypeLibraries, NULL},
4360 { szValidateProductID, NULL},
4361 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4362 { szWriteIniValues, ACTION_WriteIniValues },
4363 { szWriteRegistryValues, ACTION_WriteRegistryValues},