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 )
899 ERR("package was null!\n");
903 if (!run && !package->script->CurrentlyScripting)
908 if (strcmpW(action,szInstallFinalize) == 0 ||
909 strcmpW(action,szInstallExecute) == 0 ||
910 strcmpW(action,szInstallExecuteAgain) == 0)
915 while (StandardActions[i].action != NULL)
917 if (strcmpW(StandardActions[i].action, action)==0)
921 ui_actioninfo(package, action, TRUE, 0);
922 *rc = schedule_action(package,INSTALL_SCRIPT,action);
923 ui_actioninfo(package, action, FALSE, *rc);
927 ui_actionstart(package, action);
928 if (StandardActions[i].handler)
930 *rc = StandardActions[i].handler(package);
934 FIXME("unhandled standard action %s\n",debugstr_w(action));
946 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
947 UINT* rc, BOOL force )
952 arc = ACTION_CustomAction(package,action, force);
954 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
963 * A lot of actions are really important even if they don't do anything
964 * explicit... Lots of properties are set at the beginning of the installation
965 * CostFinalize does a bunch of work to translate the directories and such
967 * But until I get write access to the database that is hard, so I am going to
968 * hack it to see if I can get something to run.
970 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
972 UINT rc = ERROR_SUCCESS;
975 TRACE("Performing action (%s)\n",debugstr_w(action));
977 handled = ACTION_HandleStandardAction(package, action, &rc, force);
980 handled = ACTION_HandleCustomAction(package, action, &rc, force);
984 FIXME("unhandled msi action %s\n",debugstr_w(action));
985 rc = ERROR_FUNCTION_NOT_CALLED;
991 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
993 UINT rc = ERROR_SUCCESS;
994 BOOL handled = FALSE;
996 TRACE("Performing action (%s)\n",debugstr_w(action));
998 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1001 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1003 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1008 FIXME("unhandled msi action %s\n",debugstr_w(action));
1009 rc = ERROR_FUNCTION_NOT_CALLED;
1017 * Actual Action Handlers
1020 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1022 MSIPACKAGE *package = (MSIPACKAGE*)param;
1028 dir = MSI_RecordGetString(row,1);
1031 ERR("Unable to get folder id\n");
1032 return ERROR_SUCCESS;
1035 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1038 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1039 return ERROR_SUCCESS;
1042 TRACE("Folder is %s\n",debugstr_w(full_path));
1045 uirow = MSI_CreateRecord(1);
1046 MSI_RecordSetStringW(uirow,1,full_path);
1047 ui_actiondata(package,szCreateFolders,uirow);
1048 msiobj_release( &uirow->hdr );
1050 if (folder->State == 0)
1051 create_full_pathW(full_path);
1055 msi_free(full_path);
1056 return ERROR_SUCCESS;
1059 /* FIXME: probably should merge this with the above function */
1060 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1062 UINT rc = ERROR_SUCCESS;
1064 LPWSTR install_path;
1066 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1068 return ERROR_FUNCTION_FAILED;
1070 /* create the path */
1071 if (folder->State == 0)
1073 create_full_pathW(install_path);
1076 msi_free(install_path);
1081 UINT msi_create_component_directories( MSIPACKAGE *package )
1085 /* create all the folders required by the components are going to install */
1086 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1088 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1090 msi_create_directory( package, comp->Directory );
1093 return ERROR_SUCCESS;
1097 * Also we cannot enable/disable components either, so for now I am just going
1098 * to do all the directories for all the components.
1100 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1102 static const WCHAR ExecSeqQuery[] =
1103 {'S','E','L','E','C','T',' ',
1104 '`','D','i','r','e','c','t','o','r','y','_','`',
1105 ' ','F','R','O','M',' ',
1106 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1110 /* create all the empty folders specified in the CreateFolder table */
1111 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1112 if (rc != ERROR_SUCCESS)
1113 return ERROR_SUCCESS;
1115 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1116 msiobj_release(&view->hdr);
1118 msi_create_component_directories( package );
1123 static MSICOMPONENT* load_component( MSIRECORD * row )
1127 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1131 /* fill in the data */
1132 comp->Component = msi_dup_record_field( row, 1 );
1134 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1136 comp->ComponentId = msi_dup_record_field( row, 2 );
1137 comp->Directory = msi_dup_record_field( row, 3 );
1138 comp->Attributes = MSI_RecordGetInteger(row,4);
1139 comp->Condition = msi_dup_record_field( row, 5 );
1140 comp->KeyPath = msi_dup_record_field( row, 6 );
1142 comp->Installed = INSTALLSTATE_ABSENT;
1143 comp->Action = INSTALLSTATE_UNKNOWN;
1144 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1146 comp->Enabled = TRUE;
1152 MSIPACKAGE *package;
1153 MSIFEATURE *feature;
1156 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1160 cl = msi_alloc( sizeof (*cl) );
1162 return ERROR_NOT_ENOUGH_MEMORY;
1163 cl->component = comp;
1164 list_add_tail( &feature->Components, &cl->entry );
1166 return ERROR_SUCCESS;
1169 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1171 _ilfs* ilfs= (_ilfs*)param;
1172 MSIPACKAGE *package = ilfs->package;
1173 MSIFEATURE *feature = ilfs->feature;
1176 comp = load_component( row );
1178 return ERROR_FUNCTION_FAILED;
1180 list_add_tail( &package->components, &comp->entry );
1181 add_feature_component( feature, comp );
1183 TRACE("Loaded new component %p\n", comp);
1185 return ERROR_SUCCESS;
1188 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1190 _ilfs* ilfs= (_ilfs*)param;
1195 static const WCHAR Query[] =
1196 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1197 '`','C','o','m','p','o','n','e','n','t','`',' ',
1198 'W','H','E','R','E',' ',
1199 '`','C','o','m','p','o','n','e','n','t','`',' ',
1200 '=','\'','%','s','\'',0};
1202 component = MSI_RecordGetString(row,1);
1204 /* check to see if the component is already loaded */
1205 comp = get_loaded_component( ilfs->package, component );
1208 TRACE("Component %s already loaded\n", debugstr_w(component) );
1209 add_feature_component( ilfs->feature, comp );
1210 return ERROR_SUCCESS;
1213 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1214 if (rc != ERROR_SUCCESS)
1215 return ERROR_SUCCESS;
1217 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1218 msiobj_release( &view->hdr );
1220 return ERROR_SUCCESS;
1223 static UINT load_feature(MSIRECORD * row, LPVOID param)
1225 MSIPACKAGE* package = (MSIPACKAGE*)param;
1226 MSIFEATURE* feature;
1227 static const WCHAR Query1[] =
1228 {'S','E','L','E','C','T',' ',
1229 '`','C','o','m','p','o','n','e','n','t','_','`',
1230 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1231 'C','o','m','p','o','n','e','n','t','s','`',' ',
1232 'W','H','E','R','E',' ',
1233 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1238 /* fill in the data */
1240 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1242 return ERROR_NOT_ENOUGH_MEMORY;
1244 list_init( &feature->Components );
1246 feature->Feature = msi_dup_record_field( row, 1 );
1248 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1250 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1251 feature->Title = msi_dup_record_field( row, 3 );
1252 feature->Description = msi_dup_record_field( row, 4 );
1254 if (!MSI_RecordIsNull(row,5))
1255 feature->Display = MSI_RecordGetInteger(row,5);
1257 feature->Level= MSI_RecordGetInteger(row,6);
1258 feature->Directory = msi_dup_record_field( row, 7 );
1259 feature->Attributes = MSI_RecordGetInteger(row,8);
1261 feature->Installed = INSTALLSTATE_ABSENT;
1262 feature->Action = INSTALLSTATE_UNKNOWN;
1263 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1265 list_add_tail( &package->features, &feature->entry );
1267 /* load feature components */
1269 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1270 if (rc != ERROR_SUCCESS)
1271 return ERROR_SUCCESS;
1273 ilfs.package = package;
1274 ilfs.feature = feature;
1276 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1277 msiobj_release(&view->hdr);
1279 return ERROR_SUCCESS;
1282 static UINT load_file(MSIRECORD *row, LPVOID param)
1284 MSIPACKAGE* package = (MSIPACKAGE*)param;
1288 /* fill in the data */
1290 file = msi_alloc_zero( sizeof (MSIFILE) );
1292 return ERROR_NOT_ENOUGH_MEMORY;
1294 file->File = msi_dup_record_field( row, 1 );
1296 component = MSI_RecordGetString( row, 2 );
1297 file->Component = get_loaded_component( package, component );
1299 if (!file->Component)
1300 ERR("Unfound Component %s\n",debugstr_w(component));
1302 file->FileName = msi_dup_record_field( row, 3 );
1303 reduce_to_longfilename( file->FileName );
1305 file->ShortName = msi_dup_record_field( row, 3 );
1306 reduce_to_shortfilename( file->ShortName );
1308 file->FileSize = MSI_RecordGetInteger( row, 4 );
1309 file->Version = msi_dup_record_field( row, 5 );
1310 file->Language = msi_dup_record_field( row, 6 );
1311 file->Attributes = MSI_RecordGetInteger( row, 7 );
1312 file->Sequence = MSI_RecordGetInteger( row, 8 );
1314 file->state = msifs_invalid;
1316 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1318 list_add_tail( &package->files, &file->entry );
1320 return ERROR_SUCCESS;
1323 static UINT load_all_files(MSIPACKAGE *package)
1327 static const WCHAR Query[] =
1328 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1330 '`','S','e','q','u','e','n','c','e','`', 0};
1333 return ERROR_INVALID_HANDLE;
1335 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1336 if (rc != ERROR_SUCCESS)
1337 return ERROR_SUCCESS;
1339 rc = MSI_IterateRecords(view, NULL, load_file, package);
1340 msiobj_release(&view->hdr);
1342 return ERROR_SUCCESS;
1347 * I am not doing any of the costing functionality yet.
1348 * Mostly looking at doing the Component and Feature loading
1350 * The native MSI does A LOT of modification to tables here. Mostly adding
1351 * a lot of temporary columns to the Feature and Component tables.
1353 * note: Native msi also tracks the short filename. But I am only going to
1354 * track the long ones. Also looking at this directory table
1355 * it appears that the directory table does not get the parents
1356 * resolved base on property only based on their entries in the
1359 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1363 static const WCHAR Query_all[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','e','a','t','u','r','e','`',0};
1366 static const WCHAR szCosting[] =
1367 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1368 static const WCHAR szZero[] = { '0', 0 };
1370 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1371 return ERROR_SUCCESS;
1373 MSI_SetPropertyW(package, szCosting, szZero);
1374 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1376 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1377 if (rc != ERROR_SUCCESS)
1380 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1381 msiobj_release(&view->hdr);
1383 load_all_files(package);
1385 return ERROR_SUCCESS;
1388 static UINT execute_script(MSIPACKAGE *package, UINT script )
1391 UINT rc = ERROR_SUCCESS;
1393 TRACE("Executing Script %i\n",script);
1395 for (i = 0; i < package->script->ActionCount[script]; i++)
1398 action = package->script->Actions[script][i];
1399 ui_actionstart(package, action);
1400 TRACE("Executing Action (%s)\n",debugstr_w(action));
1401 rc = ACTION_PerformAction(package, action, TRUE);
1402 msi_free(package->script->Actions[script][i]);
1403 if (rc != ERROR_SUCCESS)
1406 msi_free(package->script->Actions[script]);
1408 package->script->ActionCount[script] = 0;
1409 package->script->Actions[script] = NULL;
1413 static UINT ACTION_FileCost(MSIPACKAGE *package)
1415 return ERROR_SUCCESS;
1419 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1421 static const WCHAR Query[] =
1422 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1423 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1424 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1425 ' ','=',' ','\'','%','s','\'',
1427 LPWSTR ptargetdir, targetdir, srcdir;
1429 LPWSTR shortname = NULL;
1430 MSIRECORD * row = 0;
1433 TRACE("Looking for dir %s\n",debugstr_w(dir));
1435 folder = get_loaded_folder( package, dir );
1439 TRACE("Working to load %s\n",debugstr_w(dir));
1441 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1445 folder->Directory = strdupW(dir);
1447 row = MSI_QueryGetRecord(package->db, Query, dir);
1451 ptargetdir = targetdir = msi_dup_record_field(row,3);
1453 /* split src and target dir */
1454 if (strchrW(targetdir,':'))
1456 srcdir=strchrW(targetdir,':');
1463 /* for now only pick long filename versions */
1464 if (strchrW(targetdir,'|'))
1466 shortname = targetdir;
1467 targetdir = strchrW(targetdir,'|');
1471 /* for the sourcedir pick the short filename */
1472 if (srcdir && strchrW(srcdir,'|'))
1474 LPWSTR p = strchrW(srcdir,'|');
1478 /* now check for root dirs */
1479 if (targetdir[0] == '.' && targetdir[1] == 0)
1484 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1485 msi_free( folder->TargetDefault);
1486 folder->TargetDefault = strdupW(targetdir);
1490 folder->SourceDefault = strdupW(srcdir);
1492 folder->SourceDefault = strdupW(shortname);
1494 folder->SourceDefault = strdupW(targetdir);
1495 msi_free(ptargetdir);
1496 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1498 parent = MSI_RecordGetString(row,2);
1501 folder->Parent = load_folder( package, parent );
1502 if ( folder->Parent )
1503 TRACE("loaded parent %p %s\n", folder->Parent,
1504 debugstr_w(folder->Parent->Directory));
1506 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1509 folder->Property = msi_dup_property( package, dir );
1511 msiobj_release(&row->hdr);
1513 list_add_tail( &package->folders, &folder->entry );
1515 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1520 /* scan for and update current install states */
1521 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1524 MSIFEATURE *feature;
1526 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1529 res = MsiGetComponentPathW( package->ProductCode,
1530 comp->ComponentId, NULL, NULL);
1532 res = INSTALLSTATE_ABSENT;
1533 comp->Installed = res;
1536 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1539 INSTALLSTATE res = -10;
1541 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1543 comp= cl->component;
1546 res = comp->Installed;
1549 if (res == comp->Installed)
1552 if (res != comp->Installed)
1553 res = INSTALLSTATE_INCOMPLETE;
1556 feature->Installed = res;
1560 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1563 static const WCHAR all[]={'A','L','L',0};
1565 MSIFEATURE *feature;
1567 override = msi_dup_property( package, property );
1571 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1573 if (strcmpiW(override,all)==0)
1575 feature->ActionRequest= state;
1576 feature->Action = state;
1580 LPWSTR ptr = override;
1581 LPWSTR ptr2 = strchrW(override,',');
1585 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1586 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1588 feature->ActionRequest= state;
1589 feature->Action = state;
1595 ptr2 = strchrW(ptr,',');
1607 static UINT SetFeatureStates(MSIPACKAGE *package)
1610 static const WCHAR szlevel[] =
1611 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1612 static const WCHAR szAddLocal[] =
1613 {'A','D','D','L','O','C','A','L',0};
1614 static const WCHAR szRemove[] =
1615 {'R','E','M','O','V','E',0};
1616 static const WCHAR szReinstall[] =
1617 {'R','E','I','N','S','T','A','L','L',0};
1618 BOOL override = FALSE;
1619 MSICOMPONENT* component;
1620 MSIFEATURE *feature;
1623 /* I do not know if this is where it should happen.. but */
1625 TRACE("Checking Install Level\n");
1627 install_level = msi_get_property_int( package, szlevel, 1 );
1629 /* ok hereis the _real_ rub
1630 * all these activation/deactivation things happen in order and things
1631 * later on the list override things earlier on the list.
1632 * 1) INSTALLLEVEL processing
1642 * 11) FILEADDDEFAULT
1643 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1644 * ignored for all the features. seems strange, especially since it is not
1645 * documented anywhere, but it is how it works.
1647 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1648 * REMOVE are the big ones, since we don't handle administrative installs
1651 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1652 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1653 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1657 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1659 BOOL feature_state = ((feature->Level > 0) &&
1660 (feature->Level <= install_level));
1662 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1664 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1666 feature->ActionRequest = INSTALLSTATE_SOURCE;
1667 feature->Action = INSTALLSTATE_SOURCE;
1669 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1671 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1672 feature->Action = INSTALLSTATE_ADVERTISED;
1676 feature->ActionRequest = INSTALLSTATE_LOCAL;
1677 feature->Action = INSTALLSTATE_LOCAL;
1684 /* set the Preselected Property */
1685 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1686 static const WCHAR szOne[] = { '1', 0 };
1688 MSI_SetPropertyW(package,szPreselected,szOne);
1692 * now we want to enable or disable components base on feature
1695 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1699 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1700 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1701 feature->ActionRequest);
1703 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1705 component = cl->component;
1707 if (!component->Enabled)
1709 component->Action = INSTALLSTATE_UNKNOWN;
1710 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1714 if (feature->Action == INSTALLSTATE_LOCAL)
1716 component->Action = INSTALLSTATE_LOCAL;
1717 component->ActionRequest = INSTALLSTATE_LOCAL;
1719 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1721 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1722 (component->Action == INSTALLSTATE_ABSENT) ||
1723 (component->Action == INSTALLSTATE_ADVERTISED))
1726 component->Action = INSTALLSTATE_SOURCE;
1727 component->ActionRequest = INSTALLSTATE_SOURCE;
1730 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1732 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1733 (component->Action == INSTALLSTATE_ABSENT))
1736 component->Action = INSTALLSTATE_ADVERTISED;
1737 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1740 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1742 if (component->Action == INSTALLSTATE_UNKNOWN)
1744 component->Action = INSTALLSTATE_ABSENT;
1745 component->ActionRequest = INSTALLSTATE_ABSENT;
1752 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1754 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1755 debugstr_w(component->Component), component->Installed,
1756 component->Action, component->ActionRequest);
1760 return ERROR_SUCCESS;
1763 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1765 MSIPACKAGE *package = (MSIPACKAGE*)param;
1769 name = MSI_RecordGetString(row,1);
1771 /* This helper function now does ALL the work */
1772 TRACE("Dir %s ...\n",debugstr_w(name));
1773 load_folder(package,name);
1774 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1775 TRACE("resolves to %s\n",debugstr_w(path));
1778 return ERROR_SUCCESS;
1781 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1783 MSIPACKAGE *package = (MSIPACKAGE*)param;
1785 MSIFEATURE *feature;
1787 name = MSI_RecordGetString( row, 1 );
1789 feature = get_loaded_feature( package, name );
1791 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1795 Condition = MSI_RecordGetString(row,3);
1797 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1799 int level = MSI_RecordGetInteger(row,2);
1800 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1801 feature->Level = level;
1804 return ERROR_SUCCESS;
1809 * A lot is done in this function aside from just the costing.
1810 * The costing needs to be implemented at some point but for now I am going
1811 * to focus on the directory building
1814 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1816 static const WCHAR ExecSeqQuery[] =
1817 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1818 '`','D','i','r','e','c','t','o','r','y','`',0};
1819 static const WCHAR ConditionQuery[] =
1820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1821 '`','C','o','n','d','i','t','i','o','n','`',0};
1822 static const WCHAR szCosting[] =
1823 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1824 static const WCHAR szlevel[] =
1825 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1826 static const WCHAR szOne[] = { '1', 0 };
1833 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1834 return ERROR_SUCCESS;
1836 TRACE("Building Directory properties\n");
1838 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1839 if (rc == ERROR_SUCCESS)
1841 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1843 msiobj_release(&view->hdr);
1846 TRACE("File calculations\n");
1848 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1850 MSICOMPONENT* comp = file->Component;
1856 /* calculate target */
1857 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1859 msi_free(file->TargetPath);
1861 TRACE("file %s is named %s\n",
1862 debugstr_w(file->File),debugstr_w(file->FileName));
1864 file->TargetPath = build_directory_name(2, p, file->FileName);
1868 TRACE("file %s resolves to %s\n",
1869 debugstr_w(file->File),debugstr_w(file->TargetPath));
1871 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1873 file->state = msifs_missing;
1874 comp->Cost += file->FileSize;
1884 static WCHAR name[] = {'\\',0};
1885 static const WCHAR name_fmt[] =
1886 {'%','u','.','%','u','.','%','u','.','%','u',0};
1887 WCHAR filever[0x100];
1888 VS_FIXEDFILEINFO *lpVer;
1890 TRACE("Version comparison..\n");
1891 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1892 version = msi_alloc(versize);
1893 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1895 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1897 sprintfW(filever,name_fmt,
1898 HIWORD(lpVer->dwFileVersionMS),
1899 LOWORD(lpVer->dwFileVersionMS),
1900 HIWORD(lpVer->dwFileVersionLS),
1901 LOWORD(lpVer->dwFileVersionLS));
1903 TRACE("new %s old %s\n", debugstr_w(file->Version),
1904 debugstr_w(filever));
1905 if (strcmpiW(filever,file->Version)<0)
1907 file->state = msifs_overwrite;
1908 /* FIXME: cost should be diff in size */
1909 comp->Cost += file->FileSize;
1912 file->state = msifs_present;
1916 file->state = msifs_present;
1919 TRACE("Evaluating Condition Table\n");
1921 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1922 if (rc == ERROR_SUCCESS)
1924 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1926 msiobj_release(&view->hdr);
1929 TRACE("Enabling or Disabling Components\n");
1930 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1932 if (comp->Condition)
1934 if (MSI_EvaluateConditionW(package,
1935 comp->Condition) == MSICONDITION_FALSE)
1937 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1938 comp->Enabled = FALSE;
1943 MSI_SetPropertyW(package,szCosting,szOne);
1944 /* set default run level if not set */
1945 level = msi_dup_property( package, szlevel );
1947 MSI_SetPropertyW(package,szlevel, szOne);
1950 ACTION_UpdateInstallStates(package);
1952 return SetFeatureStates(package);
1955 /* OK this value is "interpreted" and then formatted based on the
1956 first few characters */
1957 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1961 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1967 LPWSTR deformated = NULL;
1970 deformat_string(package, &value[2], &deformated);
1972 /* binary value type */
1976 *size = (strlenW(ptr)/2)+1;
1978 *size = strlenW(ptr)/2;
1980 data = msi_alloc(*size);
1986 /* if uneven pad with a zero in front */
1992 data[count] = (BYTE)strtol(byte,NULL,0);
1994 TRACE("Uneven byte count\n");
2002 data[count] = (BYTE)strtol(byte,NULL,0);
2005 msi_free(deformated);
2007 TRACE("Data %li bytes(%i)\n",*size,count);
2014 deformat_string(package, &value[1], &deformated);
2017 *size = sizeof(DWORD);
2018 data = msi_alloc(*size);
2024 if ( (*p < '0') || (*p > '9') )
2030 if (deformated[0] == '-')
2033 TRACE("DWORD %li\n",*(LPDWORD)data);
2035 msi_free(deformated);
2040 static const WCHAR szMulti[] = {'[','~',']',0};
2049 *type=REG_EXPAND_SZ;
2057 if (strstrW(value,szMulti))
2058 *type = REG_MULTI_SZ;
2060 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2065 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2067 MSIPACKAGE *package = (MSIPACKAGE*)param;
2068 static const WCHAR szHCR[] =
2069 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2070 'R','O','O','T','\\',0};
2071 static const WCHAR szHCU[] =
2072 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2073 'U','S','E','R','\\',0};
2074 static const WCHAR szHLM[] =
2075 {'H','K','E','Y','_','L','O','C','A','L','_',
2076 'M','A','C','H','I','N','E','\\',0};
2077 static const WCHAR szHU[] =
2078 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2080 LPSTR value_data = NULL;
2081 HKEY root_key, hkey;
2084 LPCWSTR szRoot, component, name, key, value;
2089 BOOL check_first = FALSE;
2092 ui_progress(package,2,0,0,0);
2099 component = MSI_RecordGetString(row, 6);
2100 comp = get_loaded_component(package,component);
2102 return ERROR_SUCCESS;
2104 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2106 TRACE("Skipping write due to disabled component %s\n",
2107 debugstr_w(component));
2109 comp->Action = comp->Installed;
2111 return ERROR_SUCCESS;
2114 comp->Action = INSTALLSTATE_LOCAL;
2116 name = MSI_RecordGetString(row, 4);
2117 if( MSI_RecordIsNull(row,5) && name )
2119 /* null values can have special meanings */
2120 if (name[0]=='-' && name[1] == 0)
2121 return ERROR_SUCCESS;
2122 else if ((name[0]=='+' && name[1] == 0) ||
2123 (name[0] == '*' && name[1] == 0))
2128 root = MSI_RecordGetInteger(row,2);
2129 key = MSI_RecordGetString(row, 3);
2131 /* get the root key */
2136 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2137 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2138 if (all_users && all_users[0] == '1')
2140 root_key = HKEY_LOCAL_MACHINE;
2145 root_key = HKEY_CURRENT_USER;
2148 msi_free(all_users);
2151 case 0: root_key = HKEY_CLASSES_ROOT;
2154 case 1: root_key = HKEY_CURRENT_USER;
2157 case 2: root_key = HKEY_LOCAL_MACHINE;
2160 case 3: root_key = HKEY_USERS;
2164 ERR("Unknown root %i\n",root);
2170 return ERROR_SUCCESS;
2172 deformat_string(package, key , &deformated);
2173 size = strlenW(deformated) + strlenW(szRoot) + 1;
2174 uikey = msi_alloc(size*sizeof(WCHAR));
2175 strcpyW(uikey,szRoot);
2176 strcatW(uikey,deformated);
2178 if (RegCreateKeyW( root_key, deformated, &hkey))
2180 ERR("Could not create key %s\n",debugstr_w(deformated));
2181 msi_free(deformated);
2183 return ERROR_SUCCESS;
2185 msi_free(deformated);
2187 value = MSI_RecordGetString(row,5);
2189 value_data = parse_value(package, value, &type, &size);
2192 static const WCHAR szEmpty[] = {0};
2193 value_data = (LPSTR)strdupW(szEmpty);
2198 deformat_string(package, name, &deformated);
2200 /* get the double nulls to terminate SZ_MULTI */
2201 if (type == REG_MULTI_SZ)
2202 size +=sizeof(WCHAR);
2206 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2208 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2213 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2214 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2216 TRACE("value %s of %s checked already exists\n",
2217 debugstr_w(deformated), debugstr_w(uikey));
2221 TRACE("Checked and setting value %s of %s\n",
2222 debugstr_w(deformated), debugstr_w(uikey));
2223 if (deformated || size)
2224 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2229 uirow = MSI_CreateRecord(3);
2230 MSI_RecordSetStringW(uirow,2,deformated);
2231 MSI_RecordSetStringW(uirow,1,uikey);
2234 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2236 MSI_RecordSetStringW(uirow,3,value);
2238 ui_actiondata(package,szWriteRegistryValues,uirow);
2239 msiobj_release( &uirow->hdr );
2241 msi_free(value_data);
2242 msi_free(deformated);
2245 return ERROR_SUCCESS;
2248 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2252 static const WCHAR ExecSeqQuery[] =
2253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2254 '`','R','e','g','i','s','t','r','y','`',0 };
2257 return ERROR_INVALID_HANDLE;
2259 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2260 if (rc != ERROR_SUCCESS)
2261 return ERROR_SUCCESS;
2263 /* increment progress bar each time action data is sent */
2264 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2266 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2268 msiobj_release(&view->hdr);
2272 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2274 package->script->CurrentlyScripting = TRUE;
2276 return ERROR_SUCCESS;
2280 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2285 static const WCHAR q1[]=
2286 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2287 '`','R','e','g','i','s','t','r','y','`',0};
2290 MSIFEATURE *feature;
2293 TRACE("InstallValidate\n");
2295 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2296 if (rc == ERROR_SUCCESS)
2298 MSI_IterateRecords( view, &progress, NULL, package );
2299 msiobj_release( &view->hdr );
2300 total += progress * REG_PROGRESS_VALUE;
2303 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2304 total += COMPONENT_PROGRESS_VALUE;
2306 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2307 total += file->FileSize;
2309 ui_progress(package,0,total,0,0);
2311 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2313 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2314 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2315 feature->ActionRequest);
2318 return ERROR_SUCCESS;
2321 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2323 MSIPACKAGE* package = (MSIPACKAGE*)param;
2324 LPCWSTR cond = NULL;
2325 LPCWSTR message = NULL;
2326 static const WCHAR title[]=
2327 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2329 cond = MSI_RecordGetString(row,1);
2331 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2334 message = MSI_RecordGetString(row,2);
2335 deformat_string(package,message,&deformated);
2336 MessageBoxW(NULL,deformated,title,MB_OK);
2337 msi_free(deformated);
2338 return ERROR_FUNCTION_FAILED;
2341 return ERROR_SUCCESS;
2344 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2347 MSIQUERY * view = NULL;
2348 static const WCHAR ExecSeqQuery[] =
2349 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2350 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2352 TRACE("Checking launch conditions\n");
2354 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2355 if (rc != ERROR_SUCCESS)
2356 return ERROR_SUCCESS;
2358 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2359 msiobj_release(&view->hdr);
2364 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2368 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2370 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2372 MSIRECORD * row = 0;
2374 LPWSTR deformated,buffer,deformated_name;
2376 static const WCHAR ExecSeqQuery[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','R','e','g','i','s','t','r','y','`',' ',
2379 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2380 ' ','=',' ' ,'\'','%','s','\'',0 };
2381 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2382 static const WCHAR fmt2[]=
2383 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2385 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2389 root = MSI_RecordGetInteger(row,2);
2390 key = MSI_RecordGetString(row, 3);
2391 name = MSI_RecordGetString(row, 4);
2392 deformat_string(package, key , &deformated);
2393 deformat_string(package, name, &deformated_name);
2395 len = strlenW(deformated) + 6;
2396 if (deformated_name)
2397 len+=strlenW(deformated_name);
2399 buffer = msi_alloc( len *sizeof(WCHAR));
2401 if (deformated_name)
2402 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2404 sprintfW(buffer,fmt,root,deformated);
2406 msi_free(deformated);
2407 msi_free(deformated_name);
2408 msiobj_release(&row->hdr);
2412 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2414 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2419 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2422 return strdupW( file->TargetPath );
2427 static HKEY openSharedDLLsKey(void)
2430 static const WCHAR path[] =
2431 {'S','o','f','t','w','a','r','e','\\',
2432 'M','i','c','r','o','s','o','f','t','\\',
2433 'W','i','n','d','o','w','s','\\',
2434 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2435 'S','h','a','r','e','d','D','L','L','s',0};
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2441 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2446 DWORD sz = sizeof(count);
2449 hkey = openSharedDLLsKey();
2450 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2451 if (rc != ERROR_SUCCESS)
2457 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2461 hkey = openSharedDLLsKey();
2463 msi_reg_set_val_dword( hkey, path, count );
2465 RegDeleteValueW(hkey,path);
2471 * Return TRUE if the count should be written out and FALSE if not
2473 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2475 MSIFEATURE *feature;
2479 /* only refcount DLLs */
2480 if (comp->KeyPath == NULL ||
2481 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2482 comp->Attributes & msidbComponentAttributesODBCDataSource)
2486 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2487 write = (count > 0);
2489 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2493 /* increment counts */
2494 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2498 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2501 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2503 if ( cl->component == comp )
2508 /* decrement counts */
2509 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2513 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2516 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2518 if ( cl->component == comp )
2523 /* ref count all the files in the component */
2528 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2530 if (file->Component == comp)
2531 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2535 /* add a count for permenent */
2536 if (comp->Attributes & msidbComponentAttributesPermanent)
2539 comp->RefCount = count;
2542 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2546 * Ok further analysis makes me think that this work is
2547 * actually done in the PublishComponents and PublishFeatures
2548 * step, and not here. It appears like the keypath and all that is
2549 * resolved in this step, however actually written in the Publish steps.
2550 * But we will leave it here for now because it is unclear
2552 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2554 WCHAR squished_pc[GUID_SIZE];
2555 WCHAR squished_cc[GUID_SIZE];
2558 HKEY hkey=0,hkey2=0;
2560 /* writes the Component and Features values to the registry */
2562 rc = MSIREG_OpenComponents(&hkey);
2563 if (rc != ERROR_SUCCESS)
2566 squash_guid(package->ProductCode,squished_pc);
2567 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2569 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2571 ui_progress(package,2,0,0,0);
2572 if (comp->ComponentId)
2576 squash_guid(comp->ComponentId,squished_cc);
2578 msi_free(comp->FullKeypath);
2579 comp->FullKeypath = resolve_keypath( package, comp );
2581 /* do the refcounting */
2582 ACTION_RefCountComponent( package, comp );
2584 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2585 debugstr_w(comp->Component),
2586 debugstr_w(squished_cc),
2587 debugstr_w(comp->FullKeypath),
2590 * Write the keypath out if the component is to be registered
2591 * and delete the key if the component is to be deregistered
2593 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2595 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2596 if (rc != ERROR_SUCCESS)
2599 if (comp->FullKeypath)
2601 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2603 if (comp->Attributes & msidbComponentAttributesPermanent)
2605 static const WCHAR szPermKey[] =
2606 { '0','0','0','0','0','0','0','0','0','0','0','0',
2607 '0','0','0','0','0','0','0','0','0','0','0','0',
2608 '0','0','0','0','0','0','0','0',0};
2610 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2616 uirow = MSI_CreateRecord(3);
2617 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2618 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2619 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2620 ui_actiondata(package,szProcessComponents,uirow);
2621 msiobj_release( &uirow->hdr );
2624 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2628 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2629 if (rc != ERROR_SUCCESS)
2632 RegDeleteValueW(hkey2,squished_pc);
2634 /* if the key is empty delete it */
2635 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2637 if (res == ERROR_NO_MORE_ITEMS)
2638 RegDeleteKeyW(hkey,squished_cc);
2641 uirow = MSI_CreateRecord(2);
2642 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2643 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2644 ui_actiondata(package,szProcessComponents,uirow);
2645 msiobj_release( &uirow->hdr );
2662 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2663 LPWSTR lpszName, LONG_PTR lParam)
2666 typelib_struct *tl_struct = (typelib_struct*) lParam;
2667 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2671 if (!IS_INTRESOURCE(lpszName))
2673 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2677 sz = strlenW(tl_struct->source)+4;
2678 sz *= sizeof(WCHAR);
2680 if ((INT)lpszName == 1)
2681 tl_struct->path = strdupW(tl_struct->source);
2684 tl_struct->path = msi_alloc(sz);
2685 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2688 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2689 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2690 if (!SUCCEEDED(res))
2692 msi_free(tl_struct->path);
2693 tl_struct->path = NULL;
2698 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2699 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2701 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2705 msi_free(tl_struct->path);
2706 tl_struct->path = NULL;
2708 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2709 ITypeLib_Release(tl_struct->ptLib);
2714 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2716 MSIPACKAGE* package = (MSIPACKAGE*)param;
2720 typelib_struct tl_struct;
2722 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2724 component = MSI_RecordGetString(row,3);
2725 comp = get_loaded_component(package,component);
2727 return ERROR_SUCCESS;
2729 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2731 TRACE("Skipping typelib reg due to disabled component\n");
2733 comp->Action = comp->Installed;
2735 return ERROR_SUCCESS;
2738 comp->Action = INSTALLSTATE_LOCAL;
2740 file = get_loaded_file( package, comp->KeyPath );
2742 return ERROR_SUCCESS;
2744 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2748 guid = MSI_RecordGetString(row,1);
2749 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2750 tl_struct.source = strdupW( file->TargetPath );
2751 tl_struct.path = NULL;
2753 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2754 (LONG_PTR)&tl_struct);
2762 helpid = MSI_RecordGetString(row,6);
2765 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2766 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2769 if (!SUCCEEDED(res))
2770 ERR("Failed to register type library %s\n",
2771 debugstr_w(tl_struct.path));
2774 ui_actiondata(package,szRegisterTypeLibraries,row);
2776 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2779 ITypeLib_Release(tl_struct.ptLib);
2780 msi_free(tl_struct.path);
2783 ERR("Failed to load type library %s\n",
2784 debugstr_w(tl_struct.source));
2786 FreeLibrary(module);
2787 msi_free(tl_struct.source);
2790 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2792 return ERROR_SUCCESS;
2795 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2798 * OK this is a bit confusing.. I am given a _Component key and I believe
2799 * that the file that is being registered as a type library is the "key file
2800 * of that component" which I interpret to mean "The file in the KeyPath of
2805 static const WCHAR Query[] =
2806 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2807 '`','T','y','p','e','L','i','b','`',0};
2809 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2810 if (rc != ERROR_SUCCESS)
2811 return ERROR_SUCCESS;
2813 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2814 msiobj_release(&view->hdr);
2818 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2820 MSIPACKAGE *package = (MSIPACKAGE*)param;
2821 LPWSTR target_file, target_folder;
2823 WCHAR filename[0x100];
2826 static const WCHAR szlnk[]={'.','l','n','k',0};
2831 buffer = MSI_RecordGetString(row,4);
2832 comp = get_loaded_component(package,buffer);
2834 return ERROR_SUCCESS;
2836 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2838 TRACE("Skipping shortcut creation due to disabled component\n");
2840 comp->Action = comp->Installed;
2842 return ERROR_SUCCESS;
2845 comp->Action = INSTALLSTATE_LOCAL;
2847 ui_actiondata(package,szCreateShortcuts,row);
2849 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2850 &IID_IShellLinkW, (LPVOID *) &sl );
2854 ERR("Is IID_IShellLink\n");
2855 return ERROR_SUCCESS;
2858 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2861 ERR("Is IID_IPersistFile\n");
2862 return ERROR_SUCCESS;
2865 buffer = MSI_RecordGetString(row,2);
2866 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2868 /* may be needed because of a bug somehwere else */
2869 create_full_pathW(target_folder);
2872 MSI_RecordGetStringW(row,3,filename,&sz);
2873 reduce_to_longfilename(filename);
2874 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2875 strcatW(filename,szlnk);
2876 target_file = build_directory_name(2, target_folder, filename);
2877 msi_free(target_folder);
2879 buffer = MSI_RecordGetString(row,5);
2880 if (strchrW(buffer,'['))
2883 deformat_string(package,buffer,&deformated);
2884 IShellLinkW_SetPath(sl,deformated);
2885 msi_free(deformated);
2889 FIXME("poorly handled shortcut format, advertised shortcut\n");
2890 IShellLinkW_SetPath(sl,comp->FullKeypath);
2893 if (!MSI_RecordIsNull(row,6))
2896 buffer = MSI_RecordGetString(row,6);
2897 deformat_string(package,buffer,&deformated);
2898 IShellLinkW_SetArguments(sl,deformated);
2899 msi_free(deformated);
2902 if (!MSI_RecordIsNull(row,7))
2904 buffer = MSI_RecordGetString(row,7);
2905 IShellLinkW_SetDescription(sl,buffer);
2908 if (!MSI_RecordIsNull(row,8))
2909 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2911 if (!MSI_RecordIsNull(row,9))
2916 buffer = MSI_RecordGetString(row,9);
2918 Path = build_icon_path(package,buffer);
2919 index = MSI_RecordGetInteger(row,10);
2921 IShellLinkW_SetIconLocation(sl,Path,index);
2925 if (!MSI_RecordIsNull(row,11))
2926 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2928 if (!MSI_RecordIsNull(row,12))
2931 buffer = MSI_RecordGetString(row,12);
2932 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2933 IShellLinkW_SetWorkingDirectory(sl,Path);
2937 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2938 IPersistFile_Save(pf,target_file,FALSE);
2940 msi_free(target_file);
2942 IPersistFile_Release( pf );
2943 IShellLinkW_Release( sl );
2945 return ERROR_SUCCESS;
2948 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2953 static const WCHAR Query[] =
2954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2955 '`','S','h','o','r','t','c','u','t','`',0};
2957 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2958 if (rc != ERROR_SUCCESS)
2959 return ERROR_SUCCESS;
2961 res = CoInitialize( NULL );
2964 ERR("CoInitialize failed\n");
2965 return ERROR_FUNCTION_FAILED;
2968 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2969 msiobj_release(&view->hdr);
2976 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2978 MSIPACKAGE* package = (MSIPACKAGE*)param;
2986 FileName = MSI_RecordGetString(row,1);
2989 ERR("Unable to get FileName\n");
2990 return ERROR_SUCCESS;
2993 FilePath = build_icon_path(package,FileName);
2995 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2997 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2998 FILE_ATTRIBUTE_NORMAL, NULL);
3000 if (the_file == INVALID_HANDLE_VALUE)
3002 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3004 return ERROR_SUCCESS;
3011 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3012 if (rc != ERROR_SUCCESS)
3014 ERR("Failed to get stream\n");
3015 CloseHandle(the_file);
3016 DeleteFileW(FilePath);
3019 WriteFile(the_file,buffer,sz,&write,NULL);
3020 } while (sz == 1024);
3024 CloseHandle(the_file);
3025 return ERROR_SUCCESS;
3029 * 99% of the work done here is only done for
3030 * advertised installs. However this is where the
3031 * Icon table is processed and written out
3032 * so that is what I am going to do here.
3034 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3038 static const WCHAR Query[]=
3039 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3040 '`','I','c','o','n','`',0};
3041 /* for registry stuff */
3044 static const WCHAR szProductLanguage[] =
3045 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3046 static const WCHAR szARPProductIcon[] =
3047 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3048 static const WCHAR szProductVersion[] =
3049 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3053 MSIHANDLE hDb, hSumInfo;
3055 /* write out icon files */
3057 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3058 if (rc == ERROR_SUCCESS)
3060 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3061 msiobj_release(&view->hdr);
3064 /* ok there is a lot more done here but i need to figure out what */
3066 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3067 if (rc != ERROR_SUCCESS)
3070 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3071 if (rc != ERROR_SUCCESS)
3075 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3076 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3079 langid = msi_get_property_int( package, szProductLanguage, 0 );
3080 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3082 buffer = msi_dup_property( package, szARPProductIcon );
3085 LPWSTR path = build_icon_path(package,buffer);
3086 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3091 buffer = msi_dup_property( package, szProductVersion );
3094 DWORD verdword = build_version_dword(buffer);
3095 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3099 FIXME("Need to write more keys to the user registry\n");
3101 hDb= alloc_msihandle( &package->db->hdr );
3102 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3103 MsiCloseHandle(hDb);
3104 if (rc == ERROR_SUCCESS)
3106 WCHAR guidbuffer[0x200];
3108 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3110 if (rc == ERROR_SUCCESS)
3112 WCHAR squashed[GUID_SIZE];
3113 /* for now we only care about the first guid */
3114 LPWSTR ptr = strchrW(guidbuffer,';');
3116 squash_guid(guidbuffer,squashed);
3117 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3121 ERR("Unable to query Revision_Number...\n");
3124 MsiCloseHandle(hSumInfo);
3128 ERR("Unable to open Summary Information\n");
3140 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3142 MSIPACKAGE *package = (MSIPACKAGE*)param;
3143 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3144 LPWSTR deformated_section, deformated_key, deformated_value;
3145 LPWSTR folder, fullname = NULL;
3149 static const WCHAR szWindowsFolder[] =
3150 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3152 component = MSI_RecordGetString(row, 8);
3153 comp = get_loaded_component(package,component);
3155 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3157 TRACE("Skipping ini file due to disabled component %s\n",
3158 debugstr_w(component));
3160 comp->Action = comp->Installed;
3162 return ERROR_SUCCESS;
3165 comp->Action = INSTALLSTATE_LOCAL;
3167 identifier = MSI_RecordGetString(row,1);
3168 filename = MSI_RecordGetString(row,2);
3169 dirproperty = MSI_RecordGetString(row,3);
3170 section = MSI_RecordGetString(row,4);
3171 key = MSI_RecordGetString(row,5);
3172 value = MSI_RecordGetString(row,6);
3173 action = MSI_RecordGetInteger(row,7);
3175 deformat_string(package,section,&deformated_section);
3176 deformat_string(package,key,&deformated_key);
3177 deformat_string(package,value,&deformated_value);
3181 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3183 folder = msi_dup_property( package, dirproperty );
3186 folder = msi_dup_property( package, szWindowsFolder );
3190 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3194 fullname = build_directory_name(2, folder, filename);
3198 TRACE("Adding value %s to section %s in %s\n",
3199 debugstr_w(deformated_key), debugstr_w(deformated_section),
3200 debugstr_w(fullname));
3201 WritePrivateProfileStringW(deformated_section, deformated_key,
3202 deformated_value, fullname);
3204 else if (action == 1)
3207 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3208 returned, 10, fullname);
3209 if (returned[0] == 0)
3211 TRACE("Adding value %s to section %s in %s\n",
3212 debugstr_w(deformated_key), debugstr_w(deformated_section),
3213 debugstr_w(fullname));
3215 WritePrivateProfileStringW(deformated_section, deformated_key,
3216 deformated_value, fullname);
3219 else if (action == 3)
3220 FIXME("Append to existing section not yet implemented\n");
3222 uirow = MSI_CreateRecord(4);
3223 MSI_RecordSetStringW(uirow,1,identifier);
3224 MSI_RecordSetStringW(uirow,2,deformated_section);
3225 MSI_RecordSetStringW(uirow,3,deformated_key);
3226 MSI_RecordSetStringW(uirow,4,deformated_value);
3227 ui_actiondata(package,szWriteIniValues,uirow);
3228 msiobj_release( &uirow->hdr );
3232 msi_free(deformated_key);
3233 msi_free(deformated_value);
3234 msi_free(deformated_section);
3235 return ERROR_SUCCESS;
3238 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3242 static const WCHAR ExecSeqQuery[] =
3243 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3244 '`','I','n','i','F','i','l','e','`',0};
3246 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3247 if (rc != ERROR_SUCCESS)
3249 TRACE("no IniFile table\n");
3250 return ERROR_SUCCESS;
3253 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3254 msiobj_release(&view->hdr);
3258 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3260 MSIPACKAGE *package = (MSIPACKAGE*)param;
3265 static const WCHAR ExeStr[] =
3266 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3267 static const WCHAR close[] = {'\"',0};
3269 PROCESS_INFORMATION info;
3272 memset(&si,0,sizeof(STARTUPINFOW));
3274 filename = MSI_RecordGetString(row,1);
3275 file = get_loaded_file( package, filename );
3279 ERR("Unable to find file id %s\n",debugstr_w(filename));
3280 return ERROR_SUCCESS;
3283 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3285 FullName = msi_alloc(len*sizeof(WCHAR));
3286 strcpyW(FullName,ExeStr);
3287 strcatW( FullName, file->TargetPath );
3288 strcatW(FullName,close);
3290 TRACE("Registering %s\n",debugstr_w(FullName));
3291 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3295 msi_dialog_check_messages(info.hProcess);
3298 return ERROR_SUCCESS;
3301 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3305 static const WCHAR ExecSeqQuery[] =
3306 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3307 '`','S','e','l','f','R','e','g','`',0};
3309 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3310 if (rc != ERROR_SUCCESS)
3312 TRACE("no SelfReg table\n");
3313 return ERROR_SUCCESS;
3316 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3317 msiobj_release(&view->hdr);
3319 return ERROR_SUCCESS;
3322 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3324 MSIFEATURE *feature;
3329 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3330 if (rc != ERROR_SUCCESS)
3333 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3334 if (rc != ERROR_SUCCESS)
3337 /* here the guids are base 85 encoded */
3338 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3344 BOOL absent = FALSE;
3346 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3347 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3348 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3352 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3356 if (feature->Feature_Parent)
3357 size += strlenW( feature->Feature_Parent )+2;
3359 data = msi_alloc(size * sizeof(WCHAR));
3362 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3364 MSICOMPONENT* component = cl->component;
3367 memset(buf,0,sizeof(buf));
3368 if (component->ComponentId)
3370 TRACE("From %s\n",debugstr_w(component->ComponentId));
3371 CLSIDFromString(component->ComponentId, &clsid);
3372 encode_base85_guid(&clsid,buf);
3373 TRACE("to %s\n",debugstr_w(buf));
3377 if (feature->Feature_Parent)
3379 static const WCHAR sep[] = {'\2',0};
3381 strcatW(data,feature->Feature_Parent);
3384 msi_reg_set_val_str( hkey, feature->Feature, data );
3388 if (feature->Feature_Parent)
3389 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3392 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3393 (LPBYTE)feature->Feature_Parent,size);
3397 size += 2*sizeof(WCHAR);
3398 data = msi_alloc(size);
3401 if (feature->Feature_Parent)
3402 strcpyW( &data[1], feature->Feature_Parent );
3403 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3415 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3417 static const WCHAR installerPathFmt[] = {
3418 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3419 static const WCHAR fmt[] = {
3421 'I','n','s','t','a','l','l','e','r','\\',
3422 '%','x','.','m','s','i',0};
3423 static const WCHAR szOriginalDatabase[] =
3424 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3425 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3430 /* copy the package locally */
3431 num = GetTickCount() & 0xffff;
3435 GetWindowsDirectoryW( windir, MAX_PATH );
3436 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3439 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3440 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3441 if (handle != INVALID_HANDLE_VALUE)
3443 CloseHandle(handle);
3446 if (GetLastError() != ERROR_FILE_EXISTS &&
3447 GetLastError() != ERROR_SHARING_VIOLATION)
3449 if (!(++num & 0xffff)) num = 1;
3450 sprintfW(packagefile,fmt,num);
3451 } while (num != start);
3453 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3454 create_full_pathW(path);
3456 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3458 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3459 r = CopyFileW( msiFilePath, packagefile, FALSE);
3460 msi_free( msiFilePath );
3464 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3465 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3466 return ERROR_FUNCTION_FAILED;
3469 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3470 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3471 return ERROR_SUCCESS;
3474 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3476 LPWSTR prop, val, key;
3477 static const LPCSTR propval[] = {
3478 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3479 "ARPCONTACT", "Contact",
3480 "ARPCOMMENTS", "Comments",
3481 "ProductName", "DisplayName",
3482 "ProductVersion", "DisplayVersion",
3483 "ARPHELPLINK", "HelpLink",
3484 "ARPHELPTELEPHONE", "HelpTelephone",
3485 "ARPINSTALLLOCATION", "InstallLocation",
3486 "SourceDir", "InstallSource",
3487 "Manufacturer", "Publisher",
3488 "ARPREADME", "Readme",
3490 "ARPURLINFOABOUT", "URLInfoAbout",
3491 "ARPURLUPDATEINFO", "URLUpdateInfo",
3494 const LPCSTR *p = propval;
3498 prop = strdupAtoW( *p++ );
3499 key = strdupAtoW( *p++ );
3500 val = msi_dup_property( package, prop );
3501 msi_reg_set_val_str( hkey, key, val );
3506 return ERROR_SUCCESS;
3509 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3512 LPWSTR buffer = NULL;
3515 static const WCHAR szWindowsInstaller[] =
3516 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3517 static const WCHAR szUpgradeCode[] =
3518 {'U','p','g','r','a','d','e','C','o','d','e',0};
3519 static const WCHAR modpath_fmt[] =
3520 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3521 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3522 static const WCHAR szModifyPath[] =
3523 {'M','o','d','i','f','y','P','a','t','h',0};
3524 static const WCHAR szUninstallString[] =
3525 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3526 static const WCHAR szEstimatedSize[] =
3527 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3528 static const WCHAR szProductLanguage[] =
3529 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3530 static const WCHAR szProductVersion[] =
3531 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3534 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3535 LPWSTR upgrade_code;
3538 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3539 if (rc != ERROR_SUCCESS)
3542 /* dump all the info i can grab */
3543 FIXME("Flesh out more information\n");
3545 msi_write_uninstall_property_vals( package, hkey );
3547 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3549 msi_make_package_local( package, hkey );
3551 /* do ModifyPath and UninstallString */
3552 size = deformat_string(package,modpath_fmt,&buffer);
3553 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3554 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3557 FIXME("Write real Estimated Size when we have it\n");
3558 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3560 GetLocalTime(&systime);
3561 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3562 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3564 langid = msi_get_property_int( package, szProductLanguage, 0 );
3565 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3567 buffer = msi_dup_property( package, szProductVersion );
3570 DWORD verdword = build_version_dword(buffer);
3572 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3573 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3574 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3578 /* Handle Upgrade Codes */
3579 upgrade_code = msi_dup_property( package, szUpgradeCode );
3584 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3585 squash_guid(package->ProductCode,squashed);
3586 msi_reg_set_val_str( hkey2, squashed, NULL );
3588 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3589 squash_guid(package->ProductCode,squashed);
3590 msi_reg_set_val_str( hkey2, squashed, NULL );
3593 msi_free(upgrade_code);
3598 return ERROR_SUCCESS;
3601 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3603 return execute_script(package,INSTALL_SCRIPT);
3606 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3610 /* turn off scheduleing */
3611 package->script->CurrentlyScripting= FALSE;
3613 /* first do the same as an InstallExecute */
3614 rc = ACTION_InstallExecute(package);
3615 if (rc != ERROR_SUCCESS)
3618 /* then handle Commit Actions */
3619 rc = execute_script(package,COMMIT_SCRIPT);
3624 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3626 static const WCHAR RunOnce[] = {
3627 'S','o','f','t','w','a','r','e','\\',
3628 'M','i','c','r','o','s','o','f','t','\\',
3629 'W','i','n','d','o','w','s','\\',
3630 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3631 'R','u','n','O','n','c','e',0};
3632 static const WCHAR InstallRunOnce[] = {
3633 'S','o','f','t','w','a','r','e','\\',
3634 'M','i','c','r','o','s','o','f','t','\\',
3635 'W','i','n','d','o','w','s','\\',
3636 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3637 'I','n','s','t','a','l','l','e','r','\\',
3638 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3640 static const WCHAR msiexec_fmt[] = {
3642 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3643 '\"','%','s','\"',0};
3644 static const WCHAR install_fmt[] = {
3645 '/','I',' ','\"','%','s','\"',' ',
3646 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3647 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3648 WCHAR buffer[256], sysdir[MAX_PATH];
3650 WCHAR squished_pc[100];
3652 squash_guid(package->ProductCode,squished_pc);
3654 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3655 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3656 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3659 msi_reg_set_val_str( hkey, squished_pc, buffer );
3662 TRACE("Reboot command %s\n",debugstr_w(buffer));
3664 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3665 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3667 msi_reg_set_val_str( hkey, squished_pc, buffer );
3670 return ERROR_INSTALL_SUSPEND;
3673 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3678 * we are currently doing what should be done here in the top level Install
3679 * however for Adminastrative and uninstalls this step will be needed
3681 if (!package->PackagePath)
3682 return ERROR_SUCCESS;
3684 attrib = GetFileAttributesW(package->PackagePath);
3685 if (attrib == INVALID_FILE_ATTRIBUTES)
3691 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3692 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3693 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3694 if (rc == ERROR_MORE_DATA)
3696 prompt = msi_alloc(size * sizeof(WCHAR));
3697 MsiSourceListGetInfoW(package->ProductCode, NULL,
3698 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3699 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3702 prompt = strdupW(package->PackagePath);
3704 msg = generate_error_string(package,1302,1,prompt);
3705 while(attrib == INVALID_FILE_ATTRIBUTES)
3707 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3710 rc = ERROR_INSTALL_USEREXIT;
3713 attrib = GetFileAttributesW(package->PackagePath);
3719 return ERROR_SUCCESS;
3724 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3731 static const WCHAR szPropKeys[][80] =
3733 {'P','r','o','d','u','c','t','I','D',0},
3734 {'U','S','E','R','N','A','M','E',0},
3735 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3739 static const WCHAR szRegKeys[][80] =
3741 {'P','r','o','d','u','c','t','I','D',0},
3742 {'R','e','g','O','w','n','e','r',0},
3743 {'R','e','g','C','o','m','p','a','n','y',0},
3747 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3749 return ERROR_SUCCESS;
3751 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3752 if (rc != ERROR_SUCCESS)
3755 for( i = 0; szPropKeys[i][0]; i++ )
3757 buffer = msi_dup_property( package, szPropKeys[i] );
3758 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3763 msi_free(productid);
3766 return ERROR_SUCCESS;
3770 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3774 package->script->InWhatSequence |= SEQUENCE_EXEC;
3775 rc = ACTION_ProcessExecSequence(package,FALSE);
3781 * Code based off of code located here
3782 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3784 * Using string index 4 (full font name) instead of 1 (family name)
3786 static LPWSTR load_ttfname_from(LPCWSTR filename)
3792 typedef struct _tagTT_OFFSET_TABLE{
3793 USHORT uMajorVersion;
3794 USHORT uMinorVersion;
3795 USHORT uNumOfTables;
3796 USHORT uSearchRange;
3797 USHORT uEntrySelector;
3801 typedef struct _tagTT_TABLE_DIRECTORY{
3802 char szTag[4]; /* table name */
3803 ULONG uCheckSum; /* Check sum */
3804 ULONG uOffset; /* Offset from beginning of file */
3805 ULONG uLength; /* length of the table in bytes */
3806 }TT_TABLE_DIRECTORY;
3808 typedef struct _tagTT_NAME_TABLE_HEADER{
3809 USHORT uFSelector; /* format selector. Always 0 */
3810 USHORT uNRCount; /* Name Records count */
3811 USHORT uStorageOffset; /* Offset for strings storage,
3812 * from start of the table */
3813 }TT_NAME_TABLE_HEADER;
3815 typedef struct _tagTT_NAME_RECORD{
3820 USHORT uStringLength;
3821 USHORT uStringOffset; /* from start of storage area */
3824 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3825 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3827 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3828 FILE_ATTRIBUTE_NORMAL, 0 );
3829 if (handle != INVALID_HANDLE_VALUE)
3831 TT_TABLE_DIRECTORY tblDir;
3832 BOOL bFound = FALSE;
3833 TT_OFFSET_TABLE ttOffsetTable;
3836 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3837 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3838 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3839 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3841 if (ttOffsetTable.uMajorVersion != 1 ||
3842 ttOffsetTable.uMinorVersion != 0)
3845 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3847 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3848 if (strncmp(tblDir.szTag,"name",4)==0)
3851 tblDir.uLength = SWAPLONG(tblDir.uLength);
3852 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3859 TT_NAME_TABLE_HEADER ttNTHeader;
3860 TT_NAME_RECORD ttRecord;
3862 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3863 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3866 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3867 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3869 for(i=0; i<ttNTHeader.uNRCount; i++)
3871 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3872 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3873 /* 4 is the Full Font Name */
3874 if(ttRecord.uNameID == 4)
3878 static LPCSTR tt = " (TrueType)";
3880 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3881 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3882 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3883 SetFilePointer(handle, tblDir.uOffset +
3884 ttRecord.uStringOffset +
3885 ttNTHeader.uStorageOffset,
3887 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3888 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3889 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3890 if (strlen(buf) > 0)
3893 ret = strdupAtoW(buf);
3899 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3903 CloseHandle(handle);
3906 ERR("Unable to open font file %s\n", debugstr_w(filename));
3908 TRACE("Returning fontname %s\n",debugstr_w(ret));
3912 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3914 MSIPACKAGE *package = (MSIPACKAGE*)param;
3918 static const WCHAR regfont1[] =
3919 {'S','o','f','t','w','a','r','e','\\',
3920 'M','i','c','r','o','s','o','f','t','\\',
3921 'W','i','n','d','o','w','s',' ','N','T','\\',
3922 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3923 'F','o','n','t','s',0};
3924 static const WCHAR regfont2[] =
3925 {'S','o','f','t','w','a','r','e','\\',
3926 'M','i','c','r','o','s','o','f','t','\\',
3927 'W','i','n','d','o','w','s','\\',
3928 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3929 'F','o','n','t','s',0};
3933 filename = MSI_RecordGetString( row, 1 );
3934 file = get_loaded_file( package, filename );
3937 ERR("Unable to load file\n");
3938 return ERROR_SUCCESS;
3941 /* check to make sure that component is installed */
3942 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3944 TRACE("Skipping: Component not scheduled for install\n");
3945 return ERROR_SUCCESS;
3948 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3949 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3951 if (MSI_RecordIsNull(row,2))
3952 name = load_ttfname_from( file->TargetPath );
3954 name = msi_dup_record_field(row,2);
3958 msi_reg_set_val_str( hkey1, name, file->FileName );
3959 msi_reg_set_val_str( hkey2, name, file->FileName );
3965 return ERROR_SUCCESS;
3968 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
3972 static const WCHAR ExecSeqQuery[] =
3973 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3974 '`','F','o','n','t','`',0};
3976 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3977 if (rc != ERROR_SUCCESS)
3979 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
3980 return ERROR_SUCCESS;
3983 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
3984 msiobj_release(&view->hdr);
3986 return ERROR_SUCCESS;
3989 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3991 MSIPACKAGE *package = (MSIPACKAGE*)param;
3992 LPCWSTR compgroupid=NULL;
3993 LPCWSTR feature=NULL;
3994 LPCWSTR text = NULL;
3995 LPCWSTR qualifier = NULL;
3996 LPCWSTR component = NULL;
3997 LPWSTR advertise = NULL;
3998 LPWSTR output = NULL;
4000 UINT rc = ERROR_SUCCESS;
4004 component = MSI_RecordGetString(rec,3);
4005 comp = get_loaded_component(package,component);
4007 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4008 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4009 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4011 TRACE("Skipping: Component %s not scheduled for install\n",
4012 debugstr_w(component));
4014 return ERROR_SUCCESS;
4017 compgroupid = MSI_RecordGetString(rec,1);
4019 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4020 if (rc != ERROR_SUCCESS)
4023 text = MSI_RecordGetString(rec,4);
4024 qualifier = MSI_RecordGetString(rec,2);
4025 feature = MSI_RecordGetString(rec,5);
4027 advertise = create_component_advertise_string(package, comp, feature);
4029 sz = strlenW(advertise);
4032 sz += lstrlenW(text);
4035 sz *= sizeof(WCHAR);
4037 output = msi_alloc(sz);
4038 memset(output,0,sz);
4039 strcpyW(output,advertise);
4040 msi_free(advertise);
4043 strcatW(output,text);
4045 msi_reg_set_val_multi_str( hkey, qualifier, output );
4055 * At present I am ignorning the advertised components part of this and only
4056 * focusing on the qualified component sets
4058 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4062 static const WCHAR ExecSeqQuery[] =
4063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4064 '`','P','u','b','l','i','s','h',
4065 'C','o','m','p','o','n','e','n','t','`',0};
4067 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4068 if (rc != ERROR_SUCCESS)
4069 return ERROR_SUCCESS;
4071 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4072 msiobj_release(&view->hdr);
4077 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4078 LPCSTR action, LPCWSTR table )
4080 static const WCHAR query[] = {
4081 'S','E','L','E','C','T',' ','*',' ',
4082 'F','R','O','M',' ','`','%','s','`',0 };
4083 MSIQUERY *view = NULL;
4087 r = MSI_OpenQuery( package->db, &view, query, table );
4088 if (r == ERROR_SUCCESS)
4090 r = MSI_IterateRecords(view, &count, NULL, package);
4091 msiobj_release(&view->hdr);
4095 FIXME("%s -> %lu ignored %s table values\n",
4096 action, count, debugstr_w(table));
4098 return ERROR_SUCCESS;
4101 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4103 TRACE("%p\n", package);
4104 return ERROR_SUCCESS;
4107 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4109 static const WCHAR table[] =
4110 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4111 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4114 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4116 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4117 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4120 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4122 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4123 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4126 static UINT ACTION_BindImage( MSIPACKAGE *package )
4128 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4129 return msi_unimplemented_action_stub( package, "BindImage", table );
4132 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4134 static const WCHAR table[] = {
4135 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4136 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4139 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4141 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4142 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4145 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4147 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4148 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4151 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4153 static const WCHAR table[] = {
4154 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4155 return msi_unimplemented_action_stub( package, "InstallServices", table );
4158 static UINT ACTION_StartServices( MSIPACKAGE *package )
4160 static const WCHAR table[] = {
4161 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4162 return msi_unimplemented_action_stub( package, "StartServices", table );
4165 static UINT ACTION_StopServices( MSIPACKAGE *package )
4167 static const WCHAR table[] = {
4168 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4169 return msi_unimplemented_action_stub( package, "StopServices", table );
4172 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4174 static const WCHAR table[] = {
4175 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4176 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4179 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4181 static const WCHAR table[] = {
4182 'E','n','v','i','r','o','n','m','e','n','t',0 };
4183 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4186 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4188 static const WCHAR table[] = {
4189 'E','n','v','i','r','o','n','m','e','n','t',0 };
4190 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4193 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4195 static const WCHAR table[] = {
4196 'M','s','i','A','s','s','e','m','b','l','y',0 };
4197 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4200 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4202 static const WCHAR table[] = {
4203 'M','s','i','A','s','s','e','m','b','l','y',0 };
4204 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4207 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4209 static const WCHAR table[] = { 'F','o','n','t',0 };
4210 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4213 static struct _actions StandardActions[] = {
4214 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4215 { szAppSearch, ACTION_AppSearch },
4216 { szBindImage, ACTION_BindImage },
4217 { szCCPSearch, NULL},
4218 { szCostFinalize, ACTION_CostFinalize },
4219 { szCostInitialize, ACTION_CostInitialize },
4220 { szCreateFolders, ACTION_CreateFolders },
4221 { szCreateShortcuts, ACTION_CreateShortcuts },
4222 { szDeleteServices, ACTION_DeleteServices },
4223 { szDisableRollback, NULL},
4224 { szDuplicateFiles, ACTION_DuplicateFiles },
4225 { szExecuteAction, ACTION_ExecuteAction },
4226 { szFileCost, ACTION_FileCost },
4227 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4228 { szForceReboot, ACTION_ForceReboot },
4229 { szInstallAdminPackage, NULL},
4230 { szInstallExecute, ACTION_InstallExecute },
4231 { szInstallExecuteAgain, ACTION_InstallExecute },
4232 { szInstallFiles, ACTION_InstallFiles},
4233 { szInstallFinalize, ACTION_InstallFinalize },
4234 { szInstallInitialize, ACTION_InstallInitialize },
4235 { szInstallSFPCatalogFile, NULL},
4236 { szInstallValidate, ACTION_InstallValidate },
4237 { szIsolateComponents, ACTION_IsolateComponents },
4238 { szLaunchConditions, ACTION_LaunchConditions },
4239 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4240 { szMoveFiles, ACTION_MoveFiles },
4241 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4242 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4243 { szInstallODBC, NULL},
4244 { szInstallServices, ACTION_InstallServices },
4245 { szPatchFiles, ACTION_PatchFiles },
4246 { szProcessComponents, ACTION_ProcessComponents },
4247 { szPublishComponents, ACTION_PublishComponents },
4248 { szPublishFeatures, ACTION_PublishFeatures },
4249 { szPublishProduct, ACTION_PublishProduct },
4250 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4251 { szRegisterComPlus, NULL},
4252 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4253 { szRegisterFonts, ACTION_RegisterFonts },
4254 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4255 { szRegisterProduct, ACTION_RegisterProduct },
4256 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4257 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4258 { szRegisterUser, ACTION_RegisterUser},
4259 { szRemoveDuplicateFiles, NULL},
4260 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4261 { szRemoveExistingProducts, NULL},
4262 { szRemoveFiles, ACTION_RemoveFiles},
4263 { szRemoveFolders, NULL},
4264 { szRemoveIniValues, ACTION_RemoveIniValues },
4265 { szRemoveODBC, NULL},
4266 { szRemoveRegistryValues, NULL},
4267 { szRemoveShortcuts, NULL},
4268 { szResolveSource, ACTION_ResolveSource},
4269 { szRMCCPSearch, NULL},
4270 { szScheduleReboot, NULL},
4271 { szSelfRegModules, ACTION_SelfRegModules },
4272 { szSelfUnregModules, ACTION_SelfUnregModules },
4273 { szSetODBCFolders, NULL},
4274 { szStartServices, ACTION_StartServices },
4275 { szStopServices, ACTION_StopServices },
4276 { szUnpublishComponents, NULL},
4277 { szUnpublishFeatures, NULL},
4278 { szUnregisterClassInfo, NULL},
4279 { szUnregisterComPlus, NULL},
4280 { szUnregisterExtensionInfo, NULL},
4281 { szUnregisterFonts, ACTION_UnregisterFonts },
4282 { szUnregisterMIMEInfo, NULL},
4283 { szUnregisterProgIdInfo, NULL},
4284 { szUnregisterTypeLibraries, NULL},
4285 { szValidateProductID, NULL},
4286 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4287 { szWriteIniValues, ACTION_WriteIniValues },
4288 { szWriteRegistryValues, ACTION_WriteRegistryValues},