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_ABSENT;
1123 switch (comp->Attributes)
1125 case msidbComponentAttributesLocalOnly:
1126 comp->Action = INSTALLSTATE_LOCAL;
1127 comp->ActionRequest = INSTALLSTATE_LOCAL;
1129 case msidbComponentAttributesSourceOnly:
1130 comp->Action = INSTALLSTATE_SOURCE;
1131 comp->ActionRequest = INSTALLSTATE_SOURCE;
1133 case msidbComponentAttributesOptional:
1134 comp->Action = INSTALLSTATE_DEFAULT;
1135 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1138 comp->Action = INSTALLSTATE_LOCAL;
1139 comp->ActionRequest = INSTALLSTATE_LOCAL;
1142 return ERROR_SUCCESS;
1145 static UINT load_all_components( MSIPACKAGE *package )
1147 static const WCHAR query[] = {
1148 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1149 '`','C','o','m','p','o','n','e','n','t','`',0 };
1153 if (!list_empty(&package->components))
1154 return ERROR_SUCCESS;
1156 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1157 if (r != ERROR_SUCCESS)
1160 r = MSI_IterateRecords(view, NULL, load_component, package);
1161 msiobj_release(&view->hdr);
1166 MSIPACKAGE *package;
1167 MSIFEATURE *feature;
1170 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1174 cl = msi_alloc( sizeof (*cl) );
1176 return ERROR_NOT_ENOUGH_MEMORY;
1177 cl->component = comp;
1178 list_add_tail( &feature->Components, &cl->entry );
1180 return ERROR_SUCCESS;
1183 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1185 _ilfs* ilfs= (_ilfs*)param;
1189 component = MSI_RecordGetString(row,1);
1191 /* check to see if the component is already loaded */
1192 comp = get_loaded_component( ilfs->package, component );
1195 ERR("unknown component %s\n", debugstr_w(component));
1196 return ERROR_FUNCTION_FAILED;
1199 add_feature_component( ilfs->feature, comp );
1200 comp->Enabled = TRUE;
1202 return ERROR_SUCCESS;
1205 static UINT load_feature(MSIRECORD * row, LPVOID param)
1207 MSIPACKAGE* package = (MSIPACKAGE*)param;
1208 MSIFEATURE* feature;
1209 static const WCHAR Query1[] =
1210 {'S','E','L','E','C','T',' ',
1211 '`','C','o','m','p','o','n','e','n','t','_','`',
1212 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1213 'C','o','m','p','o','n','e','n','t','s','`',' ',
1214 'W','H','E','R','E',' ',
1215 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1220 /* fill in the data */
1222 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1224 return ERROR_NOT_ENOUGH_MEMORY;
1226 list_init( &feature->Components );
1228 feature->Feature = msi_dup_record_field( row, 1 );
1230 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1232 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1233 feature->Title = msi_dup_record_field( row, 3 );
1234 feature->Description = msi_dup_record_field( row, 4 );
1236 if (!MSI_RecordIsNull(row,5))
1237 feature->Display = MSI_RecordGetInteger(row,5);
1239 feature->Level= MSI_RecordGetInteger(row,6);
1240 feature->Directory = msi_dup_record_field( row, 7 );
1241 feature->Attributes = MSI_RecordGetInteger(row,8);
1243 feature->Installed = INSTALLSTATE_ABSENT;
1244 feature->Action = INSTALLSTATE_UNKNOWN;
1245 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1247 list_add_tail( &package->features, &feature->entry );
1249 /* load feature components */
1251 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1252 if (rc != ERROR_SUCCESS)
1253 return ERROR_SUCCESS;
1255 ilfs.package = package;
1256 ilfs.feature = feature;
1258 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1259 msiobj_release(&view->hdr);
1261 return ERROR_SUCCESS;
1264 static UINT load_all_features( MSIPACKAGE *package )
1266 static const WCHAR query[] = {
1267 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1268 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1269 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1273 if (!list_empty(&package->features))
1274 return ERROR_SUCCESS;
1276 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1277 if (r != ERROR_SUCCESS)
1280 r = MSI_IterateRecords( view, NULL, load_feature, package );
1281 msiobj_release( &view->hdr );
1285 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1296 static UINT load_file(MSIRECORD *row, LPVOID param)
1298 MSIPACKAGE* package = (MSIPACKAGE*)param;
1302 /* fill in the data */
1304 file = msi_alloc_zero( sizeof (MSIFILE) );
1306 return ERROR_NOT_ENOUGH_MEMORY;
1308 file->File = msi_dup_record_field( row, 1 );
1310 component = MSI_RecordGetString( row, 2 );
1311 file->Component = get_loaded_component( package, component );
1313 if (!file->Component)
1314 ERR("Unfound Component %s\n",debugstr_w(component));
1316 file->FileName = msi_dup_record_field( row, 3 );
1317 reduce_to_longfilename( file->FileName );
1319 file->ShortName = msi_dup_record_field( row, 3 );
1320 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1322 file->FileSize = MSI_RecordGetInteger( row, 4 );
1323 file->Version = msi_dup_record_field( row, 5 );
1324 file->Language = msi_dup_record_field( row, 6 );
1325 file->Attributes = MSI_RecordGetInteger( row, 7 );
1326 file->Sequence = MSI_RecordGetInteger( row, 8 );
1328 file->state = msifs_invalid;
1330 /* if the compressed bits are not set in the file attributes,
1331 * then read the information from the package word count property
1333 if (file->Attributes & msidbFileAttributesCompressed)
1335 file->IsCompressed = TRUE;
1337 else if (file->Attributes & msidbFileAttributesNoncompressed)
1339 file->IsCompressed = FALSE;
1343 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1346 if (file->IsCompressed)
1348 file->Component->ForceLocalState = TRUE;
1349 file->Component->Action = INSTALLSTATE_LOCAL;
1350 file->Component->ActionRequest = INSTALLSTATE_LOCAL;
1353 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1355 list_add_tail( &package->files, &file->entry );
1357 return ERROR_SUCCESS;
1360 static UINT load_all_files(MSIPACKAGE *package)
1364 static const WCHAR Query[] =
1365 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1366 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1367 '`','S','e','q','u','e','n','c','e','`', 0};
1369 if (!list_empty(&package->files))
1370 return ERROR_SUCCESS;
1372 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1373 if (rc != ERROR_SUCCESS)
1374 return ERROR_SUCCESS;
1376 rc = MSI_IterateRecords(view, NULL, load_file, package);
1377 msiobj_release(&view->hdr);
1379 return ERROR_SUCCESS;
1384 * I am not doing any of the costing functionality yet.
1385 * Mostly looking at doing the Component and Feature loading
1387 * The native MSI does A LOT of modification to tables here. Mostly adding
1388 * a lot of temporary columns to the Feature and Component tables.
1390 * note: Native msi also tracks the short filename. But I am only going to
1391 * track the long ones. Also looking at this directory table
1392 * it appears that the directory table does not get the parents
1393 * resolved base on property only based on their entries in the
1396 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1398 static const WCHAR szCosting[] =
1399 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1400 static const WCHAR szZero[] = { '0', 0 };
1402 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1403 return ERROR_SUCCESS;
1405 MSI_SetPropertyW(package, szCosting, szZero);
1406 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1408 load_all_components( package );
1409 load_all_features( package );
1410 load_all_files( package );
1412 return ERROR_SUCCESS;
1415 static UINT execute_script(MSIPACKAGE *package, UINT script )
1418 UINT rc = ERROR_SUCCESS;
1420 TRACE("Executing Script %i\n",script);
1422 if (!package->script)
1424 ERR("no script!\n");
1425 return ERROR_FUNCTION_FAILED;
1428 for (i = 0; i < package->script->ActionCount[script]; i++)
1431 action = package->script->Actions[script][i];
1432 ui_actionstart(package, action);
1433 TRACE("Executing Action (%s)\n",debugstr_w(action));
1434 rc = ACTION_PerformAction(package, action, TRUE);
1435 msi_free(package->script->Actions[script][i]);
1436 if (rc != ERROR_SUCCESS)
1439 msi_free(package->script->Actions[script]);
1441 package->script->ActionCount[script] = 0;
1442 package->script->Actions[script] = NULL;
1446 static UINT ACTION_FileCost(MSIPACKAGE *package)
1448 return ERROR_SUCCESS;
1451 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1453 static const WCHAR Query[] =
1454 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1455 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1456 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1457 ' ','=',' ','\'','%','s','\'',
1459 static const WCHAR szDot[] = { '.',0 };
1460 static WCHAR szEmpty[] = { 0 };
1461 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1466 TRACE("Looking for dir %s\n",debugstr_w(dir));
1468 folder = get_loaded_folder( package, dir );
1472 TRACE("Working to load %s\n",debugstr_w(dir));
1474 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1478 folder->Directory = strdupW(dir);
1480 row = MSI_QueryGetRecord(package->db, Query, dir);
1484 p = msi_dup_record_field(row, 3);
1486 /* split src and target dir */
1488 src_short = folder_split_path( p, ':' );
1490 /* split the long and short paths */
1491 tgt_long = folder_split_path( tgt_short, '|' );
1492 src_long = folder_split_path( src_short, '|' );
1494 /* check for no-op dirs */
1495 if (!lstrcmpW(szDot, tgt_short))
1496 tgt_short = szEmpty;
1497 if (!lstrcmpW(szDot, src_short))
1498 src_short = szEmpty;
1501 tgt_long = tgt_short;
1504 src_short = tgt_short;
1505 src_long = tgt_long;
1509 src_long = src_short;
1511 /* FIXME: use the target short path too */
1512 folder->TargetDefault = strdupW(tgt_long);
1513 folder->SourceShortPath = strdupW(src_short);
1514 folder->SourceLongPath = strdupW(src_long);
1517 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1518 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1519 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1521 parent = MSI_RecordGetString(row, 2);
1524 folder->Parent = load_folder( package, parent );
1525 if ( folder->Parent )
1526 TRACE("loaded parent %p %s\n", folder->Parent,
1527 debugstr_w(folder->Parent->Directory));
1529 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1532 folder->Property = msi_dup_property( package, dir );
1534 msiobj_release(&row->hdr);
1536 list_add_tail( &package->folders, &folder->entry );
1538 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1543 /* scan for and update current install states */
1544 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1547 MSIFEATURE *feature;
1549 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1552 res = MsiGetComponentPathW( package->ProductCode,
1553 comp->ComponentId, NULL, NULL);
1555 res = INSTALLSTATE_ABSENT;
1556 comp->Installed = res;
1559 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1562 INSTALLSTATE res = -10;
1564 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1566 comp= cl->component;
1569 res = comp->Installed;
1572 if (res == comp->Installed)
1575 if (res != comp->Installed)
1576 res = INSTALLSTATE_INCOMPLETE;
1579 feature->Installed = res;
1583 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1586 static const WCHAR all[]={'A','L','L',0};
1588 MSIFEATURE *feature;
1590 override = msi_dup_property( package, property );
1594 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1596 if (strcmpiW(override,all)==0)
1598 feature->ActionRequest= state;
1599 feature->Action = state;
1603 LPWSTR ptr = override;
1604 LPWSTR ptr2 = strchrW(override,',');
1608 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1609 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1611 feature->ActionRequest= state;
1612 feature->Action = state;
1618 ptr2 = strchrW(ptr,',');
1630 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1633 static const WCHAR szlevel[] =
1634 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1635 static const WCHAR szAddLocal[] =
1636 {'A','D','D','L','O','C','A','L',0};
1637 static const WCHAR szRemove[] =
1638 {'R','E','M','O','V','E',0};
1639 static const WCHAR szReinstall[] =
1640 {'R','E','I','N','S','T','A','L','L',0};
1641 BOOL override = FALSE;
1642 MSICOMPONENT* component;
1643 MSIFEATURE *feature;
1646 /* I do not know if this is where it should happen.. but */
1648 TRACE("Checking Install Level\n");
1650 install_level = msi_get_property_int( package, szlevel, 1 );
1652 /* ok hereis the _real_ rub
1653 * all these activation/deactivation things happen in order and things
1654 * later on the list override things earlier on the list.
1655 * 1) INSTALLLEVEL processing
1665 * 11) FILEADDDEFAULT
1666 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1667 * ignored for all the features. seems strange, especially since it is not
1668 * documented anywhere, but it is how it works.
1670 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1671 * REMOVE are the big ones, since we don't handle administrative installs
1674 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1675 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1676 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1680 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1682 BOOL feature_state = ((feature->Level > 0) &&
1683 (feature->Level <= install_level));
1685 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1687 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1689 feature->ActionRequest = INSTALLSTATE_SOURCE;
1690 feature->Action = INSTALLSTATE_SOURCE;
1692 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1694 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1695 feature->Action = INSTALLSTATE_ADVERTISED;
1699 feature->ActionRequest = INSTALLSTATE_LOCAL;
1700 feature->Action = INSTALLSTATE_LOCAL;
1707 /* set the Preselected Property */
1708 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1709 static const WCHAR szOne[] = { '1', 0 };
1711 MSI_SetPropertyW(package,szPreselected,szOne);
1715 * now we want to enable or disable components base on feature
1718 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1722 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1723 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1724 feature->ActionRequest);
1726 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1728 component = cl->component;
1730 if (!component->Enabled)
1732 component->Action = INSTALLSTATE_UNKNOWN;
1733 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1737 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1739 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1741 component->Action = INSTALLSTATE_LOCAL;
1742 component->ActionRequest = INSTALLSTATE_LOCAL;
1745 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1747 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1748 (component->Action == INSTALLSTATE_ABSENT) ||
1749 (component->Action == INSTALLSTATE_ADVERTISED) ||
1750 (component->Action == INSTALLSTATE_DEFAULT))
1753 component->Action = INSTALLSTATE_SOURCE;
1754 component->ActionRequest = INSTALLSTATE_SOURCE;
1757 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1759 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1760 (component->Action == INSTALLSTATE_ABSENT))
1763 component->Action = INSTALLSTATE_ADVERTISED;
1764 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1767 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1769 if (component->Action == INSTALLSTATE_UNKNOWN)
1771 component->Action = INSTALLSTATE_ABSENT;
1772 component->ActionRequest = INSTALLSTATE_ABSENT;
1777 if (component->ForceLocalState)
1779 feature->Action = INSTALLSTATE_LOCAL;
1780 feature->ActionRequest = INSTALLSTATE_LOCAL;
1785 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1787 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1788 debugstr_w(component->Component), component->Installed,
1789 component->Action, component->ActionRequest);
1793 return ERROR_SUCCESS;
1796 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1798 MSIPACKAGE *package = (MSIPACKAGE*)param;
1802 name = MSI_RecordGetString(row,1);
1804 /* This helper function now does ALL the work */
1805 TRACE("Dir %s ...\n",debugstr_w(name));
1806 load_folder(package,name);
1807 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1808 TRACE("resolves to %s\n",debugstr_w(path));
1811 return ERROR_SUCCESS;
1814 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1816 MSIPACKAGE *package = (MSIPACKAGE*)param;
1818 MSIFEATURE *feature;
1820 name = MSI_RecordGetString( row, 1 );
1822 feature = get_loaded_feature( package, name );
1824 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1828 Condition = MSI_RecordGetString(row,3);
1830 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1832 int level = MSI_RecordGetInteger(row,2);
1833 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1834 feature->Level = level;
1837 return ERROR_SUCCESS;
1842 * A lot is done in this function aside from just the costing.
1843 * The costing needs to be implemented at some point but for now I am going
1844 * to focus on the directory building
1847 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1849 static const WCHAR ExecSeqQuery[] =
1850 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1851 '`','D','i','r','e','c','t','o','r','y','`',0};
1852 static const WCHAR ConditionQuery[] =
1853 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1854 '`','C','o','n','d','i','t','i','o','n','`',0};
1855 static const WCHAR szCosting[] =
1856 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1857 static const WCHAR szlevel[] =
1858 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1859 static const WCHAR szOne[] = { '1', 0 };
1866 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1867 return ERROR_SUCCESS;
1869 TRACE("Building Directory properties\n");
1871 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1872 if (rc == ERROR_SUCCESS)
1874 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1876 msiobj_release(&view->hdr);
1879 TRACE("File calculations\n");
1881 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1883 MSICOMPONENT* comp = file->Component;
1889 /* calculate target */
1890 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1892 msi_free(file->TargetPath);
1894 TRACE("file %s is named %s\n",
1895 debugstr_w(file->File),debugstr_w(file->FileName));
1897 file->TargetPath = build_directory_name(2, p, file->FileName);
1901 TRACE("file %s resolves to %s\n",
1902 debugstr_w(file->File),debugstr_w(file->TargetPath));
1904 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1906 file->state = msifs_missing;
1907 comp->Cost += file->FileSize;
1917 static WCHAR name[] = {'\\',0};
1918 static const WCHAR name_fmt[] =
1919 {'%','u','.','%','u','.','%','u','.','%','u',0};
1920 WCHAR filever[0x100];
1921 VS_FIXEDFILEINFO *lpVer;
1923 TRACE("Version comparison..\n");
1924 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1925 version = msi_alloc(versize);
1926 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1928 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1930 sprintfW(filever,name_fmt,
1931 HIWORD(lpVer->dwFileVersionMS),
1932 LOWORD(lpVer->dwFileVersionMS),
1933 HIWORD(lpVer->dwFileVersionLS),
1934 LOWORD(lpVer->dwFileVersionLS));
1936 TRACE("new %s old %s\n", debugstr_w(file->Version),
1937 debugstr_w(filever));
1938 if (strcmpiW(filever,file->Version)<0)
1940 file->state = msifs_overwrite;
1941 /* FIXME: cost should be diff in size */
1942 comp->Cost += file->FileSize;
1945 file->state = msifs_present;
1949 file->state = msifs_present;
1952 TRACE("Evaluating Condition Table\n");
1954 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1955 if (rc == ERROR_SUCCESS)
1957 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1959 msiobj_release(&view->hdr);
1962 TRACE("Enabling or Disabling Components\n");
1963 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1965 if (comp->Condition)
1967 if (MSI_EvaluateConditionW(package,
1968 comp->Condition) == MSICONDITION_FALSE)
1970 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1971 comp->Enabled = FALSE;
1976 MSI_SetPropertyW(package,szCosting,szOne);
1977 /* set default run level if not set */
1978 level = msi_dup_property( package, szlevel );
1980 MSI_SetPropertyW(package,szlevel, szOne);
1983 ACTION_UpdateInstallStates(package);
1985 return MSI_SetFeatureStates(package);
1988 /* OK this value is "interpreted" and then formatted based on the
1989 first few characters */
1990 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1994 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2000 LPWSTR deformated = NULL;
2003 deformat_string(package, &value[2], &deformated);
2005 /* binary value type */
2009 *size = (strlenW(ptr)/2)+1;
2011 *size = strlenW(ptr)/2;
2013 data = msi_alloc(*size);
2019 /* if uneven pad with a zero in front */
2025 data[count] = (BYTE)strtol(byte,NULL,0);
2027 TRACE("Uneven byte count\n");
2035 data[count] = (BYTE)strtol(byte,NULL,0);
2038 msi_free(deformated);
2040 TRACE("Data %li bytes(%i)\n",*size,count);
2047 deformat_string(package, &value[1], &deformated);
2050 *size = sizeof(DWORD);
2051 data = msi_alloc(*size);
2057 if ( (*p < '0') || (*p > '9') )
2063 if (deformated[0] == '-')
2066 TRACE("DWORD %li\n",*(LPDWORD)data);
2068 msi_free(deformated);
2073 static const WCHAR szMulti[] = {'[','~',']',0};
2082 *type=REG_EXPAND_SZ;
2090 if (strstrW(value,szMulti))
2091 *type = REG_MULTI_SZ;
2093 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2098 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2100 MSIPACKAGE *package = (MSIPACKAGE*)param;
2101 static const WCHAR szHCR[] =
2102 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2103 'R','O','O','T','\\',0};
2104 static const WCHAR szHCU[] =
2105 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2106 'U','S','E','R','\\',0};
2107 static const WCHAR szHLM[] =
2108 {'H','K','E','Y','_','L','O','C','A','L','_',
2109 'M','A','C','H','I','N','E','\\',0};
2110 static const WCHAR szHU[] =
2111 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2113 LPSTR value_data = NULL;
2114 HKEY root_key, hkey;
2117 LPCWSTR szRoot, component, name, key, value;
2122 BOOL check_first = FALSE;
2125 ui_progress(package,2,0,0,0);
2132 component = MSI_RecordGetString(row, 6);
2133 comp = get_loaded_component(package,component);
2135 return ERROR_SUCCESS;
2137 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2139 TRACE("Skipping write due to disabled component %s\n",
2140 debugstr_w(component));
2142 comp->Action = comp->Installed;
2144 return ERROR_SUCCESS;
2147 comp->Action = INSTALLSTATE_LOCAL;
2149 name = MSI_RecordGetString(row, 4);
2150 if( MSI_RecordIsNull(row,5) && name )
2152 /* null values can have special meanings */
2153 if (name[0]=='-' && name[1] == 0)
2154 return ERROR_SUCCESS;
2155 else if ((name[0]=='+' && name[1] == 0) ||
2156 (name[0] == '*' && name[1] == 0))
2161 root = MSI_RecordGetInteger(row,2);
2162 key = MSI_RecordGetString(row, 3);
2164 /* get the root key */
2169 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2170 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2171 if (all_users && all_users[0] == '1')
2173 root_key = HKEY_LOCAL_MACHINE;
2178 root_key = HKEY_CURRENT_USER;
2181 msi_free(all_users);
2184 case 0: root_key = HKEY_CLASSES_ROOT;
2187 case 1: root_key = HKEY_CURRENT_USER;
2190 case 2: root_key = HKEY_LOCAL_MACHINE;
2193 case 3: root_key = HKEY_USERS;
2197 ERR("Unknown root %i\n",root);
2203 return ERROR_SUCCESS;
2205 deformat_string(package, key , &deformated);
2206 size = strlenW(deformated) + strlenW(szRoot) + 1;
2207 uikey = msi_alloc(size*sizeof(WCHAR));
2208 strcpyW(uikey,szRoot);
2209 strcatW(uikey,deformated);
2211 if (RegCreateKeyW( root_key, deformated, &hkey))
2213 ERR("Could not create key %s\n",debugstr_w(deformated));
2214 msi_free(deformated);
2216 return ERROR_SUCCESS;
2218 msi_free(deformated);
2220 value = MSI_RecordGetString(row,5);
2222 value_data = parse_value(package, value, &type, &size);
2225 static const WCHAR szEmpty[] = {0};
2226 value_data = (LPSTR)strdupW(szEmpty);
2231 deformat_string(package, name, &deformated);
2233 /* get the double nulls to terminate SZ_MULTI */
2234 if (type == REG_MULTI_SZ)
2235 size +=sizeof(WCHAR);
2239 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2241 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2246 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2247 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2249 TRACE("value %s of %s checked already exists\n",
2250 debugstr_w(deformated), debugstr_w(uikey));
2254 TRACE("Checked and setting value %s of %s\n",
2255 debugstr_w(deformated), debugstr_w(uikey));
2256 if (deformated || size)
2257 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2262 uirow = MSI_CreateRecord(3);
2263 MSI_RecordSetStringW(uirow,2,deformated);
2264 MSI_RecordSetStringW(uirow,1,uikey);
2267 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2269 MSI_RecordSetStringW(uirow,3,value);
2271 ui_actiondata(package,szWriteRegistryValues,uirow);
2272 msiobj_release( &uirow->hdr );
2274 msi_free(value_data);
2275 msi_free(deformated);
2278 return ERROR_SUCCESS;
2281 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2285 static const WCHAR ExecSeqQuery[] =
2286 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2287 '`','R','e','g','i','s','t','r','y','`',0 };
2289 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2290 if (rc != ERROR_SUCCESS)
2291 return ERROR_SUCCESS;
2293 /* increment progress bar each time action data is sent */
2294 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2296 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2298 msiobj_release(&view->hdr);
2302 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2304 package->script->CurrentlyScripting = TRUE;
2306 return ERROR_SUCCESS;
2310 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2315 static const WCHAR q1[]=
2316 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2317 '`','R','e','g','i','s','t','r','y','`',0};
2320 MSIFEATURE *feature;
2323 TRACE("InstallValidate\n");
2325 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2326 if (rc == ERROR_SUCCESS)
2328 MSI_IterateRecords( view, &progress, NULL, package );
2329 msiobj_release( &view->hdr );
2330 total += progress * REG_PROGRESS_VALUE;
2333 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2334 total += COMPONENT_PROGRESS_VALUE;
2336 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2337 total += file->FileSize;
2339 ui_progress(package,0,total,0,0);
2341 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2343 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2344 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2345 feature->ActionRequest);
2348 return ERROR_SUCCESS;
2351 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2353 MSIPACKAGE* package = (MSIPACKAGE*)param;
2354 LPCWSTR cond = NULL;
2355 LPCWSTR message = NULL;
2356 static const WCHAR title[]=
2357 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2359 cond = MSI_RecordGetString(row,1);
2361 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2364 message = MSI_RecordGetString(row,2);
2365 deformat_string(package,message,&deformated);
2366 MessageBoxW(NULL,deformated,title,MB_OK);
2367 msi_free(deformated);
2368 return ERROR_FUNCTION_FAILED;
2371 return ERROR_SUCCESS;
2374 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2377 MSIQUERY * view = NULL;
2378 static const WCHAR ExecSeqQuery[] =
2379 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2380 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2382 TRACE("Checking launch conditions\n");
2384 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2385 if (rc != ERROR_SUCCESS)
2386 return ERROR_SUCCESS;
2388 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2389 msiobj_release(&view->hdr);
2394 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2398 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2400 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2402 MSIRECORD * row = 0;
2404 LPWSTR deformated,buffer,deformated_name;
2406 static const WCHAR ExecSeqQuery[] =
2407 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2408 '`','R','e','g','i','s','t','r','y','`',' ',
2409 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2410 ' ','=',' ' ,'\'','%','s','\'',0 };
2411 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2412 static const WCHAR fmt2[]=
2413 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2415 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2419 root = MSI_RecordGetInteger(row,2);
2420 key = MSI_RecordGetString(row, 3);
2421 name = MSI_RecordGetString(row, 4);
2422 deformat_string(package, key , &deformated);
2423 deformat_string(package, name, &deformated_name);
2425 len = strlenW(deformated) + 6;
2426 if (deformated_name)
2427 len+=strlenW(deformated_name);
2429 buffer = msi_alloc( len *sizeof(WCHAR));
2431 if (deformated_name)
2432 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2434 sprintfW(buffer,fmt,root,deformated);
2436 msi_free(deformated);
2437 msi_free(deformated_name);
2438 msiobj_release(&row->hdr);
2442 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2444 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2449 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2452 return strdupW( file->TargetPath );
2457 static HKEY openSharedDLLsKey(void)
2460 static const WCHAR path[] =
2461 {'S','o','f','t','w','a','r','e','\\',
2462 'M','i','c','r','o','s','o','f','t','\\',
2463 'W','i','n','d','o','w','s','\\',
2464 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2465 'S','h','a','r','e','d','D','L','L','s',0};
2467 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2471 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2476 DWORD sz = sizeof(count);
2479 hkey = openSharedDLLsKey();
2480 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2481 if (rc != ERROR_SUCCESS)
2487 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2491 hkey = openSharedDLLsKey();
2493 msi_reg_set_val_dword( hkey, path, count );
2495 RegDeleteValueW(hkey,path);
2501 * Return TRUE if the count should be written out and FALSE if not
2503 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2505 MSIFEATURE *feature;
2509 /* only refcount DLLs */
2510 if (comp->KeyPath == NULL ||
2511 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2512 comp->Attributes & msidbComponentAttributesODBCDataSource)
2516 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2517 write = (count > 0);
2519 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2523 /* increment counts */
2524 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2528 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2531 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2533 if ( cl->component == comp )
2538 /* decrement counts */
2539 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2543 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2546 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2548 if ( cl->component == comp )
2553 /* ref count all the files in the component */
2558 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2560 if (file->Component == comp)
2561 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2565 /* add a count for permenent */
2566 if (comp->Attributes & msidbComponentAttributesPermanent)
2569 comp->RefCount = count;
2572 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2576 * Ok further analysis makes me think that this work is
2577 * actually done in the PublishComponents and PublishFeatures
2578 * step, and not here. It appears like the keypath and all that is
2579 * resolved in this step, however actually written in the Publish steps.
2580 * But we will leave it here for now because it is unclear
2582 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2584 WCHAR squished_pc[GUID_SIZE];
2585 WCHAR squished_cc[GUID_SIZE];
2588 HKEY hkey=0,hkey2=0;
2590 /* writes the Component and Features values to the registry */
2592 rc = MSIREG_OpenComponents(&hkey);
2593 if (rc != ERROR_SUCCESS)
2596 squash_guid(package->ProductCode,squished_pc);
2597 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2599 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2603 ui_progress(package,2,0,0,0);
2604 if (!comp->ComponentId)
2607 squash_guid(comp->ComponentId,squished_cc);
2609 msi_free(comp->FullKeypath);
2610 comp->FullKeypath = resolve_keypath( package, comp );
2612 /* do the refcounting */
2613 ACTION_RefCountComponent( package, comp );
2615 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2616 debugstr_w(comp->Component),
2617 debugstr_w(squished_cc),
2618 debugstr_w(comp->FullKeypath),
2621 * Write the keypath out if the component is to be registered
2622 * and delete the key if the component is to be deregistered
2624 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2626 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2627 if (rc != ERROR_SUCCESS)
2630 if (!comp->FullKeypath)
2633 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2635 if (comp->Attributes & msidbComponentAttributesPermanent)
2637 static const WCHAR szPermKey[] =
2638 { '0','0','0','0','0','0','0','0','0','0','0','0',
2639 '0','0','0','0','0','0','0','0','0','0','0','0',
2640 '0','0','0','0','0','0','0','0',0 };
2642 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2648 uirow = MSI_CreateRecord(3);
2649 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2650 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2651 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2652 ui_actiondata(package,szProcessComponents,uirow);
2653 msiobj_release( &uirow->hdr );
2655 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2659 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2660 if (rc != ERROR_SUCCESS)
2663 RegDeleteValueW(hkey2,squished_pc);
2665 /* if the key is empty delete it */
2666 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2668 if (res == ERROR_NO_MORE_ITEMS)
2669 RegDeleteKeyW(hkey,squished_cc);
2672 uirow = MSI_CreateRecord(2);
2673 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2674 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2675 ui_actiondata(package,szProcessComponents,uirow);
2676 msiobj_release( &uirow->hdr );
2691 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2692 LPWSTR lpszName, LONG_PTR lParam)
2695 typelib_struct *tl_struct = (typelib_struct*) lParam;
2696 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2700 if (!IS_INTRESOURCE(lpszName))
2702 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2706 sz = strlenW(tl_struct->source)+4;
2707 sz *= sizeof(WCHAR);
2709 if ((INT_PTR)lpszName == 1)
2710 tl_struct->path = strdupW(tl_struct->source);
2713 tl_struct->path = msi_alloc(sz);
2714 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2717 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2718 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2719 if (!SUCCEEDED(res))
2721 msi_free(tl_struct->path);
2722 tl_struct->path = NULL;
2727 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2728 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2730 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2734 msi_free(tl_struct->path);
2735 tl_struct->path = NULL;
2737 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2738 ITypeLib_Release(tl_struct->ptLib);
2743 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2745 MSIPACKAGE* package = (MSIPACKAGE*)param;
2749 typelib_struct tl_struct;
2751 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2753 component = MSI_RecordGetString(row,3);
2754 comp = get_loaded_component(package,component);
2756 return ERROR_SUCCESS;
2758 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2760 TRACE("Skipping typelib reg due to disabled component\n");
2762 comp->Action = comp->Installed;
2764 return ERROR_SUCCESS;
2767 comp->Action = INSTALLSTATE_LOCAL;
2769 file = get_loaded_file( package, comp->KeyPath );
2771 return ERROR_SUCCESS;
2773 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2777 guid = MSI_RecordGetString(row,1);
2778 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2779 tl_struct.source = strdupW( file->TargetPath );
2780 tl_struct.path = NULL;
2782 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2783 (LONG_PTR)&tl_struct);
2791 helpid = MSI_RecordGetString(row,6);
2794 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2795 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2798 if (!SUCCEEDED(res))
2799 ERR("Failed to register type library %s\n",
2800 debugstr_w(tl_struct.path));
2803 ui_actiondata(package,szRegisterTypeLibraries,row);
2805 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2808 ITypeLib_Release(tl_struct.ptLib);
2809 msi_free(tl_struct.path);
2812 ERR("Failed to load type library %s\n",
2813 debugstr_w(tl_struct.source));
2815 FreeLibrary(module);
2816 msi_free(tl_struct.source);
2819 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2821 return ERROR_SUCCESS;
2824 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2827 * OK this is a bit confusing.. I am given a _Component key and I believe
2828 * that the file that is being registered as a type library is the "key file
2829 * of that component" which I interpret to mean "The file in the KeyPath of
2834 static const WCHAR Query[] =
2835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2836 '`','T','y','p','e','L','i','b','`',0};
2838 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2839 if (rc != ERROR_SUCCESS)
2840 return ERROR_SUCCESS;
2842 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2843 msiobj_release(&view->hdr);
2847 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2849 MSIPACKAGE *package = (MSIPACKAGE*)param;
2850 LPWSTR target_file, target_folder, filename;
2851 LPCWSTR buffer, extension;
2853 static const WCHAR szlnk[]={'.','l','n','k',0};
2854 IShellLinkW *sl = NULL;
2855 IPersistFile *pf = NULL;
2858 buffer = MSI_RecordGetString(row,4);
2859 comp = get_loaded_component(package,buffer);
2861 return ERROR_SUCCESS;
2863 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2865 TRACE("Skipping shortcut creation due to disabled component\n");
2867 comp->Action = comp->Installed;
2869 return ERROR_SUCCESS;
2872 comp->Action = INSTALLSTATE_LOCAL;
2874 ui_actiondata(package,szCreateShortcuts,row);
2876 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2877 &IID_IShellLinkW, (LPVOID *) &sl );
2881 ERR("CLSID_ShellLink not available\n");
2885 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2888 ERR("QueryInterface(IID_IPersistFile) failed\n");
2892 buffer = MSI_RecordGetString(row,2);
2893 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2895 /* may be needed because of a bug somehwere else */
2896 create_full_pathW(target_folder);
2898 filename = msi_dup_record_field( row, 3 );
2899 reduce_to_longfilename(filename);
2901 extension = strchrW(filename,'.');
2902 if (!extension || strcmpiW(extension,szlnk))
2904 int len = strlenW(filename);
2905 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2906 memcpy(filename + len, szlnk, sizeof(szlnk));
2908 target_file = build_directory_name(2, target_folder, filename);
2909 msi_free(target_folder);
2912 buffer = MSI_RecordGetString(row,5);
2913 if (strchrW(buffer,'['))
2916 deformat_string(package,buffer,&deformated);
2917 IShellLinkW_SetPath(sl,deformated);
2918 msi_free(deformated);
2922 FIXME("poorly handled shortcut format, advertised shortcut\n");
2923 IShellLinkW_SetPath(sl,comp->FullKeypath);
2926 if (!MSI_RecordIsNull(row,6))
2929 buffer = MSI_RecordGetString(row,6);
2930 deformat_string(package,buffer,&deformated);
2931 IShellLinkW_SetArguments(sl,deformated);
2932 msi_free(deformated);
2935 if (!MSI_RecordIsNull(row,7))
2937 buffer = MSI_RecordGetString(row,7);
2938 IShellLinkW_SetDescription(sl,buffer);
2941 if (!MSI_RecordIsNull(row,8))
2942 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2944 if (!MSI_RecordIsNull(row,9))
2949 buffer = MSI_RecordGetString(row,9);
2951 Path = build_icon_path(package,buffer);
2952 index = MSI_RecordGetInteger(row,10);
2954 /* no value means 0 */
2955 if (index == MSI_NULL_INTEGER)
2958 IShellLinkW_SetIconLocation(sl,Path,index);
2962 if (!MSI_RecordIsNull(row,11))
2963 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2965 if (!MSI_RecordIsNull(row,12))
2968 buffer = MSI_RecordGetString(row,12);
2969 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2971 IShellLinkW_SetWorkingDirectory(sl,Path);
2975 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2976 IPersistFile_Save(pf,target_file,FALSE);
2978 msi_free(target_file);
2982 IPersistFile_Release( pf );
2984 IShellLinkW_Release( sl );
2986 return ERROR_SUCCESS;
2989 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2994 static const WCHAR Query[] =
2995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2996 '`','S','h','o','r','t','c','u','t','`',0};
2998 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2999 if (rc != ERROR_SUCCESS)
3000 return ERROR_SUCCESS;
3002 res = CoInitialize( NULL );
3005 ERR("CoInitialize failed\n");
3006 return ERROR_FUNCTION_FAILED;
3009 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3010 msiobj_release(&view->hdr);
3017 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3019 MSIPACKAGE* package = (MSIPACKAGE*)param;
3028 FileName = MSI_RecordGetString(row,1);
3031 ERR("Unable to get FileName\n");
3032 return ERROR_SUCCESS;
3035 FilePath = build_icon_path(package,FileName);
3037 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3039 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3040 FILE_ATTRIBUTE_NORMAL, NULL);
3042 if (the_file == INVALID_HANDLE_VALUE)
3044 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3046 return ERROR_SUCCESS;
3053 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3054 if (rc != ERROR_SUCCESS)
3056 ERR("Failed to get stream\n");
3057 CloseHandle(the_file);
3058 DeleteFileW(FilePath);
3061 WriteFile(the_file,buffer,sz,&write,NULL);
3062 } while (sz == 1024);
3066 CloseHandle(the_file);
3068 uirow = MSI_CreateRecord(1);
3069 MSI_RecordSetStringW(uirow,1,FileName);
3070 ui_actiondata(package,szPublishProduct,uirow);
3071 msiobj_release( &uirow->hdr );
3073 return ERROR_SUCCESS;
3077 * 99% of the work done here is only done for
3078 * advertised installs. However this is where the
3079 * Icon table is processed and written out
3080 * so that is what I am going to do here.
3082 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3086 static const WCHAR Query[]=
3087 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3088 '`','I','c','o','n','`',0};
3089 /* for registry stuff */
3092 static const WCHAR szProductLanguage[] =
3093 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3094 static const WCHAR szARPProductIcon[] =
3095 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3096 static const WCHAR szProductVersion[] =
3097 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3101 MSIHANDLE hDb, hSumInfo;
3103 /* write out icon files */
3105 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3106 if (rc == ERROR_SUCCESS)
3108 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3109 msiobj_release(&view->hdr);
3112 /* ok there is a lot more done here but i need to figure out what */
3114 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3115 if (rc != ERROR_SUCCESS)
3118 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3119 if (rc != ERROR_SUCCESS)
3123 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3124 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3127 langid = msi_get_property_int( package, szProductLanguage, 0 );
3128 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3130 buffer = msi_dup_property( package, szARPProductIcon );
3133 LPWSTR path = build_icon_path(package,buffer);
3134 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3139 buffer = msi_dup_property( package, szProductVersion );
3142 DWORD verdword = msi_version_str_to_dword(buffer);
3143 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3147 /* FIXME: Need to write more keys to the user registry */
3149 hDb= alloc_msihandle( &package->db->hdr );
3151 rc = ERROR_NOT_ENOUGH_MEMORY;
3154 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3155 MsiCloseHandle(hDb);
3156 if (rc == ERROR_SUCCESS)
3158 WCHAR guidbuffer[0x200];
3160 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3162 if (rc == ERROR_SUCCESS)
3164 WCHAR squashed[GUID_SIZE];
3165 /* for now we only care about the first guid */
3166 LPWSTR ptr = strchrW(guidbuffer,';');
3168 squash_guid(guidbuffer,squashed);
3169 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3173 ERR("Unable to query Revision_Number...\n");
3176 MsiCloseHandle(hSumInfo);
3180 ERR("Unable to open Summary Information\n");
3192 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3194 MSIPACKAGE *package = (MSIPACKAGE*)param;
3195 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3196 LPWSTR deformated_section, deformated_key, deformated_value;
3197 LPWSTR folder, fullname = NULL;
3201 static const WCHAR szWindowsFolder[] =
3202 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3204 component = MSI_RecordGetString(row, 8);
3205 comp = get_loaded_component(package,component);
3207 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3209 TRACE("Skipping ini file due to disabled component %s\n",
3210 debugstr_w(component));
3212 comp->Action = comp->Installed;
3214 return ERROR_SUCCESS;
3217 comp->Action = INSTALLSTATE_LOCAL;
3219 identifier = MSI_RecordGetString(row,1);
3220 filename = MSI_RecordGetString(row,2);
3221 dirproperty = MSI_RecordGetString(row,3);
3222 section = MSI_RecordGetString(row,4);
3223 key = MSI_RecordGetString(row,5);
3224 value = MSI_RecordGetString(row,6);
3225 action = MSI_RecordGetInteger(row,7);
3227 deformat_string(package,section,&deformated_section);
3228 deformat_string(package,key,&deformated_key);
3229 deformat_string(package,value,&deformated_value);
3233 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3235 folder = msi_dup_property( package, dirproperty );
3238 folder = msi_dup_property( package, szWindowsFolder );
3242 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3246 fullname = build_directory_name(2, folder, filename);
3250 TRACE("Adding value %s to section %s in %s\n",
3251 debugstr_w(deformated_key), debugstr_w(deformated_section),
3252 debugstr_w(fullname));
3253 WritePrivateProfileStringW(deformated_section, deformated_key,
3254 deformated_value, fullname);
3256 else if (action == 1)
3259 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3260 returned, 10, fullname);
3261 if (returned[0] == 0)
3263 TRACE("Adding value %s to section %s in %s\n",
3264 debugstr_w(deformated_key), debugstr_w(deformated_section),
3265 debugstr_w(fullname));
3267 WritePrivateProfileStringW(deformated_section, deformated_key,
3268 deformated_value, fullname);
3271 else if (action == 3)
3272 FIXME("Append to existing section not yet implemented\n");
3274 uirow = MSI_CreateRecord(4);
3275 MSI_RecordSetStringW(uirow,1,identifier);
3276 MSI_RecordSetStringW(uirow,2,deformated_section);
3277 MSI_RecordSetStringW(uirow,3,deformated_key);
3278 MSI_RecordSetStringW(uirow,4,deformated_value);
3279 ui_actiondata(package,szWriteIniValues,uirow);
3280 msiobj_release( &uirow->hdr );
3284 msi_free(deformated_key);
3285 msi_free(deformated_value);
3286 msi_free(deformated_section);
3287 return ERROR_SUCCESS;
3290 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3294 static const WCHAR ExecSeqQuery[] =
3295 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3296 '`','I','n','i','F','i','l','e','`',0};
3298 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3299 if (rc != ERROR_SUCCESS)
3301 TRACE("no IniFile table\n");
3302 return ERROR_SUCCESS;
3305 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3306 msiobj_release(&view->hdr);
3310 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3312 MSIPACKAGE *package = (MSIPACKAGE*)param;
3317 static const WCHAR ExeStr[] =
3318 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3319 static const WCHAR close[] = {'\"',0};
3321 PROCESS_INFORMATION info;
3326 memset(&si,0,sizeof(STARTUPINFOW));
3328 filename = MSI_RecordGetString(row,1);
3329 file = get_loaded_file( package, filename );
3333 ERR("Unable to find file id %s\n",debugstr_w(filename));
3334 return ERROR_SUCCESS;
3337 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3339 FullName = msi_alloc(len*sizeof(WCHAR));
3340 strcpyW(FullName,ExeStr);
3341 strcatW( FullName, file->TargetPath );
3342 strcatW(FullName,close);
3344 TRACE("Registering %s\n",debugstr_w(FullName));
3345 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3349 msi_dialog_check_messages(info.hProcess);
3354 uirow = MSI_CreateRecord( 2 );
3355 uipath = strdupW( file->TargetPath );
3356 p = strrchrW(uipath,'\\');
3359 MSI_RecordSetStringW( uirow, 1, &p[2] );
3360 MSI_RecordSetStringW( uirow, 2, uipath);
3361 ui_actiondata( package, szSelfRegModules, uirow);
3362 msiobj_release( &uirow->hdr );
3364 /* FIXME: call ui_progress? */
3366 return ERROR_SUCCESS;
3369 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3373 static const WCHAR ExecSeqQuery[] =
3374 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3375 '`','S','e','l','f','R','e','g','`',0};
3377 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3378 if (rc != ERROR_SUCCESS)
3380 TRACE("no SelfReg table\n");
3381 return ERROR_SUCCESS;
3384 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3385 msiobj_release(&view->hdr);
3387 return ERROR_SUCCESS;
3390 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3392 MSIFEATURE *feature;
3397 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3398 if (rc != ERROR_SUCCESS)
3401 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3402 if (rc != ERROR_SUCCESS)
3405 /* here the guids are base 85 encoded */
3406 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3412 BOOL absent = FALSE;
3415 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3416 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3417 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3421 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3425 if (feature->Feature_Parent)
3426 size += strlenW( feature->Feature_Parent )+2;
3428 data = msi_alloc(size * sizeof(WCHAR));
3431 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3433 MSICOMPONENT* component = cl->component;
3437 if (component->ComponentId)
3439 TRACE("From %s\n",debugstr_w(component->ComponentId));
3440 CLSIDFromString(component->ComponentId, &clsid);
3441 encode_base85_guid(&clsid,buf);
3442 TRACE("to %s\n",debugstr_w(buf));
3446 if (feature->Feature_Parent)
3448 static const WCHAR sep[] = {'\2',0};
3450 strcatW(data,feature->Feature_Parent);
3453 msi_reg_set_val_str( hkey, feature->Feature, data );
3457 if (feature->Feature_Parent)
3458 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3461 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3462 (LPBYTE)feature->Feature_Parent,size);
3466 size += 2*sizeof(WCHAR);
3467 data = msi_alloc(size);
3470 if (feature->Feature_Parent)
3471 strcpyW( &data[1], feature->Feature_Parent );
3472 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3478 uirow = MSI_CreateRecord( 1 );
3479 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3480 ui_actiondata( package, szPublishFeatures, uirow);
3481 msiobj_release( &uirow->hdr );
3482 /* FIXME: call ui_progress? */
3491 static UINT msi_get_local_package_name( LPWSTR path )
3493 static const WCHAR szInstaller[] = {
3494 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3495 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3499 time = GetTickCount();
3500 GetWindowsDirectoryW( path, MAX_PATH );
3501 lstrcatW( path, szInstaller );
3502 CreateDirectoryW( path, NULL );
3504 len = lstrlenW(path);
3505 for (i=0; i<0x10000; i++)
3507 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3508 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3509 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3510 if (handle != INVALID_HANDLE_VALUE)
3512 CloseHandle(handle);
3515 if (GetLastError() != ERROR_FILE_EXISTS &&
3516 GetLastError() != ERROR_SHARING_VIOLATION)
3517 return ERROR_FUNCTION_FAILED;
3520 return ERROR_SUCCESS;
3523 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3525 static const WCHAR szOriginalDatabase[] =
3526 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3527 WCHAR packagefile[MAX_PATH];
3531 r = msi_get_local_package_name( packagefile );
3532 if (r != ERROR_SUCCESS)
3535 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3537 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3538 r = CopyFileW( msiFilePath, packagefile, FALSE);
3539 msi_free( msiFilePath );
3543 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3544 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3545 return ERROR_FUNCTION_FAILED;
3548 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3549 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3550 return ERROR_SUCCESS;
3553 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3555 LPWSTR prop, val, key;
3556 static const LPCSTR propval[] = {
3557 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3558 "ARPCONTACT", "Contact",
3559 "ARPCOMMENTS", "Comments",
3560 "ProductName", "DisplayName",
3561 "ProductVersion", "DisplayVersion",
3562 "ARPHELPLINK", "HelpLink",
3563 "ARPHELPTELEPHONE", "HelpTelephone",
3564 "ARPINSTALLLOCATION", "InstallLocation",
3565 "SourceDir", "InstallSource",
3566 "Manufacturer", "Publisher",
3567 "ARPREADME", "Readme",
3569 "ARPURLINFOABOUT", "URLInfoAbout",
3570 "ARPURLUPDATEINFO", "URLUpdateInfo",
3573 const LPCSTR *p = propval;
3577 prop = strdupAtoW( *p++ );
3578 key = strdupAtoW( *p++ );
3579 val = msi_dup_property( package, prop );
3580 msi_reg_set_val_str( hkey, key, val );
3585 return ERROR_SUCCESS;
3588 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3591 LPWSTR buffer = NULL;
3594 static const WCHAR szWindowsInstaller[] =
3595 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3596 static const WCHAR szUpgradeCode[] =
3597 {'U','p','g','r','a','d','e','C','o','d','e',0};
3598 static const WCHAR modpath_fmt[] =
3599 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3600 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3601 static const WCHAR szModifyPath[] =
3602 {'M','o','d','i','f','y','P','a','t','h',0};
3603 static const WCHAR szUninstallString[] =
3604 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3605 static const WCHAR szEstimatedSize[] =
3606 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3607 static const WCHAR szProductLanguage[] =
3608 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3609 static const WCHAR szProductVersion[] =
3610 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3613 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3614 LPWSTR upgrade_code;
3617 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3618 if (rc != ERROR_SUCCESS)
3621 /* dump all the info i can grab */
3622 /* FIXME: Flesh out more information */
3624 msi_write_uninstall_property_vals( package, hkey );
3626 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3628 msi_make_package_local( package, hkey );
3630 /* do ModifyPath and UninstallString */
3631 size = deformat_string(package,modpath_fmt,&buffer);
3632 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3633 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3636 /* FIXME: Write real Estimated Size when we have it */
3637 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3639 GetLocalTime(&systime);
3640 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3641 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3643 langid = msi_get_property_int( package, szProductLanguage, 0 );
3644 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3646 buffer = msi_dup_property( package, szProductVersion );
3649 DWORD verdword = msi_version_str_to_dword(buffer);
3651 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3652 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3653 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3657 /* Handle Upgrade Codes */
3658 upgrade_code = msi_dup_property( package, szUpgradeCode );
3663 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3664 squash_guid(package->ProductCode,squashed);
3665 msi_reg_set_val_str( hkey2, squashed, NULL );
3667 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3668 squash_guid(package->ProductCode,squashed);
3669 msi_reg_set_val_str( hkey2, squashed, NULL );
3672 msi_free(upgrade_code);
3677 /* FIXME: call ui_actiondata */
3679 return ERROR_SUCCESS;
3682 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3684 return execute_script(package,INSTALL_SCRIPT);
3687 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3691 /* turn off scheduleing */
3692 package->script->CurrentlyScripting= FALSE;
3694 /* first do the same as an InstallExecute */
3695 rc = ACTION_InstallExecute(package);
3696 if (rc != ERROR_SUCCESS)
3699 /* then handle Commit Actions */
3700 rc = execute_script(package,COMMIT_SCRIPT);
3705 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3707 static const WCHAR RunOnce[] = {
3708 'S','o','f','t','w','a','r','e','\\',
3709 'M','i','c','r','o','s','o','f','t','\\',
3710 'W','i','n','d','o','w','s','\\',
3711 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3712 'R','u','n','O','n','c','e',0};
3713 static const WCHAR InstallRunOnce[] = {
3714 'S','o','f','t','w','a','r','e','\\',
3715 'M','i','c','r','o','s','o','f','t','\\',
3716 'W','i','n','d','o','w','s','\\',
3717 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3718 'I','n','s','t','a','l','l','e','r','\\',
3719 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3721 static const WCHAR msiexec_fmt[] = {
3723 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3724 '\"','%','s','\"',0};
3725 static const WCHAR install_fmt[] = {
3726 '/','I',' ','\"','%','s','\"',' ',
3727 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3728 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3729 WCHAR buffer[256], sysdir[MAX_PATH];
3731 WCHAR squished_pc[100];
3733 squash_guid(package->ProductCode,squished_pc);
3735 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3736 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3737 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3740 msi_reg_set_val_str( hkey, squished_pc, buffer );
3743 TRACE("Reboot command %s\n",debugstr_w(buffer));
3745 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3746 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3748 msi_reg_set_val_str( hkey, squished_pc, buffer );
3751 return ERROR_INSTALL_SUSPEND;
3754 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3759 * we are currently doing what should be done here in the top level Install
3760 * however for Adminastrative and uninstalls this step will be needed
3762 if (!package->PackagePath)
3763 return ERROR_SUCCESS;
3765 attrib = GetFileAttributesW(package->PackagePath);
3766 if (attrib == INVALID_FILE_ATTRIBUTES)
3772 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3773 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3774 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3775 if (rc == ERROR_MORE_DATA)
3777 prompt = msi_alloc(size * sizeof(WCHAR));
3778 MsiSourceListGetInfoW(package->ProductCode, NULL,
3779 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3780 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3783 prompt = strdupW(package->PackagePath);
3785 msg = generate_error_string(package,1302,1,prompt);
3786 while(attrib == INVALID_FILE_ATTRIBUTES)
3788 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3791 rc = ERROR_INSTALL_USEREXIT;
3794 attrib = GetFileAttributesW(package->PackagePath);
3800 return ERROR_SUCCESS;
3805 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3812 static const WCHAR szPropKeys[][80] =
3814 {'P','r','o','d','u','c','t','I','D',0},
3815 {'U','S','E','R','N','A','M','E',0},
3816 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3820 static const WCHAR szRegKeys[][80] =
3822 {'P','r','o','d','u','c','t','I','D',0},
3823 {'R','e','g','O','w','n','e','r',0},
3824 {'R','e','g','C','o','m','p','a','n','y',0},
3828 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3830 return ERROR_SUCCESS;
3832 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3833 if (rc != ERROR_SUCCESS)
3836 for( i = 0; szPropKeys[i][0]; i++ )
3838 buffer = msi_dup_property( package, szPropKeys[i] );
3839 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3844 msi_free(productid);
3847 /* FIXME: call ui_actiondata */
3849 return ERROR_SUCCESS;
3853 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3857 package->script->InWhatSequence |= SEQUENCE_EXEC;
3858 rc = ACTION_ProcessExecSequence(package,FALSE);
3863 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3865 MSIPACKAGE *package = (MSIPACKAGE*)param;
3866 LPCWSTR compgroupid=NULL;
3867 LPCWSTR feature=NULL;
3868 LPCWSTR text = NULL;
3869 LPCWSTR qualifier = NULL;
3870 LPCWSTR component = NULL;
3871 LPWSTR advertise = NULL;
3872 LPWSTR output = NULL;
3874 UINT rc = ERROR_SUCCESS;
3879 component = MSI_RecordGetString(rec,3);
3880 comp = get_loaded_component(package,component);
3882 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3883 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3884 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3886 TRACE("Skipping: Component %s not scheduled for install\n",
3887 debugstr_w(component));
3889 return ERROR_SUCCESS;
3892 compgroupid = MSI_RecordGetString(rec,1);
3893 qualifier = MSI_RecordGetString(rec,2);
3895 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
3896 if (rc != ERROR_SUCCESS)
3899 text = MSI_RecordGetString(rec,4);
3900 feature = MSI_RecordGetString(rec,5);
3902 advertise = create_component_advertise_string(package, comp, feature);
3904 sz = strlenW(advertise);
3907 sz += lstrlenW(text);
3910 sz *= sizeof(WCHAR);
3912 output = msi_alloc_zero(sz);
3913 strcpyW(output,advertise);
3914 msi_free(advertise);
3917 strcatW(output,text);
3919 msi_reg_set_val_multi_str( hkey, qualifier, output );
3926 uirow = MSI_CreateRecord( 2 );
3927 MSI_RecordSetStringW( uirow, 1, compgroupid );
3928 MSI_RecordSetStringW( uirow, 2, qualifier);
3929 ui_actiondata( package, szPublishComponents, uirow);
3930 msiobj_release( &uirow->hdr );
3931 /* FIXME: call ui_progress? */
3937 * At present I am ignorning the advertised components part of this and only
3938 * focusing on the qualified component sets
3940 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
3944 static const WCHAR ExecSeqQuery[] =
3945 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3946 '`','P','u','b','l','i','s','h',
3947 'C','o','m','p','o','n','e','n','t','`',0};
3949 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3950 if (rc != ERROR_SUCCESS)
3951 return ERROR_SUCCESS;
3953 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
3954 msiobj_release(&view->hdr);
3959 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
3960 LPCSTR action, LPCWSTR table )
3962 static const WCHAR query[] = {
3963 'S','E','L','E','C','T',' ','*',' ',
3964 'F','R','O','M',' ','`','%','s','`',0 };
3965 MSIQUERY *view = NULL;
3969 r = MSI_OpenQuery( package->db, &view, query, table );
3970 if (r == ERROR_SUCCESS)
3972 r = MSI_IterateRecords(view, &count, NULL, package);
3973 msiobj_release(&view->hdr);
3977 FIXME("%s -> %lu ignored %s table values\n",
3978 action, count, debugstr_w(table));
3980 return ERROR_SUCCESS;
3983 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
3985 TRACE("%p\n", package);
3986 return ERROR_SUCCESS;
3989 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
3991 static const WCHAR table[] =
3992 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
3993 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
3996 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
3998 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
3999 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4002 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4004 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4005 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4008 static UINT ACTION_BindImage( MSIPACKAGE *package )
4010 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4011 return msi_unimplemented_action_stub( package, "BindImage", table );
4014 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4016 static const WCHAR table[] = {
4017 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4018 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4021 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4023 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4024 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4027 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4029 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4030 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4033 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4035 static const WCHAR table[] = {
4036 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4037 return msi_unimplemented_action_stub( package, "InstallServices", table );
4040 static UINT ACTION_StartServices( MSIPACKAGE *package )
4042 static const WCHAR table[] = {
4043 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4044 return msi_unimplemented_action_stub( package, "StartServices", table );
4047 static UINT ACTION_StopServices( MSIPACKAGE *package )
4049 static const WCHAR table[] = {
4050 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4051 return msi_unimplemented_action_stub( package, "StopServices", table );
4054 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4056 static const WCHAR table[] = {
4057 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4058 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4061 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4063 static const WCHAR table[] = {
4064 'E','n','v','i','r','o','n','m','e','n','t',0 };
4065 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4068 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4070 static const WCHAR table[] = {
4071 'E','n','v','i','r','o','n','m','e','n','t',0 };
4072 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4075 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4077 static const WCHAR table[] = {
4078 'M','s','i','A','s','s','e','m','b','l','y',0 };
4079 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4082 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4084 static const WCHAR table[] = {
4085 'M','s','i','A','s','s','e','m','b','l','y',0 };
4086 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4089 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4091 static const WCHAR table[] = { 'F','o','n','t',0 };
4092 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4095 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4097 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4098 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4101 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4103 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4104 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4107 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4109 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4110 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4113 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4115 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4116 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4119 static struct _actions StandardActions[] = {
4120 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4121 { szAppSearch, ACTION_AppSearch },
4122 { szBindImage, ACTION_BindImage },
4123 { szCCPSearch, ACTION_CCPSearch},
4124 { szCostFinalize, ACTION_CostFinalize },
4125 { szCostInitialize, ACTION_CostInitialize },
4126 { szCreateFolders, ACTION_CreateFolders },
4127 { szCreateShortcuts, ACTION_CreateShortcuts },
4128 { szDeleteServices, ACTION_DeleteServices },
4129 { szDisableRollback, NULL},
4130 { szDuplicateFiles, ACTION_DuplicateFiles },
4131 { szExecuteAction, ACTION_ExecuteAction },
4132 { szFileCost, ACTION_FileCost },
4133 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4134 { szForceReboot, ACTION_ForceReboot },
4135 { szInstallAdminPackage, NULL},
4136 { szInstallExecute, ACTION_InstallExecute },
4137 { szInstallExecuteAgain, ACTION_InstallExecute },
4138 { szInstallFiles, ACTION_InstallFiles},
4139 { szInstallFinalize, ACTION_InstallFinalize },
4140 { szInstallInitialize, ACTION_InstallInitialize },
4141 { szInstallSFPCatalogFile, NULL},
4142 { szInstallValidate, ACTION_InstallValidate },
4143 { szIsolateComponents, ACTION_IsolateComponents },
4144 { szLaunchConditions, ACTION_LaunchConditions },
4145 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4146 { szMoveFiles, ACTION_MoveFiles },
4147 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4148 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4149 { szInstallODBC, NULL},
4150 { szInstallServices, ACTION_InstallServices },
4151 { szPatchFiles, ACTION_PatchFiles },
4152 { szProcessComponents, ACTION_ProcessComponents },
4153 { szPublishComponents, ACTION_PublishComponents },
4154 { szPublishFeatures, ACTION_PublishFeatures },
4155 { szPublishProduct, ACTION_PublishProduct },
4156 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4157 { szRegisterComPlus, ACTION_RegisterComPlus},
4158 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4159 { szRegisterFonts, ACTION_RegisterFonts },
4160 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4161 { szRegisterProduct, ACTION_RegisterProduct },
4162 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4163 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4164 { szRegisterUser, ACTION_RegisterUser},
4165 { szRemoveDuplicateFiles, NULL},
4166 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4167 { szRemoveExistingProducts, NULL},
4168 { szRemoveFiles, ACTION_RemoveFiles},
4169 { szRemoveFolders, NULL},
4170 { szRemoveIniValues, ACTION_RemoveIniValues },
4171 { szRemoveODBC, NULL},
4172 { szRemoveRegistryValues, NULL},
4173 { szRemoveShortcuts, NULL},
4174 { szResolveSource, ACTION_ResolveSource},
4175 { szRMCCPSearch, ACTION_RMCCPSearch},
4176 { szScheduleReboot, NULL},
4177 { szSelfRegModules, ACTION_SelfRegModules },
4178 { szSelfUnregModules, ACTION_SelfUnregModules },
4179 { szSetODBCFolders, NULL},
4180 { szStartServices, ACTION_StartServices },
4181 { szStopServices, ACTION_StopServices },
4182 { szUnpublishComponents, NULL},
4183 { szUnpublishFeatures, NULL},
4184 { szUnregisterClassInfo, NULL},
4185 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4186 { szUnregisterExtensionInfo, NULL},
4187 { szUnregisterFonts, ACTION_UnregisterFonts },
4188 { szUnregisterMIMEInfo, NULL},
4189 { szUnregisterProgIdInfo, NULL},
4190 { szUnregisterTypeLibraries, NULL},
4191 { szValidateProductID, NULL},
4192 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4193 { szWriteIniValues, ACTION_WriteIniValues },
4194 { szWriteRegistryValues, ACTION_WriteRegistryValues},