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
38 #include "wine/debug.h"
43 #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->storage, 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 path = strdupW(szPackagePath);
578 p = strrchrW(path,'\\');
587 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
588 GetCurrentDirectoryW(MAX_PATH,path);
592 check = msi_dup_property( package, cszSourceDir );
594 MSI_SetPropertyW(package, cszSourceDir, path);
596 check = msi_dup_property( package, cszSOURCEDIR );
598 MSI_SetPropertyW(package, cszSOURCEDIR, path);
600 msi_free( package->PackagePath );
601 package->PackagePath = path;
606 msi_parse_command_line( package, szCommandLine );
608 msi_apply_transforms( package );
609 msi_apply_patches( package );
611 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
613 package->script->InWhatSequence |= SEQUENCE_UI;
614 rc = ACTION_ProcessUISequence(package);
616 if (rc == ERROR_SUCCESS)
618 package->script->InWhatSequence |= SEQUENCE_EXEC;
619 rc = ACTION_ProcessExecSequence(package,TRUE);
623 rc = ACTION_ProcessExecSequence(package,FALSE);
627 /* install was halted but should be considered a success */
631 package->script->CurrentlyScripting= FALSE;
633 /* process the ending type action */
634 if (rc == ERROR_SUCCESS)
635 ACTION_PerformActionSequence(package,-1,ui);
636 else if (rc == ERROR_INSTALL_USEREXIT)
637 ACTION_PerformActionSequence(package,-2,ui);
638 else if (rc == ERROR_INSTALL_SUSPEND)
639 ACTION_PerformActionSequence(package,-4,ui);
641 ACTION_PerformActionSequence(package,-3,ui);
643 /* finish up running custom actions */
644 ACTION_FinishCustomActions(package);
649 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
651 UINT rc = ERROR_SUCCESS;
653 static const WCHAR ExecSeqQuery[] =
654 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
655 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
656 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
657 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
659 static const WCHAR UISeqQuery[] =
660 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
661 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
662 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
663 ' ', '=',' ','%','i',0};
666 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
668 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
672 LPCWSTR action, cond;
674 TRACE("Running the actions\n");
676 /* check conditions */
677 cond = MSI_RecordGetString(row,2);
680 /* this is a hack to skip errors in the condition code */
681 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
685 action = MSI_RecordGetString(row,1);
688 ERR("failed to fetch action\n");
689 rc = ERROR_FUNCTION_FAILED;
694 rc = ACTION_PerformUIAction(package,action);
696 rc = ACTION_PerformAction(package,action,FALSE);
698 msiobj_release(&row->hdr);
709 } iterate_action_param;
711 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
713 iterate_action_param *iap= (iterate_action_param*)param;
715 LPCWSTR cond, action;
717 action = MSI_RecordGetString(row,1);
720 ERR("Error is retrieving action name\n");
721 return ERROR_FUNCTION_FAILED;
724 /* check conditions */
725 cond = MSI_RecordGetString(row,2);
728 /* this is a hack to skip errors in the condition code */
729 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
731 TRACE("Skipping action: %s (condition is false)\n",
733 return ERROR_SUCCESS;
738 rc = ACTION_PerformUIAction(iap->package,action);
740 rc = ACTION_PerformAction(iap->package,action,FALSE);
742 msi_dialog_check_messages( NULL );
744 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
745 rc = iap->package->CurrentInstallState;
747 if (rc == ERROR_FUNCTION_NOT_CALLED)
750 if (rc != ERROR_SUCCESS)
751 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
756 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
760 static const WCHAR query[] =
761 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
763 ' ','W','H','E','R','E',' ',
764 '`','S','e','q','u','e','n','c','e','`',' ',
765 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
766 '`','S','e','q','u','e','n','c','e','`',0};
767 iterate_action_param iap;
770 * FIXME: probably should be checking UILevel in the
771 * ACTION_PerformUIAction/ACTION_PerformAction
772 * rather than saving the UI level here. Those
773 * two functions can be merged too.
775 iap.package = package;
778 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
780 r = MSI_OpenQuery( package->db, &view, query, szTable );
781 if (r == ERROR_SUCCESS)
783 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
784 msiobj_release(&view->hdr);
790 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
794 static const WCHAR ExecSeqQuery[] =
795 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
796 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
797 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
798 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
799 'O','R','D','E','R',' ', 'B','Y',' ',
800 '`','S','e','q','u','e','n','c','e','`',0 };
802 static const WCHAR IVQuery[] =
803 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
804 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
805 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
806 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
807 ' ','\'', 'I','n','s','t','a','l','l',
808 'V','a','l','i','d','a','t','e','\'', 0};
810 iterate_action_param iap;
812 iap.package = package;
815 if (package->script->ExecuteSequenceRun)
817 TRACE("Execute Sequence already Run\n");
818 return ERROR_SUCCESS;
821 package->script->ExecuteSequenceRun = TRUE;
823 /* get the sequence number */
826 row = MSI_QueryGetRecord(package->db, IVQuery);
828 return ERROR_FUNCTION_FAILED;
829 seq = MSI_RecordGetInteger(row,1);
830 msiobj_release(&row->hdr);
833 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
834 if (rc == ERROR_SUCCESS)
836 TRACE("Running the actions\n");
838 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
839 msiobj_release(&view->hdr);
845 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
849 static const WCHAR ExecSeqQuery [] =
850 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
851 '`','I','n','s','t','a','l','l',
852 'U','I','S','e','q','u','e','n','c','e','`',
853 ' ','W','H','E','R','E',' ',
854 '`','S','e','q','u','e','n','c','e','`',' ',
855 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
856 '`','S','e','q','u','e','n','c','e','`',0};
857 iterate_action_param iap;
859 iap.package = package;
862 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
864 if (rc == ERROR_SUCCESS)
866 TRACE("Running the actions\n");
868 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
869 msiobj_release(&view->hdr);
875 /********************************************************
876 * ACTION helper functions and functions that perform the actions
877 *******************************************************/
878 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
879 UINT* rc, BOOL force )
885 if (!run && !package->script->CurrentlyScripting)
890 if (strcmpW(action,szInstallFinalize) == 0 ||
891 strcmpW(action,szInstallExecute) == 0 ||
892 strcmpW(action,szInstallExecuteAgain) == 0)
897 while (StandardActions[i].action != NULL)
899 if (strcmpW(StandardActions[i].action, action)==0)
903 ui_actioninfo(package, action, TRUE, 0);
904 *rc = schedule_action(package,INSTALL_SCRIPT,action);
905 ui_actioninfo(package, action, FALSE, *rc);
909 ui_actionstart(package, action);
910 if (StandardActions[i].handler)
912 *rc = StandardActions[i].handler(package);
916 FIXME("unhandled standard action %s\n",debugstr_w(action));
928 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
929 UINT* rc, BOOL force )
934 arc = ACTION_CustomAction(package,action, force);
936 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
945 * A lot of actions are really important even if they don't do anything
946 * explicit... Lots of properties are set at the beginning of the installation
947 * CostFinalize does a bunch of work to translate the directories and such
949 * But until I get write access to the database that is hard, so I am going to
950 * hack it to see if I can get something to run.
952 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
954 UINT rc = ERROR_SUCCESS;
957 TRACE("Performing action (%s)\n",debugstr_w(action));
959 handled = ACTION_HandleStandardAction(package, action, &rc, force);
962 handled = ACTION_HandleCustomAction(package, action, &rc, force);
966 FIXME("unhandled msi action %s\n",debugstr_w(action));
967 rc = ERROR_FUNCTION_NOT_CALLED;
973 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
975 UINT rc = ERROR_SUCCESS;
976 BOOL handled = FALSE;
978 TRACE("Performing action (%s)\n",debugstr_w(action));
980 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
983 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
985 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
990 FIXME("unhandled msi action %s\n",debugstr_w(action));
991 rc = ERROR_FUNCTION_NOT_CALLED;
999 * Actual Action Handlers
1002 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1004 MSIPACKAGE *package = (MSIPACKAGE*)param;
1010 dir = MSI_RecordGetString(row,1);
1013 ERR("Unable to get folder id\n");
1014 return ERROR_SUCCESS;
1017 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1020 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1021 return ERROR_SUCCESS;
1024 TRACE("Folder is %s\n",debugstr_w(full_path));
1027 uirow = MSI_CreateRecord(1);
1028 MSI_RecordSetStringW(uirow,1,full_path);
1029 ui_actiondata(package,szCreateFolders,uirow);
1030 msiobj_release( &uirow->hdr );
1032 if (folder->State == 0)
1033 create_full_pathW(full_path);
1037 msi_free(full_path);
1038 return ERROR_SUCCESS;
1041 /* FIXME: probably should merge this with the above function */
1042 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1044 UINT rc = ERROR_SUCCESS;
1046 LPWSTR install_path;
1048 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1050 return ERROR_FUNCTION_FAILED;
1052 /* create the path */
1053 if (folder->State == 0)
1055 create_full_pathW(install_path);
1058 msi_free(install_path);
1063 UINT msi_create_component_directories( MSIPACKAGE *package )
1067 /* create all the folders required by the components are going to install */
1068 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1070 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1072 msi_create_directory( package, comp->Directory );
1075 return ERROR_SUCCESS;
1079 * Also we cannot enable/disable components either, so for now I am just going
1080 * to do all the directories for all the components.
1082 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1084 static const WCHAR ExecSeqQuery[] =
1085 {'S','E','L','E','C','T',' ',
1086 '`','D','i','r','e','c','t','o','r','y','_','`',
1087 ' ','F','R','O','M',' ',
1088 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1092 /* create all the empty folders specified in the CreateFolder table */
1093 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1094 if (rc != ERROR_SUCCESS)
1095 return ERROR_SUCCESS;
1097 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1098 msiobj_release(&view->hdr);
1100 msi_create_component_directories( package );
1105 static UINT load_component( MSIRECORD *row, LPVOID param )
1107 MSIPACKAGE *package = param;
1110 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1112 return ERROR_FUNCTION_FAILED;
1114 list_add_tail( &package->components, &comp->entry );
1116 /* fill in the data */
1117 comp->Component = msi_dup_record_field( row, 1 );
1119 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1121 comp->ComponentId = msi_dup_record_field( row, 2 );
1122 comp->Directory = msi_dup_record_field( row, 3 );
1123 comp->Attributes = MSI_RecordGetInteger(row,4);
1124 comp->Condition = msi_dup_record_field( row, 5 );
1125 comp->KeyPath = msi_dup_record_field( row, 6 );
1127 comp->Installed = INSTALLSTATE_UNKNOWN;
1128 comp->Action = INSTALLSTATE_UNKNOWN;
1129 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1131 return ERROR_SUCCESS;
1134 static UINT load_all_components( MSIPACKAGE *package )
1136 static const WCHAR query[] = {
1137 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1138 '`','C','o','m','p','o','n','e','n','t','`',0 };
1142 if (!list_empty(&package->components))
1143 return ERROR_SUCCESS;
1145 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1146 if (r != ERROR_SUCCESS)
1149 r = MSI_IterateRecords(view, NULL, load_component, package);
1150 msiobj_release(&view->hdr);
1155 MSIPACKAGE *package;
1156 MSIFEATURE *feature;
1159 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1163 cl = msi_alloc( sizeof (*cl) );
1165 return ERROR_NOT_ENOUGH_MEMORY;
1166 cl->component = comp;
1167 list_add_tail( &feature->Components, &cl->entry );
1169 return ERROR_SUCCESS;
1172 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1176 fl = msi_alloc( sizeof(*fl) );
1178 return ERROR_NOT_ENOUGH_MEMORY;
1179 fl->feature = child;
1180 list_add_tail( &parent->Children, &fl->entry );
1182 return ERROR_SUCCESS;
1185 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1187 _ilfs* ilfs= (_ilfs*)param;
1191 component = MSI_RecordGetString(row,1);
1193 /* check to see if the component is already loaded */
1194 comp = get_loaded_component( ilfs->package, component );
1197 ERR("unknown component %s\n", debugstr_w(component));
1198 return ERROR_FUNCTION_FAILED;
1201 add_feature_component( ilfs->feature, comp );
1202 comp->Enabled = TRUE;
1204 return ERROR_SUCCESS;
1207 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1209 MSIFEATURE *feature;
1211 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1213 if ( !lstrcmpW( feature->Feature, name ) )
1220 static UINT load_feature(MSIRECORD * row, LPVOID param)
1222 MSIPACKAGE* package = (MSIPACKAGE*)param;
1223 MSIFEATURE* feature;
1224 static const WCHAR Query1[] =
1225 {'S','E','L','E','C','T',' ',
1226 '`','C','o','m','p','o','n','e','n','t','_','`',
1227 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1228 'C','o','m','p','o','n','e','n','t','s','`',' ',
1229 'W','H','E','R','E',' ',
1230 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1235 /* fill in the data */
1237 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1239 return ERROR_NOT_ENOUGH_MEMORY;
1241 list_init( &feature->Children );
1242 list_init( &feature->Components );
1244 feature->Feature = msi_dup_record_field( row, 1 );
1246 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1248 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1249 feature->Title = msi_dup_record_field( row, 3 );
1250 feature->Description = msi_dup_record_field( row, 4 );
1252 if (!MSI_RecordIsNull(row,5))
1253 feature->Display = MSI_RecordGetInteger(row,5);
1255 feature->Level= MSI_RecordGetInteger(row,6);
1256 feature->Directory = msi_dup_record_field( row, 7 );
1257 feature->Attributes = MSI_RecordGetInteger(row,8);
1259 feature->Installed = INSTALLSTATE_UNKNOWN;
1260 feature->Action = INSTALLSTATE_UNKNOWN;
1261 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1263 list_add_tail( &package->features, &feature->entry );
1265 /* load feature components */
1267 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1268 if (rc != ERROR_SUCCESS)
1269 return ERROR_SUCCESS;
1271 ilfs.package = package;
1272 ilfs.feature = feature;
1274 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1275 msiobj_release(&view->hdr);
1277 return ERROR_SUCCESS;
1280 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1282 MSIPACKAGE* package = (MSIPACKAGE*)param;
1283 MSIFEATURE *parent, *child;
1285 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1287 return ERROR_FUNCTION_FAILED;
1289 if (!child->Feature_Parent)
1290 return ERROR_SUCCESS;
1292 parent = find_feature_by_name( package, child->Feature_Parent );
1294 return ERROR_FUNCTION_FAILED;
1296 add_feature_child( parent, child );
1297 return ERROR_SUCCESS;
1300 static UINT load_all_features( MSIPACKAGE *package )
1302 static const WCHAR query[] = {
1303 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1304 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1305 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1309 if (!list_empty(&package->features))
1310 return ERROR_SUCCESS;
1312 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1313 if (r != ERROR_SUCCESS)
1316 r = MSI_IterateRecords( view, NULL, load_feature, package );
1317 if (r != ERROR_SUCCESS)
1320 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1321 msiobj_release( &view->hdr );
1326 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1337 static UINT load_file(MSIRECORD *row, LPVOID param)
1339 MSIPACKAGE* package = (MSIPACKAGE*)param;
1343 /* fill in the data */
1345 file = msi_alloc_zero( sizeof (MSIFILE) );
1347 return ERROR_NOT_ENOUGH_MEMORY;
1349 file->File = msi_dup_record_field( row, 1 );
1351 component = MSI_RecordGetString( row, 2 );
1352 file->Component = get_loaded_component( package, component );
1354 if (!file->Component)
1355 ERR("Unfound Component %s\n",debugstr_w(component));
1357 file->FileName = msi_dup_record_field( row, 3 );
1358 reduce_to_longfilename( file->FileName );
1360 file->ShortName = msi_dup_record_field( row, 3 );
1361 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1363 file->FileSize = MSI_RecordGetInteger( row, 4 );
1364 file->Version = msi_dup_record_field( row, 5 );
1365 file->Language = msi_dup_record_field( row, 6 );
1366 file->Attributes = MSI_RecordGetInteger( row, 7 );
1367 file->Sequence = MSI_RecordGetInteger( row, 8 );
1369 file->state = msifs_invalid;
1371 /* if the compressed bits are not set in the file attributes,
1372 * then read the information from the package word count property
1374 if (file->Attributes & msidbFileAttributesCompressed)
1376 file->IsCompressed = TRUE;
1378 else if (file->Attributes & msidbFileAttributesNoncompressed)
1380 file->IsCompressed = FALSE;
1384 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1387 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1389 list_add_tail( &package->files, &file->entry );
1391 return ERROR_SUCCESS;
1394 static UINT load_all_files(MSIPACKAGE *package)
1398 static const WCHAR Query[] =
1399 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1400 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1401 '`','S','e','q','u','e','n','c','e','`', 0};
1403 if (!list_empty(&package->files))
1404 return ERROR_SUCCESS;
1406 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1407 if (rc != ERROR_SUCCESS)
1408 return ERROR_SUCCESS;
1410 rc = MSI_IterateRecords(view, NULL, load_file, package);
1411 msiobj_release(&view->hdr);
1413 return ERROR_SUCCESS;
1418 * I am not doing any of the costing functionality yet.
1419 * Mostly looking at doing the Component and Feature loading
1421 * The native MSI does A LOT of modification to tables here. Mostly adding
1422 * a lot of temporary columns to the Feature and Component tables.
1424 * note: Native msi also tracks the short filename. But I am only going to
1425 * track the long ones. Also looking at this directory table
1426 * it appears that the directory table does not get the parents
1427 * resolved base on property only based on their entries in the
1430 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1432 static const WCHAR szCosting[] =
1433 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1434 static const WCHAR szZero[] = { '0', 0 };
1436 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1437 return ERROR_SUCCESS;
1439 MSI_SetPropertyW(package, szCosting, szZero);
1440 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1442 load_all_components( package );
1443 load_all_features( package );
1444 load_all_files( package );
1446 return ERROR_SUCCESS;
1449 static UINT execute_script(MSIPACKAGE *package, UINT script )
1452 UINT rc = ERROR_SUCCESS;
1454 TRACE("Executing Script %i\n",script);
1456 if (!package->script)
1458 ERR("no script!\n");
1459 return ERROR_FUNCTION_FAILED;
1462 for (i = 0; i < package->script->ActionCount[script]; i++)
1465 action = package->script->Actions[script][i];
1466 ui_actionstart(package, action);
1467 TRACE("Executing Action (%s)\n",debugstr_w(action));
1468 rc = ACTION_PerformAction(package, action, TRUE);
1469 msi_free(package->script->Actions[script][i]);
1470 if (rc != ERROR_SUCCESS)
1473 msi_free(package->script->Actions[script]);
1475 package->script->ActionCount[script] = 0;
1476 package->script->Actions[script] = NULL;
1480 static UINT ACTION_FileCost(MSIPACKAGE *package)
1482 return ERROR_SUCCESS;
1485 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1487 static const WCHAR Query[] =
1488 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1489 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1490 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1491 ' ','=',' ','\'','%','s','\'',
1493 static const WCHAR szDot[] = { '.',0 };
1494 static WCHAR szEmpty[] = { 0 };
1495 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1500 TRACE("Looking for dir %s\n",debugstr_w(dir));
1502 folder = get_loaded_folder( package, dir );
1506 TRACE("Working to load %s\n",debugstr_w(dir));
1508 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1512 folder->Directory = strdupW(dir);
1514 row = MSI_QueryGetRecord(package->db, Query, dir);
1518 p = msi_dup_record_field(row, 3);
1520 /* split src and target dir */
1522 src_short = folder_split_path( p, ':' );
1524 /* split the long and short paths */
1525 tgt_long = folder_split_path( tgt_short, '|' );
1526 src_long = folder_split_path( src_short, '|' );
1528 /* check for no-op dirs */
1529 if (!lstrcmpW(szDot, tgt_short))
1530 tgt_short = szEmpty;
1531 if (!lstrcmpW(szDot, src_short))
1532 src_short = szEmpty;
1535 tgt_long = tgt_short;
1538 src_short = tgt_short;
1539 src_long = tgt_long;
1543 src_long = src_short;
1545 /* FIXME: use the target short path too */
1546 folder->TargetDefault = strdupW(tgt_long);
1547 folder->SourceShortPath = strdupW(src_short);
1548 folder->SourceLongPath = strdupW(src_long);
1551 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1552 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1553 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1555 parent = MSI_RecordGetString(row, 2);
1558 folder->Parent = load_folder( package, parent );
1559 if ( folder->Parent )
1560 TRACE("loaded parent %p %s\n", folder->Parent,
1561 debugstr_w(folder->Parent->Directory));
1563 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1566 folder->Property = msi_dup_property( package, dir );
1568 msiobj_release(&row->hdr);
1570 list_add_tail( &package->folders, &folder->entry );
1572 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1577 /* scan for and update current install states */
1578 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1581 MSIFEATURE *feature;
1583 /* FIXME: component's installed state should be determined
1584 * by the component's registration
1586 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1590 if (!comp->ComponentId)
1593 res = MsiGetComponentPathW( package->ProductCode,
1594 comp->ComponentId, NULL, NULL);
1596 res = INSTALLSTATE_ABSENT;
1597 comp->Installed = res;
1600 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1603 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1605 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1607 comp= cl->component;
1609 if (!comp->ComponentId)
1611 res = INSTALLSTATE_ABSENT;
1615 if (res == INSTALLSTATE_ABSENT)
1616 res = comp->Installed;
1619 if (res == comp->Installed)
1622 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1623 res != INSTALLSTATE_SOURCE)
1625 res = INSTALLSTATE_INCOMPLETE;
1629 feature->Installed = res;
1633 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1636 static const WCHAR all[]={'A','L','L',0};
1638 MSIFEATURE *feature;
1640 override = msi_dup_property( package, property );
1644 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1646 if (strcmpiW(override,all)==0)
1648 feature->ActionRequest= state;
1649 feature->Action = state;
1653 LPWSTR ptr = override;
1654 LPWSTR ptr2 = strchrW(override,',');
1658 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1659 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1661 feature->ActionRequest= state;
1662 feature->Action = state;
1668 ptr2 = strchrW(ptr,',');
1680 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1683 static const WCHAR szlevel[] =
1684 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1685 static const WCHAR szAddLocal[] =
1686 {'A','D','D','L','O','C','A','L',0};
1687 static const WCHAR szRemove[] =
1688 {'R','E','M','O','V','E',0};
1689 static const WCHAR szReinstall[] =
1690 {'R','E','I','N','S','T','A','L','L',0};
1691 BOOL override = FALSE;
1692 MSICOMPONENT* component;
1693 MSIFEATURE *feature;
1696 /* I do not know if this is where it should happen.. but */
1698 TRACE("Checking Install Level\n");
1700 install_level = msi_get_property_int( package, szlevel, 1 );
1702 /* ok here is the _real_ rub
1703 * all these activation/deactivation things happen in order and things
1704 * later on the list override things earlier on the list.
1705 * 1) INSTALLLEVEL processing
1715 * 11) FILEADDDEFAULT
1716 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1717 * ignored for all the features. seems strange, especially since it is not
1718 * documented anywhere, but it is how it works.
1720 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1721 * REMOVE are the big ones, since we don't handle administrative installs
1724 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1725 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1726 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1730 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1732 BOOL feature_state = ((feature->Level > 0) &&
1733 (feature->Level <= install_level));
1735 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1737 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1739 feature->ActionRequest = INSTALLSTATE_SOURCE;
1740 feature->Action = INSTALLSTATE_SOURCE;
1742 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1744 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1745 feature->Action = INSTALLSTATE_ADVERTISED;
1749 feature->ActionRequest = INSTALLSTATE_LOCAL;
1750 feature->Action = INSTALLSTATE_LOCAL;
1755 /* disable child features of unselected parent features */
1756 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1760 if (feature->Level > 0 && feature->Level <= install_level)
1763 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1765 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1766 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1772 /* set the Preselected Property */
1773 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1774 static const WCHAR szOne[] = { '1', 0 };
1776 MSI_SetPropertyW(package,szPreselected,szOne);
1780 * now we want to enable or disable components base on feature
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1787 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1788 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1789 feature->ActionRequest);
1791 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1793 component = cl->component;
1795 switch (component->Attributes)
1797 case msidbComponentAttributesLocalOnly:
1798 component->Action = INSTALLSTATE_LOCAL;
1799 component->ActionRequest = INSTALLSTATE_LOCAL;
1801 case msidbComponentAttributesSourceOnly:
1802 component->Action = INSTALLSTATE_SOURCE;
1803 component->ActionRequest = INSTALLSTATE_SOURCE;
1805 case msidbComponentAttributesOptional:
1806 component->Action = INSTALLSTATE_DEFAULT;
1807 component->ActionRequest = INSTALLSTATE_DEFAULT;
1810 component->Action = INSTALLSTATE_LOCAL;
1811 component->ActionRequest = INSTALLSTATE_LOCAL;
1814 if (component->ForceLocalState)
1816 component->Action = INSTALLSTATE_LOCAL;
1817 component->ActionRequest = INSTALLSTATE_LOCAL;
1820 if (!component->Enabled)
1822 component->Action = INSTALLSTATE_UNKNOWN;
1823 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1827 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1829 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1831 component->Action = INSTALLSTATE_LOCAL;
1832 component->ActionRequest = INSTALLSTATE_LOCAL;
1835 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1837 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1838 (component->Action == INSTALLSTATE_ABSENT) ||
1839 (component->Action == INSTALLSTATE_ADVERTISED) ||
1840 (component->Action == INSTALLSTATE_DEFAULT))
1843 component->Action = INSTALLSTATE_SOURCE;
1844 component->ActionRequest = INSTALLSTATE_SOURCE;
1847 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1849 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1850 (component->Action == INSTALLSTATE_ABSENT))
1853 component->Action = INSTALLSTATE_ADVERTISED;
1854 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1857 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1859 if (component->Action == INSTALLSTATE_UNKNOWN)
1861 component->Action = INSTALLSTATE_ABSENT;
1862 component->ActionRequest = INSTALLSTATE_ABSENT;
1865 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1867 component->Action = INSTALLSTATE_UNKNOWN;
1868 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1872 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1874 feature->Action = INSTALLSTATE_LOCAL;
1875 feature->ActionRequest = INSTALLSTATE_LOCAL;
1880 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1882 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1883 debugstr_w(component->Component), component->Installed,
1884 component->Action, component->ActionRequest);
1888 return ERROR_SUCCESS;
1891 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1893 MSIPACKAGE *package = (MSIPACKAGE*)param;
1897 name = MSI_RecordGetString(row,1);
1899 /* This helper function now does ALL the work */
1900 TRACE("Dir %s ...\n",debugstr_w(name));
1901 load_folder(package,name);
1902 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1903 TRACE("resolves to %s\n",debugstr_w(path));
1906 return ERROR_SUCCESS;
1909 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1911 MSIPACKAGE *package = (MSIPACKAGE*)param;
1913 MSIFEATURE *feature;
1915 name = MSI_RecordGetString( row, 1 );
1917 feature = get_loaded_feature( package, name );
1919 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1923 Condition = MSI_RecordGetString(row,3);
1925 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1927 int level = MSI_RecordGetInteger(row,2);
1928 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1929 feature->Level = level;
1932 return ERROR_SUCCESS;
1936 * A lot is done in this function aside from just the costing.
1937 * The costing needs to be implemented at some point but for now I am going
1938 * to focus on the directory building
1941 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1943 static const WCHAR ExecSeqQuery[] =
1944 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1945 '`','D','i','r','e','c','t','o','r','y','`',0};
1946 static const WCHAR ConditionQuery[] =
1947 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1948 '`','C','o','n','d','i','t','i','o','n','`',0};
1949 static const WCHAR szCosting[] =
1950 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1951 static const WCHAR szlevel[] =
1952 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1953 static const WCHAR szOne[] = { '1', 0 };
1960 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1961 return ERROR_SUCCESS;
1963 TRACE("Building Directory properties\n");
1965 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1966 if (rc == ERROR_SUCCESS)
1968 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1970 msiobj_release(&view->hdr);
1973 TRACE("File calculations\n");
1975 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1977 MSICOMPONENT* comp = file->Component;
1983 if (file->IsCompressed)
1984 comp->ForceLocalState = TRUE;
1986 /* calculate target */
1987 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1989 msi_free(file->TargetPath);
1991 TRACE("file %s is named %s\n",
1992 debugstr_w(file->File),debugstr_w(file->FileName));
1994 file->TargetPath = build_directory_name(2, p, file->FileName);
1998 TRACE("file %s resolves to %s\n",
1999 debugstr_w(file->File),debugstr_w(file->TargetPath));
2001 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2003 file->state = msifs_missing;
2004 comp->Cost += file->FileSize;
2014 static WCHAR name[] = {'\\',0};
2015 static const WCHAR name_fmt[] =
2016 {'%','u','.','%','u','.','%','u','.','%','u',0};
2017 WCHAR filever[0x100];
2018 VS_FIXEDFILEINFO *lpVer;
2020 TRACE("Version comparison..\n");
2021 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2022 version = msi_alloc(versize);
2023 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2025 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2027 sprintfW(filever,name_fmt,
2028 HIWORD(lpVer->dwFileVersionMS),
2029 LOWORD(lpVer->dwFileVersionMS),
2030 HIWORD(lpVer->dwFileVersionLS),
2031 LOWORD(lpVer->dwFileVersionLS));
2033 TRACE("new %s old %s\n", debugstr_w(file->Version),
2034 debugstr_w(filever));
2035 if (strcmpiW(filever,file->Version)<0)
2037 file->state = msifs_overwrite;
2038 /* FIXME: cost should be diff in size */
2039 comp->Cost += file->FileSize;
2042 file->state = msifs_present;
2046 file->state = msifs_present;
2049 TRACE("Evaluating Condition Table\n");
2051 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2052 if (rc == ERROR_SUCCESS)
2054 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2056 msiobj_release(&view->hdr);
2059 TRACE("Enabling or Disabling Components\n");
2060 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2062 if (comp->Condition)
2064 if (MSI_EvaluateConditionW(package,
2065 comp->Condition) == MSICONDITION_FALSE)
2067 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2068 comp->Enabled = FALSE;
2073 MSI_SetPropertyW(package,szCosting,szOne);
2074 /* set default run level if not set */
2075 level = msi_dup_property( package, szlevel );
2077 MSI_SetPropertyW(package,szlevel, szOne);
2080 ACTION_UpdateInstallStates(package);
2082 return MSI_SetFeatureStates(package);
2085 /* OK this value is "interpreted" and then formatted based on the
2086 first few characters */
2087 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2091 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2097 LPWSTR deformated = NULL;
2100 deformat_string(package, &value[2], &deformated);
2102 /* binary value type */
2106 *size = (strlenW(ptr)/2)+1;
2108 *size = strlenW(ptr)/2;
2110 data = msi_alloc(*size);
2116 /* if uneven pad with a zero in front */
2122 data[count] = (BYTE)strtol(byte,NULL,0);
2124 TRACE("Uneven byte count\n");
2132 data[count] = (BYTE)strtol(byte,NULL,0);
2135 msi_free(deformated);
2137 TRACE("Data %i bytes(%i)\n",*size,count);
2144 deformat_string(package, &value[1], &deformated);
2147 *size = sizeof(DWORD);
2148 data = msi_alloc(*size);
2154 if ( (*p < '0') || (*p > '9') )
2160 if (deformated[0] == '-')
2163 TRACE("DWORD %i\n",*(LPDWORD)data);
2165 msi_free(deformated);
2170 static const WCHAR szMulti[] = {'[','~',']',0};
2179 *type=REG_EXPAND_SZ;
2187 if (strstrW(value,szMulti))
2188 *type = REG_MULTI_SZ;
2190 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2195 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2197 MSIPACKAGE *package = (MSIPACKAGE*)param;
2198 static const WCHAR szHCR[] =
2199 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2200 'R','O','O','T','\\',0};
2201 static const WCHAR szHCU[] =
2202 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2203 'U','S','E','R','\\',0};
2204 static const WCHAR szHLM[] =
2205 {'H','K','E','Y','_','L','O','C','A','L','_',
2206 'M','A','C','H','I','N','E','\\',0};
2207 static const WCHAR szHU[] =
2208 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2210 LPSTR value_data = NULL;
2211 HKEY root_key, hkey;
2214 LPCWSTR szRoot, component, name, key, value;
2219 BOOL check_first = FALSE;
2222 ui_progress(package,2,0,0,0);
2229 component = MSI_RecordGetString(row, 6);
2230 comp = get_loaded_component(package,component);
2232 return ERROR_SUCCESS;
2234 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2236 TRACE("Skipping write due to disabled component %s\n",
2237 debugstr_w(component));
2239 comp->Action = comp->Installed;
2241 return ERROR_SUCCESS;
2244 comp->Action = INSTALLSTATE_LOCAL;
2246 name = MSI_RecordGetString(row, 4);
2247 if( MSI_RecordIsNull(row,5) && name )
2249 /* null values can have special meanings */
2250 if (name[0]=='-' && name[1] == 0)
2251 return ERROR_SUCCESS;
2252 else if ((name[0]=='+' && name[1] == 0) ||
2253 (name[0] == '*' && name[1] == 0))
2258 root = MSI_RecordGetInteger(row,2);
2259 key = MSI_RecordGetString(row, 3);
2261 /* get the root key */
2266 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2267 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2268 if (all_users && all_users[0] == '1')
2270 root_key = HKEY_LOCAL_MACHINE;
2275 root_key = HKEY_CURRENT_USER;
2278 msi_free(all_users);
2281 case 0: root_key = HKEY_CLASSES_ROOT;
2284 case 1: root_key = HKEY_CURRENT_USER;
2287 case 2: root_key = HKEY_LOCAL_MACHINE;
2290 case 3: root_key = HKEY_USERS;
2294 ERR("Unknown root %i\n",root);
2300 return ERROR_SUCCESS;
2302 deformat_string(package, key , &deformated);
2303 size = strlenW(deformated) + strlenW(szRoot) + 1;
2304 uikey = msi_alloc(size*sizeof(WCHAR));
2305 strcpyW(uikey,szRoot);
2306 strcatW(uikey,deformated);
2308 if (RegCreateKeyW( root_key, deformated, &hkey))
2310 ERR("Could not create key %s\n",debugstr_w(deformated));
2311 msi_free(deformated);
2313 return ERROR_SUCCESS;
2315 msi_free(deformated);
2317 value = MSI_RecordGetString(row,5);
2319 value_data = parse_value(package, value, &type, &size);
2322 static const WCHAR szEmpty[] = {0};
2323 value_data = (LPSTR)strdupW(szEmpty);
2328 deformat_string(package, name, &deformated);
2330 /* get the double nulls to terminate SZ_MULTI */
2331 if (type == REG_MULTI_SZ)
2332 size +=sizeof(WCHAR);
2336 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2338 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2343 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2344 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2346 TRACE("value %s of %s checked already exists\n",
2347 debugstr_w(deformated), debugstr_w(uikey));
2351 TRACE("Checked and setting value %s of %s\n",
2352 debugstr_w(deformated), debugstr_w(uikey));
2353 if (deformated || size)
2354 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2359 uirow = MSI_CreateRecord(3);
2360 MSI_RecordSetStringW(uirow,2,deformated);
2361 MSI_RecordSetStringW(uirow,1,uikey);
2364 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2366 MSI_RecordSetStringW(uirow,3,value);
2368 ui_actiondata(package,szWriteRegistryValues,uirow);
2369 msiobj_release( &uirow->hdr );
2371 msi_free(value_data);
2372 msi_free(deformated);
2375 return ERROR_SUCCESS;
2378 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2382 static const WCHAR ExecSeqQuery[] =
2383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2384 '`','R','e','g','i','s','t','r','y','`',0 };
2386 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2387 if (rc != ERROR_SUCCESS)
2388 return ERROR_SUCCESS;
2390 /* increment progress bar each time action data is sent */
2391 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2393 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2395 msiobj_release(&view->hdr);
2399 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2401 package->script->CurrentlyScripting = TRUE;
2403 return ERROR_SUCCESS;
2407 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2412 static const WCHAR q1[]=
2413 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2414 '`','R','e','g','i','s','t','r','y','`',0};
2417 MSIFEATURE *feature;
2420 TRACE("InstallValidate\n");
2422 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2423 if (rc == ERROR_SUCCESS)
2425 MSI_IterateRecords( view, &progress, NULL, package );
2426 msiobj_release( &view->hdr );
2427 total += progress * REG_PROGRESS_VALUE;
2430 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2431 total += COMPONENT_PROGRESS_VALUE;
2433 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2434 total += file->FileSize;
2436 ui_progress(package,0,total,0,0);
2438 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2440 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2441 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2442 feature->ActionRequest);
2445 return ERROR_SUCCESS;
2448 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2450 MSIPACKAGE* package = (MSIPACKAGE*)param;
2451 LPCWSTR cond = NULL;
2452 LPCWSTR message = NULL;
2453 static const WCHAR title[]=
2454 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2456 cond = MSI_RecordGetString(row,1);
2458 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2461 message = MSI_RecordGetString(row,2);
2462 deformat_string(package,message,&deformated);
2463 MessageBoxW(NULL,deformated,title,MB_OK);
2464 msi_free(deformated);
2465 return ERROR_FUNCTION_FAILED;
2468 return ERROR_SUCCESS;
2471 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2474 MSIQUERY * view = NULL;
2475 static const WCHAR ExecSeqQuery[] =
2476 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2477 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2479 TRACE("Checking launch conditions\n");
2481 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2482 if (rc != ERROR_SUCCESS)
2483 return ERROR_SUCCESS;
2485 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2486 msiobj_release(&view->hdr);
2491 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2495 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2497 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2499 MSIRECORD * row = 0;
2501 LPWSTR deformated,buffer,deformated_name;
2503 static const WCHAR ExecSeqQuery[] =
2504 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2505 '`','R','e','g','i','s','t','r','y','`',' ',
2506 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2507 ' ','=',' ' ,'\'','%','s','\'',0 };
2508 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2509 static const WCHAR fmt2[]=
2510 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2512 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2516 root = MSI_RecordGetInteger(row,2);
2517 key = MSI_RecordGetString(row, 3);
2518 name = MSI_RecordGetString(row, 4);
2519 deformat_string(package, key , &deformated);
2520 deformat_string(package, name, &deformated_name);
2522 len = strlenW(deformated) + 6;
2523 if (deformated_name)
2524 len+=strlenW(deformated_name);
2526 buffer = msi_alloc( len *sizeof(WCHAR));
2528 if (deformated_name)
2529 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2531 sprintfW(buffer,fmt,root,deformated);
2533 msi_free(deformated);
2534 msi_free(deformated_name);
2535 msiobj_release(&row->hdr);
2539 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2541 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2546 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2549 return strdupW( file->TargetPath );
2554 static HKEY openSharedDLLsKey(void)
2557 static const WCHAR path[] =
2558 {'S','o','f','t','w','a','r','e','\\',
2559 'M','i','c','r','o','s','o','f','t','\\',
2560 'W','i','n','d','o','w','s','\\',
2561 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2562 'S','h','a','r','e','d','D','L','L','s',0};
2564 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2568 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2573 DWORD sz = sizeof(count);
2576 hkey = openSharedDLLsKey();
2577 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2578 if (rc != ERROR_SUCCESS)
2584 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2588 hkey = openSharedDLLsKey();
2590 msi_reg_set_val_dword( hkey, path, count );
2592 RegDeleteValueW(hkey,path);
2598 * Return TRUE if the count should be written out and FALSE if not
2600 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2602 MSIFEATURE *feature;
2606 /* only refcount DLLs */
2607 if (comp->KeyPath == NULL ||
2608 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2609 comp->Attributes & msidbComponentAttributesODBCDataSource)
2613 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2614 write = (count > 0);
2616 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2620 /* increment counts */
2621 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2625 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2628 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2630 if ( cl->component == comp )
2635 /* decrement counts */
2636 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2640 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2643 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2645 if ( cl->component == comp )
2650 /* ref count all the files in the component */
2655 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2657 if (file->Component == comp)
2658 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2662 /* add a count for permenent */
2663 if (comp->Attributes & msidbComponentAttributesPermanent)
2666 comp->RefCount = count;
2669 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2673 * Ok further analysis makes me think that this work is
2674 * actually done in the PublishComponents and PublishFeatures
2675 * step, and not here. It appears like the keypath and all that is
2676 * resolved in this step, however actually written in the Publish steps.
2677 * But we will leave it here for now because it is unclear
2679 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2681 WCHAR squished_pc[GUID_SIZE];
2682 WCHAR squished_cc[GUID_SIZE];
2685 HKEY hkey=0,hkey2=0;
2687 /* writes the Component and Features values to the registry */
2689 rc = MSIREG_OpenComponents(&hkey);
2690 if (rc != ERROR_SUCCESS)
2693 squash_guid(package->ProductCode,squished_pc);
2694 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2696 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2700 ui_progress(package,2,0,0,0);
2701 if (!comp->ComponentId)
2704 squash_guid(comp->ComponentId,squished_cc);
2706 msi_free(comp->FullKeypath);
2707 comp->FullKeypath = resolve_keypath( package, comp );
2709 /* do the refcounting */
2710 ACTION_RefCountComponent( package, comp );
2712 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2713 debugstr_w(comp->Component),
2714 debugstr_w(squished_cc),
2715 debugstr_w(comp->FullKeypath),
2718 * Write the keypath out if the component is to be registered
2719 * and delete the key if the component is to be deregistered
2721 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2723 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2724 if (rc != ERROR_SUCCESS)
2727 if (!comp->FullKeypath)
2730 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2732 if (comp->Attributes & msidbComponentAttributesPermanent)
2734 static const WCHAR szPermKey[] =
2735 { '0','0','0','0','0','0','0','0','0','0','0','0',
2736 '0','0','0','0','0','0','0','0','0','0','0','0',
2737 '0','0','0','0','0','0','0','0',0 };
2739 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2745 uirow = MSI_CreateRecord(3);
2746 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2747 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2748 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2749 ui_actiondata(package,szProcessComponents,uirow);
2750 msiobj_release( &uirow->hdr );
2752 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2756 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2757 if (rc != ERROR_SUCCESS)
2760 RegDeleteValueW(hkey2,squished_pc);
2762 /* if the key is empty delete it */
2763 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2765 if (res == ERROR_NO_MORE_ITEMS)
2766 RegDeleteKeyW(hkey,squished_cc);
2769 uirow = MSI_CreateRecord(2);
2770 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2771 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2772 ui_actiondata(package,szProcessComponents,uirow);
2773 msiobj_release( &uirow->hdr );
2788 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2789 LPWSTR lpszName, LONG_PTR lParam)
2792 typelib_struct *tl_struct = (typelib_struct*) lParam;
2793 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2797 if (!IS_INTRESOURCE(lpszName))
2799 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2803 sz = strlenW(tl_struct->source)+4;
2804 sz *= sizeof(WCHAR);
2806 if ((INT_PTR)lpszName == 1)
2807 tl_struct->path = strdupW(tl_struct->source);
2810 tl_struct->path = msi_alloc(sz);
2811 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2814 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2815 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2816 if (!SUCCEEDED(res))
2818 msi_free(tl_struct->path);
2819 tl_struct->path = NULL;
2824 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2825 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2827 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2831 msi_free(tl_struct->path);
2832 tl_struct->path = NULL;
2834 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2835 ITypeLib_Release(tl_struct->ptLib);
2840 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2842 MSIPACKAGE* package = (MSIPACKAGE*)param;
2846 typelib_struct tl_struct;
2848 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2850 component = MSI_RecordGetString(row,3);
2851 comp = get_loaded_component(package,component);
2853 return ERROR_SUCCESS;
2855 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2857 TRACE("Skipping typelib reg due to disabled component\n");
2859 comp->Action = comp->Installed;
2861 return ERROR_SUCCESS;
2864 comp->Action = INSTALLSTATE_LOCAL;
2866 file = get_loaded_file( package, comp->KeyPath );
2868 return ERROR_SUCCESS;
2870 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2874 guid = MSI_RecordGetString(row,1);
2875 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2876 tl_struct.source = strdupW( file->TargetPath );
2877 tl_struct.path = NULL;
2879 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2880 (LONG_PTR)&tl_struct);
2888 helpid = MSI_RecordGetString(row,6);
2891 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2892 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2895 if (!SUCCEEDED(res))
2896 ERR("Failed to register type library %s\n",
2897 debugstr_w(tl_struct.path));
2900 ui_actiondata(package,szRegisterTypeLibraries,row);
2902 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2905 ITypeLib_Release(tl_struct.ptLib);
2906 msi_free(tl_struct.path);
2909 ERR("Failed to load type library %s\n",
2910 debugstr_w(tl_struct.source));
2912 FreeLibrary(module);
2913 msi_free(tl_struct.source);
2916 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2918 return ERROR_SUCCESS;
2921 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2924 * OK this is a bit confusing.. I am given a _Component key and I believe
2925 * that the file that is being registered as a type library is the "key file
2926 * of that component" which I interpret to mean "The file in the KeyPath of
2931 static const WCHAR Query[] =
2932 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2933 '`','T','y','p','e','L','i','b','`',0};
2935 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2936 if (rc != ERROR_SUCCESS)
2937 return ERROR_SUCCESS;
2939 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2940 msiobj_release(&view->hdr);
2944 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2946 MSIPACKAGE *package = (MSIPACKAGE*)param;
2947 LPWSTR target_file, target_folder, filename;
2948 LPCWSTR buffer, extension;
2950 static const WCHAR szlnk[]={'.','l','n','k',0};
2951 IShellLinkW *sl = NULL;
2952 IPersistFile *pf = NULL;
2955 buffer = MSI_RecordGetString(row,4);
2956 comp = get_loaded_component(package,buffer);
2958 return ERROR_SUCCESS;
2960 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2962 TRACE("Skipping shortcut creation due to disabled component\n");
2964 comp->Action = comp->Installed;
2966 return ERROR_SUCCESS;
2969 comp->Action = INSTALLSTATE_LOCAL;
2971 ui_actiondata(package,szCreateShortcuts,row);
2973 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2974 &IID_IShellLinkW, (LPVOID *) &sl );
2978 ERR("CLSID_ShellLink not available\n");
2982 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2985 ERR("QueryInterface(IID_IPersistFile) failed\n");
2989 buffer = MSI_RecordGetString(row,2);
2990 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2992 /* may be needed because of a bug somehwere else */
2993 create_full_pathW(target_folder);
2995 filename = msi_dup_record_field( row, 3 );
2996 reduce_to_longfilename(filename);
2998 extension = strchrW(filename,'.');
2999 if (!extension || strcmpiW(extension,szlnk))
3001 int len = strlenW(filename);
3002 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3003 memcpy(filename + len, szlnk, sizeof(szlnk));
3005 target_file = build_directory_name(2, target_folder, filename);
3006 msi_free(target_folder);
3009 buffer = MSI_RecordGetString(row,5);
3010 if (strchrW(buffer,'['))
3013 deformat_string(package,buffer,&deformated);
3014 IShellLinkW_SetPath(sl,deformated);
3015 msi_free(deformated);
3019 FIXME("poorly handled shortcut format, advertised shortcut\n");
3020 IShellLinkW_SetPath(sl,comp->FullKeypath);
3023 if (!MSI_RecordIsNull(row,6))
3026 buffer = MSI_RecordGetString(row,6);
3027 deformat_string(package,buffer,&deformated);
3028 IShellLinkW_SetArguments(sl,deformated);
3029 msi_free(deformated);
3032 if (!MSI_RecordIsNull(row,7))
3034 buffer = MSI_RecordGetString(row,7);
3035 IShellLinkW_SetDescription(sl,buffer);
3038 if (!MSI_RecordIsNull(row,8))
3039 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3041 if (!MSI_RecordIsNull(row,9))
3046 buffer = MSI_RecordGetString(row,9);
3048 Path = build_icon_path(package,buffer);
3049 index = MSI_RecordGetInteger(row,10);
3051 /* no value means 0 */
3052 if (index == MSI_NULL_INTEGER)
3055 IShellLinkW_SetIconLocation(sl,Path,index);
3059 if (!MSI_RecordIsNull(row,11))
3060 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3062 if (!MSI_RecordIsNull(row,12))
3065 buffer = MSI_RecordGetString(row,12);
3066 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3068 IShellLinkW_SetWorkingDirectory(sl,Path);
3072 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3073 IPersistFile_Save(pf,target_file,FALSE);
3075 msi_free(target_file);
3079 IPersistFile_Release( pf );
3081 IShellLinkW_Release( sl );
3083 return ERROR_SUCCESS;
3086 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3091 static const WCHAR Query[] =
3092 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3093 '`','S','h','o','r','t','c','u','t','`',0};
3095 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3096 if (rc != ERROR_SUCCESS)
3097 return ERROR_SUCCESS;
3099 res = CoInitialize( NULL );
3102 ERR("CoInitialize failed\n");
3103 return ERROR_FUNCTION_FAILED;
3106 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3107 msiobj_release(&view->hdr);
3114 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3116 MSIPACKAGE* package = (MSIPACKAGE*)param;
3125 FileName = MSI_RecordGetString(row,1);
3128 ERR("Unable to get FileName\n");
3129 return ERROR_SUCCESS;
3132 FilePath = build_icon_path(package,FileName);
3134 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3136 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3137 FILE_ATTRIBUTE_NORMAL, NULL);
3139 if (the_file == INVALID_HANDLE_VALUE)
3141 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3143 return ERROR_SUCCESS;
3150 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3151 if (rc != ERROR_SUCCESS)
3153 ERR("Failed to get stream\n");
3154 CloseHandle(the_file);
3155 DeleteFileW(FilePath);
3158 WriteFile(the_file,buffer,sz,&write,NULL);
3159 } while (sz == 1024);
3163 CloseHandle(the_file);
3165 uirow = MSI_CreateRecord(1);
3166 MSI_RecordSetStringW(uirow,1,FileName);
3167 ui_actiondata(package,szPublishProduct,uirow);
3168 msiobj_release( &uirow->hdr );
3170 return ERROR_SUCCESS;
3174 * 99% of the work done here is only done for
3175 * advertised installs. However this is where the
3176 * Icon table is processed and written out
3177 * so that is what I am going to do here.
3179 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3183 static const WCHAR Query[]=
3184 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3185 '`','I','c','o','n','`',0};
3186 /* for registry stuff */
3189 static const WCHAR szProductLanguage[] =
3190 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3191 static const WCHAR szARPProductIcon[] =
3192 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3193 static const WCHAR szProductVersion[] =
3194 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3198 MSIHANDLE hDb, hSumInfo;
3200 /* write out icon files */
3202 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3203 if (rc == ERROR_SUCCESS)
3205 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3206 msiobj_release(&view->hdr);
3209 /* ok there is a lot more done here but i need to figure out what */
3211 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3212 if (rc != ERROR_SUCCESS)
3215 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3216 if (rc != ERROR_SUCCESS)
3220 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3221 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3224 langid = msi_get_property_int( package, szProductLanguage, 0 );
3225 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3227 buffer = msi_dup_property( package, szARPProductIcon );
3230 LPWSTR path = build_icon_path(package,buffer);
3231 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3236 buffer = msi_dup_property( package, szProductVersion );
3239 DWORD verdword = msi_version_str_to_dword(buffer);
3240 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3244 /* FIXME: Need to write more keys to the user registry */
3246 hDb= alloc_msihandle( &package->db->hdr );
3248 rc = ERROR_NOT_ENOUGH_MEMORY;
3251 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3252 MsiCloseHandle(hDb);
3253 if (rc == ERROR_SUCCESS)
3255 WCHAR guidbuffer[0x200];
3257 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3259 if (rc == ERROR_SUCCESS)
3261 WCHAR squashed[GUID_SIZE];
3262 /* for now we only care about the first guid */
3263 LPWSTR ptr = strchrW(guidbuffer,';');
3265 squash_guid(guidbuffer,squashed);
3266 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3270 ERR("Unable to query Revision_Number...\n");
3273 MsiCloseHandle(hSumInfo);
3277 ERR("Unable to open Summary Information\n");
3289 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3291 MSIPACKAGE *package = (MSIPACKAGE*)param;
3292 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3293 LPWSTR deformated_section, deformated_key, deformated_value;
3294 LPWSTR folder, fullname = NULL;
3298 static const WCHAR szWindowsFolder[] =
3299 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3301 component = MSI_RecordGetString(row, 8);
3302 comp = get_loaded_component(package,component);
3304 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3306 TRACE("Skipping ini file due to disabled component %s\n",
3307 debugstr_w(component));
3309 comp->Action = comp->Installed;
3311 return ERROR_SUCCESS;
3314 comp->Action = INSTALLSTATE_LOCAL;
3316 identifier = MSI_RecordGetString(row,1);
3317 filename = MSI_RecordGetString(row,2);
3318 dirproperty = MSI_RecordGetString(row,3);
3319 section = MSI_RecordGetString(row,4);
3320 key = MSI_RecordGetString(row,5);
3321 value = MSI_RecordGetString(row,6);
3322 action = MSI_RecordGetInteger(row,7);
3324 deformat_string(package,section,&deformated_section);
3325 deformat_string(package,key,&deformated_key);
3326 deformat_string(package,value,&deformated_value);
3330 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3332 folder = msi_dup_property( package, dirproperty );
3335 folder = msi_dup_property( package, szWindowsFolder );
3339 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3343 fullname = build_directory_name(2, folder, filename);
3347 TRACE("Adding value %s to section %s in %s\n",
3348 debugstr_w(deformated_key), debugstr_w(deformated_section),
3349 debugstr_w(fullname));
3350 WritePrivateProfileStringW(deformated_section, deformated_key,
3351 deformated_value, fullname);
3353 else if (action == 1)
3356 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3357 returned, 10, fullname);
3358 if (returned[0] == 0)
3360 TRACE("Adding value %s to section %s in %s\n",
3361 debugstr_w(deformated_key), debugstr_w(deformated_section),
3362 debugstr_w(fullname));
3364 WritePrivateProfileStringW(deformated_section, deformated_key,
3365 deformated_value, fullname);
3368 else if (action == 3)
3369 FIXME("Append to existing section not yet implemented\n");
3371 uirow = MSI_CreateRecord(4);
3372 MSI_RecordSetStringW(uirow,1,identifier);
3373 MSI_RecordSetStringW(uirow,2,deformated_section);
3374 MSI_RecordSetStringW(uirow,3,deformated_key);
3375 MSI_RecordSetStringW(uirow,4,deformated_value);
3376 ui_actiondata(package,szWriteIniValues,uirow);
3377 msiobj_release( &uirow->hdr );
3381 msi_free(deformated_key);
3382 msi_free(deformated_value);
3383 msi_free(deformated_section);
3384 return ERROR_SUCCESS;
3387 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3391 static const WCHAR ExecSeqQuery[] =
3392 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3393 '`','I','n','i','F','i','l','e','`',0};
3395 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3396 if (rc != ERROR_SUCCESS)
3398 TRACE("no IniFile table\n");
3399 return ERROR_SUCCESS;
3402 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3403 msiobj_release(&view->hdr);
3407 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3409 MSIPACKAGE *package = (MSIPACKAGE*)param;
3414 static const WCHAR ExeStr[] =
3415 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3416 static const WCHAR close[] = {'\"',0};
3418 PROCESS_INFORMATION info;
3423 memset(&si,0,sizeof(STARTUPINFOW));
3425 filename = MSI_RecordGetString(row,1);
3426 file = get_loaded_file( package, filename );
3430 ERR("Unable to find file id %s\n",debugstr_w(filename));
3431 return ERROR_SUCCESS;
3434 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3436 FullName = msi_alloc(len*sizeof(WCHAR));
3437 strcpyW(FullName,ExeStr);
3438 strcatW( FullName, file->TargetPath );
3439 strcatW(FullName,close);
3441 TRACE("Registering %s\n",debugstr_w(FullName));
3442 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3446 msi_dialog_check_messages(info.hProcess);
3451 uirow = MSI_CreateRecord( 2 );
3452 uipath = strdupW( file->TargetPath );
3453 p = strrchrW(uipath,'\\');
3456 MSI_RecordSetStringW( uirow, 1, &p[2] );
3457 MSI_RecordSetStringW( uirow, 2, uipath);
3458 ui_actiondata( package, szSelfRegModules, uirow);
3459 msiobj_release( &uirow->hdr );
3461 /* FIXME: call ui_progress? */
3463 return ERROR_SUCCESS;
3466 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3470 static const WCHAR ExecSeqQuery[] =
3471 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3472 '`','S','e','l','f','R','e','g','`',0};
3474 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3475 if (rc != ERROR_SUCCESS)
3477 TRACE("no SelfReg table\n");
3478 return ERROR_SUCCESS;
3481 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3482 msiobj_release(&view->hdr);
3484 return ERROR_SUCCESS;
3487 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3489 MSIFEATURE *feature;
3494 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3495 if (rc != ERROR_SUCCESS)
3498 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3499 if (rc != ERROR_SUCCESS)
3502 /* here the guids are base 85 encoded */
3503 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3509 BOOL absent = FALSE;
3512 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3513 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3514 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3518 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3522 if (feature->Feature_Parent)
3523 size += strlenW( feature->Feature_Parent )+2;
3525 data = msi_alloc(size * sizeof(WCHAR));
3528 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3530 MSICOMPONENT* component = cl->component;
3534 if (component->ComponentId)
3536 TRACE("From %s\n",debugstr_w(component->ComponentId));
3537 CLSIDFromString(component->ComponentId, &clsid);
3538 encode_base85_guid(&clsid,buf);
3539 TRACE("to %s\n",debugstr_w(buf));
3543 if (feature->Feature_Parent)
3545 static const WCHAR sep[] = {'\2',0};
3547 strcatW(data,feature->Feature_Parent);
3550 msi_reg_set_val_str( hkey, feature->Feature, data );
3554 if (feature->Feature_Parent)
3555 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3558 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3559 (LPBYTE)feature->Feature_Parent,size);
3563 size += 2*sizeof(WCHAR);
3564 data = msi_alloc(size);
3567 if (feature->Feature_Parent)
3568 strcpyW( &data[1], feature->Feature_Parent );
3569 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3575 uirow = MSI_CreateRecord( 1 );
3576 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3577 ui_actiondata( package, szPublishFeatures, uirow);
3578 msiobj_release( &uirow->hdr );
3579 /* FIXME: call ui_progress? */
3588 static UINT msi_get_local_package_name( LPWSTR path )
3590 static const WCHAR szInstaller[] = {
3591 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3592 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3596 time = GetTickCount();
3597 GetWindowsDirectoryW( path, MAX_PATH );
3598 lstrcatW( path, szInstaller );
3599 CreateDirectoryW( path, NULL );
3601 len = lstrlenW(path);
3602 for (i=0; i<0x10000; i++)
3604 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3605 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3606 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3607 if (handle != INVALID_HANDLE_VALUE)
3609 CloseHandle(handle);
3612 if (GetLastError() != ERROR_FILE_EXISTS &&
3613 GetLastError() != ERROR_SHARING_VIOLATION)
3614 return ERROR_FUNCTION_FAILED;
3617 return ERROR_SUCCESS;
3620 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3622 static const WCHAR szOriginalDatabase[] =
3623 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3624 WCHAR packagefile[MAX_PATH];
3628 r = msi_get_local_package_name( packagefile );
3629 if (r != ERROR_SUCCESS)
3632 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3634 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3635 r = CopyFileW( msiFilePath, packagefile, FALSE);
3636 msi_free( msiFilePath );
3640 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3641 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3642 return ERROR_FUNCTION_FAILED;
3645 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3646 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3647 return ERROR_SUCCESS;
3650 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3652 LPWSTR prop, val, key;
3653 static const LPCSTR propval[] = {
3654 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3655 "ARPCONTACT", "Contact",
3656 "ARPCOMMENTS", "Comments",
3657 "ProductName", "DisplayName",
3658 "ProductVersion", "DisplayVersion",
3659 "ARPHELPLINK", "HelpLink",
3660 "ARPHELPTELEPHONE", "HelpTelephone",
3661 "ARPINSTALLLOCATION", "InstallLocation",
3662 "SourceDir", "InstallSource",
3663 "Manufacturer", "Publisher",
3664 "ARPREADME", "Readme",
3666 "ARPURLINFOABOUT", "URLInfoAbout",
3667 "ARPURLUPDATEINFO", "URLUpdateInfo",
3670 const LPCSTR *p = propval;
3674 prop = strdupAtoW( *p++ );
3675 key = strdupAtoW( *p++ );
3676 val = msi_dup_property( package, prop );
3677 msi_reg_set_val_str( hkey, key, val );
3682 return ERROR_SUCCESS;
3685 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3688 LPWSTR buffer = NULL;
3691 static const WCHAR szWindowsInstaller[] =
3692 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3693 static const WCHAR szUpgradeCode[] =
3694 {'U','p','g','r','a','d','e','C','o','d','e',0};
3695 static const WCHAR modpath_fmt[] =
3696 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3697 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3698 static const WCHAR szModifyPath[] =
3699 {'M','o','d','i','f','y','P','a','t','h',0};
3700 static const WCHAR szUninstallString[] =
3701 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3702 static const WCHAR szEstimatedSize[] =
3703 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3704 static const WCHAR szProductLanguage[] =
3705 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3706 static const WCHAR szProductVersion[] =
3707 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3710 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3711 LPWSTR upgrade_code;
3714 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3715 if (rc != ERROR_SUCCESS)
3718 /* dump all the info i can grab */
3719 /* FIXME: Flesh out more information */
3721 msi_write_uninstall_property_vals( package, hkey );
3723 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3725 msi_make_package_local( package, hkey );
3727 /* do ModifyPath and UninstallString */
3728 size = deformat_string(package,modpath_fmt,&buffer);
3729 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3730 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3733 /* FIXME: Write real Estimated Size when we have it */
3734 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3736 GetLocalTime(&systime);
3737 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3738 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3740 langid = msi_get_property_int( package, szProductLanguage, 0 );
3741 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3743 buffer = msi_dup_property( package, szProductVersion );
3746 DWORD verdword = msi_version_str_to_dword(buffer);
3748 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3749 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3750 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3754 /* Handle Upgrade Codes */
3755 upgrade_code = msi_dup_property( package, szUpgradeCode );
3760 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3761 squash_guid(package->ProductCode,squashed);
3762 msi_reg_set_val_str( hkey2, squashed, NULL );
3764 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3765 squash_guid(package->ProductCode,squashed);
3766 msi_reg_set_val_str( hkey2, squashed, NULL );
3769 msi_free(upgrade_code);
3774 /* FIXME: call ui_actiondata */
3776 return ERROR_SUCCESS;
3779 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3781 return execute_script(package,INSTALL_SCRIPT);
3784 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3788 /* turn off scheduleing */
3789 package->script->CurrentlyScripting= FALSE;
3791 /* first do the same as an InstallExecute */
3792 rc = ACTION_InstallExecute(package);
3793 if (rc != ERROR_SUCCESS)
3796 /* then handle Commit Actions */
3797 rc = execute_script(package,COMMIT_SCRIPT);
3802 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3804 static const WCHAR RunOnce[] = {
3805 'S','o','f','t','w','a','r','e','\\',
3806 'M','i','c','r','o','s','o','f','t','\\',
3807 'W','i','n','d','o','w','s','\\',
3808 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3809 'R','u','n','O','n','c','e',0};
3810 static const WCHAR InstallRunOnce[] = {
3811 'S','o','f','t','w','a','r','e','\\',
3812 'M','i','c','r','o','s','o','f','t','\\',
3813 'W','i','n','d','o','w','s','\\',
3814 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3815 'I','n','s','t','a','l','l','e','r','\\',
3816 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3818 static const WCHAR msiexec_fmt[] = {
3820 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3821 '\"','%','s','\"',0};
3822 static const WCHAR install_fmt[] = {
3823 '/','I',' ','\"','%','s','\"',' ',
3824 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3825 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3826 WCHAR buffer[256], sysdir[MAX_PATH];
3828 WCHAR squished_pc[100];
3830 squash_guid(package->ProductCode,squished_pc);
3832 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3833 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3834 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3837 msi_reg_set_val_str( hkey, squished_pc, buffer );
3840 TRACE("Reboot command %s\n",debugstr_w(buffer));
3842 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3843 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3845 msi_reg_set_val_str( hkey, squished_pc, buffer );
3848 return ERROR_INSTALL_SUSPEND;
3851 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3858 * we are currently doing what should be done here in the top level Install
3859 * however for Adminastrative and uninstalls this step will be needed
3861 if (!package->PackagePath)
3862 return ERROR_SUCCESS;
3864 ptr = strrchrW(package->PackagePath, '\\');
3866 return ERROR_SUCCESS;
3868 len = ptr - package->PackagePath + 2;
3869 source = msi_alloc(len * sizeof(WCHAR));
3870 lstrcpynW(source, package->PackagePath, len);
3872 MSI_SetPropertyW(package, cszSourceDir, source);
3873 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3877 attrib = GetFileAttributesW(package->PackagePath);
3878 if (attrib == INVALID_FILE_ATTRIBUTES)
3884 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3885 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3886 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3887 if (rc == ERROR_MORE_DATA)
3889 prompt = msi_alloc(size * sizeof(WCHAR));
3890 MsiSourceListGetInfoW(package->ProductCode, NULL,
3891 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3892 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3895 prompt = strdupW(package->PackagePath);
3897 msg = generate_error_string(package,1302,1,prompt);
3898 while(attrib == INVALID_FILE_ATTRIBUTES)
3900 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3903 rc = ERROR_INSTALL_USEREXIT;
3906 attrib = GetFileAttributesW(package->PackagePath);
3912 return ERROR_SUCCESS;
3917 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3924 static const WCHAR szPropKeys[][80] =
3926 {'P','r','o','d','u','c','t','I','D',0},
3927 {'U','S','E','R','N','A','M','E',0},
3928 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3932 static const WCHAR szRegKeys[][80] =
3934 {'P','r','o','d','u','c','t','I','D',0},
3935 {'R','e','g','O','w','n','e','r',0},
3936 {'R','e','g','C','o','m','p','a','n','y',0},
3940 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3942 return ERROR_SUCCESS;
3944 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3945 if (rc != ERROR_SUCCESS)
3948 for( i = 0; szPropKeys[i][0]; i++ )
3950 buffer = msi_dup_property( package, szPropKeys[i] );
3951 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3956 msi_free(productid);
3959 /* FIXME: call ui_actiondata */
3961 return ERROR_SUCCESS;
3965 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3969 package->script->InWhatSequence |= SEQUENCE_EXEC;
3970 rc = ACTION_ProcessExecSequence(package,FALSE);
3975 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3977 MSIPACKAGE *package = (MSIPACKAGE*)param;
3978 LPCWSTR compgroupid=NULL;
3979 LPCWSTR feature=NULL;
3980 LPCWSTR text = NULL;
3981 LPCWSTR qualifier = NULL;
3982 LPCWSTR component = NULL;
3983 LPWSTR advertise = NULL;
3984 LPWSTR output = NULL;
3986 UINT rc = ERROR_SUCCESS;
3991 component = MSI_RecordGetString(rec,3);
3992 comp = get_loaded_component(package,component);
3994 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3995 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3996 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3998 TRACE("Skipping: Component %s not scheduled for install\n",
3999 debugstr_w(component));
4001 return ERROR_SUCCESS;
4004 compgroupid = MSI_RecordGetString(rec,1);
4005 qualifier = MSI_RecordGetString(rec,2);
4007 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4008 if (rc != ERROR_SUCCESS)
4011 text = MSI_RecordGetString(rec,4);
4012 feature = MSI_RecordGetString(rec,5);
4014 advertise = create_component_advertise_string(package, comp, feature);
4016 sz = strlenW(advertise);
4019 sz += lstrlenW(text);
4022 sz *= sizeof(WCHAR);
4024 output = msi_alloc_zero(sz);
4025 strcpyW(output,advertise);
4026 msi_free(advertise);
4029 strcatW(output,text);
4031 msi_reg_set_val_multi_str( hkey, qualifier, output );
4038 uirow = MSI_CreateRecord( 2 );
4039 MSI_RecordSetStringW( uirow, 1, compgroupid );
4040 MSI_RecordSetStringW( uirow, 2, qualifier);
4041 ui_actiondata( package, szPublishComponents, uirow);
4042 msiobj_release( &uirow->hdr );
4043 /* FIXME: call ui_progress? */
4049 * At present I am ignorning the advertised components part of this and only
4050 * focusing on the qualified component sets
4052 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4056 static const WCHAR ExecSeqQuery[] =
4057 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4058 '`','P','u','b','l','i','s','h',
4059 'C','o','m','p','o','n','e','n','t','`',0};
4061 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4062 if (rc != ERROR_SUCCESS)
4063 return ERROR_SUCCESS;
4065 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4066 msiobj_release(&view->hdr);
4071 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4073 MSIPACKAGE *package = (MSIPACKAGE*)param;
4076 SC_HANDLE hscm, service = NULL;
4077 LPCWSTR name, disp, comp, depends, pass;
4078 LPCWSTR load_order, serv_name, key;
4079 DWORD serv_type, start_type;
4082 static const WCHAR query[] =
4083 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4084 '`','C','o','m','p','o','n','e','n','t','`',' ',
4085 'W','H','E','R','E',' ',
4086 '`','C','o','m','p','o','n','e','n','t','`',' ',
4087 '=','\'','%','s','\'',0};
4089 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4092 ERR("Failed to open the SC Manager!\n");
4096 start_type = MSI_RecordGetInteger(rec, 5);
4097 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4100 depends = MSI_RecordGetString(rec, 8);
4101 if (depends && *depends)
4102 FIXME("Dependency list unhandled!\n");
4104 name = MSI_RecordGetString(rec, 2);
4105 disp = MSI_RecordGetString(rec, 3);
4106 serv_type = MSI_RecordGetInteger(rec, 4);
4107 err_control = MSI_RecordGetInteger(rec, 6);
4108 load_order = MSI_RecordGetString(rec, 7);
4109 serv_name = MSI_RecordGetString(rec, 9);
4110 pass = MSI_RecordGetString(rec, 10);
4111 comp = MSI_RecordGetString(rec, 12);
4113 /* fetch the service path */
4114 row = MSI_QueryGetRecord(package->db, query, comp);
4117 ERR("Control query failed!\n");
4121 key = MSI_RecordGetString(row, 6);
4122 msiobj_release(&row->hdr);
4124 file = get_loaded_file(package, key);
4127 ERR("Failed to load the service file\n");
4131 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4132 start_type, err_control, file->TargetPath,
4133 load_order, NULL, NULL, serv_name, pass);
4136 if (GetLastError() != ERROR_SERVICE_EXISTS)
4137 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4141 CloseServiceHandle(service);
4142 CloseServiceHandle(hscm);
4144 return ERROR_SUCCESS;
4147 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4151 static const WCHAR ExecSeqQuery[] =
4152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4153 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4155 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4156 if (rc != ERROR_SUCCESS)
4157 return ERROR_SUCCESS;
4159 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4160 msiobj_release(&view->hdr);
4165 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4166 LPCSTR action, LPCWSTR table )
4168 static const WCHAR query[] = {
4169 'S','E','L','E','C','T',' ','*',' ',
4170 'F','R','O','M',' ','`','%','s','`',0 };
4171 MSIQUERY *view = NULL;
4175 r = MSI_OpenQuery( package->db, &view, query, table );
4176 if (r == ERROR_SUCCESS)
4178 r = MSI_IterateRecords(view, &count, NULL, package);
4179 msiobj_release(&view->hdr);
4183 FIXME("%s -> %u ignored %s table values\n",
4184 action, count, debugstr_w(table));
4186 return ERROR_SUCCESS;
4189 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4191 TRACE("%p\n", package);
4192 return ERROR_SUCCESS;
4195 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4197 static const WCHAR table[] =
4198 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4199 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4202 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4204 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4205 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4208 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4210 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4211 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4214 static UINT ACTION_BindImage( MSIPACKAGE *package )
4216 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4217 return msi_unimplemented_action_stub( package, "BindImage", table );
4220 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4222 static const WCHAR table[] = {
4223 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4224 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4227 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4229 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4230 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4233 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4235 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4236 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4239 static UINT ACTION_StartServices( MSIPACKAGE *package )
4241 static const WCHAR table[] = {
4242 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4243 return msi_unimplemented_action_stub( package, "StartServices", table );
4246 static UINT ACTION_StopServices( MSIPACKAGE *package )
4248 static const WCHAR table[] = {
4249 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4250 return msi_unimplemented_action_stub( package, "StopServices", table );
4253 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4255 static const WCHAR table[] = {
4256 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4257 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4260 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4262 static const WCHAR table[] = {
4263 'E','n','v','i','r','o','n','m','e','n','t',0 };
4264 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4267 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4269 static const WCHAR table[] = {
4270 'E','n','v','i','r','o','n','m','e','n','t',0 };
4271 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4274 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4276 static const WCHAR table[] = {
4277 'M','s','i','A','s','s','e','m','b','l','y',0 };
4278 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4281 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4283 static const WCHAR table[] = {
4284 'M','s','i','A','s','s','e','m','b','l','y',0 };
4285 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4288 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4290 static const WCHAR table[] = { 'F','o','n','t',0 };
4291 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4294 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4296 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4297 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4300 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4302 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4303 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4306 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4308 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4309 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4312 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4314 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4315 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4318 static struct _actions StandardActions[] = {
4319 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4320 { szAppSearch, ACTION_AppSearch },
4321 { szBindImage, ACTION_BindImage },
4322 { szCCPSearch, ACTION_CCPSearch},
4323 { szCostFinalize, ACTION_CostFinalize },
4324 { szCostInitialize, ACTION_CostInitialize },
4325 { szCreateFolders, ACTION_CreateFolders },
4326 { szCreateShortcuts, ACTION_CreateShortcuts },
4327 { szDeleteServices, ACTION_DeleteServices },
4328 { szDisableRollback, NULL},
4329 { szDuplicateFiles, ACTION_DuplicateFiles },
4330 { szExecuteAction, ACTION_ExecuteAction },
4331 { szFileCost, ACTION_FileCost },
4332 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4333 { szForceReboot, ACTION_ForceReboot },
4334 { szInstallAdminPackage, NULL},
4335 { szInstallExecute, ACTION_InstallExecute },
4336 { szInstallExecuteAgain, ACTION_InstallExecute },
4337 { szInstallFiles, ACTION_InstallFiles},
4338 { szInstallFinalize, ACTION_InstallFinalize },
4339 { szInstallInitialize, ACTION_InstallInitialize },
4340 { szInstallSFPCatalogFile, NULL},
4341 { szInstallValidate, ACTION_InstallValidate },
4342 { szIsolateComponents, ACTION_IsolateComponents },
4343 { szLaunchConditions, ACTION_LaunchConditions },
4344 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4345 { szMoveFiles, ACTION_MoveFiles },
4346 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4347 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4348 { szInstallODBC, NULL},
4349 { szInstallServices, ACTION_InstallServices },
4350 { szPatchFiles, ACTION_PatchFiles },
4351 { szProcessComponents, ACTION_ProcessComponents },
4352 { szPublishComponents, ACTION_PublishComponents },
4353 { szPublishFeatures, ACTION_PublishFeatures },
4354 { szPublishProduct, ACTION_PublishProduct },
4355 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4356 { szRegisterComPlus, ACTION_RegisterComPlus},
4357 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4358 { szRegisterFonts, ACTION_RegisterFonts },
4359 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4360 { szRegisterProduct, ACTION_RegisterProduct },
4361 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4362 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4363 { szRegisterUser, ACTION_RegisterUser},
4364 { szRemoveDuplicateFiles, NULL},
4365 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4366 { szRemoveExistingProducts, NULL},
4367 { szRemoveFiles, ACTION_RemoveFiles},
4368 { szRemoveFolders, NULL},
4369 { szRemoveIniValues, ACTION_RemoveIniValues },
4370 { szRemoveODBC, NULL},
4371 { szRemoveRegistryValues, NULL},
4372 { szRemoveShortcuts, NULL},
4373 { szResolveSource, ACTION_ResolveSource},
4374 { szRMCCPSearch, ACTION_RMCCPSearch},
4375 { szScheduleReboot, NULL},
4376 { szSelfRegModules, ACTION_SelfRegModules },
4377 { szSelfUnregModules, ACTION_SelfUnregModules },
4378 { szSetODBCFolders, NULL},
4379 { szStartServices, ACTION_StartServices },
4380 { szStopServices, ACTION_StopServices },
4381 { szUnpublishComponents, NULL},
4382 { szUnpublishFeatures, NULL},
4383 { szUnregisterClassInfo, NULL},
4384 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4385 { szUnregisterExtensionInfo, NULL},
4386 { szUnregisterFonts, ACTION_UnregisterFonts },
4387 { szUnregisterMIMEInfo, NULL},
4388 { szUnregisterProgIdInfo, NULL},
4389 { szUnregisterTypeLibraries, NULL},
4390 { szValidateProductID, NULL},
4391 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4392 { szWriteIniValues, ACTION_WriteIniValues },
4393 { szWriteRegistryValues, ACTION_WriteRegistryValues},