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 ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
252 static const WCHAR szActionText[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
256 row = MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row,1,action);
258 ControlEvent_FireSubscribedEvent(package,szActionText, row);
259 msiobj_release(&row->hdr);
262 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
264 static const WCHAR template_s[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
267 static const WCHAR format[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
280 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
282 row = MSI_QueryGetRecord( package->db, Query_t, action );
286 ActionText = MSI_RecordGetString(row,2);
287 deformat_string(package, ActionText, &deformated);
289 sprintfW(message,template_s,timet,action,deformated);
290 ce_actiontext(package, deformated);
291 msiobj_release(&row->hdr);
293 row = MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row,1,message);
296 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
297 msiobj_release(&row->hdr);
298 msi_free(deformated);
301 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
305 static const WCHAR template_s[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
308 static const WCHAR template_e[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
312 static const WCHAR format[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
317 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
319 sprintfW(message,template_s,timet,action);
321 sprintfW(message,template_e,timet,action,rc);
323 row = MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row,1,message);
326 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
327 msiobj_release(&row->hdr);
330 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
332 LPWSTR str = msi_dup_property( package, prop );
333 int val = str ? atoiW( str ) : def;
338 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
343 LPWSTR prop = NULL, val = NULL;
346 return ERROR_SUCCESS;
358 TRACE("Looking at %s\n",debugstr_w(ptr));
360 ptr2 = strchrW(ptr,'=');
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
370 prop = msi_alloc((len+1)*sizeof(WCHAR));
371 memcpy(prop,ptr,len*sizeof(WCHAR));
377 while (*ptr && (quote || (!quote && *ptr!=' ')))
390 val = msi_alloc((len+1)*sizeof(WCHAR));
391 memcpy(val,ptr2,len*sizeof(WCHAR));
394 if (lstrlenW(prop) > 0)
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop), debugstr_w(val));
398 MSI_SetPropertyW(package,prop,val);
404 return ERROR_SUCCESS;
408 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
410 LPWSTR p, *ret = NULL;
416 /* count the number of substrings */
417 for ( p = (LPWSTR)str, count = 0; p; count++ )
419 p = strchrW( p, sep );
424 /* allocate space for an array of substring pointers and the substrings */
425 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
426 (lstrlenW(str)+1) * sizeof(WCHAR) );
430 /* copy the string and set the pointers */
431 p = (LPWSTR) &ret[count+1];
433 for( count = 0; (ret[count] = p); count++ )
435 p = strchrW( p, sep );
443 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
444 MSIDATABASE *patch_db, LPCWSTR name )
446 UINT ret = ERROR_FUNCTION_FAILED;
447 IStorage *stg = NULL;
450 TRACE("%p %s\n", package, debugstr_w(name) );
454 ERR("expected a colon in %s\n", debugstr_w(name));
455 return ERROR_FUNCTION_FAILED;
458 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
461 ret = msi_table_apply_transform( package->db, stg );
462 IStorage_Release( stg );
466 ERR("failed to open substorage %s\n", debugstr_w(name));
471 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
473 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list, *guids, product_id;
475 UINT i, ret = ERROR_FUNCTION_FAILED;
477 product_id = msi_dup_property( package, szProdID );
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS;
485 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
486 guids = msi_split_string( guid_list, ';' );
487 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
489 if (!lstrcmpW( guids[i], product_id ))
493 msi_free( guid_list );
494 msi_free( product_id );
499 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
502 LPWSTR str, *substorage;
503 UINT i, r = ERROR_SUCCESS;
505 si = MSI_GetSummaryInformationW( patch_db, 0 );
507 return ERROR_FUNCTION_FAILED;
509 msi_check_patch_applicable( package, si );
511 /* enumerate the substorage */
512 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
513 substorage = msi_split_string( str, ';' );
514 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
515 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
516 msi_free( substorage );
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
521 msiobj_release( &si->hdr );
526 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
528 MSIDATABASE *patch_db = NULL;
531 TRACE("%p %s\n", package, debugstr_w( file ) );
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
538 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
539 if ( r != ERROR_SUCCESS )
541 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
545 msi_parse_patch_summary( package, patch_db );
546 msiobj_release( &patch_db->hdr );
548 return ERROR_SUCCESS;
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT msi_apply_patches( MSIPACKAGE *package )
554 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list, *patches;
556 UINT i, r = ERROR_SUCCESS;
558 patch_list = msi_dup_property( package, szPatch );
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
562 patches = msi_split_string( patch_list, ';' );
563 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
564 r = msi_apply_patch_package( package, patches[i] );
567 msi_free( patch_list );
572 /****************************************************
573 * TOP level entry points
574 *****************************************************/
576 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
577 LPCWSTR szCommandLine )
581 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
582 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
583 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
585 MSI_SetPropertyW(package, szAction, szInstall);
587 package->script = msi_alloc(sizeof(MSISCRIPT));
588 memset(package->script,0,sizeof(MSISCRIPT));
590 package->script->InWhatSequence = SEQUENCE_INSTALL;
594 LPWSTR p, check, path;
596 package->PackagePath = strdupW(szPackagePath);
597 path = strdupW(szPackagePath);
598 p = strrchrW(path,'\\');
607 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
608 GetCurrentDirectoryW(MAX_PATH,path);
612 check = msi_dup_property( package, cszSourceDir );
614 MSI_SetPropertyW(package, cszSourceDir, path);
619 msi_parse_command_line( package, szCommandLine );
621 msi_apply_patches( package );
623 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
625 package->script->InWhatSequence |= SEQUENCE_UI;
626 rc = ACTION_ProcessUISequence(package);
628 if (rc == ERROR_SUCCESS)
630 package->script->InWhatSequence |= SEQUENCE_EXEC;
631 rc = ACTION_ProcessExecSequence(package,TRUE);
635 rc = ACTION_ProcessExecSequence(package,FALSE);
639 /* install was halted but should be considered a success */
643 package->script->CurrentlyScripting= FALSE;
645 /* process the ending type action */
646 if (rc == ERROR_SUCCESS)
647 ACTION_PerformActionSequence(package,-1,ui);
648 else if (rc == ERROR_INSTALL_USEREXIT)
649 ACTION_PerformActionSequence(package,-2,ui);
650 else if (rc == ERROR_INSTALL_SUSPEND)
651 ACTION_PerformActionSequence(package,-4,ui);
653 ACTION_PerformActionSequence(package,-3,ui);
655 /* finish up running custom actions */
656 ACTION_FinishCustomActions(package);
661 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
663 UINT rc = ERROR_SUCCESS;
665 static const WCHAR ExecSeqQuery[] =
666 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
667 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
668 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
669 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
671 static const WCHAR UISeqQuery[] =
672 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
673 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
674 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
675 ' ', '=',' ','%','i',0};
678 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
680 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
684 LPCWSTR action, cond;
686 TRACE("Running the actions\n");
688 /* check conditions */
689 cond = MSI_RecordGetString(row,2);
692 /* this is a hack to skip errors in the condition code */
693 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
697 action = MSI_RecordGetString(row,1);
700 ERR("failed to fetch action\n");
701 rc = ERROR_FUNCTION_FAILED;
706 rc = ACTION_PerformUIAction(package,action);
708 rc = ACTION_PerformAction(package,action,FALSE);
710 msiobj_release(&row->hdr);
721 } iterate_action_param;
723 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
725 iterate_action_param *iap= (iterate_action_param*)param;
727 LPCWSTR cond, action;
729 action = MSI_RecordGetString(row,1);
732 ERR("Error is retrieving action name\n");
733 return ERROR_FUNCTION_FAILED;
736 /* check conditions */
737 cond = MSI_RecordGetString(row,2);
740 /* this is a hack to skip errors in the condition code */
741 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
743 TRACE("Skipping action: %s (condition is false)\n",
745 return ERROR_SUCCESS;
750 rc = ACTION_PerformUIAction(iap->package,action);
752 rc = ACTION_PerformAction(iap->package,action,FALSE);
754 msi_dialog_check_messages( NULL );
756 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
757 rc = iap->package->CurrentInstallState;
759 if (rc == ERROR_FUNCTION_NOT_CALLED)
762 if (rc != ERROR_SUCCESS)
763 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
768 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
772 static const WCHAR query[] =
773 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
775 ' ','W','H','E','R','E',' ',
776 '`','S','e','q','u','e','n','c','e','`',' ',
777 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
778 '`','S','e','q','u','e','n','c','e','`',0};
779 iterate_action_param iap;
782 * FIXME: probably should be checking UILevel in the
783 * ACTION_PerformUIAction/ACTION_PerformAction
784 * rather than saving the UI level here. Those
785 * two functions can be merged too.
787 iap.package = package;
790 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
792 r = MSI_OpenQuery( package->db, &view, query, szTable );
793 if (r == ERROR_SUCCESS)
795 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
796 msiobj_release(&view->hdr);
802 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
806 static const WCHAR ExecSeqQuery[] =
807 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
808 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
809 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
810 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
811 'O','R','D','E','R',' ', 'B','Y',' ',
812 '`','S','e','q','u','e','n','c','e','`',0 };
814 static const WCHAR IVQuery[] =
815 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
816 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
817 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
818 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
819 ' ','\'', 'I','n','s','t','a','l','l',
820 'V','a','l','i','d','a','t','e','\'', 0};
822 iterate_action_param iap;
824 iap.package = package;
827 if (package->script->ExecuteSequenceRun)
829 TRACE("Execute Sequence already Run\n");
830 return ERROR_SUCCESS;
833 package->script->ExecuteSequenceRun = TRUE;
835 /* get the sequence number */
838 row = MSI_QueryGetRecord(package->db, IVQuery);
840 return ERROR_FUNCTION_FAILED;
841 seq = MSI_RecordGetInteger(row,1);
842 msiobj_release(&row->hdr);
845 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
846 if (rc == ERROR_SUCCESS)
848 TRACE("Running the actions\n");
850 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
851 msiobj_release(&view->hdr);
857 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
861 static const WCHAR ExecSeqQuery [] =
862 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
863 '`','I','n','s','t','a','l','l',
864 'U','I','S','e','q','u','e','n','c','e','`',
865 ' ','W','H','E','R','E',' ',
866 '`','S','e','q','u','e','n','c','e','`',' ',
867 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
868 '`','S','e','q','u','e','n','c','e','`',0};
869 iterate_action_param iap;
871 iap.package = package;
874 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
876 if (rc == ERROR_SUCCESS)
878 TRACE("Running the actions \n");
880 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
881 msiobj_release(&view->hdr);
887 /********************************************************
888 * ACTION helper functions and functions that perform the actions
889 *******************************************************/
890 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
891 UINT* rc, BOOL force )
897 if (!run && !package->script->CurrentlyScripting)
902 if (strcmpW(action,szInstallFinalize) == 0 ||
903 strcmpW(action,szInstallExecute) == 0 ||
904 strcmpW(action,szInstallExecuteAgain) == 0)
909 while (StandardActions[i].action != NULL)
911 if (strcmpW(StandardActions[i].action, action)==0)
915 ui_actioninfo(package, action, TRUE, 0);
916 *rc = schedule_action(package,INSTALL_SCRIPT,action);
917 ui_actioninfo(package, action, FALSE, *rc);
921 ui_actionstart(package, action);
922 if (StandardActions[i].handler)
924 *rc = StandardActions[i].handler(package);
928 FIXME("unhandled standard action %s\n",debugstr_w(action));
940 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
941 UINT* rc, BOOL force )
946 arc = ACTION_CustomAction(package,action, force);
948 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
957 * A lot of actions are really important even if they don't do anything
958 * explicit... Lots of properties are set at the beginning of the installation
959 * CostFinalize does a bunch of work to translate the directories and such
961 * But until I get write access to the database that is hard, so I am going to
962 * hack it to see if I can get something to run.
964 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
966 UINT rc = ERROR_SUCCESS;
969 TRACE("Performing action (%s)\n",debugstr_w(action));
971 handled = ACTION_HandleStandardAction(package, action, &rc, force);
974 handled = ACTION_HandleCustomAction(package, action, &rc, force);
978 FIXME("unhandled msi action %s\n",debugstr_w(action));
979 rc = ERROR_FUNCTION_NOT_CALLED;
985 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
987 UINT rc = ERROR_SUCCESS;
988 BOOL handled = FALSE;
990 TRACE("Performing action (%s)\n",debugstr_w(action));
992 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
995 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
997 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1002 FIXME("unhandled msi action %s\n",debugstr_w(action));
1003 rc = ERROR_FUNCTION_NOT_CALLED;
1011 * Actual Action Handlers
1014 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1016 MSIPACKAGE *package = (MSIPACKAGE*)param;
1022 dir = MSI_RecordGetString(row,1);
1025 ERR("Unable to get folder id \n");
1026 return ERROR_SUCCESS;
1029 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1032 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1033 return ERROR_SUCCESS;
1036 TRACE("Folder is %s\n",debugstr_w(full_path));
1039 uirow = MSI_CreateRecord(1);
1040 MSI_RecordSetStringW(uirow,1,full_path);
1041 ui_actiondata(package,szCreateFolders,uirow);
1042 msiobj_release( &uirow->hdr );
1044 if (folder->State == 0)
1045 create_full_pathW(full_path);
1049 msi_free(full_path);
1050 return ERROR_SUCCESS;
1053 /* FIXME: probably should merge this with the above function */
1054 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1056 UINT rc = ERROR_SUCCESS;
1058 LPWSTR install_path;
1060 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1062 return ERROR_FUNCTION_FAILED;
1064 /* create the path */
1065 if (folder->State == 0)
1067 create_full_pathW(install_path);
1070 msi_free(install_path);
1075 UINT msi_create_component_directories( MSIPACKAGE *package )
1079 /* create all the folders required by the components are going to install */
1080 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1082 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1084 msi_create_directory( package, comp->Directory );
1087 return ERROR_SUCCESS;
1091 * Also we cannot enable/disable components either, so for now I am just going
1092 * to do all the directories for all the components.
1094 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1096 static const WCHAR ExecSeqQuery[] =
1097 {'S','E','L','E','C','T',' ',
1098 '`','D','i','r','e','c','t','o','r','y','_','`',
1099 ' ','F','R','O','M',' ',
1100 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1104 /* create all the empty folders specified in the CreateFolder table */
1105 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1106 if (rc != ERROR_SUCCESS)
1107 return ERROR_SUCCESS;
1109 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1110 msiobj_release(&view->hdr);
1112 msi_create_component_directories( package );
1117 static MSICOMPONENT* load_component( MSIRECORD * row )
1121 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1125 /* fill in the data */
1126 comp->Component = msi_dup_record_field( row, 1 );
1128 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1130 comp->ComponentId = msi_dup_record_field( row, 2 );
1131 comp->Directory = msi_dup_record_field( row, 3 );
1132 comp->Attributes = MSI_RecordGetInteger(row,4);
1133 comp->Condition = msi_dup_record_field( row, 5 );
1134 comp->KeyPath = msi_dup_record_field( row, 6 );
1136 comp->Installed = INSTALLSTATE_ABSENT;
1137 comp->Action = INSTALLSTATE_UNKNOWN;
1138 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1140 comp->Enabled = TRUE;
1146 MSIPACKAGE *package;
1147 MSIFEATURE *feature;
1150 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1154 cl = msi_alloc( sizeof (*cl) );
1156 return ERROR_NOT_ENOUGH_MEMORY;
1157 cl->component = comp;
1158 list_add_tail( &feature->Components, &cl->entry );
1160 return ERROR_SUCCESS;
1163 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1165 _ilfs* ilfs= (_ilfs*)param;
1166 MSIPACKAGE *package = ilfs->package;
1167 MSIFEATURE *feature = ilfs->feature;
1170 comp = load_component( row );
1172 return ERROR_FUNCTION_FAILED;
1174 list_add_tail( &package->components, &comp->entry );
1175 add_feature_component( feature, comp );
1177 TRACE("Loaded new component %p\n", comp);
1179 return ERROR_SUCCESS;
1182 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1184 _ilfs* ilfs= (_ilfs*)param;
1189 static const WCHAR Query[] =
1190 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1191 '`','C','o','m','p','o','n','e','n','t','`',' ',
1192 'W','H','E','R','E',' ',
1193 '`','C','o','m','p','o','n','e','n','t','`',' ',
1194 '=','\'','%','s','\'',0};
1196 component = MSI_RecordGetString(row,1);
1198 /* check to see if the component is already loaded */
1199 comp = get_loaded_component( ilfs->package, component );
1202 TRACE("Component %s already loaded\n", debugstr_w(component) );
1203 add_feature_component( ilfs->feature, comp );
1204 return ERROR_SUCCESS;
1207 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1208 if (rc != ERROR_SUCCESS)
1209 return ERROR_SUCCESS;
1211 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1212 msiobj_release( &view->hdr );
1214 return ERROR_SUCCESS;
1217 static UINT load_feature(MSIRECORD * row, LPVOID param)
1219 MSIPACKAGE* package = (MSIPACKAGE*)param;
1220 MSIFEATURE* feature;
1221 static const WCHAR Query1[] =
1222 {'S','E','L','E','C','T',' ',
1223 '`','C','o','m','p','o','n','e','n','t','_','`',
1224 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1225 'C','o','m','p','o','n','e','n','t','s','`',' ',
1226 'W','H','E','R','E',' ',
1227 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1232 /* fill in the data */
1234 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1236 return ERROR_NOT_ENOUGH_MEMORY;
1238 list_init( &feature->Components );
1240 feature->Feature = msi_dup_record_field( row, 1 );
1242 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1244 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1245 feature->Title = msi_dup_record_field( row, 3 );
1246 feature->Description = msi_dup_record_field( row, 4 );
1248 if (!MSI_RecordIsNull(row,5))
1249 feature->Display = MSI_RecordGetInteger(row,5);
1251 feature->Level= MSI_RecordGetInteger(row,6);
1252 feature->Directory = msi_dup_record_field( row, 7 );
1253 feature->Attributes = MSI_RecordGetInteger(row,8);
1255 feature->Installed = INSTALLSTATE_ABSENT;
1256 feature->Action = INSTALLSTATE_UNKNOWN;
1257 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1259 list_add_tail( &package->features, &feature->entry );
1261 /* load feature components */
1263 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1264 if (rc != ERROR_SUCCESS)
1265 return ERROR_SUCCESS;
1267 ilfs.package = package;
1268 ilfs.feature = feature;
1270 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1271 msiobj_release(&view->hdr);
1273 return ERROR_SUCCESS;
1276 static UINT load_file(MSIRECORD *row, LPVOID param)
1278 MSIPACKAGE* package = (MSIPACKAGE*)param;
1282 /* fill in the data */
1284 file = msi_alloc_zero( sizeof (MSIFILE) );
1286 return ERROR_NOT_ENOUGH_MEMORY;
1288 file->File = msi_dup_record_field( row, 1 );
1290 component = MSI_RecordGetString( row, 2 );
1291 file->Component = get_loaded_component( package, component );
1293 if (!file->Component)
1294 ERR("Unfound Component %s\n",debugstr_w(component));
1296 file->FileName = msi_dup_record_field( row, 3 );
1297 reduce_to_longfilename( file->FileName );
1299 file->ShortName = msi_dup_record_field( row, 3 );
1300 reduce_to_shortfilename( file->ShortName );
1302 file->FileSize = MSI_RecordGetInteger( row, 4 );
1303 file->Version = msi_dup_record_field( row, 5 );
1304 file->Language = msi_dup_record_field( row, 6 );
1305 file->Attributes = MSI_RecordGetInteger( row, 7 );
1306 file->Sequence = MSI_RecordGetInteger( row, 8 );
1308 file->state = msifs_invalid;
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1312 list_add_tail( &package->files, &file->entry );
1314 return ERROR_SUCCESS;
1317 static UINT load_all_files(MSIPACKAGE *package)
1321 static const WCHAR Query[] =
1322 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1323 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1324 '`','S','e','q','u','e','n','c','e','`', 0};
1327 return ERROR_INVALID_HANDLE;
1329 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1330 if (rc != ERROR_SUCCESS)
1331 return ERROR_SUCCESS;
1333 rc = MSI_IterateRecords(view, NULL, load_file, package);
1334 msiobj_release(&view->hdr);
1336 return ERROR_SUCCESS;
1341 * I am not doing any of the costing functionality yet.
1342 * Mostly looking at doing the Component and Feature loading
1344 * The native MSI does A LOT of modification to tables here. Mostly adding
1345 * a lot of temporary columns to the Feature and Component tables.
1347 * note: Native msi also tracks the short filename. But I am only going to
1348 * track the long ones. Also looking at this directory table
1349 * it appears that the directory table does not get the parents
1350 * resolved base on property only based on their entries in the
1353 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1357 static const WCHAR Query_all[] =
1358 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1359 '`','F','e','a','t','u','r','e','`',0};
1360 static const WCHAR szCosting[] =
1361 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1362 static const WCHAR szZero[] = { '0', 0 };
1364 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1365 return ERROR_SUCCESS;
1367 MSI_SetPropertyW(package, szCosting, szZero);
1368 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1370 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1371 if (rc != ERROR_SUCCESS)
1374 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1375 msiobj_release(&view->hdr);
1377 load_all_files(package);
1379 return ERROR_SUCCESS;
1382 static UINT execute_script(MSIPACKAGE *package, UINT script )
1385 UINT rc = ERROR_SUCCESS;
1387 TRACE("Executing Script %i\n",script);
1389 for (i = 0; i < package->script->ActionCount[script]; i++)
1392 action = package->script->Actions[script][i];
1393 ui_actionstart(package, action);
1394 TRACE("Executing Action (%s)\n",debugstr_w(action));
1395 rc = ACTION_PerformAction(package, action, TRUE);
1396 msi_free(package->script->Actions[script][i]);
1397 if (rc != ERROR_SUCCESS)
1400 msi_free(package->script->Actions[script]);
1402 package->script->ActionCount[script] = 0;
1403 package->script->Actions[script] = NULL;
1407 static UINT ACTION_FileCost(MSIPACKAGE *package)
1409 return ERROR_SUCCESS;
1413 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1415 static const WCHAR Query[] =
1416 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1417 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1418 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1419 ' ','=',' ','\'','%','s','\'',
1421 LPWSTR ptargetdir, targetdir, srcdir;
1423 LPWSTR shortname = NULL;
1424 MSIRECORD * row = 0;
1427 TRACE("Looking for dir %s\n",debugstr_w(dir));
1429 folder = get_loaded_folder( package, dir );
1433 TRACE("Working to load %s\n",debugstr_w(dir));
1435 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1439 folder->Directory = strdupW(dir);
1441 row = MSI_QueryGetRecord(package->db, Query, dir);
1445 ptargetdir = targetdir = msi_dup_record_field(row,3);
1447 /* split src and target dir */
1448 if (strchrW(targetdir,':'))
1450 srcdir=strchrW(targetdir,':');
1457 /* for now only pick long filename versions */
1458 if (strchrW(targetdir,'|'))
1460 shortname = targetdir;
1461 targetdir = strchrW(targetdir,'|');
1465 /* for the sourcedir pick the short filename */
1466 if (srcdir && strchrW(srcdir,'|'))
1468 LPWSTR p = strchrW(srcdir,'|');
1472 /* now check for root dirs */
1473 if (targetdir[0] == '.' && targetdir[1] == 0)
1478 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1479 msi_free( folder->TargetDefault);
1480 folder->TargetDefault = strdupW(targetdir);
1484 folder->SourceDefault = strdupW(srcdir);
1486 folder->SourceDefault = strdupW(shortname);
1488 folder->SourceDefault = strdupW(targetdir);
1489 msi_free(ptargetdir);
1490 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1492 parent = MSI_RecordGetString(row,2);
1495 folder->Parent = load_folder( package, parent );
1496 if ( folder->Parent )
1497 TRACE("loaded parent %p %s\n", folder->Parent,
1498 debugstr_w(folder->Parent->Directory));
1500 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1503 folder->Property = msi_dup_property( package, dir );
1505 msiobj_release(&row->hdr);
1507 list_add_tail( &package->folders, &folder->entry );
1509 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1514 /* scan for and update current install states */
1515 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1518 MSIFEATURE *feature;
1520 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1523 res = MsiGetComponentPathW( package->ProductCode,
1524 comp->ComponentId, NULL, NULL);
1526 res = INSTALLSTATE_ABSENT;
1527 comp->Installed = res;
1530 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1533 INSTALLSTATE res = -10;
1535 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1537 comp= cl->component;
1540 res = comp->Installed;
1543 if (res == comp->Installed)
1546 if (res != comp->Installed)
1547 res = INSTALLSTATE_INCOMPLETE;
1550 feature->Installed = res;
1554 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1557 static const WCHAR all[]={'A','L','L',0};
1559 MSIFEATURE *feature;
1561 override = msi_dup_property( package, property );
1565 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1567 if (strcmpiW(override,all)==0)
1569 feature->ActionRequest= state;
1570 feature->Action = state;
1574 LPWSTR ptr = override;
1575 LPWSTR ptr2 = strchrW(override,',');
1579 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1580 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1582 feature->ActionRequest= state;
1583 feature->Action = state;
1589 ptr2 = strchrW(ptr,',');
1601 static UINT SetFeatureStates(MSIPACKAGE *package)
1604 static const WCHAR szlevel[] =
1605 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1606 static const WCHAR szAddLocal[] =
1607 {'A','D','D','L','O','C','A','L',0};
1608 static const WCHAR szRemove[] =
1609 {'R','E','M','O','V','E',0};
1610 BOOL override = FALSE;
1611 MSICOMPONENT* component;
1612 MSIFEATURE *feature;
1615 /* I do not know if this is where it should happen.. but */
1617 TRACE("Checking Install Level\n");
1619 install_level = msi_get_property_int( package, szlevel, 1 );
1621 /* ok hereis the _real_ rub
1622 * all these activation/deactivation things happen in order and things
1623 * later on the list override things earlier on the list.
1624 * 1) INSTALLLEVEL processing
1634 * 11) FILEADDDEFAULT
1635 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1636 * ignored for all the features. seems strange, especially since it is not
1637 * documented anywhere, but it is how it works.
1639 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1640 * REMOVE are the big ones, since we don't handle administrative installs
1643 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1644 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
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 const WCHAR name[] =
1877 static const WCHAR name_fmt[] =
1878 {'%','u','.','%','u','.','%','u','.','%','u',0};
1879 WCHAR filever[0x100];
1880 VS_FIXEDFILEINFO *lpVer;
1882 TRACE("Version comparison.. \n");
1883 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1884 version = msi_alloc(versize);
1885 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1887 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1889 sprintfW(filever,name_fmt,
1890 HIWORD(lpVer->dwFileVersionMS),
1891 LOWORD(lpVer->dwFileVersionMS),
1892 HIWORD(lpVer->dwFileVersionLS),
1893 LOWORD(lpVer->dwFileVersionLS));
1895 TRACE("new %s old %s\n", debugstr_w(file->Version),
1896 debugstr_w(filever));
1897 if (strcmpiW(filever,file->Version)<0)
1899 file->state = msifs_overwrite;
1900 /* FIXME: cost should be diff in size */
1901 comp->Cost += file->FileSize;
1904 file->state = msifs_present;
1908 file->state = msifs_present;
1911 TRACE("Evaluating Condition Table\n");
1913 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1914 if (rc == ERROR_SUCCESS)
1916 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1918 msiobj_release(&view->hdr);
1921 TRACE("Enabling or Disabling Components\n");
1922 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1924 if (comp->Condition)
1926 if (MSI_EvaluateConditionW(package,
1927 comp->Condition) == MSICONDITION_FALSE)
1929 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1930 comp->Enabled = FALSE;
1935 MSI_SetPropertyW(package,szCosting,szOne);
1936 /* set default run level if not set */
1937 level = msi_dup_property( package, szlevel );
1939 MSI_SetPropertyW(package,szlevel, szOne);
1942 ACTION_UpdateInstallStates(package);
1944 return SetFeatureStates(package);
1947 /* OK this value is "interpreted" and then formatted based on the
1948 first few characters */
1949 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1953 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1959 LPWSTR deformated = NULL;
1962 deformat_string(package, &value[2], &deformated);
1964 /* binary value type */
1968 *size = (strlenW(ptr)/2)+1;
1970 *size = strlenW(ptr)/2;
1972 data = msi_alloc(*size);
1978 /* if uneven pad with a zero in front */
1984 data[count] = (BYTE)strtol(byte,NULL,0);
1986 TRACE("Uneven byte count\n");
1994 data[count] = (BYTE)strtol(byte,NULL,0);
1997 msi_free(deformated);
1999 TRACE("Data %li bytes(%i)\n",*size,count);
2006 deformat_string(package, &value[1], &deformated);
2009 *size = sizeof(DWORD);
2010 data = msi_alloc(*size);
2016 if ( (*p < '0') || (*p > '9') )
2022 if (deformated[0] == '-')
2025 TRACE("DWORD %li\n",*(LPDWORD)data);
2027 msi_free(deformated);
2032 static const WCHAR szMulti[] = {'[','~',']',0};
2041 *type=REG_EXPAND_SZ;
2049 if (strstrW(value,szMulti))
2050 *type = REG_MULTI_SZ;
2052 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2057 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2059 MSIPACKAGE *package = (MSIPACKAGE*)param;
2060 static const WCHAR szHCR[] =
2061 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2062 'R','O','O','T','\\',0};
2063 static const WCHAR szHCU[] =
2064 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2065 'U','S','E','R','\\',0};
2066 static const WCHAR szHLM[] =
2067 {'H','K','E','Y','_','L','O','C','A','L','_',
2068 'M','A','C','H','I','N','E','\\',0};
2069 static const WCHAR szHU[] =
2070 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2072 LPSTR value_data = NULL;
2073 HKEY root_key, hkey;
2076 LPCWSTR szRoot, component, name, key, value;
2081 BOOL check_first = FALSE;
2084 ui_progress(package,2,0,0,0);
2091 component = MSI_RecordGetString(row, 6);
2092 comp = get_loaded_component(package,component);
2094 return ERROR_SUCCESS;
2096 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2098 TRACE("Skipping write due to disabled component %s\n",
2099 debugstr_w(component));
2101 comp->Action = comp->Installed;
2103 return ERROR_SUCCESS;
2106 comp->Action = INSTALLSTATE_LOCAL;
2108 name = MSI_RecordGetString(row, 4);
2109 if( MSI_RecordIsNull(row,5) && name )
2111 /* null values can have special meanings */
2112 if (name[0]=='-' && name[1] == 0)
2113 return ERROR_SUCCESS;
2114 else if ((name[0]=='+' && name[1] == 0) ||
2115 (name[0] == '*' && name[1] == 0))
2120 root = MSI_RecordGetInteger(row,2);
2121 key = MSI_RecordGetString(row, 3);
2123 /* get the root key */
2128 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2129 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2130 if (all_users && all_users[0] == '1')
2132 root_key = HKEY_LOCAL_MACHINE;
2137 root_key = HKEY_CURRENT_USER;
2140 msi_free(all_users);
2143 case 0: root_key = HKEY_CLASSES_ROOT;
2146 case 1: root_key = HKEY_CURRENT_USER;
2149 case 2: root_key = HKEY_LOCAL_MACHINE;
2152 case 3: root_key = HKEY_USERS;
2156 ERR("Unknown root %i\n",root);
2162 return ERROR_SUCCESS;
2164 deformat_string(package, key , &deformated);
2165 size = strlenW(deformated) + strlenW(szRoot) + 1;
2166 uikey = msi_alloc(size*sizeof(WCHAR));
2167 strcpyW(uikey,szRoot);
2168 strcatW(uikey,deformated);
2170 if (RegCreateKeyW( root_key, deformated, &hkey))
2172 ERR("Could not create key %s\n",debugstr_w(deformated));
2173 msi_free(deformated);
2175 return ERROR_SUCCESS;
2177 msi_free(deformated);
2179 value = MSI_RecordGetString(row,5);
2181 value_data = parse_value(package, value, &type, &size);
2184 static const WCHAR szEmpty[] = {0};
2185 value_data = (LPSTR)strdupW(szEmpty);
2190 deformat_string(package, name, &deformated);
2192 /* get the double nulls to terminate SZ_MULTI */
2193 if (type == REG_MULTI_SZ)
2194 size +=sizeof(WCHAR);
2198 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2200 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2205 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2206 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2208 TRACE("value %s of %s checked already exists\n",
2209 debugstr_w(deformated), debugstr_w(uikey));
2213 TRACE("Checked and setting value %s of %s\n",
2214 debugstr_w(deformated), debugstr_w(uikey));
2215 if (deformated || size)
2216 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2221 uirow = MSI_CreateRecord(3);
2222 MSI_RecordSetStringW(uirow,2,deformated);
2223 MSI_RecordSetStringW(uirow,1,uikey);
2226 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2228 MSI_RecordSetStringW(uirow,3,value);
2230 ui_actiondata(package,szWriteRegistryValues,uirow);
2231 msiobj_release( &uirow->hdr );
2233 msi_free(value_data);
2234 msi_free(deformated);
2237 return ERROR_SUCCESS;
2240 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2244 static const WCHAR ExecSeqQuery[] =
2245 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2246 '`','R','e','g','i','s','t','r','y','`',0 };
2249 return ERROR_INVALID_HANDLE;
2251 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2252 if (rc != ERROR_SUCCESS)
2253 return ERROR_SUCCESS;
2255 /* increment progress bar each time action data is sent */
2256 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2258 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2260 msiobj_release(&view->hdr);
2264 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2266 package->script->CurrentlyScripting = TRUE;
2268 return ERROR_SUCCESS;
2272 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2277 static const WCHAR q1[]=
2278 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2279 '`','R','e','g','i','s','t','r','y','`',0};
2282 MSIFEATURE *feature;
2285 TRACE("InstallValidate\n");
2287 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2288 if (rc == ERROR_SUCCESS)
2290 MSI_IterateRecords( view, &progress, NULL, package );
2291 msiobj_release( &view->hdr );
2292 total += progress * REG_PROGRESS_VALUE;
2295 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2296 total += COMPONENT_PROGRESS_VALUE;
2298 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2299 total += file->FileSize;
2301 ui_progress(package,0,total,0,0);
2303 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2305 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2306 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2307 feature->ActionRequest);
2310 return ERROR_SUCCESS;
2313 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2315 MSIPACKAGE* package = (MSIPACKAGE*)param;
2316 LPCWSTR cond = NULL;
2317 LPCWSTR message = NULL;
2318 static const WCHAR title[]=
2319 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2321 cond = MSI_RecordGetString(row,1);
2323 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2326 message = MSI_RecordGetString(row,2);
2327 deformat_string(package,message,&deformated);
2328 MessageBoxW(NULL,deformated,title,MB_OK);
2329 msi_free(deformated);
2330 return ERROR_FUNCTION_FAILED;
2333 return ERROR_SUCCESS;
2336 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2339 MSIQUERY * view = NULL;
2340 static const WCHAR ExecSeqQuery[] =
2341 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2342 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2344 TRACE("Checking launch conditions\n");
2346 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2347 if (rc != ERROR_SUCCESS)
2348 return ERROR_SUCCESS;
2350 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2351 msiobj_release(&view->hdr);
2356 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2360 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2362 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2364 MSIRECORD * row = 0;
2366 LPWSTR deformated,buffer,deformated_name;
2368 static const WCHAR ExecSeqQuery[] =
2369 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2370 '`','R','e','g','i','s','t','r','y','`',' ',
2371 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2372 ' ','=',' ' ,'\'','%','s','\'',0 };
2373 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2374 static const WCHAR fmt2[]=
2375 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2377 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2381 root = MSI_RecordGetInteger(row,2);
2382 key = MSI_RecordGetString(row, 3);
2383 name = MSI_RecordGetString(row, 4);
2384 deformat_string(package, key , &deformated);
2385 deformat_string(package, name, &deformated_name);
2387 len = strlenW(deformated) + 6;
2388 if (deformated_name)
2389 len+=strlenW(deformated_name);
2391 buffer = msi_alloc( len *sizeof(WCHAR));
2393 if (deformated_name)
2394 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2396 sprintfW(buffer,fmt,root,deformated);
2398 msi_free(deformated);
2399 msi_free(deformated_name);
2400 msiobj_release(&row->hdr);
2404 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2406 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2411 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2414 return strdupW( file->TargetPath );
2419 static HKEY openSharedDLLsKey(void)
2422 static const WCHAR path[] =
2423 {'S','o','f','t','w','a','r','e','\\',
2424 'M','i','c','r','o','s','o','f','t','\\',
2425 'W','i','n','d','o','w','s','\\',
2426 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2427 'S','h','a','r','e','d','D','L','L','s',0};
2429 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2433 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2438 DWORD sz = sizeof(count);
2441 hkey = openSharedDLLsKey();
2442 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2443 if (rc != ERROR_SUCCESS)
2449 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2453 hkey = openSharedDLLsKey();
2455 msi_reg_set_val_dword( hkey, path, count );
2457 RegDeleteValueW(hkey,path);
2463 * Return TRUE if the count should be written out and FALSE if not
2465 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2467 MSIFEATURE *feature;
2471 /* only refcount DLLs */
2472 if (comp->KeyPath == NULL ||
2473 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2474 comp->Attributes & msidbComponentAttributesODBCDataSource)
2478 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2479 write = (count > 0);
2481 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2485 /* increment counts */
2486 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2490 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2493 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2495 if ( cl->component == comp )
2500 /* decrement counts */
2501 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2505 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2508 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2510 if ( cl->component == comp )
2515 /* ref count all the files in the component */
2520 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2522 if (file->Component == comp)
2523 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2527 /* add a count for permenent */
2528 if (comp->Attributes & msidbComponentAttributesPermanent)
2531 comp->RefCount = count;
2534 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2538 * Ok further analysis makes me think that this work is
2539 * actually done in the PublishComponents and PublishFeatures
2540 * step, and not here. It appears like the keypath and all that is
2541 * resolved in this step, however actually written in the Publish steps.
2542 * But we will leave it here for now because it is unclear
2544 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2546 WCHAR squished_pc[GUID_SIZE];
2547 WCHAR squished_cc[GUID_SIZE];
2550 HKEY hkey=0,hkey2=0;
2553 return ERROR_INVALID_HANDLE;
2555 /* writes the Component and Features values to the registry */
2557 rc = MSIREG_OpenComponents(&hkey);
2558 if (rc != ERROR_SUCCESS)
2561 squash_guid(package->ProductCode,squished_pc);
2562 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2564 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2566 ui_progress(package,2,0,0,0);
2567 if (comp->ComponentId)
2571 squash_guid(comp->ComponentId,squished_cc);
2573 msi_free(comp->FullKeypath);
2574 comp->FullKeypath = resolve_keypath( package, comp );
2576 /* do the refcounting */
2577 ACTION_RefCountComponent( package, comp );
2579 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2580 debugstr_w(comp->Component),
2581 debugstr_w(squished_cc),
2582 debugstr_w(comp->FullKeypath),
2585 * Write the keypath out if the component is to be registered
2586 * and delete the key if the component is to be deregistered
2588 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2590 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2591 if (rc != ERROR_SUCCESS)
2594 if (comp->FullKeypath)
2596 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2598 if (comp->Attributes & msidbComponentAttributesPermanent)
2600 static const WCHAR szPermKey[] =
2601 { '0','0','0','0','0','0','0','0','0','0','0','0',
2602 '0','0','0','0','0','0','0','0','0','0','0','0',
2603 '0','0','0','0','0','0','0','0',0};
2605 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2611 uirow = MSI_CreateRecord(3);
2612 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2613 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2614 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2615 ui_actiondata(package,szProcessComponents,uirow);
2616 msiobj_release( &uirow->hdr );
2619 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2623 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2624 if (rc != ERROR_SUCCESS)
2627 RegDeleteValueW(hkey2,squished_pc);
2629 /* if the key is empty delete it */
2630 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2632 if (res == ERROR_NO_MORE_ITEMS)
2633 RegDeleteKeyW(hkey,squished_cc);
2636 uirow = MSI_CreateRecord(2);
2637 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2638 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2639 ui_actiondata(package,szProcessComponents,uirow);
2640 msiobj_release( &uirow->hdr );
2657 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2658 LPWSTR lpszName, LONG_PTR lParam)
2661 typelib_struct *tl_struct = (typelib_struct*) lParam;
2662 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2666 if (!IS_INTRESOURCE(lpszName))
2668 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2672 sz = strlenW(tl_struct->source)+4;
2673 sz *= sizeof(WCHAR);
2675 if ((INT)lpszName == 1)
2676 tl_struct->path = strdupW(tl_struct->source);
2679 tl_struct->path = msi_alloc(sz);
2680 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2683 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2684 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2685 if (!SUCCEEDED(res))
2687 msi_free(tl_struct->path);
2688 tl_struct->path = NULL;
2693 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2694 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2696 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2700 msi_free(tl_struct->path);
2701 tl_struct->path = NULL;
2703 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2704 ITypeLib_Release(tl_struct->ptLib);
2709 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2711 MSIPACKAGE* package = (MSIPACKAGE*)param;
2715 typelib_struct tl_struct;
2717 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2719 component = MSI_RecordGetString(row,3);
2720 comp = get_loaded_component(package,component);
2722 return ERROR_SUCCESS;
2724 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2726 TRACE("Skipping typelib reg due to disabled component\n");
2728 comp->Action = comp->Installed;
2730 return ERROR_SUCCESS;
2733 comp->Action = INSTALLSTATE_LOCAL;
2735 file = get_loaded_file( package, comp->KeyPath );
2737 return ERROR_SUCCESS;
2739 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2743 guid = MSI_RecordGetString(row,1);
2744 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2745 tl_struct.source = strdupW( file->TargetPath );
2746 tl_struct.path = NULL;
2748 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2749 (LONG_PTR)&tl_struct);
2757 helpid = MSI_RecordGetString(row,6);
2760 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2761 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2764 if (!SUCCEEDED(res))
2765 ERR("Failed to register type library %s\n",
2766 debugstr_w(tl_struct.path));
2769 ui_actiondata(package,szRegisterTypeLibraries,row);
2771 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2774 ITypeLib_Release(tl_struct.ptLib);
2775 msi_free(tl_struct.path);
2778 ERR("Failed to load type library %s\n",
2779 debugstr_w(tl_struct.source));
2781 FreeLibrary(module);
2782 msi_free(tl_struct.source);
2785 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2787 return ERROR_SUCCESS;
2790 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2793 * OK this is a bit confusing.. I am given a _Component key and I believe
2794 * that the file that is being registered as a type library is the "key file
2795 * of that component" which I interpret to mean "The file in the KeyPath of
2800 static const WCHAR Query[] =
2801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2802 '`','T','y','p','e','L','i','b','`',0};
2805 return ERROR_INVALID_HANDLE;
2807 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2808 if (rc != ERROR_SUCCESS)
2809 return ERROR_SUCCESS;
2811 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2812 msiobj_release(&view->hdr);
2816 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2818 MSIPACKAGE *package = (MSIPACKAGE*)param;
2819 LPWSTR target_file, target_folder;
2821 WCHAR filename[0x100];
2824 static const WCHAR szlnk[]={'.','l','n','k',0};
2829 buffer = MSI_RecordGetString(row,4);
2830 comp = get_loaded_component(package,buffer);
2832 return ERROR_SUCCESS;
2834 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2836 TRACE("Skipping shortcut creation due to disabled component\n");
2838 comp->Action = comp->Installed;
2840 return ERROR_SUCCESS;
2843 comp->Action = INSTALLSTATE_LOCAL;
2845 ui_actiondata(package,szCreateShortcuts,row);
2847 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2848 &IID_IShellLinkW, (LPVOID *) &sl );
2852 ERR("Is IID_IShellLink\n");
2853 return ERROR_SUCCESS;
2856 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2859 ERR("Is IID_IPersistFile\n");
2860 return ERROR_SUCCESS;
2863 buffer = MSI_RecordGetString(row,2);
2864 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2866 /* may be needed because of a bug somehwere else */
2867 create_full_pathW(target_folder);
2870 MSI_RecordGetStringW(row,3,filename,&sz);
2871 reduce_to_longfilename(filename);
2872 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2873 strcatW(filename,szlnk);
2874 target_file = build_directory_name(2, target_folder, filename);
2875 msi_free(target_folder);
2877 buffer = MSI_RecordGetString(row,5);
2878 if (strchrW(buffer,'['))
2881 deformat_string(package,buffer,&deformated);
2882 IShellLinkW_SetPath(sl,deformated);
2883 msi_free(deformated);
2887 FIXME("poorly handled shortcut format, advertised shortcut\n");
2888 IShellLinkW_SetPath(sl,comp->FullKeypath);
2891 if (!MSI_RecordIsNull(row,6))
2894 buffer = MSI_RecordGetString(row,6);
2895 deformat_string(package,buffer,&deformated);
2896 IShellLinkW_SetArguments(sl,deformated);
2897 msi_free(deformated);
2900 if (!MSI_RecordIsNull(row,7))
2902 buffer = MSI_RecordGetString(row,7);
2903 IShellLinkW_SetDescription(sl,buffer);
2906 if (!MSI_RecordIsNull(row,8))
2907 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2909 if (!MSI_RecordIsNull(row,9))
2914 buffer = MSI_RecordGetString(row,9);
2916 Path = build_icon_path(package,buffer);
2917 index = MSI_RecordGetInteger(row,10);
2919 IShellLinkW_SetIconLocation(sl,Path,index);
2923 if (!MSI_RecordIsNull(row,11))
2924 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2926 if (!MSI_RecordIsNull(row,12))
2929 buffer = MSI_RecordGetString(row,12);
2930 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2931 IShellLinkW_SetWorkingDirectory(sl,Path);
2935 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2936 IPersistFile_Save(pf,target_file,FALSE);
2938 msi_free(target_file);
2940 IPersistFile_Release( pf );
2941 IShellLinkW_Release( sl );
2943 return ERROR_SUCCESS;
2946 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2951 static const WCHAR Query[] =
2952 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2953 '`','S','h','o','r','t','c','u','t','`',0};
2956 return ERROR_INVALID_HANDLE;
2958 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2959 if (rc != ERROR_SUCCESS)
2960 return ERROR_SUCCESS;
2962 res = CoInitialize( NULL );
2965 ERR("CoInitialize failed\n");
2966 return ERROR_FUNCTION_FAILED;
2969 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2970 msiobj_release(&view->hdr);
2977 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2979 MSIPACKAGE* package = (MSIPACKAGE*)param;
2987 FileName = MSI_RecordGetString(row,1);
2990 ERR("Unable to get FileName\n");
2991 return ERROR_SUCCESS;
2994 FilePath = build_icon_path(package,FileName);
2996 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2998 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2999 FILE_ATTRIBUTE_NORMAL, NULL);
3001 if (the_file == INVALID_HANDLE_VALUE)
3003 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3005 return ERROR_SUCCESS;
3012 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3013 if (rc != ERROR_SUCCESS)
3015 ERR("Failed to get stream\n");
3016 CloseHandle(the_file);
3017 DeleteFileW(FilePath);
3020 WriteFile(the_file,buffer,sz,&write,NULL);
3021 } while (sz == 1024);
3025 CloseHandle(the_file);
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;
3057 return ERROR_INVALID_HANDLE;
3059 /* write out icon files */
3061 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3062 if (rc == ERROR_SUCCESS)
3064 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3065 msiobj_release(&view->hdr);
3068 /* ok there is a lot more done here but i need to figure out what */
3070 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3071 if (rc != ERROR_SUCCESS)
3074 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3075 if (rc != ERROR_SUCCESS)
3079 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3080 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3083 langid = msi_get_property_int( package, szProductLanguage, 0 );
3084 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3086 buffer = msi_dup_property( package, szARPProductIcon );
3089 LPWSTR path = build_icon_path(package,buffer);
3090 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3095 buffer = msi_dup_property( package, szProductVersion );
3098 DWORD verdword = build_version_dword(buffer);
3099 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3103 FIXME("Need to write more keys to the user registry\n");
3105 hDb= alloc_msihandle( &package->db->hdr );
3106 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3107 MsiCloseHandle(hDb);
3108 if (rc == ERROR_SUCCESS)
3110 WCHAR guidbuffer[0x200];
3112 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3114 if (rc == ERROR_SUCCESS)
3116 WCHAR squashed[GUID_SIZE];
3117 /* for now we only care about the first guid */
3118 LPWSTR ptr = strchrW(guidbuffer,';');
3120 squash_guid(guidbuffer,squashed);
3121 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3125 ERR("Unable to query Revision_Number... \n");
3128 MsiCloseHandle(hSumInfo);
3132 ERR("Unable to open Summary Information\n");
3144 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3146 MSIPACKAGE *package = (MSIPACKAGE*)param;
3147 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3148 LPWSTR deformated_section, deformated_key, deformated_value;
3149 LPWSTR folder, fullname = NULL;
3153 static const WCHAR szWindowsFolder[] =
3154 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3156 component = MSI_RecordGetString(row, 8);
3157 comp = get_loaded_component(package,component);
3159 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3161 TRACE("Skipping ini file due to disabled component %s\n",
3162 debugstr_w(component));
3164 comp->Action = comp->Installed;
3166 return ERROR_SUCCESS;
3169 comp->Action = INSTALLSTATE_LOCAL;
3171 identifier = MSI_RecordGetString(row,1);
3172 filename = MSI_RecordGetString(row,2);
3173 dirproperty = MSI_RecordGetString(row,3);
3174 section = MSI_RecordGetString(row,4);
3175 key = MSI_RecordGetString(row,5);
3176 value = MSI_RecordGetString(row,6);
3177 action = MSI_RecordGetInteger(row,7);
3179 deformat_string(package,section,&deformated_section);
3180 deformat_string(package,key,&deformated_key);
3181 deformat_string(package,value,&deformated_value);
3185 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3187 folder = msi_dup_property( package, dirproperty );
3190 folder = msi_dup_property( package, szWindowsFolder );
3194 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3198 fullname = build_directory_name(2, folder, filename);
3202 TRACE("Adding value %s to section %s in %s\n",
3203 debugstr_w(deformated_key), debugstr_w(deformated_section),
3204 debugstr_w(fullname));
3205 WritePrivateProfileStringW(deformated_section, deformated_key,
3206 deformated_value, fullname);
3208 else if (action == 1)
3211 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3212 returned, 10, fullname);
3213 if (returned[0] == 0)
3215 TRACE("Adding value %s to section %s in %s\n",
3216 debugstr_w(deformated_key), debugstr_w(deformated_section),
3217 debugstr_w(fullname));
3219 WritePrivateProfileStringW(deformated_section, deformated_key,
3220 deformated_value, fullname);
3223 else if (action == 3)
3224 FIXME("Append to existing section not yet implemented\n");
3226 uirow = MSI_CreateRecord(4);
3227 MSI_RecordSetStringW(uirow,1,identifier);
3228 MSI_RecordSetStringW(uirow,2,deformated_section);
3229 MSI_RecordSetStringW(uirow,3,deformated_key);
3230 MSI_RecordSetStringW(uirow,4,deformated_value);
3231 ui_actiondata(package,szWriteIniValues,uirow);
3232 msiobj_release( &uirow->hdr );
3236 msi_free(deformated_key);
3237 msi_free(deformated_value);
3238 msi_free(deformated_section);
3239 return ERROR_SUCCESS;
3242 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3246 static const WCHAR ExecSeqQuery[] =
3247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3248 '`','I','n','i','F','i','l','e','`',0};
3250 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3251 if (rc != ERROR_SUCCESS)
3253 TRACE("no IniFile table\n");
3254 return ERROR_SUCCESS;
3257 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3258 msiobj_release(&view->hdr);
3262 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3264 MSIPACKAGE *package = (MSIPACKAGE*)param;
3269 static const WCHAR ExeStr[] =
3270 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3271 static const WCHAR close[] = {'\"',0};
3273 PROCESS_INFORMATION info;
3276 memset(&si,0,sizeof(STARTUPINFOW));
3278 filename = MSI_RecordGetString(row,1);
3279 file = get_loaded_file( package, filename );
3283 ERR("Unable to find file id %s\n",debugstr_w(filename));
3284 return ERROR_SUCCESS;
3287 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3289 FullName = msi_alloc(len*sizeof(WCHAR));
3290 strcpyW(FullName,ExeStr);
3291 strcatW( FullName, file->TargetPath );
3292 strcatW(FullName,close);
3294 TRACE("Registering %s\n",debugstr_w(FullName));
3295 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3299 msi_dialog_check_messages(info.hProcess);
3302 return ERROR_SUCCESS;
3305 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3309 static const WCHAR ExecSeqQuery[] =
3310 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3311 '`','S','e','l','f','R','e','g','`',0};
3313 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3314 if (rc != ERROR_SUCCESS)
3316 TRACE("no SelfReg table\n");
3317 return ERROR_SUCCESS;
3320 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3321 msiobj_release(&view->hdr);
3323 return ERROR_SUCCESS;
3326 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3328 MSIFEATURE *feature;
3334 return ERROR_INVALID_HANDLE;
3336 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3337 if (rc != ERROR_SUCCESS)
3340 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3341 if (rc != ERROR_SUCCESS)
3344 /* here the guids are base 85 encoded */
3345 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3351 BOOL absent = FALSE;
3353 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3354 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3355 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3359 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3363 if (feature->Feature_Parent)
3364 size += strlenW( feature->Feature_Parent )+2;
3366 data = msi_alloc(size * sizeof(WCHAR));
3369 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3371 MSICOMPONENT* component = cl->component;
3374 memset(buf,0,sizeof(buf));
3375 if (component->ComponentId)
3377 TRACE("From %s\n",debugstr_w(component->ComponentId));
3378 CLSIDFromString(component->ComponentId, &clsid);
3379 encode_base85_guid(&clsid,buf);
3380 TRACE("to %s\n",debugstr_w(buf));
3384 if (feature->Feature_Parent)
3386 static const WCHAR sep[] = {'\2',0};
3388 strcatW(data,feature->Feature_Parent);
3391 msi_reg_set_val_str( hkey, feature->Feature, data );
3395 if (feature->Feature_Parent)
3396 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3399 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3400 (LPBYTE)feature->Feature_Parent,size);
3404 size += 2*sizeof(WCHAR);
3405 data = msi_alloc(size);
3408 if (feature->Feature_Parent)
3409 strcpyW( &data[1], feature->Feature_Parent );
3410 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3422 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3424 static const WCHAR installerPathFmt[] = {
3425 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3426 static const WCHAR fmt[] = {
3428 'I','n','s','t','a','l','l','e','r','\\',
3429 '%','x','.','m','s','i',0};
3430 static const WCHAR szOriginalDatabase[] =
3431 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3432 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3437 /* copy the package locally */
3438 num = GetTickCount() & 0xffff;
3442 GetWindowsDirectoryW( windir, MAX_PATH );
3443 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3446 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3447 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3448 if (handle != INVALID_HANDLE_VALUE)
3450 CloseHandle(handle);
3453 if (GetLastError() != ERROR_FILE_EXISTS &&
3454 GetLastError() != ERROR_SHARING_VIOLATION)
3456 if (!(++num & 0xffff)) num = 1;
3457 sprintfW(packagefile,fmt,num);
3458 } while (num != start);
3460 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3461 create_full_pathW(path);
3463 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3465 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3466 r = CopyFileW( msiFilePath, packagefile, FALSE);
3467 msi_free( msiFilePath );
3471 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3472 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3473 return ERROR_FUNCTION_FAILED;
3476 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3477 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3478 return ERROR_SUCCESS;
3481 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3483 LPWSTR prop, val, key;
3484 static const LPCSTR propval[] = {
3485 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3486 "ARPCONTACT", "Contact",
3487 "ARPCOMMENTS", "Comments",
3488 "ProductName", "DisplayName",
3489 "ProductVersion", "DisplayVersion",
3490 "ARPHELPLINK", "HelpLink",
3491 "ARPHELPTELEPHONE", "HelpTelephone",
3492 "ARPINSTALLLOCATION", "InstallLocation",
3493 "SourceDir", "InstallSource",
3494 "Manufacturer", "Publisher",
3495 "ARPREADME", "Readme",
3497 "ARPURLINFOABOUT", "URLInfoAbout",
3498 "ARPURLUPDATEINFO", "URLUpdateInfo",
3501 const LPCSTR *p = propval;
3505 prop = strdupAtoW( *p++ );
3506 key = strdupAtoW( *p++ );
3507 val = msi_dup_property( package, prop );
3508 msi_reg_set_val_str( hkey, key, val );
3513 return ERROR_SUCCESS;
3516 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3519 LPWSTR buffer = NULL;
3522 static const WCHAR szWindowsInstaller[] =
3523 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3524 static const WCHAR szUpgradeCode[] =
3525 {'U','p','g','r','a','d','e','C','o','d','e',0};
3526 static const WCHAR modpath_fmt[] =
3527 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3528 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3529 static const WCHAR szModifyPath[] =
3530 {'M','o','d','i','f','y','P','a','t','h',0};
3531 static const WCHAR szUninstallString[] =
3532 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3533 static const WCHAR szEstimatedSize[] =
3534 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3535 static const WCHAR szProductLanguage[] =
3536 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3537 static const WCHAR szProductVersion[] =
3538 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3541 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3542 LPWSTR upgrade_code;
3546 return ERROR_INVALID_HANDLE;
3548 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3549 if (rc != ERROR_SUCCESS)
3552 /* dump all the info i can grab */
3553 FIXME("Flesh out more information \n");
3555 msi_write_uninstall_property_vals( package, hkey );
3557 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3559 msi_make_package_local( package, hkey );
3561 /* do ModifyPath and UninstallString */
3562 size = deformat_string(package,modpath_fmt,&buffer);
3563 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3564 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3567 FIXME("Write real Estimated Size when we have it\n");
3568 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3570 GetLocalTime(&systime);
3571 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3572 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3574 langid = msi_get_property_int( package, szProductLanguage, 0 );
3575 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3577 buffer = msi_dup_property( package, szProductVersion );
3580 DWORD verdword = build_version_dword(buffer);
3582 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3583 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3584 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3588 /* Handle Upgrade Codes */
3589 upgrade_code = msi_dup_property( package, szUpgradeCode );
3594 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3595 squash_guid(package->ProductCode,squashed);
3596 msi_reg_set_val_str( hkey2, squashed, NULL );
3598 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3599 squash_guid(package->ProductCode,squashed);
3600 msi_reg_set_val_str( hkey2, squashed, NULL );
3603 msi_free(upgrade_code);
3608 return ERROR_SUCCESS;
3611 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3616 return ERROR_INVALID_HANDLE;
3618 rc = execute_script(package,INSTALL_SCRIPT);
3623 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3628 return ERROR_INVALID_HANDLE;
3630 /* turn off scheduleing */
3631 package->script->CurrentlyScripting= FALSE;
3633 /* first do the same as an InstallExecute */
3634 rc = ACTION_InstallExecute(package);
3635 if (rc != ERROR_SUCCESS)
3638 /* then handle Commit Actions */
3639 rc = execute_script(package,COMMIT_SCRIPT);
3644 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3646 static const WCHAR RunOnce[] = {
3647 'S','o','f','t','w','a','r','e','\\',
3648 'M','i','c','r','o','s','o','f','t','\\',
3649 'W','i','n','d','o','w','s','\\',
3650 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3651 'R','u','n','O','n','c','e',0};
3652 static const WCHAR InstallRunOnce[] = {
3653 'S','o','f','t','w','a','r','e','\\',
3654 'M','i','c','r','o','s','o','f','t','\\',
3655 'W','i','n','d','o','w','s','\\',
3656 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3657 'I','n','s','t','a','l','l','e','r','\\',
3658 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3660 static const WCHAR msiexec_fmt[] = {
3662 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3663 '\"','%','s','\"',0};
3664 static const WCHAR install_fmt[] = {
3665 '/','I',' ','\"','%','s','\"',' ',
3666 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3667 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3668 WCHAR buffer[256], sysdir[MAX_PATH];
3670 WCHAR squished_pc[100];
3673 return ERROR_INVALID_HANDLE;
3675 squash_guid(package->ProductCode,squished_pc);
3677 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3678 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3679 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3682 msi_reg_set_val_str( hkey, squished_pc, buffer );
3685 TRACE("Reboot command %s\n",debugstr_w(buffer));
3687 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3688 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3690 msi_reg_set_val_str( hkey, squished_pc, buffer );
3693 return ERROR_INSTALL_SUSPEND;
3696 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3701 * we are currently doing what should be done here in the top level Install
3702 * however for Adminastrative and uninstalls this step will be needed
3704 if (!package->PackagePath)
3705 return ERROR_SUCCESS;
3707 attrib = GetFileAttributesW(package->PackagePath);
3708 if (attrib == INVALID_FILE_ATTRIBUTES)
3714 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3715 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3716 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3717 if (rc == ERROR_MORE_DATA)
3719 prompt = msi_alloc(size * sizeof(WCHAR));
3720 MsiSourceListGetInfoW(package->ProductCode, NULL,
3721 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3722 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3725 prompt = strdupW(package->PackagePath);
3727 msg = generate_error_string(package,1302,1,prompt);
3728 while(attrib == INVALID_FILE_ATTRIBUTES)
3730 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3733 rc = ERROR_INSTALL_USEREXIT;
3736 attrib = GetFileAttributesW(package->PackagePath);
3742 return ERROR_SUCCESS;
3747 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3754 static const WCHAR szPropKeys[][80] =
3756 {'P','r','o','d','u','c','t','I','D',0},
3757 {'U','S','E','R','N','A','M','E',0},
3758 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3762 static const WCHAR szRegKeys[][80] =
3764 {'P','r','o','d','u','c','t','I','D',0},
3765 {'R','e','g','O','w','n','e','r',0},
3766 {'R','e','g','C','o','m','p','a','n','y',0},
3771 return ERROR_INVALID_HANDLE;
3773 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3775 return ERROR_SUCCESS;
3777 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3778 if (rc != ERROR_SUCCESS)
3781 for( i = 0; szPropKeys[i][0]; i++ )
3783 buffer = msi_dup_property( package, szPropKeys[i] );
3784 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3789 msi_free(productid);
3792 return ERROR_SUCCESS;
3796 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3800 package->script->InWhatSequence |= SEQUENCE_EXEC;
3801 rc = ACTION_ProcessExecSequence(package,FALSE);
3807 * Code based off of code located here
3808 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3810 * Using string index 4 (full font name) instead of 1 (family name)
3812 static LPWSTR load_ttfname_from(LPCWSTR filename)
3818 typedef struct _tagTT_OFFSET_TABLE{
3819 USHORT uMajorVersion;
3820 USHORT uMinorVersion;
3821 USHORT uNumOfTables;
3822 USHORT uSearchRange;
3823 USHORT uEntrySelector;
3827 typedef struct _tagTT_TABLE_DIRECTORY{
3828 char szTag[4]; /* table name */
3829 ULONG uCheckSum; /* Check sum */
3830 ULONG uOffset; /* Offset from beginning of file */
3831 ULONG uLength; /* length of the table in bytes */
3832 }TT_TABLE_DIRECTORY;
3834 typedef struct _tagTT_NAME_TABLE_HEADER{
3835 USHORT uFSelector; /* format selector. Always 0 */
3836 USHORT uNRCount; /* Name Records count */
3837 USHORT uStorageOffset; /* Offset for strings storage,
3838 * from start of the table */
3839 }TT_NAME_TABLE_HEADER;
3841 typedef struct _tagTT_NAME_RECORD{
3846 USHORT uStringLength;
3847 USHORT uStringOffset; /* from start of storage area */
3850 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3851 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3853 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3854 FILE_ATTRIBUTE_NORMAL, 0 );
3855 if (handle != INVALID_HANDLE_VALUE)
3857 TT_TABLE_DIRECTORY tblDir;
3858 BOOL bFound = FALSE;
3859 TT_OFFSET_TABLE ttOffsetTable;
3862 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3863 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3864 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3865 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3867 if (ttOffsetTable.uMajorVersion != 1 ||
3868 ttOffsetTable.uMinorVersion != 0)
3871 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3873 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3874 if (strncmp(tblDir.szTag,"name",4)==0)
3877 tblDir.uLength = SWAPLONG(tblDir.uLength);
3878 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3885 TT_NAME_TABLE_HEADER ttNTHeader;
3886 TT_NAME_RECORD ttRecord;
3888 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3889 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3892 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3893 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3895 for(i=0; i<ttNTHeader.uNRCount; i++)
3897 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3898 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3899 /* 4 is the Full Font Name */
3900 if(ttRecord.uNameID == 4)
3904 static LPCSTR tt = " (TrueType)";
3906 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3907 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3908 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3909 SetFilePointer(handle, tblDir.uOffset +
3910 ttRecord.uStringOffset +
3911 ttNTHeader.uStorageOffset,
3913 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3914 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3915 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3916 if (strlen(buf) > 0)
3919 ret = strdupAtoW(buf);
3925 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3929 CloseHandle(handle);
3932 ERR("Unable to open font file %s\n", debugstr_w(filename));
3934 TRACE("Returning fontname %s\n",debugstr_w(ret));
3938 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3940 MSIPACKAGE *package = (MSIPACKAGE*)param;
3944 static const WCHAR regfont1[] =
3945 {'S','o','f','t','w','a','r','e','\\',
3946 'M','i','c','r','o','s','o','f','t','\\',
3947 'W','i','n','d','o','w','s',' ','N','T','\\',
3948 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3949 'F','o','n','t','s',0};
3950 static const WCHAR regfont2[] =
3951 {'S','o','f','t','w','a','r','e','\\',
3952 'M','i','c','r','o','s','o','f','t','\\',
3953 'W','i','n','d','o','w','s','\\',
3954 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3955 'F','o','n','t','s',0};
3959 filename = MSI_RecordGetString( row, 1 );
3960 file = get_loaded_file( package, filename );
3963 ERR("Unable to load file\n");
3964 return ERROR_SUCCESS;
3967 /* check to make sure that component is installed */
3968 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3970 TRACE("Skipping: Component not scheduled for install\n");
3971 return ERROR_SUCCESS;
3974 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3975 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3977 if (MSI_RecordIsNull(row,2))
3978 name = load_ttfname_from( file->TargetPath );
3980 name = msi_dup_record_field(row,2);
3984 msi_reg_set_val_str( hkey1, name, file->FileName );
3985 msi_reg_set_val_str( hkey2, name, file->FileName );
3991 return ERROR_SUCCESS;
3994 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
3998 static const WCHAR ExecSeqQuery[] =
3999 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4000 '`','F','o','n','t','`',0};
4002 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4003 if (rc != ERROR_SUCCESS)
4005 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4006 return ERROR_SUCCESS;
4009 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4010 msiobj_release(&view->hdr);
4012 return ERROR_SUCCESS;
4015 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4017 MSIPACKAGE *package = (MSIPACKAGE*)param;
4018 LPCWSTR compgroupid=NULL;
4019 LPCWSTR feature=NULL;
4020 LPCWSTR text = NULL;
4021 LPCWSTR qualifier = NULL;
4022 LPCWSTR component = NULL;
4023 LPWSTR advertise = NULL;
4024 LPWSTR output = NULL;
4026 UINT rc = ERROR_SUCCESS;
4030 component = MSI_RecordGetString(rec,3);
4031 comp = get_loaded_component(package,component);
4033 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4034 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4035 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4037 TRACE("Skipping: Component %s not scheduled for install\n",
4038 debugstr_w(component));
4040 return ERROR_SUCCESS;
4043 compgroupid = MSI_RecordGetString(rec,1);
4045 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4046 if (rc != ERROR_SUCCESS)
4049 text = MSI_RecordGetString(rec,4);
4050 qualifier = MSI_RecordGetString(rec,2);
4051 feature = MSI_RecordGetString(rec,5);
4053 advertise = create_component_advertise_string(package, comp, feature);
4055 sz = strlenW(advertise);
4058 sz += lstrlenW(text);
4061 sz *= sizeof(WCHAR);
4063 output = msi_alloc(sz);
4064 memset(output,0,sz);
4065 strcpyW(output,advertise);
4066 msi_free(advertise);
4069 strcatW(output,text);
4071 msi_reg_set_val_multi_str( hkey, qualifier, output );
4081 * At present I am ignorning the advertised components part of this and only
4082 * focusing on the qualified component sets
4084 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4088 static const WCHAR ExecSeqQuery[] =
4089 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4090 '`','P','u','b','l','i','s','h',
4091 'C','o','m','p','o','n','e','n','t','`',0};
4093 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4094 if (rc != ERROR_SUCCESS)
4095 return ERROR_SUCCESS;
4097 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4098 msiobj_release(&view->hdr);
4103 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4104 LPCSTR action, LPCWSTR table )
4106 static const WCHAR query[] = {
4107 'S','E','L','E','C','T',' ','*',' ',
4108 'F','R','O','M',' ','`','%','s','`',0 };
4109 MSIQUERY *view = NULL;
4113 r = MSI_OpenQuery( package->db, &view, query, table );
4114 if (r == ERROR_SUCCESS)
4116 r = MSI_IterateRecords(view, &count, NULL, package);
4117 msiobj_release(&view->hdr);
4121 FIXME("%s -> %lu ignored %s table values\n",
4122 action, count, debugstr_w(table));
4124 return ERROR_SUCCESS;
4127 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4129 TRACE("%p\n", package);
4130 return ERROR_SUCCESS;
4133 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4135 static const WCHAR table[] =
4136 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4137 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4140 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4142 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4143 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4146 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4148 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4149 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4152 static UINT ACTION_BindImage( MSIPACKAGE *package )
4154 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4155 return msi_unimplemented_action_stub( package, "BindImage", table );
4158 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4160 static const WCHAR table[] = {
4161 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4162 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4165 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4167 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4168 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4171 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4173 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4174 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4177 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4179 static const WCHAR table[] = {
4180 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4181 return msi_unimplemented_action_stub( package, "InstallServices", table );
4184 static UINT ACTION_StartServices( MSIPACKAGE *package )
4186 static const WCHAR table[] = {
4187 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4188 return msi_unimplemented_action_stub( package, "StartServices", table );
4191 static UINT ACTION_StopServices( MSIPACKAGE *package )
4193 static const WCHAR table[] = {
4194 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4195 return msi_unimplemented_action_stub( package, "StopServices", table );
4198 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4200 static const WCHAR table[] = {
4201 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4202 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4205 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4207 static const WCHAR table[] = {
4208 'E','n','v','i','r','o','n','m','e','n','t',0 };
4209 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4212 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4214 static const WCHAR table[] = {
4215 'E','n','v','i','r','o','n','m','e','n','t',0 };
4216 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4219 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4221 static const WCHAR table[] = {
4222 'M','s','i','A','s','s','e','m','b','l','y',0 };
4223 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4226 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4228 static const WCHAR table[] = {
4229 'M','s','i','A','s','s','e','m','b','l','y',0 };
4230 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4233 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4235 static const WCHAR table[] = { 'F','o','n','t',0 };
4236 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4239 static struct _actions StandardActions[] = {
4240 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4241 { szAppSearch, ACTION_AppSearch },
4242 { szBindImage, ACTION_BindImage },
4243 { szCCPSearch, NULL},
4244 { szCostFinalize, ACTION_CostFinalize },
4245 { szCostInitialize, ACTION_CostInitialize },
4246 { szCreateFolders, ACTION_CreateFolders },
4247 { szCreateShortcuts, ACTION_CreateShortcuts },
4248 { szDeleteServices, ACTION_DeleteServices },
4249 { szDisableRollback, NULL},
4250 { szDuplicateFiles, ACTION_DuplicateFiles },
4251 { szExecuteAction, ACTION_ExecuteAction },
4252 { szFileCost, ACTION_FileCost },
4253 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4254 { szForceReboot, ACTION_ForceReboot },
4255 { szInstallAdminPackage, NULL},
4256 { szInstallExecute, ACTION_InstallExecute },
4257 { szInstallExecuteAgain, ACTION_InstallExecute },
4258 { szInstallFiles, ACTION_InstallFiles},
4259 { szInstallFinalize, ACTION_InstallFinalize },
4260 { szInstallInitialize, ACTION_InstallInitialize },
4261 { szInstallSFPCatalogFile, NULL},
4262 { szInstallValidate, ACTION_InstallValidate },
4263 { szIsolateComponents, ACTION_IsolateComponents },
4264 { szLaunchConditions, ACTION_LaunchConditions },
4265 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4266 { szMoveFiles, ACTION_MoveFiles },
4267 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4268 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4269 { szInstallODBC, NULL},
4270 { szInstallServices, ACTION_InstallServices },
4271 { szPatchFiles, ACTION_PatchFiles },
4272 { szProcessComponents, ACTION_ProcessComponents },
4273 { szPublishComponents, ACTION_PublishComponents },
4274 { szPublishFeatures, ACTION_PublishFeatures },
4275 { szPublishProduct, ACTION_PublishProduct },
4276 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4277 { szRegisterComPlus, NULL},
4278 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4279 { szRegisterFonts, ACTION_RegisterFonts },
4280 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4281 { szRegisterProduct, ACTION_RegisterProduct },
4282 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4283 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4284 { szRegisterUser, ACTION_RegisterUser},
4285 { szRemoveDuplicateFiles, NULL},
4286 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4287 { szRemoveExistingProducts, NULL},
4288 { szRemoveFiles, ACTION_RemoveFiles},
4289 { szRemoveFolders, NULL},
4290 { szRemoveIniValues, ACTION_RemoveIniValues },
4291 { szRemoveODBC, NULL},
4292 { szRemoveRegistryValues, NULL},
4293 { szRemoveShortcuts, NULL},
4294 { szResolveSource, ACTION_ResolveSource},
4295 { szRMCCPSearch, NULL},
4296 { szScheduleReboot, NULL},
4297 { szSelfRegModules, ACTION_SelfRegModules },
4298 { szSelfUnregModules, ACTION_SelfUnregModules },
4299 { szSetODBCFolders, NULL},
4300 { szStartServices, ACTION_StartServices },
4301 { szStopServices, ACTION_StopServices },
4302 { szUnpublishComponents, NULL},
4303 { szUnpublishFeatures, NULL},
4304 { szUnregisterClassInfo, NULL},
4305 { szUnregisterComPlus, NULL},
4306 { szUnregisterExtensionInfo, NULL},
4307 { szUnregisterFonts, ACTION_UnregisterFonts },
4308 { szUnregisterMIMEInfo, NULL},
4309 { szUnregisterProgIdInfo, NULL},
4310 { szUnregisterTypeLibraries, NULL},
4311 { szValidateProductID, NULL},
4312 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4313 { szWriteIniValues, ACTION_WriteIniValues },
4314 { szWriteRegistryValues, ACTION_WriteRegistryValues},