2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
37 #include "wine/debug.h"
42 #include "wine/unicode.h"
45 #define REG_PROGRESS_VALUE 13200
46 #define COMPONENT_PROGRESS_VALUE 24000
48 WINE_DEFAULT_DEBUG_CHANNEL(msi);
53 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
54 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
55 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
58 * consts and values used
60 static const WCHAR c_colon[] = {'C',':','\\',0};
62 static const WCHAR szCreateFolders[] =
63 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
64 static const WCHAR szCostFinalize[] =
65 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
66 const WCHAR szInstallFiles[] =
67 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
68 const WCHAR szDuplicateFiles[] =
69 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
70 static const WCHAR szWriteRegistryValues[] =
71 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
72 'V','a','l','u','e','s',0};
73 static const WCHAR szCostInitialize[] =
74 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
75 static const WCHAR szFileCost[] =
76 {'F','i','l','e','C','o','s','t',0};
77 static const WCHAR szInstallInitialize[] =
78 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
79 static const WCHAR szInstallValidate[] =
80 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
81 static const WCHAR szLaunchConditions[] =
82 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
83 static const WCHAR szProcessComponents[] =
84 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
85 static const WCHAR szRegisterTypeLibraries[] =
86 {'R','e','g','i','s','t','e','r','T','y','p','e',
87 'L','i','b','r','a','r','i','e','s',0};
88 const WCHAR szRegisterClassInfo[] =
89 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
90 const WCHAR szRegisterProgIdInfo[] =
91 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
92 static const WCHAR szCreateShortcuts[] =
93 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
94 static const WCHAR szPublishProduct[] =
95 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
96 static const WCHAR szWriteIniValues[] =
97 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
98 static const WCHAR szSelfRegModules[] =
99 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
100 static const WCHAR szPublishFeatures[] =
101 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
102 static const WCHAR szRegisterProduct[] =
103 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
104 static const WCHAR szInstallExecute[] =
105 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
106 static const WCHAR szInstallExecuteAgain[] =
107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
108 'A','g','a','i','n',0};
109 static const WCHAR szInstallFinalize[] =
110 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
111 static const WCHAR szForceReboot[] =
112 {'F','o','r','c','e','R','e','b','o','o','t',0};
113 static const WCHAR szResolveSource[] =
114 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
115 static const WCHAR szAppSearch[] =
116 {'A','p','p','S','e','a','r','c','h',0};
117 static const WCHAR szAllocateRegistrySpace[] =
118 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
119 'S','p','a','c','e',0};
120 static const WCHAR szBindImage[] =
121 {'B','i','n','d','I','m','a','g','e',0};
122 static const WCHAR szCCPSearch[] =
123 {'C','C','P','S','e','a','r','c','h',0};
124 static const WCHAR szDeleteServices[] =
125 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
126 static const WCHAR szDisableRollback[] =
127 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
128 static const WCHAR szExecuteAction[] =
129 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
130 const WCHAR szFindRelatedProducts[] =
131 {'F','i','n','d','R','e','l','a','t','e','d',
132 'P','r','o','d','u','c','t','s',0};
133 static const WCHAR szInstallAdminPackage[] =
134 {'I','n','s','t','a','l','l','A','d','m','i','n',
135 'P','a','c','k','a','g','e',0};
136 static const WCHAR szInstallSFPCatalogFile[] =
137 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 static const WCHAR szIsolateComponents[] =
140 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
141 const WCHAR szMigrateFeatureStates[] =
142 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
143 'S','t','a','t','e','s',0};
144 const WCHAR szMoveFiles[] =
145 {'M','o','v','e','F','i','l','e','s',0};
146 static const WCHAR szMsiPublishAssemblies[] =
147 {'M','s','i','P','u','b','l','i','s','h',
148 'A','s','s','e','m','b','l','i','e','s',0};
149 static const WCHAR szMsiUnpublishAssemblies[] =
150 {'M','s','i','U','n','p','u','b','l','i','s','h',
151 'A','s','s','e','m','b','l','i','e','s',0};
152 static const WCHAR szInstallODBC[] =
153 {'I','n','s','t','a','l','l','O','D','B','C',0};
154 static const WCHAR szInstallServices[] =
155 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
156 const WCHAR szPatchFiles[] =
157 {'P','a','t','c','h','F','i','l','e','s',0};
158 static const WCHAR szPublishComponents[] =
159 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
160 static const WCHAR szRegisterComPlus[] =
161 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
162 const WCHAR szRegisterExtensionInfo[] =
163 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 static const WCHAR szRegisterFonts[] =
166 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
167 const WCHAR szRegisterMIMEInfo[] =
168 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
169 static const WCHAR szRegisterUser[] =
170 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
171 const WCHAR szRemoveDuplicateFiles[] =
172 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
173 'F','i','l','e','s',0};
174 static const WCHAR szRemoveEnvironmentStrings[] =
175 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
176 'S','t','r','i','n','g','s',0};
177 const WCHAR szRemoveExistingProducts[] =
178 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
179 'P','r','o','d','u','c','t','s',0};
180 const WCHAR szRemoveFiles[] =
181 {'R','e','m','o','v','e','F','i','l','e','s',0};
182 static const WCHAR szRemoveFolders[] =
183 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
184 static const WCHAR szRemoveIniValues[] =
185 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
186 static const WCHAR szRemoveODBC[] =
187 {'R','e','m','o','v','e','O','D','B','C',0};
188 static const WCHAR szRemoveRegistryValues[] =
189 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
190 'V','a','l','u','e','s',0};
191 static const WCHAR szRemoveShortcuts[] =
192 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
193 static const WCHAR szRMCCPSearch[] =
194 {'R','M','C','C','P','S','e','a','r','c','h',0};
195 static const WCHAR szScheduleReboot[] =
196 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
197 static const WCHAR szSelfUnregModules[] =
198 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
199 static const WCHAR szSetODBCFolders[] =
200 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
201 static const WCHAR szStartServices[] =
202 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
203 static const WCHAR szStopServices[] =
204 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
205 static const WCHAR szUnpublishComponents[] =
206 {'U','n','p','u','b','l','i','s','h',
207 'C','o','m','p','o','n','e','n','t','s',0};
208 static const WCHAR szUnpublishFeatures[] =
209 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
210 const WCHAR szUnregisterClassInfo[] =
211 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 static const WCHAR szUnregisterComPlus[] =
214 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
215 const WCHAR szUnregisterExtensionInfo[] =
216 {'U','n','r','e','g','i','s','t','e','r',
217 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
218 static const WCHAR szUnregisterFonts[] =
219 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
220 const WCHAR szUnregisterMIMEInfo[] =
221 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
222 const WCHAR szUnregisterProgIdInfo[] =
223 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 static const WCHAR szUnregisterTypeLibraries[] =
226 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
227 'L','i','b','r','a','r','i','e','s',0};
228 static const WCHAR szValidateProductID[] =
229 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
230 static const WCHAR szWriteEnvironmentStrings[] =
231 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
232 'S','t','r','i','n','g','s',0};
234 /* action handlers */
235 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
239 STANDARDACTIONHANDLER handler;
242 static struct _actions StandardActions[];
245 /********************************************************
247 ********************************************************/
249 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
251 static const WCHAR Query_t[] =
252 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
253 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
254 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
255 ' ','\'','%','s','\'',0};
258 row = MSI_QueryGetRecord( package->db, Query_t, action );
261 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
262 msiobj_release(&row->hdr);
265 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
269 static const WCHAR template_s[]=
270 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272 static const WCHAR template_e[]=
273 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
274 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276 static const WCHAR format[] =
277 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
281 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283 sprintfW(message,template_s,timet,action);
285 sprintfW(message,template_e,timet,action,rc);
287 row = MSI_CreateRecord(1);
288 MSI_RecordSetStringW(row,1,message);
290 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
291 msiobj_release(&row->hdr);
294 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
299 LPWSTR prop = NULL, val = NULL;
302 return ERROR_SUCCESS;
314 TRACE("Looking at %s\n",debugstr_w(ptr));
316 ptr2 = strchrW(ptr,'=');
319 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
326 prop = msi_alloc((len+1)*sizeof(WCHAR));
327 memcpy(prop,ptr,len*sizeof(WCHAR));
333 while (*ptr && (quote || (!quote && *ptr!=' ')))
346 val = msi_alloc((len+1)*sizeof(WCHAR));
347 memcpy(val,ptr2,len*sizeof(WCHAR));
350 if (lstrlenW(prop) > 0)
352 TRACE("Found commandline property (%s) = (%s)\n",
353 debugstr_w(prop), debugstr_w(val));
354 MSI_SetPropertyW(package,prop,val);
360 return ERROR_SUCCESS;
364 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367 LPWSTR p, *ret = NULL;
373 /* count the number of substrings */
374 for ( pc = str, count = 0; pc; count++ )
376 pc = strchrW( pc, sep );
381 /* allocate space for an array of substring pointers and the substrings */
382 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
383 (lstrlenW(str)+1) * sizeof(WCHAR) );
387 /* copy the string and set the pointers */
388 p = (LPWSTR) &ret[count+1];
390 for( count = 0; (ret[count] = p); count++ )
392 p = strchrW( p, sep );
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
407 TRACE("%p %s\n", package, debugstr_w(name) );
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
418 ret = msi_table_apply_transform( package->db, stg );
419 IStorage_Release( stg );
423 ERR("failed to open substorage %s\n", debugstr_w(name));
428 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
430 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
431 LPWSTR guid_list, *guids, product_id;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_id = msi_dup_property( package, szProdID );
437 /* FIXME: the property ProductID should be written into the DB somewhere */
438 ERR("no product ID to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_id ))
450 msi_free( guid_list );
451 msi_free( product_id );
456 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
459 LPWSTR str, *substorage;
460 UINT i, r = ERROR_SUCCESS;
462 si = MSI_GetSummaryInformationW( patch_db, 0 );
464 return ERROR_FUNCTION_FAILED;
466 msi_check_patch_applicable( package, si );
468 /* enumerate the substorage */
469 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
470 substorage = msi_split_string( str, ';' );
471 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
472 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
473 msi_free( substorage );
476 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
478 msiobj_release( &si->hdr );
483 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
485 MSIDATABASE *patch_db = NULL;
488 TRACE("%p %s\n", package, debugstr_w( file ) );
491 * We probably want to make sure we only open a patch collection here.
492 * Patch collections (.msp) and databases (.msi) have different GUIDs
493 * but currently MSI_OpenDatabaseW will accept both.
495 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
496 if ( r != ERROR_SUCCESS )
498 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
502 msi_parse_patch_summary( package, patch_db );
503 msiobj_release( &patch_db->hdr );
505 return ERROR_SUCCESS;
508 /* get the PATCH property, and apply all the patches it specifies */
509 static UINT msi_apply_patches( MSIPACKAGE *package )
511 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
512 LPWSTR patch_list, *patches;
513 UINT i, r = ERROR_SUCCESS;
515 patch_list = msi_dup_property( package, szPatch );
517 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
519 patches = msi_split_string( patch_list, ';' );
520 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_patch_package( package, patches[i] );
524 msi_free( patch_list );
529 static UINT msi_apply_transforms( MSIPACKAGE *package )
531 static const WCHAR szTransforms[] = {
532 'T','R','A','N','S','F','O','R','M','S',0 };
533 LPWSTR xform_list, *xforms;
534 UINT i, r = ERROR_SUCCESS;
536 xform_list = msi_dup_property( package, szTransforms );
537 xforms = msi_split_string( xform_list, ';' );
539 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
541 if (xforms[i][0] == ':')
542 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
544 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
548 msi_free( xform_list );
553 /****************************************************
554 * TOP level entry points
555 *****************************************************/
557 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
558 LPCWSTR szCommandLine )
562 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
563 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
564 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
566 MSI_SetPropertyW(package, szAction, szInstall);
568 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
570 package->script->InWhatSequence = SEQUENCE_INSTALL;
574 LPWSTR p, check, path;
576 path = strdupW(szPackagePath);
577 p = strrchrW(path,'\\');
586 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
587 GetCurrentDirectoryW(MAX_PATH,path);
591 check = msi_dup_property( package, cszSourceDir );
593 MSI_SetPropertyW(package, cszSourceDir, path);
595 check = msi_dup_property( package, cszSOURCEDIR );
597 MSI_SetPropertyW(package, cszSOURCEDIR, path);
599 msi_free( package->PackagePath );
600 package->PackagePath = path;
605 msi_parse_command_line( package, szCommandLine );
607 msi_apply_transforms( package );
608 msi_apply_patches( package );
610 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
612 package->script->InWhatSequence |= SEQUENCE_UI;
613 rc = ACTION_ProcessUISequence(package);
615 if (rc == ERROR_SUCCESS)
617 package->script->InWhatSequence |= SEQUENCE_EXEC;
618 rc = ACTION_ProcessExecSequence(package,TRUE);
622 rc = ACTION_ProcessExecSequence(package,FALSE);
626 /* install was halted but should be considered a success */
630 package->script->CurrentlyScripting= FALSE;
632 /* process the ending type action */
633 if (rc == ERROR_SUCCESS)
634 ACTION_PerformActionSequence(package,-1,ui);
635 else if (rc == ERROR_INSTALL_USEREXIT)
636 ACTION_PerformActionSequence(package,-2,ui);
637 else if (rc == ERROR_INSTALL_SUSPEND)
638 ACTION_PerformActionSequence(package,-4,ui);
640 ACTION_PerformActionSequence(package,-3,ui);
642 /* finish up running custom actions */
643 ACTION_FinishCustomActions(package);
648 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
650 UINT rc = ERROR_SUCCESS;
652 static const WCHAR ExecSeqQuery[] =
653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
654 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
655 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
656 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
658 static const WCHAR UISeqQuery[] =
659 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
660 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
661 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
662 ' ', '=',' ','%','i',0};
665 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
667 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
671 LPCWSTR action, cond;
673 TRACE("Running the actions\n");
675 /* check conditions */
676 cond = MSI_RecordGetString(row,2);
679 /* this is a hack to skip errors in the condition code */
680 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
684 action = MSI_RecordGetString(row,1);
687 ERR("failed to fetch action\n");
688 rc = ERROR_FUNCTION_FAILED;
693 rc = ACTION_PerformUIAction(package,action);
695 rc = ACTION_PerformAction(package,action,FALSE);
697 msiobj_release(&row->hdr);
708 } iterate_action_param;
710 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
712 iterate_action_param *iap= (iterate_action_param*)param;
714 LPCWSTR cond, action;
716 action = MSI_RecordGetString(row,1);
719 ERR("Error is retrieving action name\n");
720 return ERROR_FUNCTION_FAILED;
723 /* check conditions */
724 cond = MSI_RecordGetString(row,2);
727 /* this is a hack to skip errors in the condition code */
728 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
730 TRACE("Skipping action: %s (condition is false)\n",
732 return ERROR_SUCCESS;
737 rc = ACTION_PerformUIAction(iap->package,action);
739 rc = ACTION_PerformAction(iap->package,action,FALSE);
741 msi_dialog_check_messages( NULL );
743 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
744 rc = iap->package->CurrentInstallState;
746 if (rc == ERROR_FUNCTION_NOT_CALLED)
749 if (rc != ERROR_SUCCESS)
750 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
755 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
759 static const WCHAR query[] =
760 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
762 ' ','W','H','E','R','E',' ',
763 '`','S','e','q','u','e','n','c','e','`',' ',
764 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
765 '`','S','e','q','u','e','n','c','e','`',0};
766 iterate_action_param iap;
769 * FIXME: probably should be checking UILevel in the
770 * ACTION_PerformUIAction/ACTION_PerformAction
771 * rather than saving the UI level here. Those
772 * two functions can be merged too.
774 iap.package = package;
777 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
779 r = MSI_OpenQuery( package->db, &view, query, szTable );
780 if (r == ERROR_SUCCESS)
782 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
783 msiobj_release(&view->hdr);
789 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
793 static const WCHAR ExecSeqQuery[] =
794 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
795 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
796 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
797 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
798 'O','R','D','E','R',' ', 'B','Y',' ',
799 '`','S','e','q','u','e','n','c','e','`',0 };
801 static const WCHAR IVQuery[] =
802 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
803 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
804 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
805 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
806 ' ','\'', 'I','n','s','t','a','l','l',
807 'V','a','l','i','d','a','t','e','\'', 0};
809 iterate_action_param iap;
811 iap.package = package;
814 if (package->script->ExecuteSequenceRun)
816 TRACE("Execute Sequence already Run\n");
817 return ERROR_SUCCESS;
820 package->script->ExecuteSequenceRun = TRUE;
822 /* get the sequence number */
825 row = MSI_QueryGetRecord(package->db, IVQuery);
827 return ERROR_FUNCTION_FAILED;
828 seq = MSI_RecordGetInteger(row,1);
829 msiobj_release(&row->hdr);
832 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
833 if (rc == ERROR_SUCCESS)
835 TRACE("Running the actions\n");
837 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
838 msiobj_release(&view->hdr);
844 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
848 static const WCHAR ExecSeqQuery [] =
849 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
850 '`','I','n','s','t','a','l','l',
851 'U','I','S','e','q','u','e','n','c','e','`',
852 ' ','W','H','E','R','E',' ',
853 '`','S','e','q','u','e','n','c','e','`',' ',
854 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
855 '`','S','e','q','u','e','n','c','e','`',0};
856 iterate_action_param iap;
858 iap.package = package;
861 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
863 if (rc == ERROR_SUCCESS)
865 TRACE("Running the actions\n");
867 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
868 msiobj_release(&view->hdr);
874 /********************************************************
875 * ACTION helper functions and functions that perform the actions
876 *******************************************************/
877 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
878 UINT* rc, BOOL force )
884 if (!run && !package->script->CurrentlyScripting)
889 if (strcmpW(action,szInstallFinalize) == 0 ||
890 strcmpW(action,szInstallExecute) == 0 ||
891 strcmpW(action,szInstallExecuteAgain) == 0)
896 while (StandardActions[i].action != NULL)
898 if (strcmpW(StandardActions[i].action, action)==0)
902 ui_actioninfo(package, action, TRUE, 0);
903 *rc = schedule_action(package,INSTALL_SCRIPT,action);
904 ui_actioninfo(package, action, FALSE, *rc);
908 ui_actionstart(package, action);
909 if (StandardActions[i].handler)
911 *rc = StandardActions[i].handler(package);
915 FIXME("unhandled standard action %s\n",debugstr_w(action));
927 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
928 UINT* rc, BOOL force )
933 arc = ACTION_CustomAction(package,action, force);
935 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
944 * A lot of actions are really important even if they don't do anything
945 * explicit... Lots of properties are set at the beginning of the installation
946 * CostFinalize does a bunch of work to translate the directories and such
948 * But until I get write access to the database that is hard, so I am going to
949 * hack it to see if I can get something to run.
951 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
953 UINT rc = ERROR_SUCCESS;
956 TRACE("Performing action (%s)\n",debugstr_w(action));
958 handled = ACTION_HandleStandardAction(package, action, &rc, force);
961 handled = ACTION_HandleCustomAction(package, action, &rc, force);
965 FIXME("unhandled msi action %s\n",debugstr_w(action));
966 rc = ERROR_FUNCTION_NOT_CALLED;
972 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
974 UINT rc = ERROR_SUCCESS;
975 BOOL handled = FALSE;
977 TRACE("Performing action (%s)\n",debugstr_w(action));
979 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
982 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
984 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
989 FIXME("unhandled msi action %s\n",debugstr_w(action));
990 rc = ERROR_FUNCTION_NOT_CALLED;
998 * Actual Action Handlers
1001 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1003 MSIPACKAGE *package = (MSIPACKAGE*)param;
1009 dir = MSI_RecordGetString(row,1);
1012 ERR("Unable to get folder id\n");
1013 return ERROR_SUCCESS;
1016 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1019 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1020 return ERROR_SUCCESS;
1023 TRACE("Folder is %s\n",debugstr_w(full_path));
1026 uirow = MSI_CreateRecord(1);
1027 MSI_RecordSetStringW(uirow,1,full_path);
1028 ui_actiondata(package,szCreateFolders,uirow);
1029 msiobj_release( &uirow->hdr );
1031 if (folder->State == 0)
1032 create_full_pathW(full_path);
1036 msi_free(full_path);
1037 return ERROR_SUCCESS;
1040 /* FIXME: probably should merge this with the above function */
1041 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1043 UINT rc = ERROR_SUCCESS;
1045 LPWSTR install_path;
1047 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1049 return ERROR_FUNCTION_FAILED;
1051 /* create the path */
1052 if (folder->State == 0)
1054 create_full_pathW(install_path);
1057 msi_free(install_path);
1062 UINT msi_create_component_directories( MSIPACKAGE *package )
1066 /* create all the folders required by the components are going to install */
1067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1069 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1071 msi_create_directory( package, comp->Directory );
1074 return ERROR_SUCCESS;
1078 * Also we cannot enable/disable components either, so for now I am just going
1079 * to do all the directories for all the components.
1081 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1083 static const WCHAR ExecSeqQuery[] =
1084 {'S','E','L','E','C','T',' ',
1085 '`','D','i','r','e','c','t','o','r','y','_','`',
1086 ' ','F','R','O','M',' ',
1087 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1091 /* create all the empty folders specified in the CreateFolder table */
1092 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1093 if (rc != ERROR_SUCCESS)
1094 return ERROR_SUCCESS;
1096 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1097 msiobj_release(&view->hdr);
1099 msi_create_component_directories( package );
1104 static UINT load_component( MSIRECORD *row, LPVOID param )
1106 MSIPACKAGE *package = param;
1109 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1111 return ERROR_FUNCTION_FAILED;
1113 list_add_tail( &package->components, &comp->entry );
1115 /* fill in the data */
1116 comp->Component = msi_dup_record_field( row, 1 );
1118 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1120 comp->ComponentId = msi_dup_record_field( row, 2 );
1121 comp->Directory = msi_dup_record_field( row, 3 );
1122 comp->Attributes = MSI_RecordGetInteger(row,4);
1123 comp->Condition = msi_dup_record_field( row, 5 );
1124 comp->KeyPath = msi_dup_record_field( row, 6 );
1126 comp->Installed = INSTALLSTATE_UNKNOWN;
1127 comp->Action = INSTALLSTATE_UNKNOWN;
1128 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1130 return ERROR_SUCCESS;
1133 static UINT load_all_components( MSIPACKAGE *package )
1135 static const WCHAR query[] = {
1136 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1137 '`','C','o','m','p','o','n','e','n','t','`',0 };
1141 if (!list_empty(&package->components))
1142 return ERROR_SUCCESS;
1144 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1145 if (r != ERROR_SUCCESS)
1148 r = MSI_IterateRecords(view, NULL, load_component, package);
1149 msiobj_release(&view->hdr);
1154 MSIPACKAGE *package;
1155 MSIFEATURE *feature;
1158 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1162 cl = msi_alloc( sizeof (*cl) );
1164 return ERROR_NOT_ENOUGH_MEMORY;
1165 cl->component = comp;
1166 list_add_tail( &feature->Components, &cl->entry );
1168 return ERROR_SUCCESS;
1171 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1175 fl = msi_alloc( sizeof(*fl) );
1177 return ERROR_NOT_ENOUGH_MEMORY;
1178 fl->feature = child;
1179 list_add_tail( &parent->Children, &fl->entry );
1181 return ERROR_SUCCESS;
1184 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1186 _ilfs* ilfs= (_ilfs*)param;
1190 component = MSI_RecordGetString(row,1);
1192 /* check to see if the component is already loaded */
1193 comp = get_loaded_component( ilfs->package, component );
1196 ERR("unknown component %s\n", debugstr_w(component));
1197 return ERROR_FUNCTION_FAILED;
1200 add_feature_component( ilfs->feature, comp );
1201 comp->Enabled = TRUE;
1203 return ERROR_SUCCESS;
1206 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1208 MSIFEATURE *feature;
1210 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1212 if ( !lstrcmpW( feature->Feature, name ) )
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->Children );
1241 list_init( &feature->Components );
1243 feature->Feature = msi_dup_record_field( row, 1 );
1245 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1247 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1248 feature->Title = msi_dup_record_field( row, 3 );
1249 feature->Description = msi_dup_record_field( row, 4 );
1251 if (!MSI_RecordIsNull(row,5))
1252 feature->Display = MSI_RecordGetInteger(row,5);
1254 feature->Level= MSI_RecordGetInteger(row,6);
1255 feature->Directory = msi_dup_record_field( row, 7 );
1256 feature->Attributes = MSI_RecordGetInteger(row,8);
1258 feature->Installed = INSTALLSTATE_UNKNOWN;
1259 feature->Action = INSTALLSTATE_UNKNOWN;
1260 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1262 list_add_tail( &package->features, &feature->entry );
1264 /* load feature components */
1266 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1267 if (rc != ERROR_SUCCESS)
1268 return ERROR_SUCCESS;
1270 ilfs.package = package;
1271 ilfs.feature = feature;
1273 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1274 msiobj_release(&view->hdr);
1276 return ERROR_SUCCESS;
1279 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1281 MSIPACKAGE* package = (MSIPACKAGE*)param;
1282 MSIFEATURE *parent, *child;
1284 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1286 return ERROR_FUNCTION_FAILED;
1288 if (!child->Feature_Parent)
1289 return ERROR_SUCCESS;
1291 parent = find_feature_by_name( package, child->Feature_Parent );
1293 return ERROR_FUNCTION_FAILED;
1295 add_feature_child( parent, child );
1296 return ERROR_SUCCESS;
1299 static UINT load_all_features( MSIPACKAGE *package )
1301 static const WCHAR query[] = {
1302 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1303 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1304 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1308 if (!list_empty(&package->features))
1309 return ERROR_SUCCESS;
1311 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1312 if (r != ERROR_SUCCESS)
1315 r = MSI_IterateRecords( view, NULL, load_feature, package );
1316 if (r != ERROR_SUCCESS)
1319 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1320 msiobj_release( &view->hdr );
1325 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1336 static UINT load_file(MSIRECORD *row, LPVOID param)
1338 MSIPACKAGE* package = (MSIPACKAGE*)param;
1342 /* fill in the data */
1344 file = msi_alloc_zero( sizeof (MSIFILE) );
1346 return ERROR_NOT_ENOUGH_MEMORY;
1348 file->File = msi_dup_record_field( row, 1 );
1350 component = MSI_RecordGetString( row, 2 );
1351 file->Component = get_loaded_component( package, component );
1353 if (!file->Component)
1354 ERR("Unfound Component %s\n",debugstr_w(component));
1356 file->FileName = msi_dup_record_field( row, 3 );
1357 reduce_to_longfilename( file->FileName );
1359 file->ShortName = msi_dup_record_field( row, 3 );
1360 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1362 file->FileSize = MSI_RecordGetInteger( row, 4 );
1363 file->Version = msi_dup_record_field( row, 5 );
1364 file->Language = msi_dup_record_field( row, 6 );
1365 file->Attributes = MSI_RecordGetInteger( row, 7 );
1366 file->Sequence = MSI_RecordGetInteger( row, 8 );
1368 file->state = msifs_invalid;
1370 /* if the compressed bits are not set in the file attributes,
1371 * then read the information from the package word count property
1373 if (file->Attributes & msidbFileAttributesCompressed)
1375 file->IsCompressed = TRUE;
1377 else if (file->Attributes & msidbFileAttributesNoncompressed)
1379 file->IsCompressed = FALSE;
1383 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1386 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1388 list_add_tail( &package->files, &file->entry );
1390 return ERROR_SUCCESS;
1393 static UINT load_all_files(MSIPACKAGE *package)
1397 static const WCHAR Query[] =
1398 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1399 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1400 '`','S','e','q','u','e','n','c','e','`', 0};
1402 if (!list_empty(&package->files))
1403 return ERROR_SUCCESS;
1405 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1406 if (rc != ERROR_SUCCESS)
1407 return ERROR_SUCCESS;
1409 rc = MSI_IterateRecords(view, NULL, load_file, package);
1410 msiobj_release(&view->hdr);
1412 return ERROR_SUCCESS;
1417 * I am not doing any of the costing functionality yet.
1418 * Mostly looking at doing the Component and Feature loading
1420 * The native MSI does A LOT of modification to tables here. Mostly adding
1421 * a lot of temporary columns to the Feature and Component tables.
1423 * note: Native msi also tracks the short filename. But I am only going to
1424 * track the long ones. Also looking at this directory table
1425 * it appears that the directory table does not get the parents
1426 * resolved base on property only based on their entries in the
1429 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1431 static const WCHAR szCosting[] =
1432 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1433 static const WCHAR szZero[] = { '0', 0 };
1435 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1436 return ERROR_SUCCESS;
1438 MSI_SetPropertyW(package, szCosting, szZero);
1439 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1441 load_all_components( package );
1442 load_all_features( package );
1443 load_all_files( package );
1445 return ERROR_SUCCESS;
1448 static UINT execute_script(MSIPACKAGE *package, UINT script )
1451 UINT rc = ERROR_SUCCESS;
1453 TRACE("Executing Script %i\n",script);
1455 if (!package->script)
1457 ERR("no script!\n");
1458 return ERROR_FUNCTION_FAILED;
1461 for (i = 0; i < package->script->ActionCount[script]; i++)
1464 action = package->script->Actions[script][i];
1465 ui_actionstart(package, action);
1466 TRACE("Executing Action (%s)\n",debugstr_w(action));
1467 rc = ACTION_PerformAction(package, action, TRUE);
1468 msi_free(package->script->Actions[script][i]);
1469 if (rc != ERROR_SUCCESS)
1472 msi_free(package->script->Actions[script]);
1474 package->script->ActionCount[script] = 0;
1475 package->script->Actions[script] = NULL;
1479 static UINT ACTION_FileCost(MSIPACKAGE *package)
1481 return ERROR_SUCCESS;
1484 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1486 static const WCHAR Query[] =
1487 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1488 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1489 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1490 ' ','=',' ','\'','%','s','\'',
1492 static const WCHAR szDot[] = { '.',0 };
1493 static WCHAR szEmpty[] = { 0 };
1494 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1499 TRACE("Looking for dir %s\n",debugstr_w(dir));
1501 folder = get_loaded_folder( package, dir );
1505 TRACE("Working to load %s\n",debugstr_w(dir));
1507 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1511 folder->Directory = strdupW(dir);
1513 row = MSI_QueryGetRecord(package->db, Query, dir);
1517 p = msi_dup_record_field(row, 3);
1519 /* split src and target dir */
1521 src_short = folder_split_path( p, ':' );
1523 /* split the long and short paths */
1524 tgt_long = folder_split_path( tgt_short, '|' );
1525 src_long = folder_split_path( src_short, '|' );
1527 /* check for no-op dirs */
1528 if (!lstrcmpW(szDot, tgt_short))
1529 tgt_short = szEmpty;
1530 if (!lstrcmpW(szDot, src_short))
1531 src_short = szEmpty;
1534 tgt_long = tgt_short;
1537 src_short = tgt_short;
1538 src_long = tgt_long;
1542 src_long = src_short;
1544 /* FIXME: use the target short path too */
1545 folder->TargetDefault = strdupW(tgt_long);
1546 folder->SourceShortPath = strdupW(src_short);
1547 folder->SourceLongPath = strdupW(src_long);
1550 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1551 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1552 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1554 parent = MSI_RecordGetString(row, 2);
1557 folder->Parent = load_folder( package, parent );
1558 if ( folder->Parent )
1559 TRACE("loaded parent %p %s\n", folder->Parent,
1560 debugstr_w(folder->Parent->Directory));
1562 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1565 folder->Property = msi_dup_property( package, dir );
1567 msiobj_release(&row->hdr);
1569 list_add_tail( &package->folders, &folder->entry );
1571 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1576 /* scan for and update current install states */
1577 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1580 MSIFEATURE *feature;
1582 /* FIXME: component's installed state should be determined
1583 * by the component's registration
1585 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1589 if (!comp->ComponentId)
1592 res = MsiGetComponentPathW( package->ProductCode,
1593 comp->ComponentId, NULL, NULL);
1595 res = INSTALLSTATE_ABSENT;
1596 comp->Installed = res;
1599 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1602 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1604 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1606 comp= cl->component;
1608 if (!comp->ComponentId)
1610 res = INSTALLSTATE_ABSENT;
1614 if (res == INSTALLSTATE_ABSENT)
1615 res = comp->Installed;
1618 if (res == comp->Installed)
1621 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1622 res != INSTALLSTATE_SOURCE)
1624 res = INSTALLSTATE_INCOMPLETE;
1628 feature->Installed = res;
1632 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1635 static const WCHAR all[]={'A','L','L',0};
1637 MSIFEATURE *feature;
1639 override = msi_dup_property( package, property );
1643 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1645 if (strcmpiW(override,all)==0)
1647 feature->ActionRequest= state;
1648 feature->Action = state;
1652 LPWSTR ptr = override;
1653 LPWSTR ptr2 = strchrW(override,',');
1657 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1658 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1660 feature->ActionRequest= state;
1661 feature->Action = state;
1667 ptr2 = strchrW(ptr,',');
1679 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1682 static const WCHAR szlevel[] =
1683 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1684 static const WCHAR szAddLocal[] =
1685 {'A','D','D','L','O','C','A','L',0};
1686 static const WCHAR szRemove[] =
1687 {'R','E','M','O','V','E',0};
1688 static const WCHAR szReinstall[] =
1689 {'R','E','I','N','S','T','A','L','L',0};
1690 BOOL override = FALSE;
1691 MSICOMPONENT* component;
1692 MSIFEATURE *feature;
1695 /* I do not know if this is where it should happen.. but */
1697 TRACE("Checking Install Level\n");
1699 install_level = msi_get_property_int( package, szlevel, 1 );
1701 /* ok here is the _real_ rub
1702 * all these activation/deactivation things happen in order and things
1703 * later on the list override things earlier on the list.
1704 * 1) INSTALLLEVEL processing
1714 * 11) FILEADDDEFAULT
1715 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1716 * ignored for all the features. seems strange, especially since it is not
1717 * documented anywhere, but it is how it works.
1719 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1720 * REMOVE are the big ones, since we don't handle administrative installs
1723 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1724 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1725 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1729 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1731 BOOL feature_state = ((feature->Level > 0) &&
1732 (feature->Level <= install_level));
1734 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1736 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1738 feature->ActionRequest = INSTALLSTATE_SOURCE;
1739 feature->Action = INSTALLSTATE_SOURCE;
1741 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1743 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1744 feature->Action = INSTALLSTATE_ADVERTISED;
1748 feature->ActionRequest = INSTALLSTATE_LOCAL;
1749 feature->Action = INSTALLSTATE_LOCAL;
1754 /* disable child features of unselected parent features */
1755 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1759 if (feature->Level > 0 && feature->Level <= install_level)
1762 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1764 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1765 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1771 /* set the Preselected Property */
1772 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1773 static const WCHAR szOne[] = { '1', 0 };
1775 MSI_SetPropertyW(package,szPreselected,szOne);
1779 * now we want to enable or disable components base on feature
1782 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1786 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1787 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1788 feature->ActionRequest);
1790 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1792 component = cl->component;
1794 if (!component->Enabled)
1796 component->Action = INSTALLSTATE_UNKNOWN;
1797 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1801 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1803 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1805 component->Action = INSTALLSTATE_LOCAL;
1806 component->ActionRequest = INSTALLSTATE_LOCAL;
1809 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1811 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1812 (component->Action == INSTALLSTATE_ABSENT) ||
1813 (component->Action == INSTALLSTATE_ADVERTISED) ||
1814 (component->Action == INSTALLSTATE_DEFAULT))
1817 component->Action = INSTALLSTATE_SOURCE;
1818 component->ActionRequest = INSTALLSTATE_SOURCE;
1821 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1823 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1824 (component->Action == INSTALLSTATE_ABSENT))
1827 component->Action = INSTALLSTATE_ADVERTISED;
1828 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1831 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1833 if (component->Action == INSTALLSTATE_UNKNOWN)
1835 component->Action = INSTALLSTATE_ABSENT;
1836 component->ActionRequest = INSTALLSTATE_ABSENT;
1839 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1841 component->Action = INSTALLSTATE_UNKNOWN;
1842 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1846 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1848 feature->Action = INSTALLSTATE_LOCAL;
1849 feature->ActionRequest = INSTALLSTATE_LOCAL;
1854 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1856 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1857 debugstr_w(component->Component), component->Installed,
1858 component->Action, component->ActionRequest);
1862 return ERROR_SUCCESS;
1865 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1867 MSIPACKAGE *package = (MSIPACKAGE*)param;
1871 name = MSI_RecordGetString(row,1);
1873 /* This helper function now does ALL the work */
1874 TRACE("Dir %s ...\n",debugstr_w(name));
1875 load_folder(package,name);
1876 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1877 TRACE("resolves to %s\n",debugstr_w(path));
1880 return ERROR_SUCCESS;
1883 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1885 MSIPACKAGE *package = (MSIPACKAGE*)param;
1887 MSIFEATURE *feature;
1889 name = MSI_RecordGetString( row, 1 );
1891 feature = get_loaded_feature( package, name );
1893 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1897 Condition = MSI_RecordGetString(row,3);
1899 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1901 int level = MSI_RecordGetInteger(row,2);
1902 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1903 feature->Level = level;
1906 return ERROR_SUCCESS;
1909 static void load_all_component_states(MSIPACKAGE *package)
1913 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1915 switch (comp->Attributes)
1917 case msidbComponentAttributesLocalOnly:
1918 comp->Action = INSTALLSTATE_LOCAL;
1919 comp->ActionRequest = INSTALLSTATE_LOCAL;
1921 case msidbComponentAttributesSourceOnly:
1922 comp->Action = INSTALLSTATE_SOURCE;
1923 comp->ActionRequest = INSTALLSTATE_SOURCE;
1925 case msidbComponentAttributesOptional:
1926 comp->Action = INSTALLSTATE_DEFAULT;
1927 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1930 comp->Action = INSTALLSTATE_LOCAL;
1931 comp->ActionRequest = INSTALLSTATE_LOCAL;
1937 * A lot is done in this function aside from just the costing.
1938 * The costing needs to be implemented at some point but for now I am going
1939 * to focus on the directory building
1942 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1944 static const WCHAR ExecSeqQuery[] =
1945 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1946 '`','D','i','r','e','c','t','o','r','y','`',0};
1947 static const WCHAR ConditionQuery[] =
1948 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1949 '`','C','o','n','d','i','t','i','o','n','`',0};
1950 static const WCHAR szCosting[] =
1951 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1952 static const WCHAR szlevel[] =
1953 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1954 static const WCHAR szOne[] = { '1', 0 };
1961 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1962 return ERROR_SUCCESS;
1964 TRACE("Building Directory properties\n");
1966 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1967 if (rc == ERROR_SUCCESS)
1969 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1971 msiobj_release(&view->hdr);
1974 load_all_component_states(package);
1976 TRACE("File calculations\n");
1978 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1980 MSICOMPONENT* comp = file->Component;
1986 if (file->IsCompressed)
1988 comp->ForceLocalState = TRUE;
1989 comp->Action = INSTALLSTATE_LOCAL;
1990 comp->ActionRequest = INSTALLSTATE_LOCAL;
1993 /* calculate target */
1994 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1996 msi_free(file->TargetPath);
1998 TRACE("file %s is named %s\n",
1999 debugstr_w(file->File),debugstr_w(file->FileName));
2001 file->TargetPath = build_directory_name(2, p, file->FileName);
2005 TRACE("file %s resolves to %s\n",
2006 debugstr_w(file->File),debugstr_w(file->TargetPath));
2008 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2010 file->state = msifs_missing;
2011 comp->Cost += file->FileSize;
2021 static WCHAR name[] = {'\\',0};
2022 static const WCHAR name_fmt[] =
2023 {'%','u','.','%','u','.','%','u','.','%','u',0};
2024 WCHAR filever[0x100];
2025 VS_FIXEDFILEINFO *lpVer;
2027 TRACE("Version comparison..\n");
2028 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2029 version = msi_alloc(versize);
2030 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2032 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2034 sprintfW(filever,name_fmt,
2035 HIWORD(lpVer->dwFileVersionMS),
2036 LOWORD(lpVer->dwFileVersionMS),
2037 HIWORD(lpVer->dwFileVersionLS),
2038 LOWORD(lpVer->dwFileVersionLS));
2040 TRACE("new %s old %s\n", debugstr_w(file->Version),
2041 debugstr_w(filever));
2042 if (strcmpiW(filever,file->Version)<0)
2044 file->state = msifs_overwrite;
2045 /* FIXME: cost should be diff in size */
2046 comp->Cost += file->FileSize;
2049 file->state = msifs_present;
2053 file->state = msifs_present;
2056 TRACE("Evaluating Condition Table\n");
2058 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2059 if (rc == ERROR_SUCCESS)
2061 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2063 msiobj_release(&view->hdr);
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2069 if (comp->Condition)
2071 if (MSI_EvaluateConditionW(package,
2072 comp->Condition) == MSICONDITION_FALSE)
2074 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2075 comp->Enabled = FALSE;
2080 MSI_SetPropertyW(package,szCosting,szOne);
2081 /* set default run level if not set */
2082 level = msi_dup_property( package, szlevel );
2084 MSI_SetPropertyW(package,szlevel, szOne);
2087 ACTION_UpdateInstallStates(package);
2089 return MSI_SetFeatureStates(package);
2092 /* OK this value is "interpreted" and then formatted based on the
2093 first few characters */
2094 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2098 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2104 LPWSTR deformated = NULL;
2107 deformat_string(package, &value[2], &deformated);
2109 /* binary value type */
2113 *size = (strlenW(ptr)/2)+1;
2115 *size = strlenW(ptr)/2;
2117 data = msi_alloc(*size);
2123 /* if uneven pad with a zero in front */
2129 data[count] = (BYTE)strtol(byte,NULL,0);
2131 TRACE("Uneven byte count\n");
2139 data[count] = (BYTE)strtol(byte,NULL,0);
2142 msi_free(deformated);
2144 TRACE("Data %i bytes(%i)\n",*size,count);
2151 deformat_string(package, &value[1], &deformated);
2154 *size = sizeof(DWORD);
2155 data = msi_alloc(*size);
2161 if ( (*p < '0') || (*p > '9') )
2167 if (deformated[0] == '-')
2170 TRACE("DWORD %i\n",*(LPDWORD)data);
2172 msi_free(deformated);
2177 static const WCHAR szMulti[] = {'[','~',']',0};
2186 *type=REG_EXPAND_SZ;
2194 if (strstrW(value,szMulti))
2195 *type = REG_MULTI_SZ;
2197 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2202 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2204 MSIPACKAGE *package = (MSIPACKAGE*)param;
2205 static const WCHAR szHCR[] =
2206 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2207 'R','O','O','T','\\',0};
2208 static const WCHAR szHCU[] =
2209 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2210 'U','S','E','R','\\',0};
2211 static const WCHAR szHLM[] =
2212 {'H','K','E','Y','_','L','O','C','A','L','_',
2213 'M','A','C','H','I','N','E','\\',0};
2214 static const WCHAR szHU[] =
2215 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2217 LPSTR value_data = NULL;
2218 HKEY root_key, hkey;
2221 LPCWSTR szRoot, component, name, key, value;
2226 BOOL check_first = FALSE;
2229 ui_progress(package,2,0,0,0);
2236 component = MSI_RecordGetString(row, 6);
2237 comp = get_loaded_component(package,component);
2239 return ERROR_SUCCESS;
2241 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2243 TRACE("Skipping write due to disabled component %s\n",
2244 debugstr_w(component));
2246 comp->Action = comp->Installed;
2248 return ERROR_SUCCESS;
2251 comp->Action = INSTALLSTATE_LOCAL;
2253 name = MSI_RecordGetString(row, 4);
2254 if( MSI_RecordIsNull(row,5) && name )
2256 /* null values can have special meanings */
2257 if (name[0]=='-' && name[1] == 0)
2258 return ERROR_SUCCESS;
2259 else if ((name[0]=='+' && name[1] == 0) ||
2260 (name[0] == '*' && name[1] == 0))
2265 root = MSI_RecordGetInteger(row,2);
2266 key = MSI_RecordGetString(row, 3);
2268 /* get the root key */
2273 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2274 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2275 if (all_users && all_users[0] == '1')
2277 root_key = HKEY_LOCAL_MACHINE;
2282 root_key = HKEY_CURRENT_USER;
2285 msi_free(all_users);
2288 case 0: root_key = HKEY_CLASSES_ROOT;
2291 case 1: root_key = HKEY_CURRENT_USER;
2294 case 2: root_key = HKEY_LOCAL_MACHINE;
2297 case 3: root_key = HKEY_USERS;
2301 ERR("Unknown root %i\n",root);
2307 return ERROR_SUCCESS;
2309 deformat_string(package, key , &deformated);
2310 size = strlenW(deformated) + strlenW(szRoot) + 1;
2311 uikey = msi_alloc(size*sizeof(WCHAR));
2312 strcpyW(uikey,szRoot);
2313 strcatW(uikey,deformated);
2315 if (RegCreateKeyW( root_key, deformated, &hkey))
2317 ERR("Could not create key %s\n",debugstr_w(deformated));
2318 msi_free(deformated);
2320 return ERROR_SUCCESS;
2322 msi_free(deformated);
2324 value = MSI_RecordGetString(row,5);
2326 value_data = parse_value(package, value, &type, &size);
2329 static const WCHAR szEmpty[] = {0};
2330 value_data = (LPSTR)strdupW(szEmpty);
2335 deformat_string(package, name, &deformated);
2337 /* get the double nulls to terminate SZ_MULTI */
2338 if (type == REG_MULTI_SZ)
2339 size +=sizeof(WCHAR);
2343 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2345 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2350 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2351 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2353 TRACE("value %s of %s checked already exists\n",
2354 debugstr_w(deformated), debugstr_w(uikey));
2358 TRACE("Checked and setting value %s of %s\n",
2359 debugstr_w(deformated), debugstr_w(uikey));
2360 if (deformated || size)
2361 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2366 uirow = MSI_CreateRecord(3);
2367 MSI_RecordSetStringW(uirow,2,deformated);
2368 MSI_RecordSetStringW(uirow,1,uikey);
2371 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2373 MSI_RecordSetStringW(uirow,3,value);
2375 ui_actiondata(package,szWriteRegistryValues,uirow);
2376 msiobj_release( &uirow->hdr );
2378 msi_free(value_data);
2379 msi_free(deformated);
2382 return ERROR_SUCCESS;
2385 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2389 static const WCHAR ExecSeqQuery[] =
2390 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2391 '`','R','e','g','i','s','t','r','y','`',0 };
2393 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2394 if (rc != ERROR_SUCCESS)
2395 return ERROR_SUCCESS;
2397 /* increment progress bar each time action data is sent */
2398 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2400 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2402 msiobj_release(&view->hdr);
2406 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2408 package->script->CurrentlyScripting = TRUE;
2410 return ERROR_SUCCESS;
2414 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2419 static const WCHAR q1[]=
2420 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2421 '`','R','e','g','i','s','t','r','y','`',0};
2424 MSIFEATURE *feature;
2427 TRACE("InstallValidate\n");
2429 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2430 if (rc == ERROR_SUCCESS)
2432 MSI_IterateRecords( view, &progress, NULL, package );
2433 msiobj_release( &view->hdr );
2434 total += progress * REG_PROGRESS_VALUE;
2437 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2438 total += COMPONENT_PROGRESS_VALUE;
2440 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2441 total += file->FileSize;
2443 ui_progress(package,0,total,0,0);
2445 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2447 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2448 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2449 feature->ActionRequest);
2452 return ERROR_SUCCESS;
2455 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2457 MSIPACKAGE* package = (MSIPACKAGE*)param;
2458 LPCWSTR cond = NULL;
2459 LPCWSTR message = NULL;
2460 static const WCHAR title[]=
2461 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2463 cond = MSI_RecordGetString(row,1);
2465 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2468 message = MSI_RecordGetString(row,2);
2469 deformat_string(package,message,&deformated);
2470 MessageBoxW(NULL,deformated,title,MB_OK);
2471 msi_free(deformated);
2472 return ERROR_FUNCTION_FAILED;
2475 return ERROR_SUCCESS;
2478 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2481 MSIQUERY * view = NULL;
2482 static const WCHAR ExecSeqQuery[] =
2483 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2484 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2486 TRACE("Checking launch conditions\n");
2488 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2489 if (rc != ERROR_SUCCESS)
2490 return ERROR_SUCCESS;
2492 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2493 msiobj_release(&view->hdr);
2498 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2502 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2504 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2506 MSIRECORD * row = 0;
2508 LPWSTR deformated,buffer,deformated_name;
2510 static const WCHAR ExecSeqQuery[] =
2511 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2512 '`','R','e','g','i','s','t','r','y','`',' ',
2513 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2514 ' ','=',' ' ,'\'','%','s','\'',0 };
2515 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2516 static const WCHAR fmt2[]=
2517 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2519 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2523 root = MSI_RecordGetInteger(row,2);
2524 key = MSI_RecordGetString(row, 3);
2525 name = MSI_RecordGetString(row, 4);
2526 deformat_string(package, key , &deformated);
2527 deformat_string(package, name, &deformated_name);
2529 len = strlenW(deformated) + 6;
2530 if (deformated_name)
2531 len+=strlenW(deformated_name);
2533 buffer = msi_alloc( len *sizeof(WCHAR));
2535 if (deformated_name)
2536 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2538 sprintfW(buffer,fmt,root,deformated);
2540 msi_free(deformated);
2541 msi_free(deformated_name);
2542 msiobj_release(&row->hdr);
2546 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2548 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2553 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2556 return strdupW( file->TargetPath );
2561 static HKEY openSharedDLLsKey(void)
2564 static const WCHAR path[] =
2565 {'S','o','f','t','w','a','r','e','\\',
2566 'M','i','c','r','o','s','o','f','t','\\',
2567 'W','i','n','d','o','w','s','\\',
2568 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2569 'S','h','a','r','e','d','D','L','L','s',0};
2571 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2575 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2580 DWORD sz = sizeof(count);
2583 hkey = openSharedDLLsKey();
2584 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2585 if (rc != ERROR_SUCCESS)
2591 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2595 hkey = openSharedDLLsKey();
2597 msi_reg_set_val_dword( hkey, path, count );
2599 RegDeleteValueW(hkey,path);
2605 * Return TRUE if the count should be written out and FALSE if not
2607 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2609 MSIFEATURE *feature;
2613 /* only refcount DLLs */
2614 if (comp->KeyPath == NULL ||
2615 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2616 comp->Attributes & msidbComponentAttributesODBCDataSource)
2620 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2621 write = (count > 0);
2623 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2627 /* increment counts */
2628 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2632 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2635 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2637 if ( cl->component == comp )
2642 /* decrement counts */
2643 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2647 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2650 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2652 if ( cl->component == comp )
2657 /* ref count all the files in the component */
2662 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2664 if (file->Component == comp)
2665 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2669 /* add a count for permenent */
2670 if (comp->Attributes & msidbComponentAttributesPermanent)
2673 comp->RefCount = count;
2676 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2680 * Ok further analysis makes me think that this work is
2681 * actually done in the PublishComponents and PublishFeatures
2682 * step, and not here. It appears like the keypath and all that is
2683 * resolved in this step, however actually written in the Publish steps.
2684 * But we will leave it here for now because it is unclear
2686 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2688 WCHAR squished_pc[GUID_SIZE];
2689 WCHAR squished_cc[GUID_SIZE];
2692 HKEY hkey=0,hkey2=0;
2694 /* writes the Component and Features values to the registry */
2696 rc = MSIREG_OpenComponents(&hkey);
2697 if (rc != ERROR_SUCCESS)
2700 squash_guid(package->ProductCode,squished_pc);
2701 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2703 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2707 ui_progress(package,2,0,0,0);
2708 if (!comp->ComponentId)
2711 squash_guid(comp->ComponentId,squished_cc);
2713 msi_free(comp->FullKeypath);
2714 comp->FullKeypath = resolve_keypath( package, comp );
2716 /* do the refcounting */
2717 ACTION_RefCountComponent( package, comp );
2719 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2720 debugstr_w(comp->Component),
2721 debugstr_w(squished_cc),
2722 debugstr_w(comp->FullKeypath),
2725 * Write the keypath out if the component is to be registered
2726 * and delete the key if the component is to be deregistered
2728 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2730 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2731 if (rc != ERROR_SUCCESS)
2734 if (!comp->FullKeypath)
2737 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2739 if (comp->Attributes & msidbComponentAttributesPermanent)
2741 static const WCHAR szPermKey[] =
2742 { '0','0','0','0','0','0','0','0','0','0','0','0',
2743 '0','0','0','0','0','0','0','0','0','0','0','0',
2744 '0','0','0','0','0','0','0','0',0 };
2746 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2752 uirow = MSI_CreateRecord(3);
2753 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2754 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2755 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2756 ui_actiondata(package,szProcessComponents,uirow);
2757 msiobj_release( &uirow->hdr );
2759 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2763 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2764 if (rc != ERROR_SUCCESS)
2767 RegDeleteValueW(hkey2,squished_pc);
2769 /* if the key is empty delete it */
2770 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2772 if (res == ERROR_NO_MORE_ITEMS)
2773 RegDeleteKeyW(hkey,squished_cc);
2776 uirow = MSI_CreateRecord(2);
2777 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2778 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2779 ui_actiondata(package,szProcessComponents,uirow);
2780 msiobj_release( &uirow->hdr );
2795 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2796 LPWSTR lpszName, LONG_PTR lParam)
2799 typelib_struct *tl_struct = (typelib_struct*) lParam;
2800 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2804 if (!IS_INTRESOURCE(lpszName))
2806 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2810 sz = strlenW(tl_struct->source)+4;
2811 sz *= sizeof(WCHAR);
2813 if ((INT_PTR)lpszName == 1)
2814 tl_struct->path = strdupW(tl_struct->source);
2817 tl_struct->path = msi_alloc(sz);
2818 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2821 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2822 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2823 if (!SUCCEEDED(res))
2825 msi_free(tl_struct->path);
2826 tl_struct->path = NULL;
2831 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2832 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2834 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2838 msi_free(tl_struct->path);
2839 tl_struct->path = NULL;
2841 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2842 ITypeLib_Release(tl_struct->ptLib);
2847 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2849 MSIPACKAGE* package = (MSIPACKAGE*)param;
2853 typelib_struct tl_struct;
2855 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2857 component = MSI_RecordGetString(row,3);
2858 comp = get_loaded_component(package,component);
2860 return ERROR_SUCCESS;
2862 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2864 TRACE("Skipping typelib reg due to disabled component\n");
2866 comp->Action = comp->Installed;
2868 return ERROR_SUCCESS;
2871 comp->Action = INSTALLSTATE_LOCAL;
2873 file = get_loaded_file( package, comp->KeyPath );
2875 return ERROR_SUCCESS;
2877 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2881 guid = MSI_RecordGetString(row,1);
2882 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2883 tl_struct.source = strdupW( file->TargetPath );
2884 tl_struct.path = NULL;
2886 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2887 (LONG_PTR)&tl_struct);
2895 helpid = MSI_RecordGetString(row,6);
2898 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2899 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2902 if (!SUCCEEDED(res))
2903 ERR("Failed to register type library %s\n",
2904 debugstr_w(tl_struct.path));
2907 ui_actiondata(package,szRegisterTypeLibraries,row);
2909 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2912 ITypeLib_Release(tl_struct.ptLib);
2913 msi_free(tl_struct.path);
2916 ERR("Failed to load type library %s\n",
2917 debugstr_w(tl_struct.source));
2919 FreeLibrary(module);
2920 msi_free(tl_struct.source);
2923 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2925 return ERROR_SUCCESS;
2928 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2931 * OK this is a bit confusing.. I am given a _Component key and I believe
2932 * that the file that is being registered as a type library is the "key file
2933 * of that component" which I interpret to mean "The file in the KeyPath of
2938 static const WCHAR Query[] =
2939 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2940 '`','T','y','p','e','L','i','b','`',0};
2942 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2943 if (rc != ERROR_SUCCESS)
2944 return ERROR_SUCCESS;
2946 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2947 msiobj_release(&view->hdr);
2951 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2953 MSIPACKAGE *package = (MSIPACKAGE*)param;
2954 LPWSTR target_file, target_folder, filename;
2955 LPCWSTR buffer, extension;
2957 static const WCHAR szlnk[]={'.','l','n','k',0};
2958 IShellLinkW *sl = NULL;
2959 IPersistFile *pf = NULL;
2962 buffer = MSI_RecordGetString(row,4);
2963 comp = get_loaded_component(package,buffer);
2965 return ERROR_SUCCESS;
2967 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2969 TRACE("Skipping shortcut creation due to disabled component\n");
2971 comp->Action = comp->Installed;
2973 return ERROR_SUCCESS;
2976 comp->Action = INSTALLSTATE_LOCAL;
2978 ui_actiondata(package,szCreateShortcuts,row);
2980 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2981 &IID_IShellLinkW, (LPVOID *) &sl );
2985 ERR("CLSID_ShellLink not available\n");
2989 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2992 ERR("QueryInterface(IID_IPersistFile) failed\n");
2996 buffer = MSI_RecordGetString(row,2);
2997 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2999 /* may be needed because of a bug somehwere else */
3000 create_full_pathW(target_folder);
3002 filename = msi_dup_record_field( row, 3 );
3003 reduce_to_longfilename(filename);
3005 extension = strchrW(filename,'.');
3006 if (!extension || strcmpiW(extension,szlnk))
3008 int len = strlenW(filename);
3009 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3010 memcpy(filename + len, szlnk, sizeof(szlnk));
3012 target_file = build_directory_name(2, target_folder, filename);
3013 msi_free(target_folder);
3016 buffer = MSI_RecordGetString(row,5);
3017 if (strchrW(buffer,'['))
3020 deformat_string(package,buffer,&deformated);
3021 IShellLinkW_SetPath(sl,deformated);
3022 msi_free(deformated);
3026 FIXME("poorly handled shortcut format, advertised shortcut\n");
3027 IShellLinkW_SetPath(sl,comp->FullKeypath);
3030 if (!MSI_RecordIsNull(row,6))
3033 buffer = MSI_RecordGetString(row,6);
3034 deformat_string(package,buffer,&deformated);
3035 IShellLinkW_SetArguments(sl,deformated);
3036 msi_free(deformated);
3039 if (!MSI_RecordIsNull(row,7))
3041 buffer = MSI_RecordGetString(row,7);
3042 IShellLinkW_SetDescription(sl,buffer);
3045 if (!MSI_RecordIsNull(row,8))
3046 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3048 if (!MSI_RecordIsNull(row,9))
3053 buffer = MSI_RecordGetString(row,9);
3055 Path = build_icon_path(package,buffer);
3056 index = MSI_RecordGetInteger(row,10);
3058 /* no value means 0 */
3059 if (index == MSI_NULL_INTEGER)
3062 IShellLinkW_SetIconLocation(sl,Path,index);
3066 if (!MSI_RecordIsNull(row,11))
3067 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3069 if (!MSI_RecordIsNull(row,12))
3072 buffer = MSI_RecordGetString(row,12);
3073 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3075 IShellLinkW_SetWorkingDirectory(sl,Path);
3079 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3080 IPersistFile_Save(pf,target_file,FALSE);
3082 msi_free(target_file);
3086 IPersistFile_Release( pf );
3088 IShellLinkW_Release( sl );
3090 return ERROR_SUCCESS;
3093 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3098 static const WCHAR Query[] =
3099 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3100 '`','S','h','o','r','t','c','u','t','`',0};
3102 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3103 if (rc != ERROR_SUCCESS)
3104 return ERROR_SUCCESS;
3106 res = CoInitialize( NULL );
3109 ERR("CoInitialize failed\n");
3110 return ERROR_FUNCTION_FAILED;
3113 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3114 msiobj_release(&view->hdr);
3121 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3123 MSIPACKAGE* package = (MSIPACKAGE*)param;
3132 FileName = MSI_RecordGetString(row,1);
3135 ERR("Unable to get FileName\n");
3136 return ERROR_SUCCESS;
3139 FilePath = build_icon_path(package,FileName);
3141 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3143 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3144 FILE_ATTRIBUTE_NORMAL, NULL);
3146 if (the_file == INVALID_HANDLE_VALUE)
3148 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3150 return ERROR_SUCCESS;
3157 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3158 if (rc != ERROR_SUCCESS)
3160 ERR("Failed to get stream\n");
3161 CloseHandle(the_file);
3162 DeleteFileW(FilePath);
3165 WriteFile(the_file,buffer,sz,&write,NULL);
3166 } while (sz == 1024);
3170 CloseHandle(the_file);
3172 uirow = MSI_CreateRecord(1);
3173 MSI_RecordSetStringW(uirow,1,FileName);
3174 ui_actiondata(package,szPublishProduct,uirow);
3175 msiobj_release( &uirow->hdr );
3177 return ERROR_SUCCESS;
3181 * 99% of the work done here is only done for
3182 * advertised installs. However this is where the
3183 * Icon table is processed and written out
3184 * so that is what I am going to do here.
3186 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3190 static const WCHAR Query[]=
3191 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3192 '`','I','c','o','n','`',0};
3193 /* for registry stuff */
3196 static const WCHAR szProductLanguage[] =
3197 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3198 static const WCHAR szARPProductIcon[] =
3199 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3200 static const WCHAR szProductVersion[] =
3201 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3205 MSIHANDLE hDb, hSumInfo;
3207 /* write out icon files */
3209 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3210 if (rc == ERROR_SUCCESS)
3212 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3213 msiobj_release(&view->hdr);
3216 /* ok there is a lot more done here but i need to figure out what */
3218 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3219 if (rc != ERROR_SUCCESS)
3222 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3223 if (rc != ERROR_SUCCESS)
3227 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3228 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3231 langid = msi_get_property_int( package, szProductLanguage, 0 );
3232 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3234 buffer = msi_dup_property( package, szARPProductIcon );
3237 LPWSTR path = build_icon_path(package,buffer);
3238 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3243 buffer = msi_dup_property( package, szProductVersion );
3246 DWORD verdword = msi_version_str_to_dword(buffer);
3247 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3251 /* FIXME: Need to write more keys to the user registry */
3253 hDb= alloc_msihandle( &package->db->hdr );
3255 rc = ERROR_NOT_ENOUGH_MEMORY;
3258 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3259 MsiCloseHandle(hDb);
3260 if (rc == ERROR_SUCCESS)
3262 WCHAR guidbuffer[0x200];
3264 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3266 if (rc == ERROR_SUCCESS)
3268 WCHAR squashed[GUID_SIZE];
3269 /* for now we only care about the first guid */
3270 LPWSTR ptr = strchrW(guidbuffer,';');
3272 squash_guid(guidbuffer,squashed);
3273 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3277 ERR("Unable to query Revision_Number...\n");
3280 MsiCloseHandle(hSumInfo);
3284 ERR("Unable to open Summary Information\n");
3296 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3298 MSIPACKAGE *package = (MSIPACKAGE*)param;
3299 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3300 LPWSTR deformated_section, deformated_key, deformated_value;
3301 LPWSTR folder, fullname = NULL;
3305 static const WCHAR szWindowsFolder[] =
3306 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3308 component = MSI_RecordGetString(row, 8);
3309 comp = get_loaded_component(package,component);
3311 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3313 TRACE("Skipping ini file due to disabled component %s\n",
3314 debugstr_w(component));
3316 comp->Action = comp->Installed;
3318 return ERROR_SUCCESS;
3321 comp->Action = INSTALLSTATE_LOCAL;
3323 identifier = MSI_RecordGetString(row,1);
3324 filename = MSI_RecordGetString(row,2);
3325 dirproperty = MSI_RecordGetString(row,3);
3326 section = MSI_RecordGetString(row,4);
3327 key = MSI_RecordGetString(row,5);
3328 value = MSI_RecordGetString(row,6);
3329 action = MSI_RecordGetInteger(row,7);
3331 deformat_string(package,section,&deformated_section);
3332 deformat_string(package,key,&deformated_key);
3333 deformat_string(package,value,&deformated_value);
3337 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3339 folder = msi_dup_property( package, dirproperty );
3342 folder = msi_dup_property( package, szWindowsFolder );
3346 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3350 fullname = build_directory_name(2, folder, filename);
3354 TRACE("Adding value %s to section %s in %s\n",
3355 debugstr_w(deformated_key), debugstr_w(deformated_section),
3356 debugstr_w(fullname));
3357 WritePrivateProfileStringW(deformated_section, deformated_key,
3358 deformated_value, fullname);
3360 else if (action == 1)
3363 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3364 returned, 10, fullname);
3365 if (returned[0] == 0)
3367 TRACE("Adding value %s to section %s in %s\n",
3368 debugstr_w(deformated_key), debugstr_w(deformated_section),
3369 debugstr_w(fullname));
3371 WritePrivateProfileStringW(deformated_section, deformated_key,
3372 deformated_value, fullname);
3375 else if (action == 3)
3376 FIXME("Append to existing section not yet implemented\n");
3378 uirow = MSI_CreateRecord(4);
3379 MSI_RecordSetStringW(uirow,1,identifier);
3380 MSI_RecordSetStringW(uirow,2,deformated_section);
3381 MSI_RecordSetStringW(uirow,3,deformated_key);
3382 MSI_RecordSetStringW(uirow,4,deformated_value);
3383 ui_actiondata(package,szWriteIniValues,uirow);
3384 msiobj_release( &uirow->hdr );
3388 msi_free(deformated_key);
3389 msi_free(deformated_value);
3390 msi_free(deformated_section);
3391 return ERROR_SUCCESS;
3394 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3398 static const WCHAR ExecSeqQuery[] =
3399 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3400 '`','I','n','i','F','i','l','e','`',0};
3402 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3403 if (rc != ERROR_SUCCESS)
3405 TRACE("no IniFile table\n");
3406 return ERROR_SUCCESS;
3409 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3410 msiobj_release(&view->hdr);
3414 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3416 MSIPACKAGE *package = (MSIPACKAGE*)param;
3421 static const WCHAR ExeStr[] =
3422 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3423 static const WCHAR close[] = {'\"',0};
3425 PROCESS_INFORMATION info;
3430 memset(&si,0,sizeof(STARTUPINFOW));
3432 filename = MSI_RecordGetString(row,1);
3433 file = get_loaded_file( package, filename );
3437 ERR("Unable to find file id %s\n",debugstr_w(filename));
3438 return ERROR_SUCCESS;
3441 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3443 FullName = msi_alloc(len*sizeof(WCHAR));
3444 strcpyW(FullName,ExeStr);
3445 strcatW( FullName, file->TargetPath );
3446 strcatW(FullName,close);
3448 TRACE("Registering %s\n",debugstr_w(FullName));
3449 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3453 msi_dialog_check_messages(info.hProcess);
3458 uirow = MSI_CreateRecord( 2 );
3459 uipath = strdupW( file->TargetPath );
3460 p = strrchrW(uipath,'\\');
3463 MSI_RecordSetStringW( uirow, 1, &p[2] );
3464 MSI_RecordSetStringW( uirow, 2, uipath);
3465 ui_actiondata( package, szSelfRegModules, uirow);
3466 msiobj_release( &uirow->hdr );
3468 /* FIXME: call ui_progress? */
3470 return ERROR_SUCCESS;
3473 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3477 static const WCHAR ExecSeqQuery[] =
3478 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3479 '`','S','e','l','f','R','e','g','`',0};
3481 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3482 if (rc != ERROR_SUCCESS)
3484 TRACE("no SelfReg table\n");
3485 return ERROR_SUCCESS;
3488 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3489 msiobj_release(&view->hdr);
3491 return ERROR_SUCCESS;
3494 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3496 MSIFEATURE *feature;
3501 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3502 if (rc != ERROR_SUCCESS)
3505 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3506 if (rc != ERROR_SUCCESS)
3509 /* here the guids are base 85 encoded */
3510 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3516 BOOL absent = FALSE;
3519 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3520 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3521 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3525 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3529 if (feature->Feature_Parent)
3530 size += strlenW( feature->Feature_Parent )+2;
3532 data = msi_alloc(size * sizeof(WCHAR));
3535 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3537 MSICOMPONENT* component = cl->component;
3541 if (component->ComponentId)
3543 TRACE("From %s\n",debugstr_w(component->ComponentId));
3544 CLSIDFromString(component->ComponentId, &clsid);
3545 encode_base85_guid(&clsid,buf);
3546 TRACE("to %s\n",debugstr_w(buf));
3550 if (feature->Feature_Parent)
3552 static const WCHAR sep[] = {'\2',0};
3554 strcatW(data,feature->Feature_Parent);
3557 msi_reg_set_val_str( hkey, feature->Feature, data );
3561 if (feature->Feature_Parent)
3562 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3565 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3566 (LPBYTE)feature->Feature_Parent,size);
3570 size += 2*sizeof(WCHAR);
3571 data = msi_alloc(size);
3574 if (feature->Feature_Parent)
3575 strcpyW( &data[1], feature->Feature_Parent );
3576 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3582 uirow = MSI_CreateRecord( 1 );
3583 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3584 ui_actiondata( package, szPublishFeatures, uirow);
3585 msiobj_release( &uirow->hdr );
3586 /* FIXME: call ui_progress? */
3595 static UINT msi_get_local_package_name( LPWSTR path )
3597 static const WCHAR szInstaller[] = {
3598 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3599 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3603 time = GetTickCount();
3604 GetWindowsDirectoryW( path, MAX_PATH );
3605 lstrcatW( path, szInstaller );
3606 CreateDirectoryW( path, NULL );
3608 len = lstrlenW(path);
3609 for (i=0; i<0x10000; i++)
3611 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3612 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3613 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3614 if (handle != INVALID_HANDLE_VALUE)
3616 CloseHandle(handle);
3619 if (GetLastError() != ERROR_FILE_EXISTS &&
3620 GetLastError() != ERROR_SHARING_VIOLATION)
3621 return ERROR_FUNCTION_FAILED;
3624 return ERROR_SUCCESS;
3627 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3629 static const WCHAR szOriginalDatabase[] =
3630 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3631 WCHAR packagefile[MAX_PATH];
3635 r = msi_get_local_package_name( packagefile );
3636 if (r != ERROR_SUCCESS)
3639 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3641 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3642 r = CopyFileW( msiFilePath, packagefile, FALSE);
3643 msi_free( msiFilePath );
3647 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3648 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3649 return ERROR_FUNCTION_FAILED;
3652 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3653 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3654 return ERROR_SUCCESS;
3657 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3659 LPWSTR prop, val, key;
3660 static const LPCSTR propval[] = {
3661 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3662 "ARPCONTACT", "Contact",
3663 "ARPCOMMENTS", "Comments",
3664 "ProductName", "DisplayName",
3665 "ProductVersion", "DisplayVersion",
3666 "ARPHELPLINK", "HelpLink",
3667 "ARPHELPTELEPHONE", "HelpTelephone",
3668 "ARPINSTALLLOCATION", "InstallLocation",
3669 "SourceDir", "InstallSource",
3670 "Manufacturer", "Publisher",
3671 "ARPREADME", "Readme",
3673 "ARPURLINFOABOUT", "URLInfoAbout",
3674 "ARPURLUPDATEINFO", "URLUpdateInfo",
3677 const LPCSTR *p = propval;
3681 prop = strdupAtoW( *p++ );
3682 key = strdupAtoW( *p++ );
3683 val = msi_dup_property( package, prop );
3684 msi_reg_set_val_str( hkey, key, val );
3689 return ERROR_SUCCESS;
3692 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3695 LPWSTR buffer = NULL;
3698 static const WCHAR szWindowsInstaller[] =
3699 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3700 static const WCHAR szUpgradeCode[] =
3701 {'U','p','g','r','a','d','e','C','o','d','e',0};
3702 static const WCHAR modpath_fmt[] =
3703 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3704 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3705 static const WCHAR szModifyPath[] =
3706 {'M','o','d','i','f','y','P','a','t','h',0};
3707 static const WCHAR szUninstallString[] =
3708 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3709 static const WCHAR szEstimatedSize[] =
3710 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3711 static const WCHAR szProductLanguage[] =
3712 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3713 static const WCHAR szProductVersion[] =
3714 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3717 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3718 LPWSTR upgrade_code;
3721 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3722 if (rc != ERROR_SUCCESS)
3725 /* dump all the info i can grab */
3726 /* FIXME: Flesh out more information */
3728 msi_write_uninstall_property_vals( package, hkey );
3730 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3732 msi_make_package_local( package, hkey );
3734 /* do ModifyPath and UninstallString */
3735 size = deformat_string(package,modpath_fmt,&buffer);
3736 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3737 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3740 /* FIXME: Write real Estimated Size when we have it */
3741 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3743 GetLocalTime(&systime);
3744 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3745 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3747 langid = msi_get_property_int( package, szProductLanguage, 0 );
3748 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3750 buffer = msi_dup_property( package, szProductVersion );
3753 DWORD verdword = msi_version_str_to_dword(buffer);
3755 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3756 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3757 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3761 /* Handle Upgrade Codes */
3762 upgrade_code = msi_dup_property( package, szUpgradeCode );
3767 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3768 squash_guid(package->ProductCode,squashed);
3769 msi_reg_set_val_str( hkey2, squashed, NULL );
3771 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3772 squash_guid(package->ProductCode,squashed);
3773 msi_reg_set_val_str( hkey2, squashed, NULL );
3776 msi_free(upgrade_code);
3781 /* FIXME: call ui_actiondata */
3783 return ERROR_SUCCESS;
3786 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3788 return execute_script(package,INSTALL_SCRIPT);
3791 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3795 /* turn off scheduleing */
3796 package->script->CurrentlyScripting= FALSE;
3798 /* first do the same as an InstallExecute */
3799 rc = ACTION_InstallExecute(package);
3800 if (rc != ERROR_SUCCESS)
3803 /* then handle Commit Actions */
3804 rc = execute_script(package,COMMIT_SCRIPT);
3809 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3811 static const WCHAR RunOnce[] = {
3812 'S','o','f','t','w','a','r','e','\\',
3813 'M','i','c','r','o','s','o','f','t','\\',
3814 'W','i','n','d','o','w','s','\\',
3815 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3816 'R','u','n','O','n','c','e',0};
3817 static const WCHAR InstallRunOnce[] = {
3818 'S','o','f','t','w','a','r','e','\\',
3819 'M','i','c','r','o','s','o','f','t','\\',
3820 'W','i','n','d','o','w','s','\\',
3821 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3822 'I','n','s','t','a','l','l','e','r','\\',
3823 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3825 static const WCHAR msiexec_fmt[] = {
3827 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3828 '\"','%','s','\"',0};
3829 static const WCHAR install_fmt[] = {
3830 '/','I',' ','\"','%','s','\"',' ',
3831 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3832 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3833 WCHAR buffer[256], sysdir[MAX_PATH];
3835 WCHAR squished_pc[100];
3837 squash_guid(package->ProductCode,squished_pc);
3839 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3840 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3841 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3844 msi_reg_set_val_str( hkey, squished_pc, buffer );
3847 TRACE("Reboot command %s\n",debugstr_w(buffer));
3849 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3850 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3852 msi_reg_set_val_str( hkey, squished_pc, buffer );
3855 return ERROR_INSTALL_SUSPEND;
3858 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3865 * we are currently doing what should be done here in the top level Install
3866 * however for Adminastrative and uninstalls this step will be needed
3868 if (!package->PackagePath)
3869 return ERROR_SUCCESS;
3871 ptr = strrchrW(package->PackagePath, '\\');
3873 return ERROR_SUCCESS;
3875 len = ptr - package->PackagePath + 2;
3876 source = msi_alloc(len * sizeof(WCHAR));
3877 lstrcpynW(source, package->PackagePath, len);
3879 MSI_SetPropertyW(package, cszSourceDir, source);
3880 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3884 attrib = GetFileAttributesW(package->PackagePath);
3885 if (attrib == INVALID_FILE_ATTRIBUTES)
3891 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3892 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3893 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3894 if (rc == ERROR_MORE_DATA)
3896 prompt = msi_alloc(size * sizeof(WCHAR));
3897 MsiSourceListGetInfoW(package->ProductCode, NULL,
3898 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3899 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3902 prompt = strdupW(package->PackagePath);
3904 msg = generate_error_string(package,1302,1,prompt);
3905 while(attrib == INVALID_FILE_ATTRIBUTES)
3907 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3910 rc = ERROR_INSTALL_USEREXIT;
3913 attrib = GetFileAttributesW(package->PackagePath);
3919 return ERROR_SUCCESS;
3924 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3931 static const WCHAR szPropKeys[][80] =
3933 {'P','r','o','d','u','c','t','I','D',0},
3934 {'U','S','E','R','N','A','M','E',0},
3935 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3939 static const WCHAR szRegKeys[][80] =
3941 {'P','r','o','d','u','c','t','I','D',0},
3942 {'R','e','g','O','w','n','e','r',0},
3943 {'R','e','g','C','o','m','p','a','n','y',0},
3947 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3949 return ERROR_SUCCESS;
3951 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3952 if (rc != ERROR_SUCCESS)
3955 for( i = 0; szPropKeys[i][0]; i++ )
3957 buffer = msi_dup_property( package, szPropKeys[i] );
3958 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3963 msi_free(productid);
3966 /* FIXME: call ui_actiondata */
3968 return ERROR_SUCCESS;
3972 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3976 package->script->InWhatSequence |= SEQUENCE_EXEC;
3977 rc = ACTION_ProcessExecSequence(package,FALSE);
3982 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3984 MSIPACKAGE *package = (MSIPACKAGE*)param;
3985 LPCWSTR compgroupid=NULL;
3986 LPCWSTR feature=NULL;
3987 LPCWSTR text = NULL;
3988 LPCWSTR qualifier = NULL;
3989 LPCWSTR component = NULL;
3990 LPWSTR advertise = NULL;
3991 LPWSTR output = NULL;
3993 UINT rc = ERROR_SUCCESS;
3998 component = MSI_RecordGetString(rec,3);
3999 comp = get_loaded_component(package,component);
4001 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4002 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4003 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4005 TRACE("Skipping: Component %s not scheduled for install\n",
4006 debugstr_w(component));
4008 return ERROR_SUCCESS;
4011 compgroupid = MSI_RecordGetString(rec,1);
4012 qualifier = MSI_RecordGetString(rec,2);
4014 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4015 if (rc != ERROR_SUCCESS)
4018 text = MSI_RecordGetString(rec,4);
4019 feature = MSI_RecordGetString(rec,5);
4021 advertise = create_component_advertise_string(package, comp, feature);
4023 sz = strlenW(advertise);
4026 sz += lstrlenW(text);
4029 sz *= sizeof(WCHAR);
4031 output = msi_alloc_zero(sz);
4032 strcpyW(output,advertise);
4033 msi_free(advertise);
4036 strcatW(output,text);
4038 msi_reg_set_val_multi_str( hkey, qualifier, output );
4045 uirow = MSI_CreateRecord( 2 );
4046 MSI_RecordSetStringW( uirow, 1, compgroupid );
4047 MSI_RecordSetStringW( uirow, 2, qualifier);
4048 ui_actiondata( package, szPublishComponents, uirow);
4049 msiobj_release( &uirow->hdr );
4050 /* FIXME: call ui_progress? */
4056 * At present I am ignorning the advertised components part of this and only
4057 * focusing on the qualified component sets
4059 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4063 static const WCHAR ExecSeqQuery[] =
4064 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4065 '`','P','u','b','l','i','s','h',
4066 'C','o','m','p','o','n','e','n','t','`',0};
4068 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4069 if (rc != ERROR_SUCCESS)
4070 return ERROR_SUCCESS;
4072 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4073 msiobj_release(&view->hdr);
4078 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4079 LPCSTR action, LPCWSTR table )
4081 static const WCHAR query[] = {
4082 'S','E','L','E','C','T',' ','*',' ',
4083 'F','R','O','M',' ','`','%','s','`',0 };
4084 MSIQUERY *view = NULL;
4088 r = MSI_OpenQuery( package->db, &view, query, table );
4089 if (r == ERROR_SUCCESS)
4091 r = MSI_IterateRecords(view, &count, NULL, package);
4092 msiobj_release(&view->hdr);
4096 FIXME("%s -> %u ignored %s table values\n",
4097 action, count, debugstr_w(table));
4099 return ERROR_SUCCESS;
4102 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4104 TRACE("%p\n", package);
4105 return ERROR_SUCCESS;
4108 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4110 static const WCHAR table[] =
4111 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4112 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4115 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4117 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4118 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4121 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4123 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4124 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4127 static UINT ACTION_BindImage( MSIPACKAGE *package )
4129 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4130 return msi_unimplemented_action_stub( package, "BindImage", table );
4133 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4135 static const WCHAR table[] = {
4136 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4137 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4140 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4142 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4143 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4146 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4148 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4149 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4152 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4154 static const WCHAR table[] = {
4155 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4156 return msi_unimplemented_action_stub( package, "InstallServices", table );
4159 static UINT ACTION_StartServices( MSIPACKAGE *package )
4161 static const WCHAR table[] = {
4162 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4163 return msi_unimplemented_action_stub( package, "StartServices", table );
4166 static UINT ACTION_StopServices( MSIPACKAGE *package )
4168 static const WCHAR table[] = {
4169 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4170 return msi_unimplemented_action_stub( package, "StopServices", table );
4173 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4175 static const WCHAR table[] = {
4176 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4177 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4180 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4182 static const WCHAR table[] = {
4183 'E','n','v','i','r','o','n','m','e','n','t',0 };
4184 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4187 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4189 static const WCHAR table[] = {
4190 'E','n','v','i','r','o','n','m','e','n','t',0 };
4191 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4194 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4196 static const WCHAR table[] = {
4197 'M','s','i','A','s','s','e','m','b','l','y',0 };
4198 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4201 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4203 static const WCHAR table[] = {
4204 'M','s','i','A','s','s','e','m','b','l','y',0 };
4205 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4208 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4210 static const WCHAR table[] = { 'F','o','n','t',0 };
4211 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4214 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4216 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4217 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4220 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4222 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4223 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4226 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4228 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4229 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4232 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4234 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4235 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4238 static struct _actions StandardActions[] = {
4239 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4240 { szAppSearch, ACTION_AppSearch },
4241 { szBindImage, ACTION_BindImage },
4242 { szCCPSearch, ACTION_CCPSearch},
4243 { szCostFinalize, ACTION_CostFinalize },
4244 { szCostInitialize, ACTION_CostInitialize },
4245 { szCreateFolders, ACTION_CreateFolders },
4246 { szCreateShortcuts, ACTION_CreateShortcuts },
4247 { szDeleteServices, ACTION_DeleteServices },
4248 { szDisableRollback, NULL},
4249 { szDuplicateFiles, ACTION_DuplicateFiles },
4250 { szExecuteAction, ACTION_ExecuteAction },
4251 { szFileCost, ACTION_FileCost },
4252 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4253 { szForceReboot, ACTION_ForceReboot },
4254 { szInstallAdminPackage, NULL},
4255 { szInstallExecute, ACTION_InstallExecute },
4256 { szInstallExecuteAgain, ACTION_InstallExecute },
4257 { szInstallFiles, ACTION_InstallFiles},
4258 { szInstallFinalize, ACTION_InstallFinalize },
4259 { szInstallInitialize, ACTION_InstallInitialize },
4260 { szInstallSFPCatalogFile, NULL},
4261 { szInstallValidate, ACTION_InstallValidate },
4262 { szIsolateComponents, ACTION_IsolateComponents },
4263 { szLaunchConditions, ACTION_LaunchConditions },
4264 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4265 { szMoveFiles, ACTION_MoveFiles },
4266 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4267 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4268 { szInstallODBC, NULL},
4269 { szInstallServices, ACTION_InstallServices },
4270 { szPatchFiles, ACTION_PatchFiles },
4271 { szProcessComponents, ACTION_ProcessComponents },
4272 { szPublishComponents, ACTION_PublishComponents },
4273 { szPublishFeatures, ACTION_PublishFeatures },
4274 { szPublishProduct, ACTION_PublishProduct },
4275 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4276 { szRegisterComPlus, ACTION_RegisterComPlus},
4277 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4278 { szRegisterFonts, ACTION_RegisterFonts },
4279 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4280 { szRegisterProduct, ACTION_RegisterProduct },
4281 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4282 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4283 { szRegisterUser, ACTION_RegisterUser},
4284 { szRemoveDuplicateFiles, NULL},
4285 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4286 { szRemoveExistingProducts, NULL},
4287 { szRemoveFiles, ACTION_RemoveFiles},
4288 { szRemoveFolders, NULL},
4289 { szRemoveIniValues, ACTION_RemoveIniValues },
4290 { szRemoveODBC, NULL},
4291 { szRemoveRegistryValues, NULL},
4292 { szRemoveShortcuts, NULL},
4293 { szResolveSource, ACTION_ResolveSource},
4294 { szRMCCPSearch, ACTION_RMCCPSearch},
4295 { szScheduleReboot, NULL},
4296 { szSelfRegModules, ACTION_SelfRegModules },
4297 { szSelfUnregModules, ACTION_SelfUnregModules },
4298 { szSetODBCFolders, NULL},
4299 { szStartServices, ACTION_StartServices },
4300 { szStopServices, ACTION_StopServices },
4301 { szUnpublishComponents, NULL},
4302 { szUnpublishFeatures, NULL},
4303 { szUnregisterClassInfo, NULL},
4304 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4305 { szUnregisterExtensionInfo, NULL},
4306 { szUnregisterFonts, ACTION_UnregisterFonts },
4307 { szUnregisterMIMEInfo, NULL},
4308 { szUnregisterProgIdInfo, NULL},
4309 { szUnregisterTypeLibraries, NULL},
4310 { szValidateProductID, NULL},
4311 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4312 { szWriteIniValues, ACTION_WriteIniValues },
4313 { szWriteRegistryValues, ACTION_WriteRegistryValues},