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 #define LPCTSTR LPCWSTR
51 WINE_DEFAULT_DEBUG_CHANNEL(msi);
56 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
57 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
58 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
61 * consts and values used
63 static const WCHAR c_colon[] = {'C',':','\\',0};
65 const static WCHAR szCreateFolders[] =
66 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
67 const static WCHAR szCostFinalize[] =
68 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
69 const WCHAR szInstallFiles[] =
70 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
71 const WCHAR szDuplicateFiles[] =
72 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
73 const static WCHAR szWriteRegistryValues[] =
74 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
75 'V','a','l','u','e','s',0};
76 const static WCHAR szCostInitialize[] =
77 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
78 const static WCHAR szFileCost[] =
79 {'F','i','l','e','C','o','s','t',0};
80 const static WCHAR szInstallInitialize[] =
81 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
82 const static WCHAR szInstallValidate[] =
83 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
84 const static WCHAR szLaunchConditions[] =
85 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
86 const static WCHAR szProcessComponents[] =
87 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
88 const static WCHAR szRegisterTypeLibraries[] =
89 {'R','e','g','i','s','t','e','r','T','y','p','e',
90 'L','i','b','r','a','r','i','e','s',0};
91 const WCHAR szRegisterClassInfo[] =
92 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
93 const WCHAR szRegisterProgIdInfo[] =
94 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
95 const static WCHAR szCreateShortcuts[] =
96 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
97 const static WCHAR szPublishProduct[] =
98 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
99 const static WCHAR szWriteIniValues[] =
100 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
101 const static WCHAR szSelfRegModules[] =
102 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
103 const static WCHAR szPublishFeatures[] =
104 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
105 const static WCHAR szRegisterProduct[] =
106 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
107 const static WCHAR szInstallExecute[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
109 const static WCHAR szInstallExecuteAgain[] =
110 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
111 'A','g','a','i','n',0};
112 const static WCHAR szInstallFinalize[] =
113 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
114 const static WCHAR szForceReboot[] =
115 {'F','o','r','c','e','R','e','b','o','o','t',0};
116 const static WCHAR szResolveSource[] =
117 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
118 const WCHAR szAppSearch[] =
119 {'A','p','p','S','e','a','r','c','h',0};
120 const static WCHAR szAllocateRegistrySpace[] =
121 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
122 'S','p','a','c','e',0};
123 const static WCHAR szBindImage[] =
124 {'B','i','n','d','I','m','a','g','e',0};
125 const static WCHAR szCCPSearch[] =
126 {'C','C','P','S','e','a','r','c','h',0};
127 const static WCHAR szDeleteServices[] =
128 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
129 const static WCHAR szDisableRollback[] =
130 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
131 const static WCHAR szExecuteAction[] =
132 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
133 const WCHAR szFindRelatedProducts[] =
134 {'F','i','n','d','R','e','l','a','t','e','d',
135 'P','r','o','d','u','c','t','s',0};
136 const static WCHAR szInstallAdminPackage[] =
137 {'I','n','s','t','a','l','l','A','d','m','i','n',
138 'P','a','c','k','a','g','e',0};
139 const static WCHAR szInstallSFPCatalogFile[] =
140 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
142 const static WCHAR szIsolateComponents[] =
143 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
144 const WCHAR szMigrateFeatureStates[] =
145 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
146 'S','t','a','t','e','s',0};
147 const WCHAR szMoveFiles[] =
148 {'M','o','v','e','F','i','l','e','s',0};
149 const static WCHAR szMsiPublishAssemblies[] =
150 {'M','s','i','P','u','b','l','i','s','h',
151 'A','s','s','e','m','b','l','i','e','s',0};
152 const static WCHAR szMsiUnpublishAssemblies[] =
153 {'M','s','i','U','n','p','u','b','l','i','s','h',
154 'A','s','s','e','m','b','l','i','e','s',0};
155 const static WCHAR szInstallODBC[] =
156 {'I','n','s','t','a','l','l','O','D','B','C',0};
157 const static WCHAR szInstallServices[] =
158 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
159 const WCHAR szPatchFiles[] =
160 {'P','a','t','c','h','F','i','l','e','s',0};
161 const static WCHAR szPublishComponents[] =
162 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
163 const static WCHAR szRegisterComPlus[] =
164 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
165 const WCHAR szRegisterExtensionInfo[] =
166 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
168 const static WCHAR szRegisterFonts[] =
169 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
170 const WCHAR szRegisterMIMEInfo[] =
171 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
172 const static WCHAR szRegisterUser[] =
173 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
174 const WCHAR szRemoveDuplicateFiles[] =
175 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
176 'F','i','l','e','s',0};
177 const static WCHAR szRemoveEnvironmentStrings[] =
178 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
179 'S','t','r','i','n','g','s',0};
180 const WCHAR szRemoveExistingProducts[] =
181 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
182 'P','r','o','d','u','c','t','s',0};
183 const WCHAR szRemoveFiles[] =
184 {'R','e','m','o','v','e','F','i','l','e','s',0};
185 const static WCHAR szRemoveFolders[] =
186 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
187 const static WCHAR szRemoveIniValues[] =
188 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
189 const static WCHAR szRemoveODBC[] =
190 {'R','e','m','o','v','e','O','D','B','C',0};
191 const static WCHAR szRemoveRegistryValues[] =
192 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
193 'V','a','l','u','e','s',0};
194 const static WCHAR szRemoveShortcuts[] =
195 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
196 const static WCHAR szRMCCPSearch[] =
197 {'R','M','C','C','P','S','e','a','r','c','h',0};
198 const static WCHAR szScheduleReboot[] =
199 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
200 const static WCHAR szSelfUnregModules[] =
201 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
202 const static WCHAR szSetODBCFolders[] =
203 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
204 const static WCHAR szStartServices[] =
205 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
206 const static WCHAR szStopServices[] =
207 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
208 const static WCHAR szUnpublishComponents[] =
209 {'U','n','p','u','b','l','i','s','h',
210 'C','o','m','p','o','n','e','n','t','s',0};
211 const static WCHAR szUnpublishFeatures[] =
212 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
213 const WCHAR szUnregisterClassInfo[] =
214 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
216 const static WCHAR szUnregisterComPlus[] =
217 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
218 const WCHAR szUnregisterExtensionInfo[] =
219 {'U','n','r','e','g','i','s','t','e','r',
220 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
221 const static WCHAR szUnregisterFonts[] =
222 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
223 const WCHAR szUnregisterMIMEInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
225 const WCHAR szUnregisterProgIdInfo[] =
226 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
228 const static WCHAR szUnregisterTypeLibraries[] =
229 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
230 'L','i','b','r','a','r','i','e','s',0};
231 const static WCHAR szValidateProductID[] =
232 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
233 const static WCHAR szWriteEnvironmentStrings[] =
234 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
235 'S','t','r','i','n','g','s',0};
237 /* action handlers */
238 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
242 STANDARDACTIONHANDLER handler;
245 static struct _actions StandardActions[];
248 /********************************************************
250 ********************************************************/
252 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
254 static const WCHAR szActionText[] =
255 {'A','c','t','i','o','n','T','e','x','t',0};
258 row = MSI_CreateRecord(1);
259 MSI_RecordSetStringW(row,1,action);
260 ControlEvent_FireSubscribedEvent(package,szActionText, row);
261 msiobj_release(&row->hdr);
264 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
266 static const WCHAR template_s[]=
267 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
269 static const WCHAR format[] =
270 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
271 static const WCHAR Query_t[] =
272 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
273 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
274 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
275 ' ','\'','%','s','\'',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 row = MSI_QueryGetRecord( package->db, Query_t, action );
288 ActionText = MSI_RecordGetString(row,2);
289 deformat_string(package, ActionText, &deformated);
291 sprintfW(message,template_s,timet,action,deformated);
292 ce_actiontext(package, deformated);
293 msiobj_release(&row->hdr);
295 row = MSI_CreateRecord(1);
296 MSI_RecordSetStringW(row,1,message);
298 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
299 msiobj_release(&row->hdr);
300 msi_free(deformated);
303 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
307 static const WCHAR template_s[]=
308 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
310 static const WCHAR template_e[]=
311 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
312 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
314 static const WCHAR format[] =
315 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
319 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
321 sprintfW(message,template_s,timet,action);
323 sprintfW(message,template_e,timet,action,rc);
325 row = MSI_CreateRecord(1);
326 MSI_RecordSetStringW(row,1,message);
328 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
329 msiobj_release(&row->hdr);
332 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
334 LPWSTR str = msi_dup_property( package, prop );
335 int val = str ? atoiW( str ) : def;
340 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
345 LPWSTR prop = NULL, val = NULL;
348 return ERROR_SUCCESS;
360 TRACE("Looking at %s\n",debugstr_w(ptr));
362 ptr2 = strchrW(ptr,'=');
365 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
372 prop = msi_alloc((len+1)*sizeof(WCHAR));
373 memcpy(prop,ptr,len*sizeof(WCHAR));
379 while (*ptr && (quote || (!quote && *ptr!=' ')))
392 val = msi_alloc((len+1)*sizeof(WCHAR));
393 memcpy(val,ptr2,len*sizeof(WCHAR));
396 if (lstrlenW(prop) > 0)
398 TRACE("Found commandline property (%s) = (%s)\n",
399 debugstr_w(prop), debugstr_w(val));
400 MSI_SetPropertyW(package,prop,val);
406 return ERROR_SUCCESS;
410 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
412 LPWSTR p, *ret = NULL;
418 /* count the number of substrings */
419 for ( p = (LPWSTR)str, count = 0; p; count++ )
421 p = strchrW( p, sep );
426 /* allocate space for an array of substring pointers and the substrings */
427 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
428 (lstrlenW(str)+1) * sizeof(WCHAR) );
432 /* copy the string and set the pointers */
433 p = (LPWSTR) &ret[count+1];
435 for( count = 0; (ret[count] = p); count++ )
437 p = strchrW( p, sep );
445 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
446 MSIDATABASE *patch_db, LPCWSTR name )
448 UINT ret = ERROR_FUNCTION_FAILED;
449 IStorage *stg = NULL;
452 TRACE("%p %s\n", package, debugstr_w(name) );
456 ERR("expected a colon in %s\n", debugstr_w(name));
457 return ERROR_FUNCTION_FAILED;
460 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
463 ret = msi_table_apply_transform( package->db, stg );
464 IStorage_Release( stg );
468 ERR("failed to open substorage %s\n", debugstr_w(name));
473 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
475 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
476 LPWSTR guid_list, *guids, product_id;
477 UINT i, ret = ERROR_FUNCTION_FAILED;
479 product_id = msi_dup_property( package, szProdID );
482 /* FIXME: the property ProductID should be written into the DB somewhere */
483 ERR("no product ID to check\n");
484 return ERROR_SUCCESS;
487 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
488 guids = msi_split_string( guid_list, ';' );
489 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
491 if (!lstrcmpW( guids[i], product_id ))
495 msi_free( guid_list );
496 msi_free( product_id );
501 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
504 LPWSTR str, *substorage;
505 UINT i, r = ERROR_SUCCESS;
507 si = MSI_GetSummaryInformationW( patch_db, 0 );
509 return ERROR_FUNCTION_FAILED;
511 msi_check_patch_applicable( package, si );
513 /* enumerate the substorage */
514 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
515 substorage = msi_split_string( str, ';' );
516 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
517 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
518 msi_free( substorage );
521 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
523 msiobj_release( &si->hdr );
528 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
530 MSIDATABASE *patch_db = NULL;
533 TRACE("%p %s\n", package, debugstr_w( file ) );
536 * We probably want to make sure we only open a patch collection here.
537 * Patch collections (.msp) and databases (.msi) have different GUIDs
538 * but currently MSI_OpenDatabaseW will accept both.
540 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
541 if ( r != ERROR_SUCCESS )
543 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
547 msi_parse_patch_summary( package, patch_db );
548 msiobj_release( &patch_db->hdr );
550 return ERROR_SUCCESS;
553 /* get the PATCH property, and apply all the patches it specifies */
554 static UINT msi_apply_patches( MSIPACKAGE *package )
556 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
557 LPWSTR patch_list, *patches;
558 UINT i, r = ERROR_SUCCESS;
560 patch_list = msi_dup_property( package, szPatch );
562 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
564 patches = msi_split_string( patch_list, ';' );
565 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
566 r = msi_apply_patch_package( package, patches[i] );
569 msi_free( patch_list );
574 /****************************************************
575 * TOP level entry points
576 *****************************************************/
578 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
579 LPCWSTR szCommandLine )
583 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
584 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
585 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
587 MSI_SetPropertyW(package, szAction, szInstall);
589 package->script = msi_alloc(sizeof(MSISCRIPT));
590 memset(package->script,0,sizeof(MSISCRIPT));
592 package->script->InWhatSequence = SEQUENCE_INSTALL;
596 LPWSTR p, check, path;
598 package->PackagePath = strdupW(szPackagePath);
599 path = strdupW(szPackagePath);
600 p = strrchrW(path,'\\');
609 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
610 GetCurrentDirectoryW(MAX_PATH,path);
614 check = msi_dup_property( package, cszSourceDir );
616 MSI_SetPropertyW(package, cszSourceDir, path);
621 msi_parse_command_line( package, szCommandLine );
623 msi_apply_patches( package );
625 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
627 package->script->InWhatSequence |= SEQUENCE_UI;
628 rc = ACTION_ProcessUISequence(package);
630 if (rc == ERROR_SUCCESS)
632 package->script->InWhatSequence |= SEQUENCE_EXEC;
633 rc = ACTION_ProcessExecSequence(package,TRUE);
637 rc = ACTION_ProcessExecSequence(package,FALSE);
641 /* install was halted but should be considered a success */
645 package->script->CurrentlyScripting= FALSE;
647 /* process the ending type action */
648 if (rc == ERROR_SUCCESS)
649 ACTION_PerformActionSequence(package,-1,ui);
650 else if (rc == ERROR_INSTALL_USEREXIT)
651 ACTION_PerformActionSequence(package,-2,ui);
652 else if (rc == ERROR_INSTALL_SUSPEND)
653 ACTION_PerformActionSequence(package,-4,ui);
655 ACTION_PerformActionSequence(package,-3,ui);
657 /* finish up running custom actions */
658 ACTION_FinishCustomActions(package);
663 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
665 UINT rc = ERROR_SUCCESS;
667 static const WCHAR ExecSeqQuery[] =
668 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
669 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
670 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
671 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
673 static const WCHAR UISeqQuery[] =
674 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
675 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
676 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
677 ' ', '=',' ','%','i',0};
680 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
682 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
686 LPCWSTR action, cond;
688 TRACE("Running the actions\n");
690 /* check conditions */
691 cond = MSI_RecordGetString(row,2);
694 /* this is a hack to skip errors in the condition code */
695 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
699 action = MSI_RecordGetString(row,1);
702 ERR("failed to fetch action\n");
703 rc = ERROR_FUNCTION_FAILED;
708 rc = ACTION_PerformUIAction(package,action);
710 rc = ACTION_PerformAction(package,action,FALSE);
712 msiobj_release(&row->hdr);
723 } iterate_action_param;
725 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
727 iterate_action_param *iap= (iterate_action_param*)param;
729 LPCWSTR cond, action;
731 action = MSI_RecordGetString(row,1);
734 ERR("Error is retrieving action name\n");
735 return ERROR_FUNCTION_FAILED;
738 /* check conditions */
739 cond = MSI_RecordGetString(row,2);
742 /* this is a hack to skip errors in the condition code */
743 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
745 TRACE("Skipping action: %s (condition is false)\n",
747 return ERROR_SUCCESS;
752 rc = ACTION_PerformUIAction(iap->package,action);
754 rc = ACTION_PerformAction(iap->package,action,FALSE);
756 msi_dialog_check_messages( NULL );
758 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
759 rc = iap->package->CurrentInstallState;
761 if (rc == ERROR_FUNCTION_NOT_CALLED)
764 if (rc != ERROR_SUCCESS)
765 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
770 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
774 static const WCHAR query[] =
775 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
777 ' ','W','H','E','R','E',' ',
778 '`','S','e','q','u','e','n','c','e','`',' ',
779 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
780 '`','S','e','q','u','e','n','c','e','`',0};
781 iterate_action_param iap;
784 * FIXME: probably should be checking UILevel in the
785 * ACTION_PerformUIAction/ACTION_PerformAction
786 * rather than saving the UI level here. Those
787 * two functions can be merged too.
789 iap.package = package;
792 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
794 r = MSI_OpenQuery( package->db, &view, query, szTable );
795 if (r == ERROR_SUCCESS)
797 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
798 msiobj_release(&view->hdr);
804 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
808 static const WCHAR ExecSeqQuery[] =
809 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
810 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
811 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
812 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
813 'O','R','D','E','R',' ', 'B','Y',' ',
814 '`','S','e','q','u','e','n','c','e','`',0 };
816 static const WCHAR IVQuery[] =
817 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
818 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
819 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
820 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
821 ' ','\'', 'I','n','s','t','a','l','l',
822 'V','a','l','i','d','a','t','e','\'', 0};
824 iterate_action_param iap;
826 iap.package = package;
829 if (package->script->ExecuteSequenceRun)
831 TRACE("Execute Sequence already Run\n");
832 return ERROR_SUCCESS;
835 package->script->ExecuteSequenceRun = TRUE;
837 /* get the sequence number */
840 row = MSI_QueryGetRecord(package->db, IVQuery);
842 return ERROR_FUNCTION_FAILED;
843 seq = MSI_RecordGetInteger(row,1);
844 msiobj_release(&row->hdr);
847 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
848 if (rc == ERROR_SUCCESS)
850 TRACE("Running the actions\n");
852 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
853 msiobj_release(&view->hdr);
859 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
863 static const WCHAR ExecSeqQuery [] =
864 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
865 '`','I','n','s','t','a','l','l',
866 'U','I','S','e','q','u','e','n','c','e','`',
867 ' ','W','H','E','R','E',' ',
868 '`','S','e','q','u','e','n','c','e','`',' ',
869 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
870 '`','S','e','q','u','e','n','c','e','`',0};
871 iterate_action_param iap;
873 iap.package = package;
876 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
878 if (rc == ERROR_SUCCESS)
880 TRACE("Running the actions \n");
882 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
883 msiobj_release(&view->hdr);
889 /********************************************************
890 * ACTION helper functions and functions that perform the actions
891 *******************************************************/
892 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
893 UINT* rc, BOOL force )
899 if (!run && !package->script->CurrentlyScripting)
904 if (strcmpW(action,szInstallFinalize) == 0 ||
905 strcmpW(action,szInstallExecute) == 0 ||
906 strcmpW(action,szInstallExecuteAgain) == 0)
911 while (StandardActions[i].action != NULL)
913 if (strcmpW(StandardActions[i].action, action)==0)
917 ui_actioninfo(package, action, TRUE, 0);
918 *rc = schedule_action(package,INSTALL_SCRIPT,action);
919 ui_actioninfo(package, action, FALSE, *rc);
923 ui_actionstart(package, action);
924 if (StandardActions[i].handler)
926 *rc = StandardActions[i].handler(package);
930 FIXME("unhandled standard action %s\n",debugstr_w(action));
942 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
943 UINT* rc, BOOL force )
948 arc = ACTION_CustomAction(package,action, force);
950 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
959 * A lot of actions are really important even if they don't do anything
960 * explicit... Lots of properties are set at the beginning of the installation
961 * CostFinalize does a bunch of work to translate the directories and such
963 * But until I get write access to the database that is hard, so I am going to
964 * hack it to see if I can get something to run.
966 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
968 UINT rc = ERROR_SUCCESS;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc, force);
976 handled = ACTION_HandleCustomAction(package, action, &rc, force);
980 FIXME("unhandled msi action %s\n",debugstr_w(action));
981 rc = ERROR_FUNCTION_NOT_CALLED;
987 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
989 UINT rc = ERROR_SUCCESS;
990 BOOL handled = FALSE;
992 TRACE("Performing action (%s)\n",debugstr_w(action));
994 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
997 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
999 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1004 FIXME("unhandled msi action %s\n",debugstr_w(action));
1005 rc = ERROR_FUNCTION_NOT_CALLED;
1013 * Actual Action Handlers
1016 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1018 MSIPACKAGE *package = (MSIPACKAGE*)param;
1024 dir = MSI_RecordGetString(row,1);
1027 ERR("Unable to get folder id \n");
1028 return ERROR_SUCCESS;
1031 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1034 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1035 return ERROR_SUCCESS;
1038 TRACE("Folder is %s\n",debugstr_w(full_path));
1041 uirow = MSI_CreateRecord(1);
1042 MSI_RecordSetStringW(uirow,1,full_path);
1043 ui_actiondata(package,szCreateFolders,uirow);
1044 msiobj_release( &uirow->hdr );
1046 if (folder->State == 0)
1047 create_full_pathW(full_path);
1051 msi_free(full_path);
1052 return ERROR_SUCCESS;
1055 /* FIXME: probably should merge this with the above function */
1056 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1058 UINT rc = ERROR_SUCCESS;
1060 LPWSTR install_path;
1062 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1064 return ERROR_FUNCTION_FAILED;
1066 /* create the path */
1067 if (folder->State == 0)
1069 create_full_pathW(install_path);
1072 msi_free(install_path);
1077 UINT msi_create_component_directories( MSIPACKAGE *package )
1081 /* create all the folders required by the components are going to install */
1082 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1084 if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
1086 msi_create_directory( package, comp->Directory );
1089 return ERROR_SUCCESS;
1093 * Also we cannot enable/disable components either, so for now I am just going
1094 * to do all the directories for all the components.
1096 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1098 static const WCHAR ExecSeqQuery[] =
1099 {'S','E','L','E','C','T',' ',
1100 '`','D','i','r','e','c','t','o','r','y','_','`',
1101 ' ','F','R','O','M',' ',
1102 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1106 /* create all the empty folders specified in the CreateFolder table */
1107 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1108 if (rc != ERROR_SUCCESS)
1109 return ERROR_SUCCESS;
1111 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1112 msiobj_release(&view->hdr);
1114 msi_create_component_directories( package );
1119 static MSICOMPONENT* load_component( MSIRECORD * row )
1123 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1127 /* fill in the data */
1128 comp->Component = msi_dup_record_field( row, 1 );
1130 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1132 comp->ComponentId = msi_dup_record_field( row, 2 );
1133 comp->Directory = msi_dup_record_field( row, 3 );
1134 comp->Attributes = MSI_RecordGetInteger(row,4);
1135 comp->Condition = msi_dup_record_field( row, 5 );
1136 comp->KeyPath = msi_dup_record_field( row, 6 );
1138 comp->Installed = INSTALLSTATE_ABSENT;
1139 comp->Action = INSTALLSTATE_UNKNOWN;
1140 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1142 comp->Enabled = TRUE;
1148 MSIPACKAGE *package;
1149 MSIFEATURE *feature;
1152 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1156 cl = msi_alloc( sizeof (*cl) );
1158 return ERROR_NOT_ENOUGH_MEMORY;
1159 cl->component = comp;
1160 list_add_tail( &feature->Components, &cl->entry );
1162 return ERROR_SUCCESS;
1165 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1167 _ilfs* ilfs= (_ilfs*)param;
1168 MSIPACKAGE *package = ilfs->package;
1169 MSIFEATURE *feature = ilfs->feature;
1172 comp = load_component( row );
1174 return ERROR_FUNCTION_FAILED;
1176 list_add_tail( &package->components, &comp->entry );
1177 add_feature_component( feature, comp );
1179 TRACE("Loaded new component %p\n", comp);
1181 return ERROR_SUCCESS;
1184 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1186 _ilfs* ilfs= (_ilfs*)param;
1191 static const WCHAR Query[] =
1192 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1193 '`','C','o','m','p','o','n','e','n','t','`',' ',
1194 'W','H','E','R','E',' ',
1195 '`','C','o','m','p','o','n','e','n','t','`',' ',
1196 '=','\'','%','s','\'',0};
1198 component = MSI_RecordGetString(row,1);
1200 /* check to see if the component is already loaded */
1201 comp = get_loaded_component( ilfs->package, component );
1204 TRACE("Component %s already loaded\n", debugstr_w(component) );
1205 add_feature_component( ilfs->feature, comp );
1206 return ERROR_SUCCESS;
1209 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1210 if (rc != ERROR_SUCCESS)
1211 return ERROR_SUCCESS;
1213 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1214 msiobj_release( &view->hdr );
1216 return ERROR_SUCCESS;
1219 static UINT load_feature(MSIRECORD * row, LPVOID param)
1221 MSIPACKAGE* package = (MSIPACKAGE*)param;
1222 MSIFEATURE* feature;
1223 static const WCHAR Query1[] =
1224 {'S','E','L','E','C','T',' ',
1225 '`','C','o','m','p','o','n','e','n','t','_','`',
1226 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1227 'C','o','m','p','o','n','e','n','t','s','`',' ',
1228 'W','H','E','R','E',' ',
1229 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1234 /* fill in the data */
1236 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1238 return ERROR_NOT_ENOUGH_MEMORY;
1240 list_init( &feature->Components );
1242 feature->Feature = msi_dup_record_field( row, 1 );
1244 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1246 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1247 feature->Title = msi_dup_record_field( row, 3 );
1248 feature->Description = msi_dup_record_field( row, 4 );
1250 if (!MSI_RecordIsNull(row,5))
1251 feature->Display = MSI_RecordGetInteger(row,5);
1253 feature->Level= MSI_RecordGetInteger(row,6);
1254 feature->Directory = msi_dup_record_field( row, 7 );
1255 feature->Attributes = MSI_RecordGetInteger(row,8);
1257 feature->Installed = INSTALLSTATE_ABSENT;
1258 feature->Action = INSTALLSTATE_UNKNOWN;
1259 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1261 list_add_tail( &package->features, &feature->entry );
1263 /* load feature components */
1265 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1266 if (rc != ERROR_SUCCESS)
1267 return ERROR_SUCCESS;
1269 ilfs.package = package;
1270 ilfs.feature = feature;
1272 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1273 msiobj_release(&view->hdr);
1275 return ERROR_SUCCESS;
1278 static UINT load_file(MSIRECORD *row, LPVOID param)
1280 MSIPACKAGE* package = (MSIPACKAGE*)param;
1284 /* fill in the data */
1286 file = msi_alloc_zero( sizeof (MSIFILE) );
1288 return ERROR_NOT_ENOUGH_MEMORY;
1290 file->File = msi_dup_record_field( row, 1 );
1292 component = MSI_RecordGetString( row, 2 );
1293 file->Component = get_loaded_component( package, component );
1295 if (!file->Component)
1296 ERR("Unfound Component %s\n",debugstr_w(component));
1298 file->FileName = msi_dup_record_field( row, 3 );
1299 reduce_to_longfilename( file->FileName );
1301 file->ShortName = msi_dup_record_field( row, 3 );
1302 reduce_to_shortfilename( file->ShortName );
1304 file->FileSize = MSI_RecordGetInteger( row, 4 );
1305 file->Version = msi_dup_record_field( row, 5 );
1306 file->Language = msi_dup_record_field( row, 6 );
1307 file->Attributes = MSI_RecordGetInteger( row, 7 );
1308 file->Sequence = MSI_RecordGetInteger( row, 8 );
1312 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1314 list_add_tail( &package->files, &file->entry );
1316 return ERROR_SUCCESS;
1319 static UINT load_all_files(MSIPACKAGE *package)
1323 static const WCHAR Query[] =
1324 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1325 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1326 '`','S','e','q','u','e','n','c','e','`', 0};
1329 return ERROR_INVALID_HANDLE;
1331 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1332 if (rc != ERROR_SUCCESS)
1333 return ERROR_SUCCESS;
1335 rc = MSI_IterateRecords(view, NULL, load_file, package);
1336 msiobj_release(&view->hdr);
1338 return ERROR_SUCCESS;
1343 * I am not doing any of the costing functionality yet.
1344 * Mostly looking at doing the Component and Feature loading
1346 * The native MSI does A LOT of modification to tables here. Mostly adding
1347 * a lot of temporary columns to the Feature and Component tables.
1349 * note: Native msi also tracks the short filename. But I am only going to
1350 * track the long ones. Also looking at this directory table
1351 * it appears that the directory table does not get the parents
1352 * resolved base on property only based on their entries in the
1355 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1359 static const WCHAR Query_all[] =
1360 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1361 '`','F','e','a','t','u','r','e','`',0};
1362 static const WCHAR szCosting[] =
1363 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1364 static const WCHAR szZero[] = { '0', 0 };
1368 MSI_GetPropertyW(package, szCosting, buffer, &sz);
1370 return ERROR_SUCCESS;
1372 MSI_SetPropertyW(package, szCosting, szZero);
1373 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1375 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1376 if (rc != ERROR_SUCCESS)
1379 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1380 msiobj_release(&view->hdr);
1382 load_all_files(package);
1384 return ERROR_SUCCESS;
1387 static UINT execute_script(MSIPACKAGE *package, UINT script )
1390 UINT rc = ERROR_SUCCESS;
1392 TRACE("Executing Script %i\n",script);
1394 for (i = 0; i < package->script->ActionCount[script]; i++)
1397 action = package->script->Actions[script][i];
1398 ui_actionstart(package, action);
1399 TRACE("Executing Action (%s)\n",debugstr_w(action));
1400 rc = ACTION_PerformAction(package, action, TRUE);
1401 msi_free(package->script->Actions[script][i]);
1402 if (rc != ERROR_SUCCESS)
1405 msi_free(package->script->Actions[script]);
1407 package->script->ActionCount[script] = 0;
1408 package->script->Actions[script] = NULL;
1412 static UINT ACTION_FileCost(MSIPACKAGE *package)
1414 return ERROR_SUCCESS;
1418 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1420 static const WCHAR Query[] =
1421 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1422 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1423 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1424 ' ','=',' ','\'','%','s','\'',
1426 LPWSTR ptargetdir, targetdir, srcdir;
1428 LPWSTR shortname = NULL;
1429 MSIRECORD * row = 0;
1432 TRACE("Looking for dir %s\n",debugstr_w(dir));
1434 folder = get_loaded_folder( package, dir );
1438 TRACE("Working to load %s\n",debugstr_w(dir));
1440 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1444 folder->Directory = strdupW(dir);
1446 row = MSI_QueryGetRecord(package->db, Query, dir);
1450 ptargetdir = targetdir = msi_dup_record_field(row,3);
1452 /* split src and target dir */
1453 if (strchrW(targetdir,':'))
1455 srcdir=strchrW(targetdir,':');
1462 /* for now only pick long filename versions */
1463 if (strchrW(targetdir,'|'))
1465 shortname = targetdir;
1466 targetdir = strchrW(targetdir,'|');
1470 /* for the sourcedir pick the short filename */
1471 if (srcdir && strchrW(srcdir,'|'))
1473 LPWSTR p = strchrW(srcdir,'|');
1477 /* now check for root dirs */
1478 if (targetdir[0] == '.' && targetdir[1] == 0)
1483 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1484 msi_free( folder->TargetDefault);
1485 folder->TargetDefault = strdupW(targetdir);
1489 folder->SourceDefault = strdupW(srcdir);
1491 folder->SourceDefault = strdupW(shortname);
1493 folder->SourceDefault = strdupW(targetdir);
1494 msi_free(ptargetdir);
1495 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1497 parent = MSI_RecordGetString(row,2);
1500 folder->Parent = load_folder( package, parent );
1501 if ( folder->Parent )
1502 TRACE("loaded parent %p %s\n", folder->Parent,
1503 debugstr_w(folder->Parent->Directory));
1505 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1508 folder->Property = msi_dup_property( package, dir );
1510 msiobj_release(&row->hdr);
1512 list_add_tail( &package->folders, &folder->entry );
1514 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1519 /* scan for and update current install states */
1520 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1523 MSIFEATURE *feature;
1525 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1528 res = MsiGetComponentPathW( package->ProductCode,
1529 comp->ComponentId, NULL, NULL);
1531 res = INSTALLSTATE_ABSENT;
1532 comp->Installed = res;
1535 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1538 INSTALLSTATE res = -10;
1540 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1542 comp= cl->component;
1545 res = comp->Installed;
1548 if (res == comp->Installed)
1551 if (res != comp->Installed)
1552 res = INSTALLSTATE_INCOMPLETE;
1555 feature->Installed = res;
1559 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1562 static const WCHAR all[]={'A','L','L',0};
1564 MSIFEATURE *feature;
1566 override = msi_dup_property( package, property );
1570 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1572 if (strcmpiW(override,all)==0)
1574 feature->ActionRequest= state;
1575 feature->Action = state;
1579 LPWSTR ptr = override;
1580 LPWSTR ptr2 = strchrW(override,',');
1584 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1585 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1587 feature->ActionRequest= state;
1588 feature->Action = state;
1594 ptr2 = strchrW(ptr,',');
1606 static UINT SetFeatureStates(MSIPACKAGE *package)
1609 static const WCHAR szlevel[] =
1610 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1611 static const WCHAR szAddLocal[] =
1612 {'A','D','D','L','O','C','A','L',0};
1613 static const WCHAR szRemove[] =
1614 {'R','E','M','O','V','E',0};
1615 BOOL override = FALSE;
1616 MSICOMPONENT* component;
1617 MSIFEATURE *feature;
1620 /* I do not know if this is where it should happen.. but */
1622 TRACE("Checking Install Level\n");
1624 install_level = msi_get_property_int( package, szlevel, 1 );
1626 /* ok hereis the _real_ rub
1627 * all these activation/deactivation things happen in order and things
1628 * later on the list override things earlier on the list.
1629 * 1) INSTALLLEVEL processing
1639 * 11) FILEADDDEFAULT
1640 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1641 * ignored for all the features. seems strange, especially since it is not
1642 * documented anywhere, but it is how it works.
1644 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1645 * REMOVE are the big ones, since we don't handle administrative installs
1648 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1649 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1655 BOOL feature_state = ((feature->Level > 0) &&
1656 (feature->Level <= install_level));
1658 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1660 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1662 feature->ActionRequest = INSTALLSTATE_SOURCE;
1663 feature->Action = INSTALLSTATE_SOURCE;
1665 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1667 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1668 feature->Action = INSTALLSTATE_ADVERTISED;
1672 feature->ActionRequest = INSTALLSTATE_LOCAL;
1673 feature->Action = INSTALLSTATE_LOCAL;
1680 /* set the Preselected Property */
1681 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1682 static const WCHAR szOne[] = { '1', 0 };
1684 MSI_SetPropertyW(package,szPreselected,szOne);
1688 * now we want to enable or disable components base on feature
1691 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1695 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1696 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1697 feature->ActionRequest);
1699 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1701 component = cl->component;
1703 if (!component->Enabled)
1705 component->Action = INSTALLSTATE_UNKNOWN;
1706 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1710 if (feature->Action == INSTALLSTATE_LOCAL)
1712 component->Action = INSTALLSTATE_LOCAL;
1713 component->ActionRequest = INSTALLSTATE_LOCAL;
1715 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1717 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1718 (component->Action == INSTALLSTATE_ABSENT) ||
1719 (component->Action == INSTALLSTATE_ADVERTISED))
1722 component->Action = INSTALLSTATE_SOURCE;
1723 component->ActionRequest = INSTALLSTATE_SOURCE;
1726 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1728 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1729 (component->Action == INSTALLSTATE_ABSENT))
1732 component->Action = INSTALLSTATE_ADVERTISED;
1733 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1736 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1738 if (component->Action == INSTALLSTATE_UNKNOWN)
1740 component->Action = INSTALLSTATE_ABSENT;
1741 component->ActionRequest = INSTALLSTATE_ABSENT;
1748 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1750 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1751 debugstr_w(component->Component), component->Installed,
1752 component->Action, component->ActionRequest);
1756 return ERROR_SUCCESS;
1759 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1761 MSIPACKAGE *package = (MSIPACKAGE*)param;
1765 name = MSI_RecordGetString(row,1);
1767 /* This helper function now does ALL the work */
1768 TRACE("Dir %s ...\n",debugstr_w(name));
1769 load_folder(package,name);
1770 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1771 TRACE("resolves to %s\n",debugstr_w(path));
1774 return ERROR_SUCCESS;
1777 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1779 MSIPACKAGE *package = (MSIPACKAGE*)param;
1781 MSIFEATURE *feature;
1783 name = MSI_RecordGetString( row, 1 );
1785 feature = get_loaded_feature( package, name );
1787 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1791 Condition = MSI_RecordGetString(row,3);
1793 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1795 int level = MSI_RecordGetInteger(row,2);
1796 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1797 feature->Level = level;
1800 return ERROR_SUCCESS;
1805 * A lot is done in this function aside from just the costing.
1806 * The costing needs to be implemented at some point but for now I am going
1807 * to focus on the directory building
1810 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1812 static const WCHAR ExecSeqQuery[] =
1813 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1814 '`','D','i','r','e','c','t','o','r','y','`',0};
1815 static const WCHAR ConditionQuery[] =
1816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1817 '`','C','o','n','d','i','t','i','o','n','`',0};
1818 static const WCHAR szCosting[] =
1819 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1820 static const WCHAR szlevel[] =
1821 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1822 static const WCHAR szOne[] = { '1', 0 };
1831 MSI_GetPropertyW(package, szCosting, buffer, &sz);
1833 return ERROR_SUCCESS;
1835 TRACE("Building Directory properties\n");
1837 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1838 if (rc == ERROR_SUCCESS)
1840 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1842 msiobj_release(&view->hdr);
1845 TRACE("File calculations\n");
1847 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1849 MSICOMPONENT* comp = file->Component;
1855 /* calculate target */
1856 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1858 msi_free(file->TargetPath);
1860 TRACE("file %s is named %s\n",
1861 debugstr_w(file->File),debugstr_w(file->FileName));
1863 file->TargetPath = build_directory_name(2, p, file->FileName);
1867 TRACE("file %s resolves to %s\n",
1868 debugstr_w(file->File),debugstr_w(file->TargetPath));
1870 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1873 comp->Cost += file->FileSize;
1883 static const WCHAR name[] =
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)
1908 FIXME("cost should be diff in size\n");
1909 comp->Cost += file->FileSize;
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(package, 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;
2561 return ERROR_INVALID_HANDLE;
2563 /* writes the Component and Features values to the registry */
2565 rc = MSIREG_OpenComponents(&hkey);
2566 if (rc != ERROR_SUCCESS)
2569 squash_guid(package->ProductCode,squished_pc);
2570 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2572 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2574 ui_progress(package,2,0,0,0);
2575 if (comp->ComponentId)
2579 squash_guid(comp->ComponentId,squished_cc);
2581 msi_free(comp->FullKeypath);
2582 comp->FullKeypath = resolve_keypath( package, comp );
2584 /* do the refcounting */
2585 ACTION_RefCountComponent( package, comp );
2587 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2588 debugstr_w(comp->Component),
2589 debugstr_w(squished_cc),
2590 debugstr_w(comp->FullKeypath),
2593 * Write the keypath out if the component is to be registered
2594 * and delete the key if the component is to be deregistered
2596 if (ACTION_VerifyComponentForAction(package, comp,
2597 INSTALLSTATE_LOCAL))
2599 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2600 if (rc != ERROR_SUCCESS)
2603 if (comp->FullKeypath)
2605 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2607 if (comp->Attributes & msidbComponentAttributesPermanent)
2609 static const WCHAR szPermKey[] =
2610 { '0','0','0','0','0','0','0','0','0','0','0','0',
2611 '0','0','0','0','0','0','0','0','0','0','0','0',
2612 '0','0','0','0','0','0','0','0',0};
2614 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2620 uirow = MSI_CreateRecord(3);
2621 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2622 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2623 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2624 ui_actiondata(package,szProcessComponents,uirow);
2625 msiobj_release( &uirow->hdr );
2628 else if (ACTION_VerifyComponentForAction(package, comp,
2629 INSTALLSTATE_ABSENT))
2633 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2634 if (rc != ERROR_SUCCESS)
2637 RegDeleteValueW(hkey2,squished_pc);
2639 /* if the key is empty delete it */
2640 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2642 if (res == ERROR_NO_MORE_ITEMS)
2643 RegDeleteKeyW(hkey,squished_cc);
2646 uirow = MSI_CreateRecord(2);
2647 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2648 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2649 ui_actiondata(package,szProcessComponents,uirow);
2650 msiobj_release( &uirow->hdr );
2667 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2668 LPWSTR lpszName, LONG_PTR lParam)
2671 typelib_struct *tl_struct = (typelib_struct*) lParam;
2672 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2676 if (!IS_INTRESOURCE(lpszName))
2678 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2682 sz = strlenW(tl_struct->source)+4;
2683 sz *= sizeof(WCHAR);
2685 if ((INT)lpszName == 1)
2686 tl_struct->path = strdupW(tl_struct->source);
2689 tl_struct->path = msi_alloc(sz);
2690 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2693 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2694 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2695 if (!SUCCEEDED(res))
2697 msi_free(tl_struct->path);
2698 tl_struct->path = NULL;
2703 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2704 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2706 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2710 msi_free(tl_struct->path);
2711 tl_struct->path = NULL;
2713 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2714 ITypeLib_Release(tl_struct->ptLib);
2719 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2721 MSIPACKAGE* package = (MSIPACKAGE*)param;
2725 typelib_struct tl_struct;
2727 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2729 component = MSI_RecordGetString(row,3);
2730 comp = get_loaded_component(package,component);
2732 return ERROR_SUCCESS;
2734 if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
2736 TRACE("Skipping typelib reg due to disabled component\n");
2738 comp->Action = comp->Installed;
2740 return ERROR_SUCCESS;
2743 comp->Action = INSTALLSTATE_LOCAL;
2745 file = get_loaded_file( package, comp->KeyPath );
2747 return ERROR_SUCCESS;
2749 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2753 guid = MSI_RecordGetString(row,1);
2754 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2755 tl_struct.source = strdupW( file->TargetPath );
2756 tl_struct.path = NULL;
2758 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2759 (LONG_PTR)&tl_struct);
2767 helpid = MSI_RecordGetString(row,6);
2770 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2771 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2774 if (!SUCCEEDED(res))
2775 ERR("Failed to register type library %s\n",
2776 debugstr_w(tl_struct.path));
2779 ui_actiondata(package,szRegisterTypeLibraries,row);
2781 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2784 ITypeLib_Release(tl_struct.ptLib);
2785 msi_free(tl_struct.path);
2788 ERR("Failed to load type library %s\n",
2789 debugstr_w(tl_struct.source));
2791 FreeLibrary(module);
2792 msi_free(tl_struct.source);
2795 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2797 return ERROR_SUCCESS;
2800 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2803 * OK this is a bit confusing.. I am given a _Component key and I believe
2804 * that the file that is being registered as a type library is the "key file
2805 * of that component" which I interpret to mean "The file in the KeyPath of
2810 static const WCHAR Query[] =
2811 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2812 '`','T','y','p','e','L','i','b','`',0};
2815 return ERROR_INVALID_HANDLE;
2817 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2818 if (rc != ERROR_SUCCESS)
2819 return ERROR_SUCCESS;
2821 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2822 msiobj_release(&view->hdr);
2826 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2828 MSIPACKAGE *package = (MSIPACKAGE*)param;
2829 LPWSTR target_file, target_folder;
2831 WCHAR filename[0x100];
2834 static const WCHAR szlnk[]={'.','l','n','k',0};
2839 buffer = MSI_RecordGetString(row,4);
2840 comp = get_loaded_component(package,buffer);
2842 return ERROR_SUCCESS;
2844 if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
2846 TRACE("Skipping shortcut creation due to disabled component\n");
2848 comp->Action = comp->Installed;
2850 return ERROR_SUCCESS;
2853 comp->Action = INSTALLSTATE_LOCAL;
2855 ui_actiondata(package,szCreateShortcuts,row);
2857 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2858 &IID_IShellLinkW, (LPVOID *) &sl );
2862 ERR("Is IID_IShellLink\n");
2863 return ERROR_SUCCESS;
2866 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2869 ERR("Is IID_IPersistFile\n");
2870 return ERROR_SUCCESS;
2873 buffer = MSI_RecordGetString(row,2);
2874 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2876 /* may be needed because of a bug somehwere else */
2877 create_full_pathW(target_folder);
2880 MSI_RecordGetStringW(row,3,filename,&sz);
2881 reduce_to_longfilename(filename);
2882 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2883 strcatW(filename,szlnk);
2884 target_file = build_directory_name(2, target_folder, filename);
2885 msi_free(target_folder);
2887 buffer = MSI_RecordGetString(row,5);
2888 if (strchrW(buffer,'['))
2891 deformat_string(package,buffer,&deformated);
2892 IShellLinkW_SetPath(sl,deformated);
2893 msi_free(deformated);
2897 FIXME("poorly handled shortcut format, advertised shortcut\n");
2898 IShellLinkW_SetPath(sl,comp->FullKeypath);
2901 if (!MSI_RecordIsNull(row,6))
2904 buffer = MSI_RecordGetString(row,6);
2905 deformat_string(package,buffer,&deformated);
2906 IShellLinkW_SetArguments(sl,deformated);
2907 msi_free(deformated);
2910 if (!MSI_RecordIsNull(row,7))
2912 buffer = MSI_RecordGetString(row,7);
2913 IShellLinkW_SetDescription(sl,buffer);
2916 if (!MSI_RecordIsNull(row,8))
2917 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2919 if (!MSI_RecordIsNull(row,9))
2924 buffer = MSI_RecordGetString(row,9);
2926 Path = build_icon_path(package,buffer);
2927 index = MSI_RecordGetInteger(row,10);
2929 IShellLinkW_SetIconLocation(sl,Path,index);
2933 if (!MSI_RecordIsNull(row,11))
2934 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2936 if (!MSI_RecordIsNull(row,12))
2939 buffer = MSI_RecordGetString(row,12);
2940 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2941 IShellLinkW_SetWorkingDirectory(sl,Path);
2945 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2946 IPersistFile_Save(pf,target_file,FALSE);
2948 msi_free(target_file);
2950 IPersistFile_Release( pf );
2951 IShellLinkW_Release( sl );
2953 return ERROR_SUCCESS;
2956 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2961 static const WCHAR Query[] =
2962 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2963 '`','S','h','o','r','t','c','u','t','`',0};
2966 return ERROR_INVALID_HANDLE;
2968 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2969 if (rc != ERROR_SUCCESS)
2970 return ERROR_SUCCESS;
2972 res = CoInitialize( NULL );
2975 ERR("CoInitialize failed\n");
2976 return ERROR_FUNCTION_FAILED;
2979 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2980 msiobj_release(&view->hdr);
2987 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2989 MSIPACKAGE* package = (MSIPACKAGE*)param;
2997 FileName = MSI_RecordGetString(row,1);
3000 ERR("Unable to get FileName\n");
3001 return ERROR_SUCCESS;
3004 FilePath = build_icon_path(package,FileName);
3006 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3008 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3009 FILE_ATTRIBUTE_NORMAL, NULL);
3011 if (the_file == INVALID_HANDLE_VALUE)
3013 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3015 return ERROR_SUCCESS;
3022 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3023 if (rc != ERROR_SUCCESS)
3025 ERR("Failed to get stream\n");
3026 CloseHandle(the_file);
3027 DeleteFileW(FilePath);
3030 WriteFile(the_file,buffer,sz,&write,NULL);
3031 } while (sz == 1024);
3035 CloseHandle(the_file);
3036 return ERROR_SUCCESS;
3040 * 99% of the work done here is only done for
3041 * advertised installs. However this is where the
3042 * Icon table is processed and written out
3043 * so that is what I am going to do here.
3045 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3049 static const WCHAR Query[]=
3050 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3051 '`','I','c','o','n','`',0};
3052 /* for registry stuff */
3055 static const WCHAR szProductLanguage[] =
3056 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3057 static const WCHAR szARPProductIcon[] =
3058 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3059 static const WCHAR szProductVersion[] =
3060 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3064 MSIHANDLE hDb, hSumInfo;
3067 return ERROR_INVALID_HANDLE;
3069 /* write out icon files */
3071 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3072 if (rc == ERROR_SUCCESS)
3074 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3075 msiobj_release(&view->hdr);
3078 /* ok there is a lot more done here but i need to figure out what */
3080 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3081 if (rc != ERROR_SUCCESS)
3084 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3085 if (rc != ERROR_SUCCESS)
3089 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3090 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3093 langid = msi_get_property_int( package, szProductLanguage, 0 );
3094 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3096 buffer = msi_dup_property( package, szARPProductIcon );
3099 LPWSTR path = build_icon_path(package,buffer);
3100 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3105 buffer = msi_dup_property( package, szProductVersion );
3108 DWORD verdword = build_version_dword(buffer);
3109 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3113 FIXME("Need to write more keys to the user registry\n");
3115 hDb= alloc_msihandle( &package->db->hdr );
3116 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3117 MsiCloseHandle(hDb);
3118 if (rc == ERROR_SUCCESS)
3120 WCHAR guidbuffer[0x200];
3122 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3124 if (rc == ERROR_SUCCESS)
3126 WCHAR squashed[GUID_SIZE];
3127 /* for now we only care about the first guid */
3128 LPWSTR ptr = strchrW(guidbuffer,';');
3130 squash_guid(guidbuffer,squashed);
3131 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3135 ERR("Unable to query Revision_Number... \n");
3138 MsiCloseHandle(hSumInfo);
3142 ERR("Unable to open Summary Information\n");
3154 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3156 MSIPACKAGE *package = (MSIPACKAGE*)param;
3157 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3158 LPWSTR deformated_section, deformated_key, deformated_value;
3159 LPWSTR folder, fullname = NULL;
3163 static const WCHAR szWindowsFolder[] =
3164 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3166 component = MSI_RecordGetString(row, 8);
3167 comp = get_loaded_component(package,component);
3169 if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
3171 TRACE("Skipping ini file due to disabled component %s\n",
3172 debugstr_w(component));
3174 comp->Action = comp->Installed;
3176 return ERROR_SUCCESS;
3179 comp->Action = INSTALLSTATE_LOCAL;
3181 identifier = MSI_RecordGetString(row,1);
3182 filename = MSI_RecordGetString(row,2);
3183 dirproperty = MSI_RecordGetString(row,3);
3184 section = MSI_RecordGetString(row,4);
3185 key = MSI_RecordGetString(row,5);
3186 value = MSI_RecordGetString(row,6);
3187 action = MSI_RecordGetInteger(row,7);
3189 deformat_string(package,section,&deformated_section);
3190 deformat_string(package,key,&deformated_key);
3191 deformat_string(package,value,&deformated_value);
3195 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3197 folder = msi_dup_property( package, dirproperty );
3200 folder = msi_dup_property( package, szWindowsFolder );
3204 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3208 fullname = build_directory_name(2, folder, filename);
3212 TRACE("Adding value %s to section %s in %s\n",
3213 debugstr_w(deformated_key), debugstr_w(deformated_section),
3214 debugstr_w(fullname));
3215 WritePrivateProfileStringW(deformated_section, deformated_key,
3216 deformated_value, fullname);
3218 else if (action == 1)
3221 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3222 returned, 10, fullname);
3223 if (returned[0] == 0)
3225 TRACE("Adding value %s to section %s in %s\n",
3226 debugstr_w(deformated_key), debugstr_w(deformated_section),
3227 debugstr_w(fullname));
3229 WritePrivateProfileStringW(deformated_section, deformated_key,
3230 deformated_value, fullname);
3233 else if (action == 3)
3234 FIXME("Append to existing section not yet implemented\n");
3236 uirow = MSI_CreateRecord(4);
3237 MSI_RecordSetStringW(uirow,1,identifier);
3238 MSI_RecordSetStringW(uirow,2,deformated_section);
3239 MSI_RecordSetStringW(uirow,3,deformated_key);
3240 MSI_RecordSetStringW(uirow,4,deformated_value);
3241 ui_actiondata(package,szWriteIniValues,uirow);
3242 msiobj_release( &uirow->hdr );
3246 msi_free(deformated_key);
3247 msi_free(deformated_value);
3248 msi_free(deformated_section);
3249 return ERROR_SUCCESS;
3252 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3256 static const WCHAR ExecSeqQuery[] =
3257 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3258 '`','I','n','i','F','i','l','e','`',0};
3260 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3261 if (rc != ERROR_SUCCESS)
3263 TRACE("no IniFile table\n");
3264 return ERROR_SUCCESS;
3267 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3268 msiobj_release(&view->hdr);
3272 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3274 MSIPACKAGE *package = (MSIPACKAGE*)param;
3279 static const WCHAR ExeStr[] =
3280 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3281 static const WCHAR close[] = {'\"',0};
3283 PROCESS_INFORMATION info;
3286 memset(&si,0,sizeof(STARTUPINFOW));
3288 filename = MSI_RecordGetString(row,1);
3289 file = get_loaded_file( package, filename );
3293 ERR("Unable to find file id %s\n",debugstr_w(filename));
3294 return ERROR_SUCCESS;
3297 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3299 FullName = msi_alloc(len*sizeof(WCHAR));
3300 strcpyW(FullName,ExeStr);
3301 strcatW( FullName, file->TargetPath );
3302 strcatW(FullName,close);
3304 TRACE("Registering %s\n",debugstr_w(FullName));
3305 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3309 msi_dialog_check_messages(info.hProcess);
3312 return ERROR_SUCCESS;
3315 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3319 static const WCHAR ExecSeqQuery[] =
3320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3321 '`','S','e','l','f','R','e','g','`',0};
3323 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3324 if (rc != ERROR_SUCCESS)
3326 TRACE("no SelfReg table\n");
3327 return ERROR_SUCCESS;
3330 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3331 msiobj_release(&view->hdr);
3333 return ERROR_SUCCESS;
3336 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3338 MSIFEATURE *feature;
3344 return ERROR_INVALID_HANDLE;
3346 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3347 if (rc != ERROR_SUCCESS)
3350 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3351 if (rc != ERROR_SUCCESS)
3354 /* here the guids are base 85 encoded */
3355 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3361 BOOL absent = FALSE;
3363 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3364 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3365 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3369 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3373 if (feature->Feature_Parent)
3374 size += strlenW( feature->Feature_Parent )+2;
3376 data = msi_alloc(size * sizeof(WCHAR));
3379 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3381 MSICOMPONENT* component = cl->component;
3384 memset(buf,0,sizeof(buf));
3385 if (component->ComponentId)
3387 TRACE("From %s\n",debugstr_w(component->ComponentId));
3388 CLSIDFromString(component->ComponentId, &clsid);
3389 encode_base85_guid(&clsid,buf);
3390 TRACE("to %s\n",debugstr_w(buf));
3394 if (feature->Feature_Parent)
3396 static const WCHAR sep[] = {'\2',0};
3398 strcatW(data,feature->Feature_Parent);
3401 msi_reg_set_val_str( hkey, feature->Feature, data );
3405 if (feature->Feature_Parent)
3406 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3409 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3410 (LPBYTE)feature->Feature_Parent,size);
3414 size += 2*sizeof(WCHAR);
3415 data = msi_alloc(size);
3418 if (feature->Feature_Parent)
3419 strcpyW( &data[1], feature->Feature_Parent );
3420 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3432 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3434 static const WCHAR installerPathFmt[] = {
3435 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3436 static const WCHAR fmt[] = {
3438 'I','n','s','t','a','l','l','e','r','\\',
3439 '%','x','.','m','s','i',0};
3440 static const WCHAR szOriginalDatabase[] =
3441 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3442 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3447 /* copy the package locally */
3448 num = GetTickCount() & 0xffff;
3452 GetWindowsDirectoryW( windir, MAX_PATH );
3453 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3456 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3457 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3458 if (handle != INVALID_HANDLE_VALUE)
3460 CloseHandle(handle);
3463 if (GetLastError() != ERROR_FILE_EXISTS &&
3464 GetLastError() != ERROR_SHARING_VIOLATION)
3466 if (!(++num & 0xffff)) num = 1;
3467 sprintfW(packagefile,fmt,num);
3468 } while (num != start);
3470 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3471 create_full_pathW(path);
3473 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3475 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3476 r = CopyFileW( msiFilePath, packagefile, FALSE);
3477 msi_free( msiFilePath );
3481 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3482 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3483 return ERROR_FUNCTION_FAILED;
3486 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3487 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3488 return ERROR_SUCCESS;
3491 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3493 LPWSTR prop, val, key;
3494 static const LPCSTR propval[] = {
3495 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3496 "ARPCONTACT", "Contact",
3497 "ARPCOMMENTS", "Comments",
3498 "ProductName", "DisplayName",
3499 "ProductVersion", "DisplayVersion",
3500 "ARPHELPLINK", "HelpLink",
3501 "ARPHELPTELEPHONE", "HelpTelephone",
3502 "ARPINSTALLLOCATION", "InstallLocation",
3503 "SourceDir", "InstallSource",
3504 "Manufacturer", "Publisher",
3505 "ARPREADME", "Readme",
3507 "ARPURLINFOABOUT", "URLInfoAbout",
3508 "ARPURLUPDATEINFO", "URLUpdateInfo",
3511 const LPCSTR *p = propval;
3515 prop = strdupAtoW( *p++ );
3516 key = strdupAtoW( *p++ );
3517 val = msi_dup_property( package, prop );
3518 msi_reg_set_val_str( hkey, key, val );
3523 return ERROR_SUCCESS;
3526 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3529 LPWSTR buffer = NULL;
3532 static const WCHAR szWindowsInstaller[] =
3533 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3534 static const WCHAR szUpgradeCode[] =
3535 {'U','p','g','r','a','d','e','C','o','d','e',0};
3536 static const WCHAR modpath_fmt[] =
3537 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3538 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3539 static const WCHAR szModifyPath[] =
3540 {'M','o','d','i','f','y','P','a','t','h',0};
3541 static const WCHAR szUninstallString[] =
3542 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3543 static const WCHAR szEstimatedSize[] =
3544 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3545 static const WCHAR szProductLanguage[] =
3546 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3547 static const WCHAR szProductVersion[] =
3548 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3551 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3552 LPWSTR upgrade_code;
3556 return ERROR_INVALID_HANDLE;
3558 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3559 if (rc != ERROR_SUCCESS)
3562 /* dump all the info i can grab */
3563 FIXME("Flesh out more information \n");
3565 msi_write_uninstall_property_vals( package, hkey );
3567 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3569 msi_make_package_local( package, hkey );
3571 /* do ModifyPath and UninstallString */
3572 size = deformat_string(package,modpath_fmt,&buffer);
3573 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3574 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3577 FIXME("Write real Estimated Size when we have it\n");
3578 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3580 GetLocalTime(&systime);
3581 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3582 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3584 langid = msi_get_property_int( package, szProductLanguage, 0 );
3585 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3587 buffer = msi_dup_property( package, szProductVersion );
3590 DWORD verdword = build_version_dword(buffer);
3592 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3593 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3594 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3598 /* Handle Upgrade Codes */
3599 upgrade_code = msi_dup_property( package, szUpgradeCode );
3604 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3605 squash_guid(package->ProductCode,squashed);
3606 msi_reg_set_val_str( hkey2, squashed, NULL );
3608 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3609 squash_guid(package->ProductCode,squashed);
3610 msi_reg_set_val_str( hkey2, squashed, NULL );
3613 msi_free(upgrade_code);
3618 return ERROR_SUCCESS;
3621 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3626 return ERROR_INVALID_HANDLE;
3628 rc = execute_script(package,INSTALL_SCRIPT);
3633 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3638 return ERROR_INVALID_HANDLE;
3640 /* turn off scheduleing */
3641 package->script->CurrentlyScripting= FALSE;
3643 /* first do the same as an InstallExecute */
3644 rc = ACTION_InstallExecute(package);
3645 if (rc != ERROR_SUCCESS)
3648 /* then handle Commit Actions */
3649 rc = execute_script(package,COMMIT_SCRIPT);
3654 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3656 static const WCHAR RunOnce[] = {
3657 'S','o','f','t','w','a','r','e','\\',
3658 'M','i','c','r','o','s','o','f','t','\\',
3659 'W','i','n','d','o','w','s','\\',
3660 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3661 'R','u','n','O','n','c','e',0};
3662 static const WCHAR InstallRunOnce[] = {
3663 'S','o','f','t','w','a','r','e','\\',
3664 'M','i','c','r','o','s','o','f','t','\\',
3665 'W','i','n','d','o','w','s','\\',
3666 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3667 'I','n','s','t','a','l','l','e','r','\\',
3668 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3670 static const WCHAR msiexec_fmt[] = {
3672 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3673 '\"','%','s','\"',0};
3674 static const WCHAR install_fmt[] = {
3675 '/','I',' ','\"','%','s','\"',' ',
3676 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3677 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3678 WCHAR buffer[256], sysdir[MAX_PATH];
3680 WCHAR squished_pc[100];
3683 return ERROR_INVALID_HANDLE;
3685 squash_guid(package->ProductCode,squished_pc);
3687 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3688 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3689 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3692 msi_reg_set_val_str( hkey, squished_pc, buffer );
3695 TRACE("Reboot command %s\n",debugstr_w(buffer));
3697 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3698 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3700 msi_reg_set_val_str( hkey, squished_pc, buffer );
3703 return ERROR_INSTALL_SUSPEND;
3706 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3711 * we are currently doing what should be done here in the top level Install
3712 * however for Adminastrative and uninstalls this step will be needed
3714 if (!package->PackagePath)
3715 return ERROR_SUCCESS;
3717 attrib = GetFileAttributesW(package->PackagePath);
3718 if (attrib == INVALID_FILE_ATTRIBUTES)
3724 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3725 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3726 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3727 if (rc == ERROR_MORE_DATA)
3729 prompt = msi_alloc(size * sizeof(WCHAR));
3730 MsiSourceListGetInfoW(package->ProductCode, NULL,
3731 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3732 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3735 prompt = strdupW(package->PackagePath);
3737 msg = generate_error_string(package,1302,1,prompt);
3738 while(attrib == INVALID_FILE_ATTRIBUTES)
3740 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3743 rc = ERROR_INSTALL_USEREXIT;
3746 attrib = GetFileAttributesW(package->PackagePath);
3752 return ERROR_SUCCESS;
3757 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3764 static const WCHAR szPropKeys[][80] =
3766 {'P','r','o','d','u','c','t','I','D',0},
3767 {'U','S','E','R','N','A','M','E',0},
3768 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3772 static const WCHAR szRegKeys[][80] =
3774 {'P','r','o','d','u','c','t','I','D',0},
3775 {'R','e','g','O','w','n','e','r',0},
3776 {'R','e','g','C','o','m','p','a','n','y',0},
3781 return ERROR_INVALID_HANDLE;
3783 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3785 return ERROR_SUCCESS;
3787 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3788 if (rc != ERROR_SUCCESS)
3791 for( i = 0; szPropKeys[i][0]; i++ )
3793 buffer = msi_dup_property( package, szPropKeys[i] );
3794 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3799 msi_free(productid);
3802 return ERROR_SUCCESS;
3806 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3808 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
3809 static const WCHAR szTwo[] = {'2',0};
3812 level = msi_dup_property( package, szUILevel );
3814 MSI_SetPropertyW(package,szUILevel,szTwo);
3815 package->script->InWhatSequence |= SEQUENCE_EXEC;
3816 rc = ACTION_ProcessExecSequence(package,FALSE);
3817 MSI_SetPropertyW(package,szUILevel,level);
3824 * Code based off of code located here
3825 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3827 * Using string index 4 (full font name) instead of 1 (family name)
3829 static LPWSTR load_ttfname_from(LPCWSTR filename)
3835 typedef struct _tagTT_OFFSET_TABLE{
3836 USHORT uMajorVersion;
3837 USHORT uMinorVersion;
3838 USHORT uNumOfTables;
3839 USHORT uSearchRange;
3840 USHORT uEntrySelector;
3844 typedef struct _tagTT_TABLE_DIRECTORY{
3845 char szTag[4]; /* table name */
3846 ULONG uCheckSum; /* Check sum */
3847 ULONG uOffset; /* Offset from beginning of file */
3848 ULONG uLength; /* length of the table in bytes */
3849 }TT_TABLE_DIRECTORY;
3851 typedef struct _tagTT_NAME_TABLE_HEADER{
3852 USHORT uFSelector; /* format selector. Always 0 */
3853 USHORT uNRCount; /* Name Records count */
3854 USHORT uStorageOffset; /* Offset for strings storage,
3855 * from start of the table */
3856 }TT_NAME_TABLE_HEADER;
3858 typedef struct _tagTT_NAME_RECORD{
3863 USHORT uStringLength;
3864 USHORT uStringOffset; /* from start of storage area */
3867 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3868 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3870 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3871 FILE_ATTRIBUTE_NORMAL, 0 );
3872 if (handle != INVALID_HANDLE_VALUE)
3874 TT_TABLE_DIRECTORY tblDir;
3875 BOOL bFound = FALSE;
3876 TT_OFFSET_TABLE ttOffsetTable;
3879 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3880 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3881 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3882 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3884 if (ttOffsetTable.uMajorVersion != 1 ||
3885 ttOffsetTable.uMinorVersion != 0)
3888 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3890 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3891 if (strncmp(tblDir.szTag,"name",4)==0)
3894 tblDir.uLength = SWAPLONG(tblDir.uLength);
3895 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3902 TT_NAME_TABLE_HEADER ttNTHeader;
3903 TT_NAME_RECORD ttRecord;
3905 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3906 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3909 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3910 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3912 for(i=0; i<ttNTHeader.uNRCount; i++)
3914 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3915 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3916 /* 4 is the Full Font Name */
3917 if(ttRecord.uNameID == 4)
3921 static LPCSTR tt = " (TrueType)";
3923 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3924 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3925 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3926 SetFilePointer(handle, tblDir.uOffset +
3927 ttRecord.uStringOffset +
3928 ttNTHeader.uStorageOffset,
3930 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3931 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3932 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3933 if (strlen(buf) > 0)
3936 ret = strdupAtoW(buf);
3942 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3946 CloseHandle(handle);
3949 ERR("Unable to open font file %s\n", debugstr_w(filename));
3951 TRACE("Returning fontname %s\n",debugstr_w(ret));
3955 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3957 MSIPACKAGE *package = (MSIPACKAGE*)param;
3961 static const WCHAR regfont1[] =
3962 {'S','o','f','t','w','a','r','e','\\',
3963 'M','i','c','r','o','s','o','f','t','\\',
3964 'W','i','n','d','o','w','s',' ','N','T','\\',
3965 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3966 'F','o','n','t','s',0};
3967 static const WCHAR regfont2[] =
3968 {'S','o','f','t','w','a','r','e','\\',
3969 'M','i','c','r','o','s','o','f','t','\\',
3970 'W','i','n','d','o','w','s','\\',
3971 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3972 'F','o','n','t','s',0};
3976 filename = MSI_RecordGetString( row, 1 );
3977 file = get_loaded_file( package, filename );
3980 ERR("Unable to load file\n");
3981 return ERROR_SUCCESS;
3984 /* check to make sure that component is installed */
3985 if (!ACTION_VerifyComponentForAction(package,
3986 file->Component, INSTALLSTATE_LOCAL))
3988 TRACE("Skipping: Component not scheduled for install\n");
3989 return ERROR_SUCCESS;
3992 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3993 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3995 if (MSI_RecordIsNull(row,2))
3996 name = load_ttfname_from( file->TargetPath );
3998 name = msi_dup_record_field(row,2);
4002 msi_reg_set_val_str( hkey1, name, file->FileName );
4003 msi_reg_set_val_str( hkey2, name, file->FileName );
4009 return ERROR_SUCCESS;
4012 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4016 static const WCHAR ExecSeqQuery[] =
4017 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4018 '`','F','o','n','t','`',0};
4020 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4021 if (rc != ERROR_SUCCESS)
4023 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4024 return ERROR_SUCCESS;
4027 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4028 msiobj_release(&view->hdr);
4030 return ERROR_SUCCESS;
4033 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4035 MSIPACKAGE *package = (MSIPACKAGE*)param;
4036 LPCWSTR compgroupid=NULL;
4037 LPCWSTR feature=NULL;
4038 LPCWSTR text = NULL;
4039 LPCWSTR qualifier = NULL;
4040 LPCWSTR component = NULL;
4041 LPWSTR advertise = NULL;
4042 LPWSTR output = NULL;
4044 UINT rc = ERROR_SUCCESS;
4048 component = MSI_RecordGetString(rec,3);
4049 comp = get_loaded_component(package,component);
4051 if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL) &&
4052 !ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_SOURCE) &&
4053 !ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_ADVERTISED))
4055 TRACE("Skipping: Component %s not scheduled for install\n",
4056 debugstr_w(component));
4058 return ERROR_SUCCESS;
4061 compgroupid = MSI_RecordGetString(rec,1);
4063 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4064 if (rc != ERROR_SUCCESS)
4067 text = MSI_RecordGetString(rec,4);
4068 qualifier = MSI_RecordGetString(rec,2);
4069 feature = MSI_RecordGetString(rec,5);
4071 advertise = create_component_advertise_string(package, comp, feature);
4073 sz = strlenW(advertise);
4076 sz += lstrlenW(text);
4079 sz *= sizeof(WCHAR);
4081 output = msi_alloc(sz);
4082 memset(output,0,sz);
4083 strcpyW(output,advertise);
4084 msi_free(advertise);
4087 strcatW(output,text);
4089 msi_reg_set_val_multi_str( hkey, qualifier, output );
4099 * At present I am ignorning the advertised components part of this and only
4100 * focusing on the qualified component sets
4102 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4106 static const WCHAR ExecSeqQuery[] =
4107 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4108 '`','P','u','b','l','i','s','h',
4109 'C','o','m','p','o','n','e','n','t','`',0};
4111 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4112 if (rc != ERROR_SUCCESS)
4113 return ERROR_SUCCESS;
4115 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4116 msiobj_release(&view->hdr);
4121 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4122 LPCSTR action, LPCWSTR table )
4124 static const WCHAR query[] = {
4125 'S','E','L','E','C','T',' ','*',' ',
4126 'F','R','O','M',' ','`','%','s','`',0 };
4127 MSIQUERY *view = NULL;
4131 r = MSI_OpenQuery( package->db, &view, query, table );
4132 if (r == ERROR_SUCCESS)
4134 r = MSI_IterateRecords(view, &count, NULL, package);
4135 msiobj_release(&view->hdr);
4139 FIXME("%s -> %lu ignored %s table values\n",
4140 action, count, debugstr_w(table));
4142 return ERROR_SUCCESS;
4145 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4147 static const WCHAR table[] =
4148 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4149 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4152 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4154 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4155 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4158 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4160 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4161 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4164 static UINT ACTION_BindImage( MSIPACKAGE *package )
4166 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4167 return msi_unimplemented_action_stub( package, "BindImage", table );
4170 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4172 static const WCHAR table[] = {
4173 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4174 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4177 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4179 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4180 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4183 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4185 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4186 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4189 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4191 static const WCHAR table[] = {
4192 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4193 return msi_unimplemented_action_stub( package, "InstallServices", table );
4196 static UINT ACTION_StartServices( MSIPACKAGE *package )
4198 static const WCHAR table[] = {
4199 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4200 return msi_unimplemented_action_stub( package, "StartServices", table );
4203 static UINT ACTION_StopServices( MSIPACKAGE *package )
4205 static const WCHAR table[] = {
4206 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4207 return msi_unimplemented_action_stub( package, "StopServices", table );
4210 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4212 static const WCHAR table[] = {
4213 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4214 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4217 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4219 static const WCHAR table[] = {
4220 'E','n','v','i','r','o','n','m','e','n','t',0 };
4221 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4224 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4226 static const WCHAR table[] = {
4227 'E','n','v','i','r','o','n','m','e','n','t',0 };
4228 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4231 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4233 static const WCHAR table[] = {
4234 'M','s','i','A','s','s','e','m','b','l','y',0 };
4235 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4238 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4240 static const WCHAR table[] = {
4241 'M','s','i','A','s','s','e','m','b','l','y',0 };
4242 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4245 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4247 static const WCHAR table[] = { 'F','o','n','t',0 };
4248 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4251 static struct _actions StandardActions[] = {
4252 { szAllocateRegistrySpace, NULL},
4253 { szAppSearch, ACTION_AppSearch },
4254 { szBindImage, ACTION_BindImage },
4255 { szCCPSearch, NULL},
4256 { szCostFinalize, ACTION_CostFinalize },
4257 { szCostInitialize, ACTION_CostInitialize },
4258 { szCreateFolders, ACTION_CreateFolders },
4259 { szCreateShortcuts, ACTION_CreateShortcuts },
4260 { szDeleteServices, ACTION_DeleteServices },
4261 { szDisableRollback, NULL},
4262 { szDuplicateFiles, ACTION_DuplicateFiles },
4263 { szExecuteAction, ACTION_ExecuteAction },
4264 { szFileCost, ACTION_FileCost },
4265 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4266 { szForceReboot, ACTION_ForceReboot },
4267 { szInstallAdminPackage, NULL},
4268 { szInstallExecute, ACTION_InstallExecute },
4269 { szInstallExecuteAgain, ACTION_InstallExecute },
4270 { szInstallFiles, ACTION_InstallFiles},
4271 { szInstallFinalize, ACTION_InstallFinalize },
4272 { szInstallInitialize, ACTION_InstallInitialize },
4273 { szInstallSFPCatalogFile, NULL},
4274 { szInstallValidate, ACTION_InstallValidate },
4275 { szIsolateComponents, ACTION_IsolateComponents },
4276 { szLaunchConditions, ACTION_LaunchConditions },
4277 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4278 { szMoveFiles, ACTION_MoveFiles },
4279 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4280 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4281 { szInstallODBC, NULL},
4282 { szInstallServices, ACTION_InstallServices },
4283 { szPatchFiles, ACTION_PatchFiles },
4284 { szProcessComponents, ACTION_ProcessComponents },
4285 { szPublishComponents, ACTION_PublishComponents },
4286 { szPublishFeatures, ACTION_PublishFeatures },
4287 { szPublishProduct, ACTION_PublishProduct },
4288 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4289 { szRegisterComPlus, NULL},
4290 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4291 { szRegisterFonts, ACTION_RegisterFonts },
4292 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4293 { szRegisterProduct, ACTION_RegisterProduct },
4294 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4295 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4296 { szRegisterUser, ACTION_RegisterUser},
4297 { szRemoveDuplicateFiles, NULL},
4298 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4299 { szRemoveExistingProducts, NULL},
4300 { szRemoveFiles, NULL},
4301 { szRemoveFolders, NULL},
4302 { szRemoveIniValues, ACTION_RemoveIniValues },
4303 { szRemoveODBC, NULL},
4304 { szRemoveRegistryValues, NULL},
4305 { szRemoveShortcuts, NULL},
4306 { szResolveSource, ACTION_ResolveSource},
4307 { szRMCCPSearch, NULL},
4308 { szScheduleReboot, NULL},
4309 { szSelfRegModules, ACTION_SelfRegModules },
4310 { szSelfUnregModules, ACTION_SelfUnregModules },
4311 { szSetODBCFolders, NULL},
4312 { szStartServices, ACTION_StartServices },
4313 { szStopServices, ACTION_StopServices },
4314 { szUnpublishComponents, NULL},
4315 { szUnpublishFeatures, NULL},
4316 { szUnregisterClassInfo, NULL},
4317 { szUnregisterComPlus, NULL},
4318 { szUnregisterExtensionInfo, NULL},
4319 { szUnregisterFonts, ACTION_UnregisterFonts },
4320 { szUnregisterMIMEInfo, NULL},
4321 { szUnregisterProgIdInfo, NULL},
4322 { szUnregisterTypeLibraries, NULL},
4323 { szValidateProductID, NULL},
4324 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4325 { szWriteIniValues, ACTION_WriteIniValues },
4326 { szWriteRegistryValues, ACTION_WriteRegistryValues},