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"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 sprintfW(message,template_s,timet,action);
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
300 LPWSTR prop = NULL, val = NULL;
303 return ERROR_SUCCESS;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
368 LPWSTR p, *ret = NULL;
374 /* count the number of substrings */
375 for ( pc = str, count = 0; pc; count++ )
377 pc = strchrW( pc, sep );
382 /* allocate space for an array of substring pointers and the substrings */
383 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384 (lstrlenW(str)+1) * sizeof(WCHAR) );
388 /* copy the string and set the pointers */
389 p = (LPWSTR) &ret[count+1];
391 for( count = 0; (ret[count] = p); count++ )
393 p = strchrW( p, sep );
401 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
402 MSIDATABASE *patch_db, LPCWSTR name )
404 UINT ret = ERROR_FUNCTION_FAILED;
405 IStorage *stg = NULL;
408 TRACE("%p %s\n", package, debugstr_w(name) );
412 ERR("expected a colon in %s\n", debugstr_w(name));
413 return ERROR_FUNCTION_FAILED;
416 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
419 ret = msi_table_apply_transform( package->db, stg );
420 IStorage_Release( stg );
424 ERR("failed to open substorage %s\n", debugstr_w(name));
429 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
431 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
432 LPWSTR guid_list, *guids, product_id;
433 UINT i, ret = ERROR_FUNCTION_FAILED;
435 product_id = msi_dup_property( package, szProdID );
438 /* FIXME: the property ProductID should be written into the DB somewhere */
439 ERR("no product ID to check\n");
440 return ERROR_SUCCESS;
443 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
444 guids = msi_split_string( guid_list, ';' );
445 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
447 if (!lstrcmpW( guids[i], product_id ))
451 msi_free( guid_list );
452 msi_free( product_id );
457 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
460 LPWSTR str, *substorage;
461 UINT i, r = ERROR_SUCCESS;
463 si = MSI_GetSummaryInformationW( patch_db, 0 );
465 return ERROR_FUNCTION_FAILED;
467 msi_check_patch_applicable( package, si );
469 /* enumerate the substorage */
470 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
471 substorage = msi_split_string( str, ';' );
472 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
473 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
474 msi_free( substorage );
477 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
479 msiobj_release( &si->hdr );
484 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
486 MSIDATABASE *patch_db = NULL;
489 TRACE("%p %s\n", package, debugstr_w( file ) );
492 * We probably want to make sure we only open a patch collection here.
493 * Patch collections (.msp) and databases (.msi) have different GUIDs
494 * but currently MSI_OpenDatabaseW will accept both.
496 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
497 if ( r != ERROR_SUCCESS )
499 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
503 msi_parse_patch_summary( package, patch_db );
504 msiobj_release( &patch_db->hdr );
506 return ERROR_SUCCESS;
509 /* get the PATCH property, and apply all the patches it specifies */
510 static UINT msi_apply_patches( MSIPACKAGE *package )
512 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
513 LPWSTR patch_list, *patches;
514 UINT i, r = ERROR_SUCCESS;
516 patch_list = msi_dup_property( package, szPatch );
518 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
520 patches = msi_split_string( patch_list, ';' );
521 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
522 r = msi_apply_patch_package( package, patches[i] );
525 msi_free( patch_list );
530 static UINT msi_apply_transforms( MSIPACKAGE *package )
532 static const WCHAR szTransforms[] = {
533 'T','R','A','N','S','F','O','R','M','S',0 };
534 LPWSTR xform_list, *xforms;
535 UINT i, r = ERROR_SUCCESS;
537 xform_list = msi_dup_property( package, szTransforms );
538 xforms = msi_split_string( xform_list, ';' );
540 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
542 if (xforms[i][0] == ':')
543 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
545 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
549 msi_free( xform_list );
554 /****************************************************
555 * TOP level entry points
556 *****************************************************/
558 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
559 LPCWSTR szCommandLine )
563 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
564 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
565 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
567 MSI_SetPropertyW(package, szAction, szInstall);
569 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
571 package->script->InWhatSequence = SEQUENCE_INSTALL;
575 LPWSTR p, check, path;
577 package->PackagePath = strdupW(szPackagePath);
578 path = strdupW(szPackagePath);
579 p = strrchrW(path,'\\');
588 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
589 GetCurrentDirectoryW(MAX_PATH,path);
593 check = msi_dup_property( package, cszSourceDir );
595 MSI_SetPropertyW(package, cszSourceDir, path);
600 msi_parse_command_line( package, szCommandLine );
602 msi_apply_transforms( package );
603 msi_apply_patches( package );
605 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
607 package->script->InWhatSequence |= SEQUENCE_UI;
608 rc = ACTION_ProcessUISequence(package);
610 if (rc == ERROR_SUCCESS)
612 package->script->InWhatSequence |= SEQUENCE_EXEC;
613 rc = ACTION_ProcessExecSequence(package,TRUE);
617 rc = ACTION_ProcessExecSequence(package,FALSE);
621 /* install was halted but should be considered a success */
625 package->script->CurrentlyScripting= FALSE;
627 /* process the ending type action */
628 if (rc == ERROR_SUCCESS)
629 ACTION_PerformActionSequence(package,-1,ui);
630 else if (rc == ERROR_INSTALL_USEREXIT)
631 ACTION_PerformActionSequence(package,-2,ui);
632 else if (rc == ERROR_INSTALL_SUSPEND)
633 ACTION_PerformActionSequence(package,-4,ui);
635 ACTION_PerformActionSequence(package,-3,ui);
637 /* finish up running custom actions */
638 ACTION_FinishCustomActions(package);
643 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
645 UINT rc = ERROR_SUCCESS;
647 static const WCHAR ExecSeqQuery[] =
648 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
649 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
650 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
651 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
653 static const WCHAR UISeqQuery[] =
654 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
655 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
656 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
657 ' ', '=',' ','%','i',0};
660 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
662 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
666 LPCWSTR action, cond;
668 TRACE("Running the actions\n");
670 /* check conditions */
671 cond = MSI_RecordGetString(row,2);
674 /* this is a hack to skip errors in the condition code */
675 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
679 action = MSI_RecordGetString(row,1);
682 ERR("failed to fetch action\n");
683 rc = ERROR_FUNCTION_FAILED;
688 rc = ACTION_PerformUIAction(package,action);
690 rc = ACTION_PerformAction(package,action,FALSE);
692 msiobj_release(&row->hdr);
703 } iterate_action_param;
705 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
707 iterate_action_param *iap= (iterate_action_param*)param;
709 LPCWSTR cond, action;
711 action = MSI_RecordGetString(row,1);
714 ERR("Error is retrieving action name\n");
715 return ERROR_FUNCTION_FAILED;
718 /* check conditions */
719 cond = MSI_RecordGetString(row,2);
722 /* this is a hack to skip errors in the condition code */
723 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
725 TRACE("Skipping action: %s (condition is false)\n",
727 return ERROR_SUCCESS;
732 rc = ACTION_PerformUIAction(iap->package,action);
734 rc = ACTION_PerformAction(iap->package,action,FALSE);
736 msi_dialog_check_messages( NULL );
738 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
739 rc = iap->package->CurrentInstallState;
741 if (rc == ERROR_FUNCTION_NOT_CALLED)
744 if (rc != ERROR_SUCCESS)
745 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
750 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
754 static const WCHAR query[] =
755 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
757 ' ','W','H','E','R','E',' ',
758 '`','S','e','q','u','e','n','c','e','`',' ',
759 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
760 '`','S','e','q','u','e','n','c','e','`',0};
761 iterate_action_param iap;
764 * FIXME: probably should be checking UILevel in the
765 * ACTION_PerformUIAction/ACTION_PerformAction
766 * rather than saving the UI level here. Those
767 * two functions can be merged too.
769 iap.package = package;
772 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
774 r = MSI_OpenQuery( package->db, &view, query, szTable );
775 if (r == ERROR_SUCCESS)
777 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
778 msiobj_release(&view->hdr);
784 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
788 static const WCHAR ExecSeqQuery[] =
789 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
790 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
791 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
792 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
793 'O','R','D','E','R',' ', 'B','Y',' ',
794 '`','S','e','q','u','e','n','c','e','`',0 };
796 static const WCHAR IVQuery[] =
797 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
798 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
799 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
800 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
801 ' ','\'', 'I','n','s','t','a','l','l',
802 'V','a','l','i','d','a','t','e','\'', 0};
804 iterate_action_param iap;
806 iap.package = package;
809 if (package->script->ExecuteSequenceRun)
811 TRACE("Execute Sequence already Run\n");
812 return ERROR_SUCCESS;
815 package->script->ExecuteSequenceRun = TRUE;
817 /* get the sequence number */
820 row = MSI_QueryGetRecord(package->db, IVQuery);
822 return ERROR_FUNCTION_FAILED;
823 seq = MSI_RecordGetInteger(row,1);
824 msiobj_release(&row->hdr);
827 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
828 if (rc == ERROR_SUCCESS)
830 TRACE("Running the actions\n");
832 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
833 msiobj_release(&view->hdr);
839 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
843 static const WCHAR ExecSeqQuery [] =
844 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
845 '`','I','n','s','t','a','l','l',
846 'U','I','S','e','q','u','e','n','c','e','`',
847 ' ','W','H','E','R','E',' ',
848 '`','S','e','q','u','e','n','c','e','`',' ',
849 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
850 '`','S','e','q','u','e','n','c','e','`',0};
851 iterate_action_param iap;
853 iap.package = package;
856 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
858 if (rc == ERROR_SUCCESS)
860 TRACE("Running the actions\n");
862 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
863 msiobj_release(&view->hdr);
869 /********************************************************
870 * ACTION helper functions and functions that perform the actions
871 *******************************************************/
872 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
873 UINT* rc, BOOL force )
879 if (!run && !package->script->CurrentlyScripting)
884 if (strcmpW(action,szInstallFinalize) == 0 ||
885 strcmpW(action,szInstallExecute) == 0 ||
886 strcmpW(action,szInstallExecuteAgain) == 0)
891 while (StandardActions[i].action != NULL)
893 if (strcmpW(StandardActions[i].action, action)==0)
897 ui_actioninfo(package, action, TRUE, 0);
898 *rc = schedule_action(package,INSTALL_SCRIPT,action);
899 ui_actioninfo(package, action, FALSE, *rc);
903 ui_actionstart(package, action);
904 if (StandardActions[i].handler)
906 *rc = StandardActions[i].handler(package);
910 FIXME("unhandled standard action %s\n",debugstr_w(action));
922 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
923 UINT* rc, BOOL force )
928 arc = ACTION_CustomAction(package,action, force);
930 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
939 * A lot of actions are really important even if they don't do anything
940 * explicit... Lots of properties are set at the beginning of the installation
941 * CostFinalize does a bunch of work to translate the directories and such
943 * But until I get write access to the database that is hard, so I am going to
944 * hack it to see if I can get something to run.
946 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
948 UINT rc = ERROR_SUCCESS;
951 TRACE("Performing action (%s)\n",debugstr_w(action));
953 handled = ACTION_HandleStandardAction(package, action, &rc, force);
956 handled = ACTION_HandleCustomAction(package, action, &rc, force);
960 FIXME("unhandled msi action %s\n",debugstr_w(action));
961 rc = ERROR_FUNCTION_NOT_CALLED;
967 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
969 UINT rc = ERROR_SUCCESS;
970 BOOL handled = FALSE;
972 TRACE("Performing action (%s)\n",debugstr_w(action));
974 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
977 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
979 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
984 FIXME("unhandled msi action %s\n",debugstr_w(action));
985 rc = ERROR_FUNCTION_NOT_CALLED;
993 * Actual Action Handlers
996 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
998 MSIPACKAGE *package = (MSIPACKAGE*)param;
1004 dir = MSI_RecordGetString(row,1);
1007 ERR("Unable to get folder id\n");
1008 return ERROR_SUCCESS;
1011 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1014 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1015 return ERROR_SUCCESS;
1018 TRACE("Folder is %s\n",debugstr_w(full_path));
1021 uirow = MSI_CreateRecord(1);
1022 MSI_RecordSetStringW(uirow,1,full_path);
1023 ui_actiondata(package,szCreateFolders,uirow);
1024 msiobj_release( &uirow->hdr );
1026 if (folder->State == 0)
1027 create_full_pathW(full_path);
1031 msi_free(full_path);
1032 return ERROR_SUCCESS;
1035 /* FIXME: probably should merge this with the above function */
1036 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1038 UINT rc = ERROR_SUCCESS;
1040 LPWSTR install_path;
1042 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1044 return ERROR_FUNCTION_FAILED;
1046 /* create the path */
1047 if (folder->State == 0)
1049 create_full_pathW(install_path);
1052 msi_free(install_path);
1057 UINT msi_create_component_directories( MSIPACKAGE *package )
1061 /* create all the folders required by the components are going to install */
1062 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1064 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1066 msi_create_directory( package, comp->Directory );
1069 return ERROR_SUCCESS;
1073 * Also we cannot enable/disable components either, so for now I am just going
1074 * to do all the directories for all the components.
1076 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1078 static const WCHAR ExecSeqQuery[] =
1079 {'S','E','L','E','C','T',' ',
1080 '`','D','i','r','e','c','t','o','r','y','_','`',
1081 ' ','F','R','O','M',' ',
1082 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1086 /* create all the empty folders specified in the CreateFolder table */
1087 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1088 if (rc != ERROR_SUCCESS)
1089 return ERROR_SUCCESS;
1091 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1092 msiobj_release(&view->hdr);
1094 msi_create_component_directories( package );
1099 static UINT load_component( MSIRECORD *row, LPVOID param )
1101 MSIPACKAGE *package = param;
1104 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1106 return ERROR_FUNCTION_FAILED;
1108 list_add_tail( &package->components, &comp->entry );
1110 /* fill in the data */
1111 comp->Component = msi_dup_record_field( row, 1 );
1113 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1115 comp->ComponentId = msi_dup_record_field( row, 2 );
1116 comp->Directory = msi_dup_record_field( row, 3 );
1117 comp->Attributes = MSI_RecordGetInteger(row,4);
1118 comp->Condition = msi_dup_record_field( row, 5 );
1119 comp->KeyPath = msi_dup_record_field( row, 6 );
1121 comp->Installed = INSTALLSTATE_UNKNOWN;
1122 comp->Action = INSTALLSTATE_UNKNOWN;
1123 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1125 return ERROR_SUCCESS;
1128 static UINT load_all_components( MSIPACKAGE *package )
1130 static const WCHAR query[] = {
1131 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1132 '`','C','o','m','p','o','n','e','n','t','`',0 };
1136 if (!list_empty(&package->components))
1137 return ERROR_SUCCESS;
1139 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1140 if (r != ERROR_SUCCESS)
1143 r = MSI_IterateRecords(view, NULL, load_component, package);
1144 msiobj_release(&view->hdr);
1149 MSIPACKAGE *package;
1150 MSIFEATURE *feature;
1153 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1157 cl = msi_alloc( sizeof (*cl) );
1159 return ERROR_NOT_ENOUGH_MEMORY;
1160 cl->component = comp;
1161 list_add_tail( &feature->Components, &cl->entry );
1163 return ERROR_SUCCESS;
1166 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1168 _ilfs* ilfs= (_ilfs*)param;
1172 component = MSI_RecordGetString(row,1);
1174 /* check to see if the component is already loaded */
1175 comp = get_loaded_component( ilfs->package, component );
1178 ERR("unknown component %s\n", debugstr_w(component));
1179 return ERROR_FUNCTION_FAILED;
1182 add_feature_component( ilfs->feature, comp );
1183 comp->Enabled = TRUE;
1185 return ERROR_SUCCESS;
1188 static UINT load_feature(MSIRECORD * row, LPVOID param)
1190 MSIPACKAGE* package = (MSIPACKAGE*)param;
1191 MSIFEATURE* feature;
1192 static const WCHAR Query1[] =
1193 {'S','E','L','E','C','T',' ',
1194 '`','C','o','m','p','o','n','e','n','t','_','`',
1195 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1196 'C','o','m','p','o','n','e','n','t','s','`',' ',
1197 'W','H','E','R','E',' ',
1198 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1203 /* fill in the data */
1205 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1207 return ERROR_NOT_ENOUGH_MEMORY;
1209 list_init( &feature->Components );
1211 feature->Feature = msi_dup_record_field( row, 1 );
1213 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1215 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1216 feature->Title = msi_dup_record_field( row, 3 );
1217 feature->Description = msi_dup_record_field( row, 4 );
1219 if (!MSI_RecordIsNull(row,5))
1220 feature->Display = MSI_RecordGetInteger(row,5);
1222 feature->Level= MSI_RecordGetInteger(row,6);
1223 feature->Directory = msi_dup_record_field( row, 7 );
1224 feature->Attributes = MSI_RecordGetInteger(row,8);
1226 feature->Installed = INSTALLSTATE_UNKNOWN;
1227 feature->Action = INSTALLSTATE_UNKNOWN;
1228 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1230 list_add_tail( &package->features, &feature->entry );
1232 /* load feature components */
1234 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1235 if (rc != ERROR_SUCCESS)
1236 return ERROR_SUCCESS;
1238 ilfs.package = package;
1239 ilfs.feature = feature;
1241 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1242 msiobj_release(&view->hdr);
1244 return ERROR_SUCCESS;
1247 static UINT load_all_features( MSIPACKAGE *package )
1249 static const WCHAR query[] = {
1250 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1251 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1252 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1256 if (!list_empty(&package->features))
1257 return ERROR_SUCCESS;
1259 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1260 if (r != ERROR_SUCCESS)
1263 r = MSI_IterateRecords( view, NULL, load_feature, package );
1264 msiobj_release( &view->hdr );
1268 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1279 static UINT load_file(MSIRECORD *row, LPVOID param)
1281 MSIPACKAGE* package = (MSIPACKAGE*)param;
1285 /* fill in the data */
1287 file = msi_alloc_zero( sizeof (MSIFILE) );
1289 return ERROR_NOT_ENOUGH_MEMORY;
1291 file->File = msi_dup_record_field( row, 1 );
1293 component = MSI_RecordGetString( row, 2 );
1294 file->Component = get_loaded_component( package, component );
1296 if (!file->Component)
1297 ERR("Unfound Component %s\n",debugstr_w(component));
1299 file->FileName = msi_dup_record_field( row, 3 );
1300 reduce_to_longfilename( file->FileName );
1302 file->ShortName = msi_dup_record_field( row, 3 );
1303 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1305 file->FileSize = MSI_RecordGetInteger( row, 4 );
1306 file->Version = msi_dup_record_field( row, 5 );
1307 file->Language = msi_dup_record_field( row, 6 );
1308 file->Attributes = MSI_RecordGetInteger( row, 7 );
1309 file->Sequence = MSI_RecordGetInteger( row, 8 );
1311 file->state = msifs_invalid;
1313 /* if the compressed bits are not set in the file attributes,
1314 * then read the information from the package word count property
1316 if (file->Attributes & msidbFileAttributesCompressed)
1318 file->IsCompressed = TRUE;
1320 else if (file->Attributes & msidbFileAttributesNoncompressed)
1322 file->IsCompressed = FALSE;
1326 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1329 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1331 list_add_tail( &package->files, &file->entry );
1333 return ERROR_SUCCESS;
1336 static UINT load_all_files(MSIPACKAGE *package)
1340 static const WCHAR Query[] =
1341 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1342 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1343 '`','S','e','q','u','e','n','c','e','`', 0};
1345 if (!list_empty(&package->files))
1346 return ERROR_SUCCESS;
1348 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1349 if (rc != ERROR_SUCCESS)
1350 return ERROR_SUCCESS;
1352 rc = MSI_IterateRecords(view, NULL, load_file, package);
1353 msiobj_release(&view->hdr);
1355 return ERROR_SUCCESS;
1360 * I am not doing any of the costing functionality yet.
1361 * Mostly looking at doing the Component and Feature loading
1363 * The native MSI does A LOT of modification to tables here. Mostly adding
1364 * a lot of temporary columns to the Feature and Component tables.
1366 * note: Native msi also tracks the short filename. But I am only going to
1367 * track the long ones. Also looking at this directory table
1368 * it appears that the directory table does not get the parents
1369 * resolved base on property only based on their entries in the
1372 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1374 static const WCHAR szCosting[] =
1375 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1376 static const WCHAR szZero[] = { '0', 0 };
1378 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1379 return ERROR_SUCCESS;
1381 MSI_SetPropertyW(package, szCosting, szZero);
1382 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1384 load_all_components( package );
1385 load_all_features( package );
1386 load_all_files( package );
1388 return ERROR_SUCCESS;
1391 static UINT execute_script(MSIPACKAGE *package, UINT script )
1394 UINT rc = ERROR_SUCCESS;
1396 TRACE("Executing Script %i\n",script);
1398 if (!package->script)
1400 ERR("no script!\n");
1401 return ERROR_FUNCTION_FAILED;
1404 for (i = 0; i < package->script->ActionCount[script]; i++)
1407 action = package->script->Actions[script][i];
1408 ui_actionstart(package, action);
1409 TRACE("Executing Action (%s)\n",debugstr_w(action));
1410 rc = ACTION_PerformAction(package, action, TRUE);
1411 msi_free(package->script->Actions[script][i]);
1412 if (rc != ERROR_SUCCESS)
1415 msi_free(package->script->Actions[script]);
1417 package->script->ActionCount[script] = 0;
1418 package->script->Actions[script] = NULL;
1422 static UINT ACTION_FileCost(MSIPACKAGE *package)
1424 return ERROR_SUCCESS;
1427 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1429 static const WCHAR Query[] =
1430 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1431 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1432 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1433 ' ','=',' ','\'','%','s','\'',
1435 static const WCHAR szDot[] = { '.',0 };
1436 static WCHAR szEmpty[] = { 0 };
1437 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1442 TRACE("Looking for dir %s\n",debugstr_w(dir));
1444 folder = get_loaded_folder( package, dir );
1448 TRACE("Working to load %s\n",debugstr_w(dir));
1450 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1454 folder->Directory = strdupW(dir);
1456 row = MSI_QueryGetRecord(package->db, Query, dir);
1460 p = msi_dup_record_field(row, 3);
1462 /* split src and target dir */
1464 src_short = folder_split_path( p, ':' );
1466 /* split the long and short paths */
1467 tgt_long = folder_split_path( tgt_short, '|' );
1468 src_long = folder_split_path( src_short, '|' );
1470 /* check for no-op dirs */
1471 if (!lstrcmpW(szDot, tgt_short))
1472 tgt_short = szEmpty;
1473 if (!lstrcmpW(szDot, src_short))
1474 src_short = szEmpty;
1477 tgt_long = tgt_short;
1480 src_short = tgt_short;
1481 src_long = tgt_long;
1485 src_long = src_short;
1487 /* FIXME: use the target short path too */
1488 folder->TargetDefault = strdupW(tgt_long);
1489 folder->SourceShortPath = strdupW(src_short);
1490 folder->SourceLongPath = strdupW(src_long);
1493 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1494 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1495 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1497 parent = MSI_RecordGetString(row, 2);
1500 folder->Parent = load_folder( package, parent );
1501 if ( folder->Parent )
1502 TRACE("loaded parent %p %s\n", folder->Parent,
1503 debugstr_w(folder->Parent->Directory));
1505 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1508 folder->Property = msi_dup_property( package, dir );
1510 msiobj_release(&row->hdr);
1512 list_add_tail( &package->folders, &folder->entry );
1514 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1519 /* scan for and update current install states */
1520 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1523 MSIFEATURE *feature;
1525 /* FIXME: component's installed state should be determined
1526 * by the component's registration
1528 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1532 if (!comp->ComponentId)
1535 res = MsiGetComponentPathW( package->ProductCode,
1536 comp->ComponentId, NULL, NULL);
1538 res = INSTALLSTATE_ABSENT;
1539 comp->Installed = res;
1542 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1545 INSTALLSTATE res = -10;
1547 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1549 comp= cl->component;
1551 if (!comp->ComponentId)
1553 res = INSTALLSTATE_ABSENT;
1558 res = comp->Installed;
1561 if (res == comp->Installed)
1564 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1565 res != INSTALLSTATE_SOURCE)
1567 res = INSTALLSTATE_INCOMPLETE;
1571 feature->Installed = res;
1575 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1578 static const WCHAR all[]={'A','L','L',0};
1580 MSIFEATURE *feature;
1582 override = msi_dup_property( package, property );
1586 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1588 if (strcmpiW(override,all)==0)
1590 feature->ActionRequest= state;
1591 feature->Action = state;
1595 LPWSTR ptr = override;
1596 LPWSTR ptr2 = strchrW(override,',');
1600 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1601 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1603 feature->ActionRequest= state;
1604 feature->Action = state;
1610 ptr2 = strchrW(ptr,',');
1622 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1625 static const WCHAR szlevel[] =
1626 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1627 static const WCHAR szAddLocal[] =
1628 {'A','D','D','L','O','C','A','L',0};
1629 static const WCHAR szRemove[] =
1630 {'R','E','M','O','V','E',0};
1631 static const WCHAR szReinstall[] =
1632 {'R','E','I','N','S','T','A','L','L',0};
1633 BOOL override = FALSE;
1634 MSICOMPONENT* component;
1635 MSIFEATURE *feature;
1638 /* I do not know if this is where it should happen.. but */
1640 TRACE("Checking Install Level\n");
1642 install_level = msi_get_property_int( package, szlevel, 1 );
1644 /* ok hereis the _real_ rub
1645 * all these activation/deactivation things happen in order and things
1646 * later on the list override things earlier on the list.
1647 * 1) INSTALLLEVEL processing
1657 * 11) FILEADDDEFAULT
1658 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1659 * ignored for all the features. seems strange, especially since it is not
1660 * documented anywhere, but it is how it works.
1662 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1663 * REMOVE are the big ones, since we don't handle administrative installs
1666 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1667 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1668 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1672 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1674 BOOL feature_state = ((feature->Level > 0) &&
1675 (feature->Level <= install_level));
1677 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1679 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1681 feature->ActionRequest = INSTALLSTATE_SOURCE;
1682 feature->Action = INSTALLSTATE_SOURCE;
1684 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1686 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1687 feature->Action = INSTALLSTATE_ADVERTISED;
1691 feature->ActionRequest = INSTALLSTATE_LOCAL;
1692 feature->Action = INSTALLSTATE_LOCAL;
1699 /* set the Preselected Property */
1700 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1701 static const WCHAR szOne[] = { '1', 0 };
1703 MSI_SetPropertyW(package,szPreselected,szOne);
1707 * now we want to enable or disable components base on feature
1710 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1714 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1715 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1716 feature->ActionRequest);
1718 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1720 component = cl->component;
1722 if (!component->Enabled)
1724 component->Action = INSTALLSTATE_UNKNOWN;
1725 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1729 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1731 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1733 component->Action = INSTALLSTATE_LOCAL;
1734 component->ActionRequest = INSTALLSTATE_LOCAL;
1737 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1739 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1740 (component->Action == INSTALLSTATE_ABSENT) ||
1741 (component->Action == INSTALLSTATE_ADVERTISED) ||
1742 (component->Action == INSTALLSTATE_DEFAULT))
1745 component->Action = INSTALLSTATE_SOURCE;
1746 component->ActionRequest = INSTALLSTATE_SOURCE;
1749 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1751 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1752 (component->Action == INSTALLSTATE_ABSENT))
1755 component->Action = INSTALLSTATE_ADVERTISED;
1756 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1759 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1761 if (component->Action == INSTALLSTATE_UNKNOWN)
1763 component->Action = INSTALLSTATE_ABSENT;
1764 component->ActionRequest = INSTALLSTATE_ABSENT;
1769 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1771 feature->Action = INSTALLSTATE_LOCAL;
1772 feature->ActionRequest = INSTALLSTATE_LOCAL;
1777 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1779 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1780 debugstr_w(component->Component), component->Installed,
1781 component->Action, component->ActionRequest);
1785 return ERROR_SUCCESS;
1788 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1790 MSIPACKAGE *package = (MSIPACKAGE*)param;
1794 name = MSI_RecordGetString(row,1);
1796 /* This helper function now does ALL the work */
1797 TRACE("Dir %s ...\n",debugstr_w(name));
1798 load_folder(package,name);
1799 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1800 TRACE("resolves to %s\n",debugstr_w(path));
1803 return ERROR_SUCCESS;
1806 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1808 MSIPACKAGE *package = (MSIPACKAGE*)param;
1810 MSIFEATURE *feature;
1812 name = MSI_RecordGetString( row, 1 );
1814 feature = get_loaded_feature( package, name );
1816 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1820 Condition = MSI_RecordGetString(row,3);
1822 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1824 int level = MSI_RecordGetInteger(row,2);
1825 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1826 feature->Level = level;
1829 return ERROR_SUCCESS;
1832 static void load_all_component_states(MSIPACKAGE *package)
1836 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1838 switch (comp->Attributes)
1840 case msidbComponentAttributesLocalOnly:
1841 comp->Action = INSTALLSTATE_LOCAL;
1842 comp->ActionRequest = INSTALLSTATE_LOCAL;
1844 case msidbComponentAttributesSourceOnly:
1845 comp->Action = INSTALLSTATE_SOURCE;
1846 comp->ActionRequest = INSTALLSTATE_SOURCE;
1848 case msidbComponentAttributesOptional:
1849 comp->Action = INSTALLSTATE_DEFAULT;
1850 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1853 comp->Action = INSTALLSTATE_LOCAL;
1854 comp->ActionRequest = INSTALLSTATE_LOCAL;
1860 * A lot is done in this function aside from just the costing.
1861 * The costing needs to be implemented at some point but for now I am going
1862 * to focus on the directory building
1865 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1867 static const WCHAR ExecSeqQuery[] =
1868 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1869 '`','D','i','r','e','c','t','o','r','y','`',0};
1870 static const WCHAR ConditionQuery[] =
1871 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1872 '`','C','o','n','d','i','t','i','o','n','`',0};
1873 static const WCHAR szCosting[] =
1874 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1875 static const WCHAR szlevel[] =
1876 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1877 static const WCHAR szOne[] = { '1', 0 };
1884 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1885 return ERROR_SUCCESS;
1887 TRACE("Building Directory properties\n");
1889 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1890 if (rc == ERROR_SUCCESS)
1892 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1894 msiobj_release(&view->hdr);
1897 load_all_component_states(package);
1899 TRACE("File calculations\n");
1901 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1903 MSICOMPONENT* comp = file->Component;
1909 if (file->IsCompressed)
1911 comp->ForceLocalState = TRUE;
1912 comp->Action = INSTALLSTATE_LOCAL;
1913 comp->ActionRequest = INSTALLSTATE_LOCAL;
1916 /* calculate target */
1917 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1919 msi_free(file->TargetPath);
1921 TRACE("file %s is named %s\n",
1922 debugstr_w(file->File),debugstr_w(file->FileName));
1924 file->TargetPath = build_directory_name(2, p, file->FileName);
1928 TRACE("file %s resolves to %s\n",
1929 debugstr_w(file->File),debugstr_w(file->TargetPath));
1931 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1933 file->state = msifs_missing;
1934 comp->Cost += file->FileSize;
1944 static WCHAR name[] = {'\\',0};
1945 static const WCHAR name_fmt[] =
1946 {'%','u','.','%','u','.','%','u','.','%','u',0};
1947 WCHAR filever[0x100];
1948 VS_FIXEDFILEINFO *lpVer;
1950 TRACE("Version comparison..\n");
1951 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1952 version = msi_alloc(versize);
1953 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1955 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1957 sprintfW(filever,name_fmt,
1958 HIWORD(lpVer->dwFileVersionMS),
1959 LOWORD(lpVer->dwFileVersionMS),
1960 HIWORD(lpVer->dwFileVersionLS),
1961 LOWORD(lpVer->dwFileVersionLS));
1963 TRACE("new %s old %s\n", debugstr_w(file->Version),
1964 debugstr_w(filever));
1965 if (strcmpiW(filever,file->Version)<0)
1967 file->state = msifs_overwrite;
1968 /* FIXME: cost should be diff in size */
1969 comp->Cost += file->FileSize;
1972 file->state = msifs_present;
1976 file->state = msifs_present;
1979 TRACE("Evaluating Condition Table\n");
1981 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1982 if (rc == ERROR_SUCCESS)
1984 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1986 msiobj_release(&view->hdr);
1989 TRACE("Enabling or Disabling Components\n");
1990 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1992 if (comp->Condition)
1994 if (MSI_EvaluateConditionW(package,
1995 comp->Condition) == MSICONDITION_FALSE)
1997 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1998 comp->Enabled = FALSE;
2003 MSI_SetPropertyW(package,szCosting,szOne);
2004 /* set default run level if not set */
2005 level = msi_dup_property( package, szlevel );
2007 MSI_SetPropertyW(package,szlevel, szOne);
2010 ACTION_UpdateInstallStates(package);
2012 return MSI_SetFeatureStates(package);
2015 /* OK this value is "interpreted" and then formatted based on the
2016 first few characters */
2017 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2021 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2027 LPWSTR deformated = NULL;
2030 deformat_string(package, &value[2], &deformated);
2032 /* binary value type */
2036 *size = (strlenW(ptr)/2)+1;
2038 *size = strlenW(ptr)/2;
2040 data = msi_alloc(*size);
2046 /* if uneven pad with a zero in front */
2052 data[count] = (BYTE)strtol(byte,NULL,0);
2054 TRACE("Uneven byte count\n");
2062 data[count] = (BYTE)strtol(byte,NULL,0);
2065 msi_free(deformated);
2067 TRACE("Data %li bytes(%i)\n",*size,count);
2074 deformat_string(package, &value[1], &deformated);
2077 *size = sizeof(DWORD);
2078 data = msi_alloc(*size);
2084 if ( (*p < '0') || (*p > '9') )
2090 if (deformated[0] == '-')
2093 TRACE("DWORD %li\n",*(LPDWORD)data);
2095 msi_free(deformated);
2100 static const WCHAR szMulti[] = {'[','~',']',0};
2109 *type=REG_EXPAND_SZ;
2117 if (strstrW(value,szMulti))
2118 *type = REG_MULTI_SZ;
2120 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2125 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2127 MSIPACKAGE *package = (MSIPACKAGE*)param;
2128 static const WCHAR szHCR[] =
2129 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2130 'R','O','O','T','\\',0};
2131 static const WCHAR szHCU[] =
2132 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2133 'U','S','E','R','\\',0};
2134 static const WCHAR szHLM[] =
2135 {'H','K','E','Y','_','L','O','C','A','L','_',
2136 'M','A','C','H','I','N','E','\\',0};
2137 static const WCHAR szHU[] =
2138 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2140 LPSTR value_data = NULL;
2141 HKEY root_key, hkey;
2144 LPCWSTR szRoot, component, name, key, value;
2149 BOOL check_first = FALSE;
2152 ui_progress(package,2,0,0,0);
2159 component = MSI_RecordGetString(row, 6);
2160 comp = get_loaded_component(package,component);
2162 return ERROR_SUCCESS;
2164 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2166 TRACE("Skipping write due to disabled component %s\n",
2167 debugstr_w(component));
2169 comp->Action = comp->Installed;
2171 return ERROR_SUCCESS;
2174 comp->Action = INSTALLSTATE_LOCAL;
2176 name = MSI_RecordGetString(row, 4);
2177 if( MSI_RecordIsNull(row,5) && name )
2179 /* null values can have special meanings */
2180 if (name[0]=='-' && name[1] == 0)
2181 return ERROR_SUCCESS;
2182 else if ((name[0]=='+' && name[1] == 0) ||
2183 (name[0] == '*' && name[1] == 0))
2188 root = MSI_RecordGetInteger(row,2);
2189 key = MSI_RecordGetString(row, 3);
2191 /* get the root key */
2196 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2197 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2198 if (all_users && all_users[0] == '1')
2200 root_key = HKEY_LOCAL_MACHINE;
2205 root_key = HKEY_CURRENT_USER;
2208 msi_free(all_users);
2211 case 0: root_key = HKEY_CLASSES_ROOT;
2214 case 1: root_key = HKEY_CURRENT_USER;
2217 case 2: root_key = HKEY_LOCAL_MACHINE;
2220 case 3: root_key = HKEY_USERS;
2224 ERR("Unknown root %i\n",root);
2230 return ERROR_SUCCESS;
2232 deformat_string(package, key , &deformated);
2233 size = strlenW(deformated) + strlenW(szRoot) + 1;
2234 uikey = msi_alloc(size*sizeof(WCHAR));
2235 strcpyW(uikey,szRoot);
2236 strcatW(uikey,deformated);
2238 if (RegCreateKeyW( root_key, deformated, &hkey))
2240 ERR("Could not create key %s\n",debugstr_w(deformated));
2241 msi_free(deformated);
2243 return ERROR_SUCCESS;
2245 msi_free(deformated);
2247 value = MSI_RecordGetString(row,5);
2249 value_data = parse_value(package, value, &type, &size);
2252 static const WCHAR szEmpty[] = {0};
2253 value_data = (LPSTR)strdupW(szEmpty);
2258 deformat_string(package, name, &deformated);
2260 /* get the double nulls to terminate SZ_MULTI */
2261 if (type == REG_MULTI_SZ)
2262 size +=sizeof(WCHAR);
2266 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2268 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2273 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2274 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2276 TRACE("value %s of %s checked already exists\n",
2277 debugstr_w(deformated), debugstr_w(uikey));
2281 TRACE("Checked and setting value %s of %s\n",
2282 debugstr_w(deformated), debugstr_w(uikey));
2283 if (deformated || size)
2284 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2289 uirow = MSI_CreateRecord(3);
2290 MSI_RecordSetStringW(uirow,2,deformated);
2291 MSI_RecordSetStringW(uirow,1,uikey);
2294 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2296 MSI_RecordSetStringW(uirow,3,value);
2298 ui_actiondata(package,szWriteRegistryValues,uirow);
2299 msiobj_release( &uirow->hdr );
2301 msi_free(value_data);
2302 msi_free(deformated);
2305 return ERROR_SUCCESS;
2308 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2312 static const WCHAR ExecSeqQuery[] =
2313 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2314 '`','R','e','g','i','s','t','r','y','`',0 };
2316 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2317 if (rc != ERROR_SUCCESS)
2318 return ERROR_SUCCESS;
2320 /* increment progress bar each time action data is sent */
2321 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2323 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2325 msiobj_release(&view->hdr);
2329 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2331 package->script->CurrentlyScripting = TRUE;
2333 return ERROR_SUCCESS;
2337 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2342 static const WCHAR q1[]=
2343 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2344 '`','R','e','g','i','s','t','r','y','`',0};
2347 MSIFEATURE *feature;
2350 TRACE("InstallValidate\n");
2352 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2353 if (rc == ERROR_SUCCESS)
2355 MSI_IterateRecords( view, &progress, NULL, package );
2356 msiobj_release( &view->hdr );
2357 total += progress * REG_PROGRESS_VALUE;
2360 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2361 total += COMPONENT_PROGRESS_VALUE;
2363 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2364 total += file->FileSize;
2366 ui_progress(package,0,total,0,0);
2368 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2370 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2371 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2372 feature->ActionRequest);
2375 return ERROR_SUCCESS;
2378 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2380 MSIPACKAGE* package = (MSIPACKAGE*)param;
2381 LPCWSTR cond = NULL;
2382 LPCWSTR message = NULL;
2383 static const WCHAR title[]=
2384 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2386 cond = MSI_RecordGetString(row,1);
2388 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2391 message = MSI_RecordGetString(row,2);
2392 deformat_string(package,message,&deformated);
2393 MessageBoxW(NULL,deformated,title,MB_OK);
2394 msi_free(deformated);
2395 return ERROR_FUNCTION_FAILED;
2398 return ERROR_SUCCESS;
2401 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2404 MSIQUERY * view = NULL;
2405 static const WCHAR ExecSeqQuery[] =
2406 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2407 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2409 TRACE("Checking launch conditions\n");
2411 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2412 if (rc != ERROR_SUCCESS)
2413 return ERROR_SUCCESS;
2415 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2416 msiobj_release(&view->hdr);
2421 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2425 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2427 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2429 MSIRECORD * row = 0;
2431 LPWSTR deformated,buffer,deformated_name;
2433 static const WCHAR ExecSeqQuery[] =
2434 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2435 '`','R','e','g','i','s','t','r','y','`',' ',
2436 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2437 ' ','=',' ' ,'\'','%','s','\'',0 };
2438 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2439 static const WCHAR fmt2[]=
2440 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2442 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2446 root = MSI_RecordGetInteger(row,2);
2447 key = MSI_RecordGetString(row, 3);
2448 name = MSI_RecordGetString(row, 4);
2449 deformat_string(package, key , &deformated);
2450 deformat_string(package, name, &deformated_name);
2452 len = strlenW(deformated) + 6;
2453 if (deformated_name)
2454 len+=strlenW(deformated_name);
2456 buffer = msi_alloc( len *sizeof(WCHAR));
2458 if (deformated_name)
2459 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2461 sprintfW(buffer,fmt,root,deformated);
2463 msi_free(deformated);
2464 msi_free(deformated_name);
2465 msiobj_release(&row->hdr);
2469 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2471 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2476 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2479 return strdupW( file->TargetPath );
2484 static HKEY openSharedDLLsKey(void)
2487 static const WCHAR path[] =
2488 {'S','o','f','t','w','a','r','e','\\',
2489 'M','i','c','r','o','s','o','f','t','\\',
2490 'W','i','n','d','o','w','s','\\',
2491 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2492 'S','h','a','r','e','d','D','L','L','s',0};
2494 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2498 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2503 DWORD sz = sizeof(count);
2506 hkey = openSharedDLLsKey();
2507 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2508 if (rc != ERROR_SUCCESS)
2514 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2518 hkey = openSharedDLLsKey();
2520 msi_reg_set_val_dword( hkey, path, count );
2522 RegDeleteValueW(hkey,path);
2528 * Return TRUE if the count should be written out and FALSE if not
2530 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2532 MSIFEATURE *feature;
2536 /* only refcount DLLs */
2537 if (comp->KeyPath == NULL ||
2538 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2539 comp->Attributes & msidbComponentAttributesODBCDataSource)
2543 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2544 write = (count > 0);
2546 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2550 /* increment counts */
2551 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2555 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2558 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2560 if ( cl->component == comp )
2565 /* decrement counts */
2566 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2570 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2573 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2575 if ( cl->component == comp )
2580 /* ref count all the files in the component */
2585 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2587 if (file->Component == comp)
2588 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2592 /* add a count for permenent */
2593 if (comp->Attributes & msidbComponentAttributesPermanent)
2596 comp->RefCount = count;
2599 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2603 * Ok further analysis makes me think that this work is
2604 * actually done in the PublishComponents and PublishFeatures
2605 * step, and not here. It appears like the keypath and all that is
2606 * resolved in this step, however actually written in the Publish steps.
2607 * But we will leave it here for now because it is unclear
2609 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2611 WCHAR squished_pc[GUID_SIZE];
2612 WCHAR squished_cc[GUID_SIZE];
2615 HKEY hkey=0,hkey2=0;
2617 /* writes the Component and Features values to the registry */
2619 rc = MSIREG_OpenComponents(&hkey);
2620 if (rc != ERROR_SUCCESS)
2623 squash_guid(package->ProductCode,squished_pc);
2624 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2626 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2630 ui_progress(package,2,0,0,0);
2631 if (!comp->ComponentId)
2634 squash_guid(comp->ComponentId,squished_cc);
2636 msi_free(comp->FullKeypath);
2637 comp->FullKeypath = resolve_keypath( package, comp );
2639 /* do the refcounting */
2640 ACTION_RefCountComponent( package, comp );
2642 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2643 debugstr_w(comp->Component),
2644 debugstr_w(squished_cc),
2645 debugstr_w(comp->FullKeypath),
2648 * Write the keypath out if the component is to be registered
2649 * and delete the key if the component is to be deregistered
2651 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2653 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2654 if (rc != ERROR_SUCCESS)
2657 if (!comp->FullKeypath)
2660 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2662 if (comp->Attributes & msidbComponentAttributesPermanent)
2664 static const WCHAR szPermKey[] =
2665 { '0','0','0','0','0','0','0','0','0','0','0','0',
2666 '0','0','0','0','0','0','0','0','0','0','0','0',
2667 '0','0','0','0','0','0','0','0',0 };
2669 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2675 uirow = MSI_CreateRecord(3);
2676 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2677 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2678 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2679 ui_actiondata(package,szProcessComponents,uirow);
2680 msiobj_release( &uirow->hdr );
2682 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2686 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2687 if (rc != ERROR_SUCCESS)
2690 RegDeleteValueW(hkey2,squished_pc);
2692 /* if the key is empty delete it */
2693 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2695 if (res == ERROR_NO_MORE_ITEMS)
2696 RegDeleteKeyW(hkey,squished_cc);
2699 uirow = MSI_CreateRecord(2);
2700 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2701 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2702 ui_actiondata(package,szProcessComponents,uirow);
2703 msiobj_release( &uirow->hdr );
2718 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2719 LPWSTR lpszName, LONG_PTR lParam)
2722 typelib_struct *tl_struct = (typelib_struct*) lParam;
2723 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2727 if (!IS_INTRESOURCE(lpszName))
2729 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2733 sz = strlenW(tl_struct->source)+4;
2734 sz *= sizeof(WCHAR);
2736 if ((INT_PTR)lpszName == 1)
2737 tl_struct->path = strdupW(tl_struct->source);
2740 tl_struct->path = msi_alloc(sz);
2741 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2744 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2745 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2746 if (!SUCCEEDED(res))
2748 msi_free(tl_struct->path);
2749 tl_struct->path = NULL;
2754 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2755 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2757 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2761 msi_free(tl_struct->path);
2762 tl_struct->path = NULL;
2764 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2765 ITypeLib_Release(tl_struct->ptLib);
2770 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2772 MSIPACKAGE* package = (MSIPACKAGE*)param;
2776 typelib_struct tl_struct;
2778 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2780 component = MSI_RecordGetString(row,3);
2781 comp = get_loaded_component(package,component);
2783 return ERROR_SUCCESS;
2785 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2787 TRACE("Skipping typelib reg due to disabled component\n");
2789 comp->Action = comp->Installed;
2791 return ERROR_SUCCESS;
2794 comp->Action = INSTALLSTATE_LOCAL;
2796 file = get_loaded_file( package, comp->KeyPath );
2798 return ERROR_SUCCESS;
2800 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2804 guid = MSI_RecordGetString(row,1);
2805 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2806 tl_struct.source = strdupW( file->TargetPath );
2807 tl_struct.path = NULL;
2809 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2810 (LONG_PTR)&tl_struct);
2818 helpid = MSI_RecordGetString(row,6);
2821 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2822 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2825 if (!SUCCEEDED(res))
2826 ERR("Failed to register type library %s\n",
2827 debugstr_w(tl_struct.path));
2830 ui_actiondata(package,szRegisterTypeLibraries,row);
2832 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2835 ITypeLib_Release(tl_struct.ptLib);
2836 msi_free(tl_struct.path);
2839 ERR("Failed to load type library %s\n",
2840 debugstr_w(tl_struct.source));
2842 FreeLibrary(module);
2843 msi_free(tl_struct.source);
2846 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2848 return ERROR_SUCCESS;
2851 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2854 * OK this is a bit confusing.. I am given a _Component key and I believe
2855 * that the file that is being registered as a type library is the "key file
2856 * of that component" which I interpret to mean "The file in the KeyPath of
2861 static const WCHAR Query[] =
2862 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2863 '`','T','y','p','e','L','i','b','`',0};
2865 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2866 if (rc != ERROR_SUCCESS)
2867 return ERROR_SUCCESS;
2869 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2870 msiobj_release(&view->hdr);
2874 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2876 MSIPACKAGE *package = (MSIPACKAGE*)param;
2877 LPWSTR target_file, target_folder, filename;
2878 LPCWSTR buffer, extension;
2880 static const WCHAR szlnk[]={'.','l','n','k',0};
2881 IShellLinkW *sl = NULL;
2882 IPersistFile *pf = NULL;
2885 buffer = MSI_RecordGetString(row,4);
2886 comp = get_loaded_component(package,buffer);
2888 return ERROR_SUCCESS;
2890 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2892 TRACE("Skipping shortcut creation due to disabled component\n");
2894 comp->Action = comp->Installed;
2896 return ERROR_SUCCESS;
2899 comp->Action = INSTALLSTATE_LOCAL;
2901 ui_actiondata(package,szCreateShortcuts,row);
2903 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2904 &IID_IShellLinkW, (LPVOID *) &sl );
2908 ERR("CLSID_ShellLink not available\n");
2912 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2915 ERR("QueryInterface(IID_IPersistFile) failed\n");
2919 buffer = MSI_RecordGetString(row,2);
2920 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2922 /* may be needed because of a bug somehwere else */
2923 create_full_pathW(target_folder);
2925 filename = msi_dup_record_field( row, 3 );
2926 reduce_to_longfilename(filename);
2928 extension = strchrW(filename,'.');
2929 if (!extension || strcmpiW(extension,szlnk))
2931 int len = strlenW(filename);
2932 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2933 memcpy(filename + len, szlnk, sizeof(szlnk));
2935 target_file = build_directory_name(2, target_folder, filename);
2936 msi_free(target_folder);
2939 buffer = MSI_RecordGetString(row,5);
2940 if (strchrW(buffer,'['))
2943 deformat_string(package,buffer,&deformated);
2944 IShellLinkW_SetPath(sl,deformated);
2945 msi_free(deformated);
2949 FIXME("poorly handled shortcut format, advertised shortcut\n");
2950 IShellLinkW_SetPath(sl,comp->FullKeypath);
2953 if (!MSI_RecordIsNull(row,6))
2956 buffer = MSI_RecordGetString(row,6);
2957 deformat_string(package,buffer,&deformated);
2958 IShellLinkW_SetArguments(sl,deformated);
2959 msi_free(deformated);
2962 if (!MSI_RecordIsNull(row,7))
2964 buffer = MSI_RecordGetString(row,7);
2965 IShellLinkW_SetDescription(sl,buffer);
2968 if (!MSI_RecordIsNull(row,8))
2969 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2971 if (!MSI_RecordIsNull(row,9))
2976 buffer = MSI_RecordGetString(row,9);
2978 Path = build_icon_path(package,buffer);
2979 index = MSI_RecordGetInteger(row,10);
2981 /* no value means 0 */
2982 if (index == MSI_NULL_INTEGER)
2985 IShellLinkW_SetIconLocation(sl,Path,index);
2989 if (!MSI_RecordIsNull(row,11))
2990 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2992 if (!MSI_RecordIsNull(row,12))
2995 buffer = MSI_RecordGetString(row,12);
2996 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2998 IShellLinkW_SetWorkingDirectory(sl,Path);
3002 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3003 IPersistFile_Save(pf,target_file,FALSE);
3005 msi_free(target_file);
3009 IPersistFile_Release( pf );
3011 IShellLinkW_Release( sl );
3013 return ERROR_SUCCESS;
3016 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3021 static const WCHAR Query[] =
3022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3023 '`','S','h','o','r','t','c','u','t','`',0};
3025 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3026 if (rc != ERROR_SUCCESS)
3027 return ERROR_SUCCESS;
3029 res = CoInitialize( NULL );
3032 ERR("CoInitialize failed\n");
3033 return ERROR_FUNCTION_FAILED;
3036 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3037 msiobj_release(&view->hdr);
3044 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3046 MSIPACKAGE* package = (MSIPACKAGE*)param;
3055 FileName = MSI_RecordGetString(row,1);
3058 ERR("Unable to get FileName\n");
3059 return ERROR_SUCCESS;
3062 FilePath = build_icon_path(package,FileName);
3064 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3066 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3067 FILE_ATTRIBUTE_NORMAL, NULL);
3069 if (the_file == INVALID_HANDLE_VALUE)
3071 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3073 return ERROR_SUCCESS;
3080 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3081 if (rc != ERROR_SUCCESS)
3083 ERR("Failed to get stream\n");
3084 CloseHandle(the_file);
3085 DeleteFileW(FilePath);
3088 WriteFile(the_file,buffer,sz,&write,NULL);
3089 } while (sz == 1024);
3093 CloseHandle(the_file);
3095 uirow = MSI_CreateRecord(1);
3096 MSI_RecordSetStringW(uirow,1,FileName);
3097 ui_actiondata(package,szPublishProduct,uirow);
3098 msiobj_release( &uirow->hdr );
3100 return ERROR_SUCCESS;
3104 * 99% of the work done here is only done for
3105 * advertised installs. However this is where the
3106 * Icon table is processed and written out
3107 * so that is what I am going to do here.
3109 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3113 static const WCHAR Query[]=
3114 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3115 '`','I','c','o','n','`',0};
3116 /* for registry stuff */
3119 static const WCHAR szProductLanguage[] =
3120 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3121 static const WCHAR szARPProductIcon[] =
3122 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3123 static const WCHAR szProductVersion[] =
3124 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3128 MSIHANDLE hDb, hSumInfo;
3130 /* write out icon files */
3132 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3133 if (rc == ERROR_SUCCESS)
3135 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3136 msiobj_release(&view->hdr);
3139 /* ok there is a lot more done here but i need to figure out what */
3141 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3142 if (rc != ERROR_SUCCESS)
3145 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3146 if (rc != ERROR_SUCCESS)
3150 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3151 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3154 langid = msi_get_property_int( package, szProductLanguage, 0 );
3155 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3157 buffer = msi_dup_property( package, szARPProductIcon );
3160 LPWSTR path = build_icon_path(package,buffer);
3161 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3166 buffer = msi_dup_property( package, szProductVersion );
3169 DWORD verdword = msi_version_str_to_dword(buffer);
3170 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3174 /* FIXME: Need to write more keys to the user registry */
3176 hDb= alloc_msihandle( &package->db->hdr );
3178 rc = ERROR_NOT_ENOUGH_MEMORY;
3181 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3182 MsiCloseHandle(hDb);
3183 if (rc == ERROR_SUCCESS)
3185 WCHAR guidbuffer[0x200];
3187 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3189 if (rc == ERROR_SUCCESS)
3191 WCHAR squashed[GUID_SIZE];
3192 /* for now we only care about the first guid */
3193 LPWSTR ptr = strchrW(guidbuffer,';');
3195 squash_guid(guidbuffer,squashed);
3196 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3200 ERR("Unable to query Revision_Number...\n");
3203 MsiCloseHandle(hSumInfo);
3207 ERR("Unable to open Summary Information\n");
3219 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3221 MSIPACKAGE *package = (MSIPACKAGE*)param;
3222 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3223 LPWSTR deformated_section, deformated_key, deformated_value;
3224 LPWSTR folder, fullname = NULL;
3228 static const WCHAR szWindowsFolder[] =
3229 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3231 component = MSI_RecordGetString(row, 8);
3232 comp = get_loaded_component(package,component);
3234 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3236 TRACE("Skipping ini file due to disabled component %s\n",
3237 debugstr_w(component));
3239 comp->Action = comp->Installed;
3241 return ERROR_SUCCESS;
3244 comp->Action = INSTALLSTATE_LOCAL;
3246 identifier = MSI_RecordGetString(row,1);
3247 filename = MSI_RecordGetString(row,2);
3248 dirproperty = MSI_RecordGetString(row,3);
3249 section = MSI_RecordGetString(row,4);
3250 key = MSI_RecordGetString(row,5);
3251 value = MSI_RecordGetString(row,6);
3252 action = MSI_RecordGetInteger(row,7);
3254 deformat_string(package,section,&deformated_section);
3255 deformat_string(package,key,&deformated_key);
3256 deformat_string(package,value,&deformated_value);
3260 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3262 folder = msi_dup_property( package, dirproperty );
3265 folder = msi_dup_property( package, szWindowsFolder );
3269 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3273 fullname = build_directory_name(2, folder, filename);
3277 TRACE("Adding value %s to section %s in %s\n",
3278 debugstr_w(deformated_key), debugstr_w(deformated_section),
3279 debugstr_w(fullname));
3280 WritePrivateProfileStringW(deformated_section, deformated_key,
3281 deformated_value, fullname);
3283 else if (action == 1)
3286 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3287 returned, 10, fullname);
3288 if (returned[0] == 0)
3290 TRACE("Adding value %s to section %s in %s\n",
3291 debugstr_w(deformated_key), debugstr_w(deformated_section),
3292 debugstr_w(fullname));
3294 WritePrivateProfileStringW(deformated_section, deformated_key,
3295 deformated_value, fullname);
3298 else if (action == 3)
3299 FIXME("Append to existing section not yet implemented\n");
3301 uirow = MSI_CreateRecord(4);
3302 MSI_RecordSetStringW(uirow,1,identifier);
3303 MSI_RecordSetStringW(uirow,2,deformated_section);
3304 MSI_RecordSetStringW(uirow,3,deformated_key);
3305 MSI_RecordSetStringW(uirow,4,deformated_value);
3306 ui_actiondata(package,szWriteIniValues,uirow);
3307 msiobj_release( &uirow->hdr );
3311 msi_free(deformated_key);
3312 msi_free(deformated_value);
3313 msi_free(deformated_section);
3314 return ERROR_SUCCESS;
3317 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3321 static const WCHAR ExecSeqQuery[] =
3322 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3323 '`','I','n','i','F','i','l','e','`',0};
3325 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3326 if (rc != ERROR_SUCCESS)
3328 TRACE("no IniFile table\n");
3329 return ERROR_SUCCESS;
3332 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3333 msiobj_release(&view->hdr);
3337 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3339 MSIPACKAGE *package = (MSIPACKAGE*)param;
3344 static const WCHAR ExeStr[] =
3345 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3346 static const WCHAR close[] = {'\"',0};
3348 PROCESS_INFORMATION info;
3353 memset(&si,0,sizeof(STARTUPINFOW));
3355 filename = MSI_RecordGetString(row,1);
3356 file = get_loaded_file( package, filename );
3360 ERR("Unable to find file id %s\n",debugstr_w(filename));
3361 return ERROR_SUCCESS;
3364 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3366 FullName = msi_alloc(len*sizeof(WCHAR));
3367 strcpyW(FullName,ExeStr);
3368 strcatW( FullName, file->TargetPath );
3369 strcatW(FullName,close);
3371 TRACE("Registering %s\n",debugstr_w(FullName));
3372 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3376 msi_dialog_check_messages(info.hProcess);
3381 uirow = MSI_CreateRecord( 2 );
3382 uipath = strdupW( file->TargetPath );
3383 p = strrchrW(uipath,'\\');
3386 MSI_RecordSetStringW( uirow, 1, &p[2] );
3387 MSI_RecordSetStringW( uirow, 2, uipath);
3388 ui_actiondata( package, szSelfRegModules, uirow);
3389 msiobj_release( &uirow->hdr );
3391 /* FIXME: call ui_progress? */
3393 return ERROR_SUCCESS;
3396 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3400 static const WCHAR ExecSeqQuery[] =
3401 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3402 '`','S','e','l','f','R','e','g','`',0};
3404 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3405 if (rc != ERROR_SUCCESS)
3407 TRACE("no SelfReg table\n");
3408 return ERROR_SUCCESS;
3411 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3412 msiobj_release(&view->hdr);
3414 return ERROR_SUCCESS;
3417 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3419 MSIFEATURE *feature;
3424 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3425 if (rc != ERROR_SUCCESS)
3428 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3429 if (rc != ERROR_SUCCESS)
3432 /* here the guids are base 85 encoded */
3433 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3439 BOOL absent = FALSE;
3442 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3443 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3444 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3448 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3452 if (feature->Feature_Parent)
3453 size += strlenW( feature->Feature_Parent )+2;
3455 data = msi_alloc(size * sizeof(WCHAR));
3458 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3460 MSICOMPONENT* component = cl->component;
3464 if (component->ComponentId)
3466 TRACE("From %s\n",debugstr_w(component->ComponentId));
3467 CLSIDFromString(component->ComponentId, &clsid);
3468 encode_base85_guid(&clsid,buf);
3469 TRACE("to %s\n",debugstr_w(buf));
3473 if (feature->Feature_Parent)
3475 static const WCHAR sep[] = {'\2',0};
3477 strcatW(data,feature->Feature_Parent);
3480 msi_reg_set_val_str( hkey, feature->Feature, data );
3484 if (feature->Feature_Parent)
3485 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3488 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3489 (LPBYTE)feature->Feature_Parent,size);
3493 size += 2*sizeof(WCHAR);
3494 data = msi_alloc(size);
3497 if (feature->Feature_Parent)
3498 strcpyW( &data[1], feature->Feature_Parent );
3499 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3505 uirow = MSI_CreateRecord( 1 );
3506 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3507 ui_actiondata( package, szPublishFeatures, uirow);
3508 msiobj_release( &uirow->hdr );
3509 /* FIXME: call ui_progress? */
3518 static UINT msi_get_local_package_name( LPWSTR path )
3520 static const WCHAR szInstaller[] = {
3521 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3522 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3526 time = GetTickCount();
3527 GetWindowsDirectoryW( path, MAX_PATH );
3528 lstrcatW( path, szInstaller );
3529 CreateDirectoryW( path, NULL );
3531 len = lstrlenW(path);
3532 for (i=0; i<0x10000; i++)
3534 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3535 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3536 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3537 if (handle != INVALID_HANDLE_VALUE)
3539 CloseHandle(handle);
3542 if (GetLastError() != ERROR_FILE_EXISTS &&
3543 GetLastError() != ERROR_SHARING_VIOLATION)
3544 return ERROR_FUNCTION_FAILED;
3547 return ERROR_SUCCESS;
3550 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3552 static const WCHAR szOriginalDatabase[] =
3553 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3554 WCHAR packagefile[MAX_PATH];
3558 r = msi_get_local_package_name( packagefile );
3559 if (r != ERROR_SUCCESS)
3562 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3564 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3565 r = CopyFileW( msiFilePath, packagefile, FALSE);
3566 msi_free( msiFilePath );
3570 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3571 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3572 return ERROR_FUNCTION_FAILED;
3575 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3576 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3577 return ERROR_SUCCESS;
3580 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3582 LPWSTR prop, val, key;
3583 static const LPCSTR propval[] = {
3584 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3585 "ARPCONTACT", "Contact",
3586 "ARPCOMMENTS", "Comments",
3587 "ProductName", "DisplayName",
3588 "ProductVersion", "DisplayVersion",
3589 "ARPHELPLINK", "HelpLink",
3590 "ARPHELPTELEPHONE", "HelpTelephone",
3591 "ARPINSTALLLOCATION", "InstallLocation",
3592 "SourceDir", "InstallSource",
3593 "Manufacturer", "Publisher",
3594 "ARPREADME", "Readme",
3596 "ARPURLINFOABOUT", "URLInfoAbout",
3597 "ARPURLUPDATEINFO", "URLUpdateInfo",
3600 const LPCSTR *p = propval;
3604 prop = strdupAtoW( *p++ );
3605 key = strdupAtoW( *p++ );
3606 val = msi_dup_property( package, prop );
3607 msi_reg_set_val_str( hkey, key, val );
3612 return ERROR_SUCCESS;
3615 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3618 LPWSTR buffer = NULL;
3621 static const WCHAR szWindowsInstaller[] =
3622 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3623 static const WCHAR szUpgradeCode[] =
3624 {'U','p','g','r','a','d','e','C','o','d','e',0};
3625 static const WCHAR modpath_fmt[] =
3626 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3627 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3628 static const WCHAR szModifyPath[] =
3629 {'M','o','d','i','f','y','P','a','t','h',0};
3630 static const WCHAR szUninstallString[] =
3631 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3632 static const WCHAR szEstimatedSize[] =
3633 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3634 static const WCHAR szProductLanguage[] =
3635 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3636 static const WCHAR szProductVersion[] =
3637 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3640 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3641 LPWSTR upgrade_code;
3644 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3645 if (rc != ERROR_SUCCESS)
3648 /* dump all the info i can grab */
3649 /* FIXME: Flesh out more information */
3651 msi_write_uninstall_property_vals( package, hkey );
3653 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3655 msi_make_package_local( package, hkey );
3657 /* do ModifyPath and UninstallString */
3658 size = deformat_string(package,modpath_fmt,&buffer);
3659 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3660 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3663 /* FIXME: Write real Estimated Size when we have it */
3664 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3666 GetLocalTime(&systime);
3667 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3668 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3670 langid = msi_get_property_int( package, szProductLanguage, 0 );
3671 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3673 buffer = msi_dup_property( package, szProductVersion );
3676 DWORD verdword = msi_version_str_to_dword(buffer);
3678 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3679 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3680 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3684 /* Handle Upgrade Codes */
3685 upgrade_code = msi_dup_property( package, szUpgradeCode );
3690 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3691 squash_guid(package->ProductCode,squashed);
3692 msi_reg_set_val_str( hkey2, squashed, NULL );
3694 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3695 squash_guid(package->ProductCode,squashed);
3696 msi_reg_set_val_str( hkey2, squashed, NULL );
3699 msi_free(upgrade_code);
3704 /* FIXME: call ui_actiondata */
3706 return ERROR_SUCCESS;
3709 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3711 return execute_script(package,INSTALL_SCRIPT);
3714 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3718 /* turn off scheduleing */
3719 package->script->CurrentlyScripting= FALSE;
3721 /* first do the same as an InstallExecute */
3722 rc = ACTION_InstallExecute(package);
3723 if (rc != ERROR_SUCCESS)
3726 /* then handle Commit Actions */
3727 rc = execute_script(package,COMMIT_SCRIPT);
3732 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3734 static const WCHAR RunOnce[] = {
3735 'S','o','f','t','w','a','r','e','\\',
3736 'M','i','c','r','o','s','o','f','t','\\',
3737 'W','i','n','d','o','w','s','\\',
3738 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3739 'R','u','n','O','n','c','e',0};
3740 static const WCHAR InstallRunOnce[] = {
3741 'S','o','f','t','w','a','r','e','\\',
3742 'M','i','c','r','o','s','o','f','t','\\',
3743 'W','i','n','d','o','w','s','\\',
3744 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3745 'I','n','s','t','a','l','l','e','r','\\',
3746 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3748 static const WCHAR msiexec_fmt[] = {
3750 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3751 '\"','%','s','\"',0};
3752 static const WCHAR install_fmt[] = {
3753 '/','I',' ','\"','%','s','\"',' ',
3754 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3755 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3756 WCHAR buffer[256], sysdir[MAX_PATH];
3758 WCHAR squished_pc[100];
3760 squash_guid(package->ProductCode,squished_pc);
3762 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3763 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3764 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3767 msi_reg_set_val_str( hkey, squished_pc, buffer );
3770 TRACE("Reboot command %s\n",debugstr_w(buffer));
3772 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3773 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3775 msi_reg_set_val_str( hkey, squished_pc, buffer );
3778 return ERROR_INSTALL_SUSPEND;
3781 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3786 * we are currently doing what should be done here in the top level Install
3787 * however for Adminastrative and uninstalls this step will be needed
3789 if (!package->PackagePath)
3790 return ERROR_SUCCESS;
3792 attrib = GetFileAttributesW(package->PackagePath);
3793 if (attrib == INVALID_FILE_ATTRIBUTES)
3799 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3800 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3801 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3802 if (rc == ERROR_MORE_DATA)
3804 prompt = msi_alloc(size * sizeof(WCHAR));
3805 MsiSourceListGetInfoW(package->ProductCode, NULL,
3806 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3807 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3810 prompt = strdupW(package->PackagePath);
3812 msg = generate_error_string(package,1302,1,prompt);
3813 while(attrib == INVALID_FILE_ATTRIBUTES)
3815 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3818 rc = ERROR_INSTALL_USEREXIT;
3821 attrib = GetFileAttributesW(package->PackagePath);
3827 return ERROR_SUCCESS;
3832 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3839 static const WCHAR szPropKeys[][80] =
3841 {'P','r','o','d','u','c','t','I','D',0},
3842 {'U','S','E','R','N','A','M','E',0},
3843 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3847 static const WCHAR szRegKeys[][80] =
3849 {'P','r','o','d','u','c','t','I','D',0},
3850 {'R','e','g','O','w','n','e','r',0},
3851 {'R','e','g','C','o','m','p','a','n','y',0},
3855 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3857 return ERROR_SUCCESS;
3859 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3860 if (rc != ERROR_SUCCESS)
3863 for( i = 0; szPropKeys[i][0]; i++ )
3865 buffer = msi_dup_property( package, szPropKeys[i] );
3866 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3871 msi_free(productid);
3874 /* FIXME: call ui_actiondata */
3876 return ERROR_SUCCESS;
3880 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3884 package->script->InWhatSequence |= SEQUENCE_EXEC;
3885 rc = ACTION_ProcessExecSequence(package,FALSE);
3890 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3892 MSIPACKAGE *package = (MSIPACKAGE*)param;
3893 LPCWSTR compgroupid=NULL;
3894 LPCWSTR feature=NULL;
3895 LPCWSTR text = NULL;
3896 LPCWSTR qualifier = NULL;
3897 LPCWSTR component = NULL;
3898 LPWSTR advertise = NULL;
3899 LPWSTR output = NULL;
3901 UINT rc = ERROR_SUCCESS;
3906 component = MSI_RecordGetString(rec,3);
3907 comp = get_loaded_component(package,component);
3909 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3910 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3911 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3913 TRACE("Skipping: Component %s not scheduled for install\n",
3914 debugstr_w(component));
3916 return ERROR_SUCCESS;
3919 compgroupid = MSI_RecordGetString(rec,1);
3920 qualifier = MSI_RecordGetString(rec,2);
3922 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
3923 if (rc != ERROR_SUCCESS)
3926 text = MSI_RecordGetString(rec,4);
3927 feature = MSI_RecordGetString(rec,5);
3929 advertise = create_component_advertise_string(package, comp, feature);
3931 sz = strlenW(advertise);
3934 sz += lstrlenW(text);
3937 sz *= sizeof(WCHAR);
3939 output = msi_alloc_zero(sz);
3940 strcpyW(output,advertise);
3941 msi_free(advertise);
3944 strcatW(output,text);
3946 msi_reg_set_val_multi_str( hkey, qualifier, output );
3953 uirow = MSI_CreateRecord( 2 );
3954 MSI_RecordSetStringW( uirow, 1, compgroupid );
3955 MSI_RecordSetStringW( uirow, 2, qualifier);
3956 ui_actiondata( package, szPublishComponents, uirow);
3957 msiobj_release( &uirow->hdr );
3958 /* FIXME: call ui_progress? */
3964 * At present I am ignorning the advertised components part of this and only
3965 * focusing on the qualified component sets
3967 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
3971 static const WCHAR ExecSeqQuery[] =
3972 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3973 '`','P','u','b','l','i','s','h',
3974 'C','o','m','p','o','n','e','n','t','`',0};
3976 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3977 if (rc != ERROR_SUCCESS)
3978 return ERROR_SUCCESS;
3980 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
3981 msiobj_release(&view->hdr);
3986 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
3987 LPCSTR action, LPCWSTR table )
3989 static const WCHAR query[] = {
3990 'S','E','L','E','C','T',' ','*',' ',
3991 'F','R','O','M',' ','`','%','s','`',0 };
3992 MSIQUERY *view = NULL;
3996 r = MSI_OpenQuery( package->db, &view, query, table );
3997 if (r == ERROR_SUCCESS)
3999 r = MSI_IterateRecords(view, &count, NULL, package);
4000 msiobj_release(&view->hdr);
4004 FIXME("%s -> %lu ignored %s table values\n",
4005 action, count, debugstr_w(table));
4007 return ERROR_SUCCESS;
4010 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4012 TRACE("%p\n", package);
4013 return ERROR_SUCCESS;
4016 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4018 static const WCHAR table[] =
4019 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4020 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4023 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4025 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4026 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4029 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4031 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4032 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4035 static UINT ACTION_BindImage( MSIPACKAGE *package )
4037 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4038 return msi_unimplemented_action_stub( package, "BindImage", table );
4041 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4043 static const WCHAR table[] = {
4044 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4045 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4048 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4050 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4051 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4054 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4056 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4057 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4060 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4062 static const WCHAR table[] = {
4063 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4064 return msi_unimplemented_action_stub( package, "InstallServices", table );
4067 static UINT ACTION_StartServices( MSIPACKAGE *package )
4069 static const WCHAR table[] = {
4070 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4071 return msi_unimplemented_action_stub( package, "StartServices", table );
4074 static UINT ACTION_StopServices( MSIPACKAGE *package )
4076 static const WCHAR table[] = {
4077 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4078 return msi_unimplemented_action_stub( package, "StopServices", table );
4081 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4083 static const WCHAR table[] = {
4084 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4085 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4088 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4090 static const WCHAR table[] = {
4091 'E','n','v','i','r','o','n','m','e','n','t',0 };
4092 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4095 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4097 static const WCHAR table[] = {
4098 'E','n','v','i','r','o','n','m','e','n','t',0 };
4099 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4102 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4104 static const WCHAR table[] = {
4105 'M','s','i','A','s','s','e','m','b','l','y',0 };
4106 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4109 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4111 static const WCHAR table[] = {
4112 'M','s','i','A','s','s','e','m','b','l','y',0 };
4113 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4116 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4118 static const WCHAR table[] = { 'F','o','n','t',0 };
4119 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4122 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4124 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4125 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4128 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4130 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4131 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4134 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4136 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4137 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4140 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4142 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4143 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4146 static struct _actions StandardActions[] = {
4147 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4148 { szAppSearch, ACTION_AppSearch },
4149 { szBindImage, ACTION_BindImage },
4150 { szCCPSearch, ACTION_CCPSearch},
4151 { szCostFinalize, ACTION_CostFinalize },
4152 { szCostInitialize, ACTION_CostInitialize },
4153 { szCreateFolders, ACTION_CreateFolders },
4154 { szCreateShortcuts, ACTION_CreateShortcuts },
4155 { szDeleteServices, ACTION_DeleteServices },
4156 { szDisableRollback, NULL},
4157 { szDuplicateFiles, ACTION_DuplicateFiles },
4158 { szExecuteAction, ACTION_ExecuteAction },
4159 { szFileCost, ACTION_FileCost },
4160 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4161 { szForceReboot, ACTION_ForceReboot },
4162 { szInstallAdminPackage, NULL},
4163 { szInstallExecute, ACTION_InstallExecute },
4164 { szInstallExecuteAgain, ACTION_InstallExecute },
4165 { szInstallFiles, ACTION_InstallFiles},
4166 { szInstallFinalize, ACTION_InstallFinalize },
4167 { szInstallInitialize, ACTION_InstallInitialize },
4168 { szInstallSFPCatalogFile, NULL},
4169 { szInstallValidate, ACTION_InstallValidate },
4170 { szIsolateComponents, ACTION_IsolateComponents },
4171 { szLaunchConditions, ACTION_LaunchConditions },
4172 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4173 { szMoveFiles, ACTION_MoveFiles },
4174 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4175 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4176 { szInstallODBC, NULL},
4177 { szInstallServices, ACTION_InstallServices },
4178 { szPatchFiles, ACTION_PatchFiles },
4179 { szProcessComponents, ACTION_ProcessComponents },
4180 { szPublishComponents, ACTION_PublishComponents },
4181 { szPublishFeatures, ACTION_PublishFeatures },
4182 { szPublishProduct, ACTION_PublishProduct },
4183 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4184 { szRegisterComPlus, ACTION_RegisterComPlus},
4185 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4186 { szRegisterFonts, ACTION_RegisterFonts },
4187 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4188 { szRegisterProduct, ACTION_RegisterProduct },
4189 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4190 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4191 { szRegisterUser, ACTION_RegisterUser},
4192 { szRemoveDuplicateFiles, NULL},
4193 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4194 { szRemoveExistingProducts, NULL},
4195 { szRemoveFiles, ACTION_RemoveFiles},
4196 { szRemoveFolders, NULL},
4197 { szRemoveIniValues, ACTION_RemoveIniValues },
4198 { szRemoveODBC, NULL},
4199 { szRemoveRegistryValues, NULL},
4200 { szRemoveShortcuts, NULL},
4201 { szResolveSource, ACTION_ResolveSource},
4202 { szRMCCPSearch, ACTION_RMCCPSearch},
4203 { szScheduleReboot, NULL},
4204 { szSelfRegModules, ACTION_SelfRegModules },
4205 { szSelfUnregModules, ACTION_SelfUnregModules },
4206 { szSetODBCFolders, NULL},
4207 { szStartServices, ACTION_StartServices },
4208 { szStopServices, ACTION_StopServices },
4209 { szUnpublishComponents, NULL},
4210 { szUnpublishFeatures, NULL},
4211 { szUnregisterClassInfo, NULL},
4212 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4213 { szUnregisterExtensionInfo, NULL},
4214 { szUnregisterFonts, ACTION_UnregisterFonts },
4215 { szUnregisterMIMEInfo, NULL},
4216 { szUnregisterProgIdInfo, NULL},
4217 { szUnregisterTypeLibraries, NULL},
4218 { szValidateProductID, NULL},
4219 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4220 { szWriteIniValues, ACTION_WriteIniValues },
4221 { szWriteRegistryValues, ACTION_WriteRegistryValues},