2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
37 #include "wine/debug.h"
42 #include "wine/unicode.h"
45 #define REG_PROGRESS_VALUE 13200
46 #define COMPONENT_PROGRESS_VALUE 24000
48 WINE_DEFAULT_DEBUG_CHANNEL(msi);
53 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
54 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
55 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
58 * consts and values used
60 static const WCHAR c_colon[] = {'C',':','\\',0};
62 static const WCHAR szCreateFolders[] =
63 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
64 static const WCHAR szCostFinalize[] =
65 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
66 const WCHAR szInstallFiles[] =
67 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
68 const WCHAR szDuplicateFiles[] =
69 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
70 static const WCHAR szWriteRegistryValues[] =
71 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
72 'V','a','l','u','e','s',0};
73 static const WCHAR szCostInitialize[] =
74 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
75 static const WCHAR szFileCost[] =
76 {'F','i','l','e','C','o','s','t',0};
77 static const WCHAR szInstallInitialize[] =
78 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
79 static const WCHAR szInstallValidate[] =
80 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
81 static const WCHAR szLaunchConditions[] =
82 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
83 static const WCHAR szProcessComponents[] =
84 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
85 static const WCHAR szRegisterTypeLibraries[] =
86 {'R','e','g','i','s','t','e','r','T','y','p','e',
87 'L','i','b','r','a','r','i','e','s',0};
88 const WCHAR szRegisterClassInfo[] =
89 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
90 const WCHAR szRegisterProgIdInfo[] =
91 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
92 static const WCHAR szCreateShortcuts[] =
93 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
94 static const WCHAR szPublishProduct[] =
95 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
96 static const WCHAR szWriteIniValues[] =
97 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
98 static const WCHAR szSelfRegModules[] =
99 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
100 static const WCHAR szPublishFeatures[] =
101 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
102 static const WCHAR szRegisterProduct[] =
103 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
104 static const WCHAR szInstallExecute[] =
105 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
106 static const WCHAR szInstallExecuteAgain[] =
107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
108 'A','g','a','i','n',0};
109 static const WCHAR szInstallFinalize[] =
110 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
111 static const WCHAR szForceReboot[] =
112 {'F','o','r','c','e','R','e','b','o','o','t',0};
113 static const WCHAR szResolveSource[] =
114 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
115 static const WCHAR szAppSearch[] =
116 {'A','p','p','S','e','a','r','c','h',0};
117 static const WCHAR szAllocateRegistrySpace[] =
118 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
119 'S','p','a','c','e',0};
120 static const WCHAR szBindImage[] =
121 {'B','i','n','d','I','m','a','g','e',0};
122 static const WCHAR szCCPSearch[] =
123 {'C','C','P','S','e','a','r','c','h',0};
124 static const WCHAR szDeleteServices[] =
125 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
126 static const WCHAR szDisableRollback[] =
127 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
128 static const WCHAR szExecuteAction[] =
129 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
130 const WCHAR szFindRelatedProducts[] =
131 {'F','i','n','d','R','e','l','a','t','e','d',
132 'P','r','o','d','u','c','t','s',0};
133 static const WCHAR szInstallAdminPackage[] =
134 {'I','n','s','t','a','l','l','A','d','m','i','n',
135 'P','a','c','k','a','g','e',0};
136 static const WCHAR szInstallSFPCatalogFile[] =
137 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 static const WCHAR szIsolateComponents[] =
140 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
141 const WCHAR szMigrateFeatureStates[] =
142 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
143 'S','t','a','t','e','s',0};
144 const WCHAR szMoveFiles[] =
145 {'M','o','v','e','F','i','l','e','s',0};
146 static const WCHAR szMsiPublishAssemblies[] =
147 {'M','s','i','P','u','b','l','i','s','h',
148 'A','s','s','e','m','b','l','i','e','s',0};
149 static const WCHAR szMsiUnpublishAssemblies[] =
150 {'M','s','i','U','n','p','u','b','l','i','s','h',
151 'A','s','s','e','m','b','l','i','e','s',0};
152 static const WCHAR szInstallODBC[] =
153 {'I','n','s','t','a','l','l','O','D','B','C',0};
154 static const WCHAR szInstallServices[] =
155 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
156 const WCHAR szPatchFiles[] =
157 {'P','a','t','c','h','F','i','l','e','s',0};
158 static const WCHAR szPublishComponents[] =
159 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
160 static const WCHAR szRegisterComPlus[] =
161 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
162 const WCHAR szRegisterExtensionInfo[] =
163 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 static const WCHAR szRegisterFonts[] =
166 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
167 const WCHAR szRegisterMIMEInfo[] =
168 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
169 static const WCHAR szRegisterUser[] =
170 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
171 const WCHAR szRemoveDuplicateFiles[] =
172 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
173 'F','i','l','e','s',0};
174 static const WCHAR szRemoveEnvironmentStrings[] =
175 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
176 'S','t','r','i','n','g','s',0};
177 const WCHAR szRemoveExistingProducts[] =
178 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
179 'P','r','o','d','u','c','t','s',0};
180 const WCHAR szRemoveFiles[] =
181 {'R','e','m','o','v','e','F','i','l','e','s',0};
182 static const WCHAR szRemoveFolders[] =
183 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
184 static const WCHAR szRemoveIniValues[] =
185 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
186 static const WCHAR szRemoveODBC[] =
187 {'R','e','m','o','v','e','O','D','B','C',0};
188 static const WCHAR szRemoveRegistryValues[] =
189 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
190 'V','a','l','u','e','s',0};
191 static const WCHAR szRemoveShortcuts[] =
192 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
193 static const WCHAR szRMCCPSearch[] =
194 {'R','M','C','C','P','S','e','a','r','c','h',0};
195 static const WCHAR szScheduleReboot[] =
196 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
197 static const WCHAR szSelfUnregModules[] =
198 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
199 static const WCHAR szSetODBCFolders[] =
200 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
201 static const WCHAR szStartServices[] =
202 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
203 static const WCHAR szStopServices[] =
204 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
205 static const WCHAR szUnpublishComponents[] =
206 {'U','n','p','u','b','l','i','s','h',
207 'C','o','m','p','o','n','e','n','t','s',0};
208 static const WCHAR szUnpublishFeatures[] =
209 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
210 const WCHAR szUnregisterClassInfo[] =
211 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 static const WCHAR szUnregisterComPlus[] =
214 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
215 const WCHAR szUnregisterExtensionInfo[] =
216 {'U','n','r','e','g','i','s','t','e','r',
217 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
218 static const WCHAR szUnregisterFonts[] =
219 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
220 const WCHAR szUnregisterMIMEInfo[] =
221 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
222 const WCHAR szUnregisterProgIdInfo[] =
223 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 static const WCHAR szUnregisterTypeLibraries[] =
226 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
227 'L','i','b','r','a','r','i','e','s',0};
228 static const WCHAR szValidateProductID[] =
229 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
230 static const WCHAR szWriteEnvironmentStrings[] =
231 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
232 'S','t','r','i','n','g','s',0};
234 /* action handlers */
235 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
239 STANDARDACTIONHANDLER handler;
242 static struct _actions StandardActions[];
245 /********************************************************
247 ********************************************************/
249 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
251 static const WCHAR Query_t[] =
252 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
253 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
254 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
255 ' ','\'','%','s','\'',0};
258 row = MSI_QueryGetRecord( package->db, Query_t, action );
261 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
262 msiobj_release(&row->hdr);
265 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
269 static const WCHAR template_s[]=
270 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272 static const WCHAR template_e[]=
273 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
274 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276 static const WCHAR format[] =
277 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
281 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283 sprintfW(message,template_s,timet,action);
285 sprintfW(message,template_e,timet,action,rc);
287 row = MSI_CreateRecord(1);
288 MSI_RecordSetStringW(row,1,message);
290 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
291 msiobj_release(&row->hdr);
294 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
299 LPWSTR prop = NULL, val = NULL;
302 return ERROR_SUCCESS;
314 TRACE("Looking at %s\n",debugstr_w(ptr));
316 ptr2 = strchrW(ptr,'=');
319 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
326 prop = msi_alloc((len+1)*sizeof(WCHAR));
327 memcpy(prop,ptr,len*sizeof(WCHAR));
333 while (*ptr && (quote || (!quote && *ptr!=' ')))
346 val = msi_alloc((len+1)*sizeof(WCHAR));
347 memcpy(val,ptr2,len*sizeof(WCHAR));
350 if (lstrlenW(prop) > 0)
352 TRACE("Found commandline property (%s) = (%s)\n",
353 debugstr_w(prop), debugstr_w(val));
354 MSI_SetPropertyW(package,prop,val);
360 return ERROR_SUCCESS;
364 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367 LPWSTR p, *ret = NULL;
373 /* count the number of substrings */
374 for ( pc = str, count = 0; pc; count++ )
376 pc = strchrW( pc, sep );
381 /* allocate space for an array of substring pointers and the substrings */
382 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
383 (lstrlenW(str)+1) * sizeof(WCHAR) );
387 /* copy the string and set the pointers */
388 p = (LPWSTR) &ret[count+1];
390 for( count = 0; (ret[count] = p); count++ )
392 p = strchrW( p, sep );
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
407 TRACE("%p %s\n", package, debugstr_w(name) );
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
418 ret = msi_table_apply_transform( package->db, stg );
419 IStorage_Release( stg );
423 ERR("failed to open substorage %s\n", debugstr_w(name));
428 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
430 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
431 LPWSTR guid_list, *guids, product_id;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_id = msi_dup_property( package, szProdID );
437 /* FIXME: the property ProductID should be written into the DB somewhere */
438 ERR("no product ID to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_id ))
450 msi_free( guid_list );
451 msi_free( product_id );
456 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
459 LPWSTR str, *substorage;
460 UINT i, r = ERROR_SUCCESS;
462 si = MSI_GetSummaryInformationW( patch_db, 0 );
464 return ERROR_FUNCTION_FAILED;
466 msi_check_patch_applicable( package, si );
468 /* enumerate the substorage */
469 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
470 substorage = msi_split_string( str, ';' );
471 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
472 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
473 msi_free( substorage );
476 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
478 msiobj_release( &si->hdr );
483 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
485 MSIDATABASE *patch_db = NULL;
488 TRACE("%p %s\n", package, debugstr_w( file ) );
491 * We probably want to make sure we only open a patch collection here.
492 * Patch collections (.msp) and databases (.msi) have different GUIDs
493 * but currently MSI_OpenDatabaseW will accept both.
495 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
496 if ( r != ERROR_SUCCESS )
498 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
502 msi_parse_patch_summary( package, patch_db );
503 msiobj_release( &patch_db->hdr );
505 return ERROR_SUCCESS;
508 /* get the PATCH property, and apply all the patches it specifies */
509 static UINT msi_apply_patches( MSIPACKAGE *package )
511 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
512 LPWSTR patch_list, *patches;
513 UINT i, r = ERROR_SUCCESS;
515 patch_list = msi_dup_property( package, szPatch );
517 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
519 patches = msi_split_string( patch_list, ';' );
520 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_patch_package( package, patches[i] );
524 msi_free( patch_list );
529 static UINT msi_apply_transforms( MSIPACKAGE *package )
531 static const WCHAR szTransforms[] = {
532 'T','R','A','N','S','F','O','R','M','S',0 };
533 LPWSTR xform_list, *xforms;
534 UINT i, r = ERROR_SUCCESS;
536 xform_list = msi_dup_property( package, szTransforms );
537 xforms = msi_split_string( xform_list, ';' );
539 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
541 if (xforms[i][0] == ':')
542 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
544 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
548 msi_free( xform_list );
553 /****************************************************
554 * TOP level entry points
555 *****************************************************/
557 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
558 LPCWSTR szCommandLine )
562 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
563 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
564 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
566 MSI_SetPropertyW(package, szAction, szInstall);
568 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
570 package->script->InWhatSequence = SEQUENCE_INSTALL;
574 LPWSTR p, check, path;
576 package->PackagePath = strdupW(szPackagePath);
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);
599 msi_parse_command_line( package, szCommandLine );
601 msi_apply_transforms( package );
602 msi_apply_patches( package );
604 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
606 package->script->InWhatSequence |= SEQUENCE_UI;
607 rc = ACTION_ProcessUISequence(package);
609 if (rc == ERROR_SUCCESS)
611 package->script->InWhatSequence |= SEQUENCE_EXEC;
612 rc = ACTION_ProcessExecSequence(package,TRUE);
616 rc = ACTION_ProcessExecSequence(package,FALSE);
620 /* install was halted but should be considered a success */
624 package->script->CurrentlyScripting= FALSE;
626 /* process the ending type action */
627 if (rc == ERROR_SUCCESS)
628 ACTION_PerformActionSequence(package,-1,ui);
629 else if (rc == ERROR_INSTALL_USEREXIT)
630 ACTION_PerformActionSequence(package,-2,ui);
631 else if (rc == ERROR_INSTALL_SUSPEND)
632 ACTION_PerformActionSequence(package,-4,ui);
634 ACTION_PerformActionSequence(package,-3,ui);
636 /* finish up running custom actions */
637 ACTION_FinishCustomActions(package);
642 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
644 UINT rc = ERROR_SUCCESS;
646 static const WCHAR ExecSeqQuery[] =
647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
648 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
649 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
650 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
652 static const WCHAR UISeqQuery[] =
653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
654 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
655 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
656 ' ', '=',' ','%','i',0};
659 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
661 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
665 LPCWSTR action, cond;
667 TRACE("Running the actions\n");
669 /* check conditions */
670 cond = MSI_RecordGetString(row,2);
673 /* this is a hack to skip errors in the condition code */
674 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
678 action = MSI_RecordGetString(row,1);
681 ERR("failed to fetch action\n");
682 rc = ERROR_FUNCTION_FAILED;
687 rc = ACTION_PerformUIAction(package,action);
689 rc = ACTION_PerformAction(package,action,FALSE);
691 msiobj_release(&row->hdr);
702 } iterate_action_param;
704 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
706 iterate_action_param *iap= (iterate_action_param*)param;
708 LPCWSTR cond, action;
710 action = MSI_RecordGetString(row,1);
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED;
717 /* check conditions */
718 cond = MSI_RecordGetString(row,2);
721 /* this is a hack to skip errors in the condition code */
722 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
724 TRACE("Skipping action: %s (condition is false)\n",
726 return ERROR_SUCCESS;
731 rc = ACTION_PerformUIAction(iap->package,action);
733 rc = ACTION_PerformAction(iap->package,action,FALSE);
735 msi_dialog_check_messages( NULL );
737 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
738 rc = iap->package->CurrentInstallState;
740 if (rc == ERROR_FUNCTION_NOT_CALLED)
743 if (rc != ERROR_SUCCESS)
744 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
749 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
753 static const WCHAR query[] =
754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
756 ' ','W','H','E','R','E',' ',
757 '`','S','e','q','u','e','n','c','e','`',' ',
758 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
759 '`','S','e','q','u','e','n','c','e','`',0};
760 iterate_action_param iap;
763 * FIXME: probably should be checking UILevel in the
764 * ACTION_PerformUIAction/ACTION_PerformAction
765 * rather than saving the UI level here. Those
766 * two functions can be merged too.
768 iap.package = package;
771 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
773 r = MSI_OpenQuery( package->db, &view, query, szTable );
774 if (r == ERROR_SUCCESS)
776 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
777 msiobj_release(&view->hdr);
783 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
787 static const WCHAR ExecSeqQuery[] =
788 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
789 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
790 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
792 'O','R','D','E','R',' ', 'B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0 };
795 static const WCHAR IVQuery[] =
796 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
797 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
798 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
799 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
800 ' ','\'', 'I','n','s','t','a','l','l',
801 'V','a','l','i','d','a','t','e','\'', 0};
803 iterate_action_param iap;
805 iap.package = package;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
819 row = MSI_QueryGetRecord(package->db, IVQuery);
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
832 msiobj_release(&view->hdr);
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
850 iterate_action_param iap;
852 iap.package = package;
855 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
857 if (rc == ERROR_SUCCESS)
859 TRACE("Running the actions\n");
861 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
862 msiobj_release(&view->hdr);
868 /********************************************************
869 * ACTION helper functions and functions that perform the actions
870 *******************************************************/
871 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
872 UINT* rc, BOOL force )
878 if (!run && !package->script->CurrentlyScripting)
883 if (strcmpW(action,szInstallFinalize) == 0 ||
884 strcmpW(action,szInstallExecute) == 0 ||
885 strcmpW(action,szInstallExecuteAgain) == 0)
890 while (StandardActions[i].action != NULL)
892 if (strcmpW(StandardActions[i].action, action)==0)
896 ui_actioninfo(package, action, TRUE, 0);
897 *rc = schedule_action(package,INSTALL_SCRIPT,action);
898 ui_actioninfo(package, action, FALSE, *rc);
902 ui_actionstart(package, action);
903 if (StandardActions[i].handler)
905 *rc = StandardActions[i].handler(package);
909 FIXME("unhandled standard action %s\n",debugstr_w(action));
921 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
922 UINT* rc, BOOL force )
927 arc = ACTION_CustomAction(package,action, force);
929 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
938 * A lot of actions are really important even if they don't do anything
939 * explicit... Lots of properties are set at the beginning of the installation
940 * CostFinalize does a bunch of work to translate the directories and such
942 * But until I get write access to the database that is hard, so I am going to
943 * hack it to see if I can get something to run.
945 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
947 UINT rc = ERROR_SUCCESS;
950 TRACE("Performing action (%s)\n",debugstr_w(action));
952 handled = ACTION_HandleStandardAction(package, action, &rc, force);
955 handled = ACTION_HandleCustomAction(package, action, &rc, force);
959 FIXME("unhandled msi action %s\n",debugstr_w(action));
960 rc = ERROR_FUNCTION_NOT_CALLED;
966 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
968 UINT rc = ERROR_SUCCESS;
969 BOOL handled = FALSE;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
976 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
978 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
983 FIXME("unhandled msi action %s\n",debugstr_w(action));
984 rc = ERROR_FUNCTION_NOT_CALLED;
992 * Actual Action Handlers
995 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
997 MSIPACKAGE *package = (MSIPACKAGE*)param;
1003 dir = MSI_RecordGetString(row,1);
1006 ERR("Unable to get folder id\n");
1007 return ERROR_SUCCESS;
1010 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1013 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1014 return ERROR_SUCCESS;
1017 TRACE("Folder is %s\n",debugstr_w(full_path));
1020 uirow = MSI_CreateRecord(1);
1021 MSI_RecordSetStringW(uirow,1,full_path);
1022 ui_actiondata(package,szCreateFolders,uirow);
1023 msiobj_release( &uirow->hdr );
1025 if (folder->State == 0)
1026 create_full_pathW(full_path);
1030 msi_free(full_path);
1031 return ERROR_SUCCESS;
1034 /* FIXME: probably should merge this with the above function */
1035 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1037 UINT rc = ERROR_SUCCESS;
1039 LPWSTR install_path;
1041 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1043 return ERROR_FUNCTION_FAILED;
1045 /* create the path */
1046 if (folder->State == 0)
1048 create_full_pathW(install_path);
1051 msi_free(install_path);
1056 UINT msi_create_component_directories( MSIPACKAGE *package )
1060 /* create all the folders required by the components are going to install */
1061 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1063 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1065 msi_create_directory( package, comp->Directory );
1068 return ERROR_SUCCESS;
1072 * Also we cannot enable/disable components either, so for now I am just going
1073 * to do all the directories for all the components.
1075 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1077 static const WCHAR ExecSeqQuery[] =
1078 {'S','E','L','E','C','T',' ',
1079 '`','D','i','r','e','c','t','o','r','y','_','`',
1080 ' ','F','R','O','M',' ',
1081 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1085 /* create all the empty folders specified in the CreateFolder table */
1086 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1087 if (rc != ERROR_SUCCESS)
1088 return ERROR_SUCCESS;
1090 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1091 msiobj_release(&view->hdr);
1093 msi_create_component_directories( package );
1098 static UINT load_component( MSIRECORD *row, LPVOID param )
1100 MSIPACKAGE *package = param;
1103 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1105 return ERROR_FUNCTION_FAILED;
1107 list_add_tail( &package->components, &comp->entry );
1109 /* fill in the data */
1110 comp->Component = msi_dup_record_field( row, 1 );
1112 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1114 comp->ComponentId = msi_dup_record_field( row, 2 );
1115 comp->Directory = msi_dup_record_field( row, 3 );
1116 comp->Attributes = MSI_RecordGetInteger(row,4);
1117 comp->Condition = msi_dup_record_field( row, 5 );
1118 comp->KeyPath = msi_dup_record_field( row, 6 );
1120 comp->Installed = INSTALLSTATE_UNKNOWN;
1121 comp->Action = INSTALLSTATE_UNKNOWN;
1122 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1124 return ERROR_SUCCESS;
1127 static UINT load_all_components( MSIPACKAGE *package )
1129 static const WCHAR query[] = {
1130 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1131 '`','C','o','m','p','o','n','e','n','t','`',0 };
1135 if (!list_empty(&package->components))
1136 return ERROR_SUCCESS;
1138 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1139 if (r != ERROR_SUCCESS)
1142 r = MSI_IterateRecords(view, NULL, load_component, package);
1143 msiobj_release(&view->hdr);
1148 MSIPACKAGE *package;
1149 MSIFEATURE *feature;
1152 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1156 cl = msi_alloc( sizeof (*cl) );
1158 return ERROR_NOT_ENOUGH_MEMORY;
1159 cl->component = comp;
1160 list_add_tail( &feature->Components, &cl->entry );
1162 return ERROR_SUCCESS;
1165 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1169 fl = msi_alloc( sizeof(*fl) );
1171 return ERROR_NOT_ENOUGH_MEMORY;
1172 fl->feature = child;
1173 list_add_tail( &parent->Children, &fl->entry );
1175 return ERROR_SUCCESS;
1178 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1180 _ilfs* ilfs= (_ilfs*)param;
1184 component = MSI_RecordGetString(row,1);
1186 /* check to see if the component is already loaded */
1187 comp = get_loaded_component( ilfs->package, component );
1190 ERR("unknown component %s\n", debugstr_w(component));
1191 return ERROR_FUNCTION_FAILED;
1194 add_feature_component( ilfs->feature, comp );
1195 comp->Enabled = TRUE;
1197 return ERROR_SUCCESS;
1200 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1202 MSIFEATURE *feature;
1204 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1206 if ( !lstrcmpW( feature->Feature, name ) )
1213 static UINT load_feature(MSIRECORD * row, LPVOID param)
1215 MSIPACKAGE* package = (MSIPACKAGE*)param;
1216 MSIFEATURE* feature;
1217 static const WCHAR Query1[] =
1218 {'S','E','L','E','C','T',' ',
1219 '`','C','o','m','p','o','n','e','n','t','_','`',
1220 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1221 'C','o','m','p','o','n','e','n','t','s','`',' ',
1222 'W','H','E','R','E',' ',
1223 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1228 /* fill in the data */
1230 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1232 return ERROR_NOT_ENOUGH_MEMORY;
1234 list_init( &feature->Children );
1235 list_init( &feature->Components );
1237 feature->Feature = msi_dup_record_field( row, 1 );
1239 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1241 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1242 feature->Title = msi_dup_record_field( row, 3 );
1243 feature->Description = msi_dup_record_field( row, 4 );
1245 if (!MSI_RecordIsNull(row,5))
1246 feature->Display = MSI_RecordGetInteger(row,5);
1248 feature->Level= MSI_RecordGetInteger(row,6);
1249 feature->Directory = msi_dup_record_field( row, 7 );
1250 feature->Attributes = MSI_RecordGetInteger(row,8);
1252 feature->Installed = INSTALLSTATE_UNKNOWN;
1253 feature->Action = INSTALLSTATE_UNKNOWN;
1254 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1256 list_add_tail( &package->features, &feature->entry );
1258 /* load feature components */
1260 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1261 if (rc != ERROR_SUCCESS)
1262 return ERROR_SUCCESS;
1264 ilfs.package = package;
1265 ilfs.feature = feature;
1267 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1268 msiobj_release(&view->hdr);
1270 return ERROR_SUCCESS;
1273 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1275 MSIPACKAGE* package = (MSIPACKAGE*)param;
1276 MSIFEATURE *parent, *child;
1278 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1280 return ERROR_FUNCTION_FAILED;
1282 if (!child->Feature_Parent)
1283 return ERROR_SUCCESS;
1285 parent = find_feature_by_name( package, child->Feature_Parent );
1287 return ERROR_FUNCTION_FAILED;
1289 add_feature_child( parent, child );
1290 return ERROR_SUCCESS;
1293 static UINT load_all_features( MSIPACKAGE *package )
1295 static const WCHAR query[] = {
1296 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1297 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1298 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1302 if (!list_empty(&package->features))
1303 return ERROR_SUCCESS;
1305 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1306 if (r != ERROR_SUCCESS)
1309 r = MSI_IterateRecords( view, NULL, load_feature, package );
1310 if (r != ERROR_SUCCESS)
1313 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1314 msiobj_release( &view->hdr );
1319 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1330 static UINT load_file(MSIRECORD *row, LPVOID param)
1332 MSIPACKAGE* package = (MSIPACKAGE*)param;
1336 /* fill in the data */
1338 file = msi_alloc_zero( sizeof (MSIFILE) );
1340 return ERROR_NOT_ENOUGH_MEMORY;
1342 file->File = msi_dup_record_field( row, 1 );
1344 component = MSI_RecordGetString( row, 2 );
1345 file->Component = get_loaded_component( package, component );
1347 if (!file->Component)
1348 ERR("Unfound Component %s\n",debugstr_w(component));
1350 file->FileName = msi_dup_record_field( row, 3 );
1351 reduce_to_longfilename( file->FileName );
1353 file->ShortName = msi_dup_record_field( row, 3 );
1354 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1356 file->FileSize = MSI_RecordGetInteger( row, 4 );
1357 file->Version = msi_dup_record_field( row, 5 );
1358 file->Language = msi_dup_record_field( row, 6 );
1359 file->Attributes = MSI_RecordGetInteger( row, 7 );
1360 file->Sequence = MSI_RecordGetInteger( row, 8 );
1362 file->state = msifs_invalid;
1364 /* if the compressed bits are not set in the file attributes,
1365 * then read the information from the package word count property
1367 if (file->Attributes & msidbFileAttributesCompressed)
1369 file->IsCompressed = TRUE;
1371 else if (file->Attributes & msidbFileAttributesNoncompressed)
1373 file->IsCompressed = FALSE;
1377 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1380 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1382 list_add_tail( &package->files, &file->entry );
1384 return ERROR_SUCCESS;
1387 static UINT load_all_files(MSIPACKAGE *package)
1391 static const WCHAR Query[] =
1392 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1393 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1394 '`','S','e','q','u','e','n','c','e','`', 0};
1396 if (!list_empty(&package->files))
1397 return ERROR_SUCCESS;
1399 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1400 if (rc != ERROR_SUCCESS)
1401 return ERROR_SUCCESS;
1403 rc = MSI_IterateRecords(view, NULL, load_file, package);
1404 msiobj_release(&view->hdr);
1406 return ERROR_SUCCESS;
1411 * I am not doing any of the costing functionality yet.
1412 * Mostly looking at doing the Component and Feature loading
1414 * The native MSI does A LOT of modification to tables here. Mostly adding
1415 * a lot of temporary columns to the Feature and Component tables.
1417 * note: Native msi also tracks the short filename. But I am only going to
1418 * track the long ones. Also looking at this directory table
1419 * it appears that the directory table does not get the parents
1420 * resolved base on property only based on their entries in the
1423 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1425 static const WCHAR szCosting[] =
1426 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1427 static const WCHAR szZero[] = { '0', 0 };
1429 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1430 return ERROR_SUCCESS;
1432 MSI_SetPropertyW(package, szCosting, szZero);
1433 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1435 load_all_components( package );
1436 load_all_features( package );
1437 load_all_files( package );
1439 return ERROR_SUCCESS;
1442 static UINT execute_script(MSIPACKAGE *package, UINT script )
1445 UINT rc = ERROR_SUCCESS;
1447 TRACE("Executing Script %i\n",script);
1449 if (!package->script)
1451 ERR("no script!\n");
1452 return ERROR_FUNCTION_FAILED;
1455 for (i = 0; i < package->script->ActionCount[script]; i++)
1458 action = package->script->Actions[script][i];
1459 ui_actionstart(package, action);
1460 TRACE("Executing Action (%s)\n",debugstr_w(action));
1461 rc = ACTION_PerformAction(package, action, TRUE);
1462 msi_free(package->script->Actions[script][i]);
1463 if (rc != ERROR_SUCCESS)
1466 msi_free(package->script->Actions[script]);
1468 package->script->ActionCount[script] = 0;
1469 package->script->Actions[script] = NULL;
1473 static UINT ACTION_FileCost(MSIPACKAGE *package)
1475 return ERROR_SUCCESS;
1478 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1480 static const WCHAR Query[] =
1481 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1482 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1483 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1484 ' ','=',' ','\'','%','s','\'',
1486 static const WCHAR szDot[] = { '.',0 };
1487 static WCHAR szEmpty[] = { 0 };
1488 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1493 TRACE("Looking for dir %s\n",debugstr_w(dir));
1495 folder = get_loaded_folder( package, dir );
1499 TRACE("Working to load %s\n",debugstr_w(dir));
1501 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1505 folder->Directory = strdupW(dir);
1507 row = MSI_QueryGetRecord(package->db, Query, dir);
1511 p = msi_dup_record_field(row, 3);
1513 /* split src and target dir */
1515 src_short = folder_split_path( p, ':' );
1517 /* split the long and short paths */
1518 tgt_long = folder_split_path( tgt_short, '|' );
1519 src_long = folder_split_path( src_short, '|' );
1521 /* check for no-op dirs */
1522 if (!lstrcmpW(szDot, tgt_short))
1523 tgt_short = szEmpty;
1524 if (!lstrcmpW(szDot, src_short))
1525 src_short = szEmpty;
1528 tgt_long = tgt_short;
1531 src_short = tgt_short;
1532 src_long = tgt_long;
1536 src_long = src_short;
1538 /* FIXME: use the target short path too */
1539 folder->TargetDefault = strdupW(tgt_long);
1540 folder->SourceShortPath = strdupW(src_short);
1541 folder->SourceLongPath = strdupW(src_long);
1544 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1545 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1546 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1548 parent = MSI_RecordGetString(row, 2);
1551 folder->Parent = load_folder( package, parent );
1552 if ( folder->Parent )
1553 TRACE("loaded parent %p %s\n", folder->Parent,
1554 debugstr_w(folder->Parent->Directory));
1556 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1559 folder->Property = msi_dup_property( package, dir );
1561 msiobj_release(&row->hdr);
1563 list_add_tail( &package->folders, &folder->entry );
1565 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1570 /* scan for and update current install states */
1571 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1574 MSIFEATURE *feature;
1576 /* FIXME: component's installed state should be determined
1577 * by the component's registration
1579 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1583 if (!comp->ComponentId)
1586 res = MsiGetComponentPathW( package->ProductCode,
1587 comp->ComponentId, NULL, NULL);
1589 res = INSTALLSTATE_ABSENT;
1590 comp->Installed = res;
1593 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1596 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1598 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1600 comp= cl->component;
1602 if (!comp->ComponentId)
1604 res = INSTALLSTATE_ABSENT;
1608 if (res == INSTALLSTATE_ABSENT)
1609 res = comp->Installed;
1612 if (res == comp->Installed)
1615 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1616 res != INSTALLSTATE_SOURCE)
1618 res = INSTALLSTATE_INCOMPLETE;
1622 feature->Installed = res;
1626 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1629 static const WCHAR all[]={'A','L','L',0};
1631 MSIFEATURE *feature;
1633 override = msi_dup_property( package, property );
1637 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1639 if (strcmpiW(override,all)==0)
1641 feature->ActionRequest= state;
1642 feature->Action = state;
1646 LPWSTR ptr = override;
1647 LPWSTR ptr2 = strchrW(override,',');
1651 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1652 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1654 feature->ActionRequest= state;
1655 feature->Action = state;
1661 ptr2 = strchrW(ptr,',');
1673 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1676 static const WCHAR szlevel[] =
1677 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1678 static const WCHAR szAddLocal[] =
1679 {'A','D','D','L','O','C','A','L',0};
1680 static const WCHAR szRemove[] =
1681 {'R','E','M','O','V','E',0};
1682 static const WCHAR szReinstall[] =
1683 {'R','E','I','N','S','T','A','L','L',0};
1684 BOOL override = FALSE;
1685 MSICOMPONENT* component;
1686 MSIFEATURE *feature;
1689 /* I do not know if this is where it should happen.. but */
1691 TRACE("Checking Install Level\n");
1693 install_level = msi_get_property_int( package, szlevel, 1 );
1695 /* ok hereis the _real_ rub
1696 * all these activation/deactivation things happen in order and things
1697 * later on the list override things earlier on the list.
1698 * 1) INSTALLLEVEL processing
1708 * 11) FILEADDDEFAULT
1709 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1710 * ignored for all the features. seems strange, especially since it is not
1711 * documented anywhere, but it is how it works.
1713 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1714 * REMOVE are the big ones, since we don't handle administrative installs
1717 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1718 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1719 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1723 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1725 BOOL feature_state = ((feature->Level > 0) &&
1726 (feature->Level <= install_level));
1728 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1730 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1732 feature->ActionRequest = INSTALLSTATE_SOURCE;
1733 feature->Action = INSTALLSTATE_SOURCE;
1735 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1737 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1738 feature->Action = INSTALLSTATE_ADVERTISED;
1742 feature->ActionRequest = INSTALLSTATE_LOCAL;
1743 feature->Action = INSTALLSTATE_LOCAL;
1748 /* disable child features of unselected parent features */
1749 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1753 if (feature->Level > 0 && feature->Level <= install_level)
1756 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1758 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1759 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1765 /* set the Preselected Property */
1766 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1767 static const WCHAR szOne[] = { '1', 0 };
1769 MSI_SetPropertyW(package,szPreselected,szOne);
1773 * now we want to enable or disable components base on feature
1776 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1780 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1781 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1782 feature->ActionRequest);
1784 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1786 component = cl->component;
1788 if (!component->Enabled)
1790 component->Action = INSTALLSTATE_UNKNOWN;
1791 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1795 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1797 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1799 component->Action = INSTALLSTATE_LOCAL;
1800 component->ActionRequest = INSTALLSTATE_LOCAL;
1803 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1805 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1806 (component->Action == INSTALLSTATE_ABSENT) ||
1807 (component->Action == INSTALLSTATE_ADVERTISED) ||
1808 (component->Action == INSTALLSTATE_DEFAULT))
1811 component->Action = INSTALLSTATE_SOURCE;
1812 component->ActionRequest = INSTALLSTATE_SOURCE;
1815 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1817 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1818 (component->Action == INSTALLSTATE_ABSENT))
1821 component->Action = INSTALLSTATE_ADVERTISED;
1822 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1825 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1827 if (component->Action == INSTALLSTATE_UNKNOWN)
1829 component->Action = INSTALLSTATE_ABSENT;
1830 component->ActionRequest = INSTALLSTATE_ABSENT;
1833 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1835 component->Action = INSTALLSTATE_UNKNOWN;
1836 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1840 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1842 feature->Action = INSTALLSTATE_LOCAL;
1843 feature->ActionRequest = INSTALLSTATE_LOCAL;
1848 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1850 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1851 debugstr_w(component->Component), component->Installed,
1852 component->Action, component->ActionRequest);
1856 return ERROR_SUCCESS;
1859 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1861 MSIPACKAGE *package = (MSIPACKAGE*)param;
1865 name = MSI_RecordGetString(row,1);
1867 /* This helper function now does ALL the work */
1868 TRACE("Dir %s ...\n",debugstr_w(name));
1869 load_folder(package,name);
1870 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1871 TRACE("resolves to %s\n",debugstr_w(path));
1874 return ERROR_SUCCESS;
1877 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1879 MSIPACKAGE *package = (MSIPACKAGE*)param;
1881 MSIFEATURE *feature;
1883 name = MSI_RecordGetString( row, 1 );
1885 feature = get_loaded_feature( package, name );
1887 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1891 Condition = MSI_RecordGetString(row,3);
1893 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1895 int level = MSI_RecordGetInteger(row,2);
1896 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1897 feature->Level = level;
1900 return ERROR_SUCCESS;
1903 static void load_all_component_states(MSIPACKAGE *package)
1907 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1909 switch (comp->Attributes)
1911 case msidbComponentAttributesLocalOnly:
1912 comp->Action = INSTALLSTATE_LOCAL;
1913 comp->ActionRequest = INSTALLSTATE_LOCAL;
1915 case msidbComponentAttributesSourceOnly:
1916 comp->Action = INSTALLSTATE_SOURCE;
1917 comp->ActionRequest = INSTALLSTATE_SOURCE;
1919 case msidbComponentAttributesOptional:
1920 comp->Action = INSTALLSTATE_DEFAULT;
1921 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1924 comp->Action = INSTALLSTATE_LOCAL;
1925 comp->ActionRequest = INSTALLSTATE_LOCAL;
1931 * A lot is done in this function aside from just the costing.
1932 * The costing needs to be implemented at some point but for now I am going
1933 * to focus on the directory building
1936 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1938 static const WCHAR ExecSeqQuery[] =
1939 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1940 '`','D','i','r','e','c','t','o','r','y','`',0};
1941 static const WCHAR ConditionQuery[] =
1942 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1943 '`','C','o','n','d','i','t','i','o','n','`',0};
1944 static const WCHAR szCosting[] =
1945 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1946 static const WCHAR szlevel[] =
1947 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1948 static const WCHAR szOne[] = { '1', 0 };
1955 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1956 return ERROR_SUCCESS;
1958 TRACE("Building Directory properties\n");
1960 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1961 if (rc == ERROR_SUCCESS)
1963 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1965 msiobj_release(&view->hdr);
1968 load_all_component_states(package);
1970 TRACE("File calculations\n");
1972 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1974 MSICOMPONENT* comp = file->Component;
1980 if (file->IsCompressed)
1982 comp->ForceLocalState = TRUE;
1983 comp->Action = INSTALLSTATE_LOCAL;
1984 comp->ActionRequest = INSTALLSTATE_LOCAL;
1987 /* calculate target */
1988 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1990 msi_free(file->TargetPath);
1992 TRACE("file %s is named %s\n",
1993 debugstr_w(file->File),debugstr_w(file->FileName));
1995 file->TargetPath = build_directory_name(2, p, file->FileName);
1999 TRACE("file %s resolves to %s\n",
2000 debugstr_w(file->File),debugstr_w(file->TargetPath));
2002 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2004 file->state = msifs_missing;
2005 comp->Cost += file->FileSize;
2015 static WCHAR name[] = {'\\',0};
2016 static const WCHAR name_fmt[] =
2017 {'%','u','.','%','u','.','%','u','.','%','u',0};
2018 WCHAR filever[0x100];
2019 VS_FIXEDFILEINFO *lpVer;
2021 TRACE("Version comparison..\n");
2022 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2023 version = msi_alloc(versize);
2024 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2026 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2028 sprintfW(filever,name_fmt,
2029 HIWORD(lpVer->dwFileVersionMS),
2030 LOWORD(lpVer->dwFileVersionMS),
2031 HIWORD(lpVer->dwFileVersionLS),
2032 LOWORD(lpVer->dwFileVersionLS));
2034 TRACE("new %s old %s\n", debugstr_w(file->Version),
2035 debugstr_w(filever));
2036 if (strcmpiW(filever,file->Version)<0)
2038 file->state = msifs_overwrite;
2039 /* FIXME: cost should be diff in size */
2040 comp->Cost += file->FileSize;
2043 file->state = msifs_present;
2047 file->state = msifs_present;
2050 TRACE("Evaluating Condition Table\n");
2052 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2053 if (rc == ERROR_SUCCESS)
2055 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2057 msiobj_release(&view->hdr);
2060 TRACE("Enabling or Disabling Components\n");
2061 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2063 if (comp->Condition)
2065 if (MSI_EvaluateConditionW(package,
2066 comp->Condition) == MSICONDITION_FALSE)
2068 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2069 comp->Enabled = FALSE;
2074 MSI_SetPropertyW(package,szCosting,szOne);
2075 /* set default run level if not set */
2076 level = msi_dup_property( package, szlevel );
2078 MSI_SetPropertyW(package,szlevel, szOne);
2081 ACTION_UpdateInstallStates(package);
2083 return MSI_SetFeatureStates(package);
2086 /* OK this value is "interpreted" and then formatted based on the
2087 first few characters */
2088 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2092 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2098 LPWSTR deformated = NULL;
2101 deformat_string(package, &value[2], &deformated);
2103 /* binary value type */
2107 *size = (strlenW(ptr)/2)+1;
2109 *size = strlenW(ptr)/2;
2111 data = msi_alloc(*size);
2117 /* if uneven pad with a zero in front */
2123 data[count] = (BYTE)strtol(byte,NULL,0);
2125 TRACE("Uneven byte count\n");
2133 data[count] = (BYTE)strtol(byte,NULL,0);
2136 msi_free(deformated);
2138 TRACE("Data %i bytes(%i)\n",*size,count);
2145 deformat_string(package, &value[1], &deformated);
2148 *size = sizeof(DWORD);
2149 data = msi_alloc(*size);
2155 if ( (*p < '0') || (*p > '9') )
2161 if (deformated[0] == '-')
2164 TRACE("DWORD %i\n",*(LPDWORD)data);
2166 msi_free(deformated);
2171 static const WCHAR szMulti[] = {'[','~',']',0};
2180 *type=REG_EXPAND_SZ;
2188 if (strstrW(value,szMulti))
2189 *type = REG_MULTI_SZ;
2191 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2196 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2198 MSIPACKAGE *package = (MSIPACKAGE*)param;
2199 static const WCHAR szHCR[] =
2200 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2201 'R','O','O','T','\\',0};
2202 static const WCHAR szHCU[] =
2203 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2204 'U','S','E','R','\\',0};
2205 static const WCHAR szHLM[] =
2206 {'H','K','E','Y','_','L','O','C','A','L','_',
2207 'M','A','C','H','I','N','E','\\',0};
2208 static const WCHAR szHU[] =
2209 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2211 LPSTR value_data = NULL;
2212 HKEY root_key, hkey;
2215 LPCWSTR szRoot, component, name, key, value;
2220 BOOL check_first = FALSE;
2223 ui_progress(package,2,0,0,0);
2230 component = MSI_RecordGetString(row, 6);
2231 comp = get_loaded_component(package,component);
2233 return ERROR_SUCCESS;
2235 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2237 TRACE("Skipping write due to disabled component %s\n",
2238 debugstr_w(component));
2240 comp->Action = comp->Installed;
2242 return ERROR_SUCCESS;
2245 comp->Action = INSTALLSTATE_LOCAL;
2247 name = MSI_RecordGetString(row, 4);
2248 if( MSI_RecordIsNull(row,5) && name )
2250 /* null values can have special meanings */
2251 if (name[0]=='-' && name[1] == 0)
2252 return ERROR_SUCCESS;
2253 else if ((name[0]=='+' && name[1] == 0) ||
2254 (name[0] == '*' && name[1] == 0))
2259 root = MSI_RecordGetInteger(row,2);
2260 key = MSI_RecordGetString(row, 3);
2262 /* get the root key */
2267 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2268 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2269 if (all_users && all_users[0] == '1')
2271 root_key = HKEY_LOCAL_MACHINE;
2276 root_key = HKEY_CURRENT_USER;
2279 msi_free(all_users);
2282 case 0: root_key = HKEY_CLASSES_ROOT;
2285 case 1: root_key = HKEY_CURRENT_USER;
2288 case 2: root_key = HKEY_LOCAL_MACHINE;
2291 case 3: root_key = HKEY_USERS;
2295 ERR("Unknown root %i\n",root);
2301 return ERROR_SUCCESS;
2303 deformat_string(package, key , &deformated);
2304 size = strlenW(deformated) + strlenW(szRoot) + 1;
2305 uikey = msi_alloc(size*sizeof(WCHAR));
2306 strcpyW(uikey,szRoot);
2307 strcatW(uikey,deformated);
2309 if (RegCreateKeyW( root_key, deformated, &hkey))
2311 ERR("Could not create key %s\n",debugstr_w(deformated));
2312 msi_free(deformated);
2314 return ERROR_SUCCESS;
2316 msi_free(deformated);
2318 value = MSI_RecordGetString(row,5);
2320 value_data = parse_value(package, value, &type, &size);
2323 static const WCHAR szEmpty[] = {0};
2324 value_data = (LPSTR)strdupW(szEmpty);
2329 deformat_string(package, name, &deformated);
2331 /* get the double nulls to terminate SZ_MULTI */
2332 if (type == REG_MULTI_SZ)
2333 size +=sizeof(WCHAR);
2337 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2339 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2344 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2345 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2347 TRACE("value %s of %s checked already exists\n",
2348 debugstr_w(deformated), debugstr_w(uikey));
2352 TRACE("Checked and setting value %s of %s\n",
2353 debugstr_w(deformated), debugstr_w(uikey));
2354 if (deformated || size)
2355 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2360 uirow = MSI_CreateRecord(3);
2361 MSI_RecordSetStringW(uirow,2,deformated);
2362 MSI_RecordSetStringW(uirow,1,uikey);
2365 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2367 MSI_RecordSetStringW(uirow,3,value);
2369 ui_actiondata(package,szWriteRegistryValues,uirow);
2370 msiobj_release( &uirow->hdr );
2372 msi_free(value_data);
2373 msi_free(deformated);
2376 return ERROR_SUCCESS;
2379 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2383 static const WCHAR ExecSeqQuery[] =
2384 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2385 '`','R','e','g','i','s','t','r','y','`',0 };
2387 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2388 if (rc != ERROR_SUCCESS)
2389 return ERROR_SUCCESS;
2391 /* increment progress bar each time action data is sent */
2392 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2394 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2396 msiobj_release(&view->hdr);
2400 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2402 package->script->CurrentlyScripting = TRUE;
2404 return ERROR_SUCCESS;
2408 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2413 static const WCHAR q1[]=
2414 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2415 '`','R','e','g','i','s','t','r','y','`',0};
2418 MSIFEATURE *feature;
2421 TRACE("InstallValidate\n");
2423 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2424 if (rc == ERROR_SUCCESS)
2426 MSI_IterateRecords( view, &progress, NULL, package );
2427 msiobj_release( &view->hdr );
2428 total += progress * REG_PROGRESS_VALUE;
2431 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2432 total += COMPONENT_PROGRESS_VALUE;
2434 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2435 total += file->FileSize;
2437 ui_progress(package,0,total,0,0);
2439 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2441 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2442 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2443 feature->ActionRequest);
2446 return ERROR_SUCCESS;
2449 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2451 MSIPACKAGE* package = (MSIPACKAGE*)param;
2452 LPCWSTR cond = NULL;
2453 LPCWSTR message = NULL;
2454 static const WCHAR title[]=
2455 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2457 cond = MSI_RecordGetString(row,1);
2459 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2462 message = MSI_RecordGetString(row,2);
2463 deformat_string(package,message,&deformated);
2464 MessageBoxW(NULL,deformated,title,MB_OK);
2465 msi_free(deformated);
2466 return ERROR_FUNCTION_FAILED;
2469 return ERROR_SUCCESS;
2472 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2475 MSIQUERY * view = NULL;
2476 static const WCHAR ExecSeqQuery[] =
2477 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2478 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2480 TRACE("Checking launch conditions\n");
2482 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2483 if (rc != ERROR_SUCCESS)
2484 return ERROR_SUCCESS;
2486 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2487 msiobj_release(&view->hdr);
2492 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2496 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2498 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2500 MSIRECORD * row = 0;
2502 LPWSTR deformated,buffer,deformated_name;
2504 static const WCHAR ExecSeqQuery[] =
2505 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2506 '`','R','e','g','i','s','t','r','y','`',' ',
2507 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2508 ' ','=',' ' ,'\'','%','s','\'',0 };
2509 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2510 static const WCHAR fmt2[]=
2511 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2513 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2517 root = MSI_RecordGetInteger(row,2);
2518 key = MSI_RecordGetString(row, 3);
2519 name = MSI_RecordGetString(row, 4);
2520 deformat_string(package, key , &deformated);
2521 deformat_string(package, name, &deformated_name);
2523 len = strlenW(deformated) + 6;
2524 if (deformated_name)
2525 len+=strlenW(deformated_name);
2527 buffer = msi_alloc( len *sizeof(WCHAR));
2529 if (deformated_name)
2530 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2532 sprintfW(buffer,fmt,root,deformated);
2534 msi_free(deformated);
2535 msi_free(deformated_name);
2536 msiobj_release(&row->hdr);
2540 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2542 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2547 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2550 return strdupW( file->TargetPath );
2555 static HKEY openSharedDLLsKey(void)
2558 static const WCHAR path[] =
2559 {'S','o','f','t','w','a','r','e','\\',
2560 'M','i','c','r','o','s','o','f','t','\\',
2561 'W','i','n','d','o','w','s','\\',
2562 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2563 'S','h','a','r','e','d','D','L','L','s',0};
2565 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2569 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2574 DWORD sz = sizeof(count);
2577 hkey = openSharedDLLsKey();
2578 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2579 if (rc != ERROR_SUCCESS)
2585 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2589 hkey = openSharedDLLsKey();
2591 msi_reg_set_val_dword( hkey, path, count );
2593 RegDeleteValueW(hkey,path);
2599 * Return TRUE if the count should be written out and FALSE if not
2601 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2603 MSIFEATURE *feature;
2607 /* only refcount DLLs */
2608 if (comp->KeyPath == NULL ||
2609 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2610 comp->Attributes & msidbComponentAttributesODBCDataSource)
2614 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2615 write = (count > 0);
2617 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2621 /* increment counts */
2622 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2626 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2629 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2631 if ( cl->component == comp )
2636 /* decrement counts */
2637 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2641 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2644 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2646 if ( cl->component == comp )
2651 /* ref count all the files in the component */
2656 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2658 if (file->Component == comp)
2659 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2663 /* add a count for permenent */
2664 if (comp->Attributes & msidbComponentAttributesPermanent)
2667 comp->RefCount = count;
2670 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2674 * Ok further analysis makes me think that this work is
2675 * actually done in the PublishComponents and PublishFeatures
2676 * step, and not here. It appears like the keypath and all that is
2677 * resolved in this step, however actually written in the Publish steps.
2678 * But we will leave it here for now because it is unclear
2680 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2682 WCHAR squished_pc[GUID_SIZE];
2683 WCHAR squished_cc[GUID_SIZE];
2686 HKEY hkey=0,hkey2=0;
2688 /* writes the Component and Features values to the registry */
2690 rc = MSIREG_OpenComponents(&hkey);
2691 if (rc != ERROR_SUCCESS)
2694 squash_guid(package->ProductCode,squished_pc);
2695 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2697 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2701 ui_progress(package,2,0,0,0);
2702 if (!comp->ComponentId)
2705 squash_guid(comp->ComponentId,squished_cc);
2707 msi_free(comp->FullKeypath);
2708 comp->FullKeypath = resolve_keypath( package, comp );
2710 /* do the refcounting */
2711 ACTION_RefCountComponent( package, comp );
2713 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2714 debugstr_w(comp->Component),
2715 debugstr_w(squished_cc),
2716 debugstr_w(comp->FullKeypath),
2719 * Write the keypath out if the component is to be registered
2720 * and delete the key if the component is to be deregistered
2722 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2724 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2725 if (rc != ERROR_SUCCESS)
2728 if (!comp->FullKeypath)
2731 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2733 if (comp->Attributes & msidbComponentAttributesPermanent)
2735 static const WCHAR szPermKey[] =
2736 { '0','0','0','0','0','0','0','0','0','0','0','0',
2737 '0','0','0','0','0','0','0','0','0','0','0','0',
2738 '0','0','0','0','0','0','0','0',0 };
2740 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2746 uirow = MSI_CreateRecord(3);
2747 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2748 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2749 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2750 ui_actiondata(package,szProcessComponents,uirow);
2751 msiobj_release( &uirow->hdr );
2753 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2757 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2758 if (rc != ERROR_SUCCESS)
2761 RegDeleteValueW(hkey2,squished_pc);
2763 /* if the key is empty delete it */
2764 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2766 if (res == ERROR_NO_MORE_ITEMS)
2767 RegDeleteKeyW(hkey,squished_cc);
2770 uirow = MSI_CreateRecord(2);
2771 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2772 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2773 ui_actiondata(package,szProcessComponents,uirow);
2774 msiobj_release( &uirow->hdr );
2789 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2790 LPWSTR lpszName, LONG_PTR lParam)
2793 typelib_struct *tl_struct = (typelib_struct*) lParam;
2794 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2798 if (!IS_INTRESOURCE(lpszName))
2800 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2804 sz = strlenW(tl_struct->source)+4;
2805 sz *= sizeof(WCHAR);
2807 if ((INT_PTR)lpszName == 1)
2808 tl_struct->path = strdupW(tl_struct->source);
2811 tl_struct->path = msi_alloc(sz);
2812 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2815 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2816 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2817 if (!SUCCEEDED(res))
2819 msi_free(tl_struct->path);
2820 tl_struct->path = NULL;
2825 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2826 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2828 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2832 msi_free(tl_struct->path);
2833 tl_struct->path = NULL;
2835 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2836 ITypeLib_Release(tl_struct->ptLib);
2841 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2843 MSIPACKAGE* package = (MSIPACKAGE*)param;
2847 typelib_struct tl_struct;
2849 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2851 component = MSI_RecordGetString(row,3);
2852 comp = get_loaded_component(package,component);
2854 return ERROR_SUCCESS;
2856 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2858 TRACE("Skipping typelib reg due to disabled component\n");
2860 comp->Action = comp->Installed;
2862 return ERROR_SUCCESS;
2865 comp->Action = INSTALLSTATE_LOCAL;
2867 file = get_loaded_file( package, comp->KeyPath );
2869 return ERROR_SUCCESS;
2871 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2875 guid = MSI_RecordGetString(row,1);
2876 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2877 tl_struct.source = strdupW( file->TargetPath );
2878 tl_struct.path = NULL;
2880 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2881 (LONG_PTR)&tl_struct);
2889 helpid = MSI_RecordGetString(row,6);
2892 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2893 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2896 if (!SUCCEEDED(res))
2897 ERR("Failed to register type library %s\n",
2898 debugstr_w(tl_struct.path));
2901 ui_actiondata(package,szRegisterTypeLibraries,row);
2903 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2906 ITypeLib_Release(tl_struct.ptLib);
2907 msi_free(tl_struct.path);
2910 ERR("Failed to load type library %s\n",
2911 debugstr_w(tl_struct.source));
2913 FreeLibrary(module);
2914 msi_free(tl_struct.source);
2917 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2919 return ERROR_SUCCESS;
2922 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2925 * OK this is a bit confusing.. I am given a _Component key and I believe
2926 * that the file that is being registered as a type library is the "key file
2927 * of that component" which I interpret to mean "The file in the KeyPath of
2932 static const WCHAR Query[] =
2933 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2934 '`','T','y','p','e','L','i','b','`',0};
2936 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2937 if (rc != ERROR_SUCCESS)
2938 return ERROR_SUCCESS;
2940 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2941 msiobj_release(&view->hdr);
2945 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2947 MSIPACKAGE *package = (MSIPACKAGE*)param;
2948 LPWSTR target_file, target_folder, filename;
2949 LPCWSTR buffer, extension;
2951 static const WCHAR szlnk[]={'.','l','n','k',0};
2952 IShellLinkW *sl = NULL;
2953 IPersistFile *pf = NULL;
2956 buffer = MSI_RecordGetString(row,4);
2957 comp = get_loaded_component(package,buffer);
2959 return ERROR_SUCCESS;
2961 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2963 TRACE("Skipping shortcut creation due to disabled component\n");
2965 comp->Action = comp->Installed;
2967 return ERROR_SUCCESS;
2970 comp->Action = INSTALLSTATE_LOCAL;
2972 ui_actiondata(package,szCreateShortcuts,row);
2974 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2975 &IID_IShellLinkW, (LPVOID *) &sl );
2979 ERR("CLSID_ShellLink not available\n");
2983 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2986 ERR("QueryInterface(IID_IPersistFile) failed\n");
2990 buffer = MSI_RecordGetString(row,2);
2991 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2993 /* may be needed because of a bug somehwere else */
2994 create_full_pathW(target_folder);
2996 filename = msi_dup_record_field( row, 3 );
2997 reduce_to_longfilename(filename);
2999 extension = strchrW(filename,'.');
3000 if (!extension || strcmpiW(extension,szlnk))
3002 int len = strlenW(filename);
3003 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3004 memcpy(filename + len, szlnk, sizeof(szlnk));
3006 target_file = build_directory_name(2, target_folder, filename);
3007 msi_free(target_folder);
3010 buffer = MSI_RecordGetString(row,5);
3011 if (strchrW(buffer,'['))
3014 deformat_string(package,buffer,&deformated);
3015 IShellLinkW_SetPath(sl,deformated);
3016 msi_free(deformated);
3020 FIXME("poorly handled shortcut format, advertised shortcut\n");
3021 IShellLinkW_SetPath(sl,comp->FullKeypath);
3024 if (!MSI_RecordIsNull(row,6))
3027 buffer = MSI_RecordGetString(row,6);
3028 deformat_string(package,buffer,&deformated);
3029 IShellLinkW_SetArguments(sl,deformated);
3030 msi_free(deformated);
3033 if (!MSI_RecordIsNull(row,7))
3035 buffer = MSI_RecordGetString(row,7);
3036 IShellLinkW_SetDescription(sl,buffer);
3039 if (!MSI_RecordIsNull(row,8))
3040 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3042 if (!MSI_RecordIsNull(row,9))
3047 buffer = MSI_RecordGetString(row,9);
3049 Path = build_icon_path(package,buffer);
3050 index = MSI_RecordGetInteger(row,10);
3052 /* no value means 0 */
3053 if (index == MSI_NULL_INTEGER)
3056 IShellLinkW_SetIconLocation(sl,Path,index);
3060 if (!MSI_RecordIsNull(row,11))
3061 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3063 if (!MSI_RecordIsNull(row,12))
3066 buffer = MSI_RecordGetString(row,12);
3067 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3069 IShellLinkW_SetWorkingDirectory(sl,Path);
3073 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3074 IPersistFile_Save(pf,target_file,FALSE);
3076 msi_free(target_file);
3080 IPersistFile_Release( pf );
3082 IShellLinkW_Release( sl );
3084 return ERROR_SUCCESS;
3087 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3092 static const WCHAR Query[] =
3093 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3094 '`','S','h','o','r','t','c','u','t','`',0};
3096 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3097 if (rc != ERROR_SUCCESS)
3098 return ERROR_SUCCESS;
3100 res = CoInitialize( NULL );
3103 ERR("CoInitialize failed\n");
3104 return ERROR_FUNCTION_FAILED;
3107 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3108 msiobj_release(&view->hdr);
3115 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3117 MSIPACKAGE* package = (MSIPACKAGE*)param;
3126 FileName = MSI_RecordGetString(row,1);
3129 ERR("Unable to get FileName\n");
3130 return ERROR_SUCCESS;
3133 FilePath = build_icon_path(package,FileName);
3135 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3137 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3138 FILE_ATTRIBUTE_NORMAL, NULL);
3140 if (the_file == INVALID_HANDLE_VALUE)
3142 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3144 return ERROR_SUCCESS;
3151 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3152 if (rc != ERROR_SUCCESS)
3154 ERR("Failed to get stream\n");
3155 CloseHandle(the_file);
3156 DeleteFileW(FilePath);
3159 WriteFile(the_file,buffer,sz,&write,NULL);
3160 } while (sz == 1024);
3164 CloseHandle(the_file);
3166 uirow = MSI_CreateRecord(1);
3167 MSI_RecordSetStringW(uirow,1,FileName);
3168 ui_actiondata(package,szPublishProduct,uirow);
3169 msiobj_release( &uirow->hdr );
3171 return ERROR_SUCCESS;
3175 * 99% of the work done here is only done for
3176 * advertised installs. However this is where the
3177 * Icon table is processed and written out
3178 * so that is what I am going to do here.
3180 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3184 static const WCHAR Query[]=
3185 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3186 '`','I','c','o','n','`',0};
3187 /* for registry stuff */
3190 static const WCHAR szProductLanguage[] =
3191 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3192 static const WCHAR szARPProductIcon[] =
3193 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3194 static const WCHAR szProductVersion[] =
3195 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3199 MSIHANDLE hDb, hSumInfo;
3201 /* write out icon files */
3203 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3204 if (rc == ERROR_SUCCESS)
3206 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3207 msiobj_release(&view->hdr);
3210 /* ok there is a lot more done here but i need to figure out what */
3212 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3213 if (rc != ERROR_SUCCESS)
3216 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3217 if (rc != ERROR_SUCCESS)
3221 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3222 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3225 langid = msi_get_property_int( package, szProductLanguage, 0 );
3226 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3228 buffer = msi_dup_property( package, szARPProductIcon );
3231 LPWSTR path = build_icon_path(package,buffer);
3232 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3237 buffer = msi_dup_property( package, szProductVersion );
3240 DWORD verdword = msi_version_str_to_dword(buffer);
3241 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3245 /* FIXME: Need to write more keys to the user registry */
3247 hDb= alloc_msihandle( &package->db->hdr );
3249 rc = ERROR_NOT_ENOUGH_MEMORY;
3252 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3253 MsiCloseHandle(hDb);
3254 if (rc == ERROR_SUCCESS)
3256 WCHAR guidbuffer[0x200];
3258 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3260 if (rc == ERROR_SUCCESS)
3262 WCHAR squashed[GUID_SIZE];
3263 /* for now we only care about the first guid */
3264 LPWSTR ptr = strchrW(guidbuffer,';');
3266 squash_guid(guidbuffer,squashed);
3267 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3271 ERR("Unable to query Revision_Number...\n");
3274 MsiCloseHandle(hSumInfo);
3278 ERR("Unable to open Summary Information\n");
3290 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3292 MSIPACKAGE *package = (MSIPACKAGE*)param;
3293 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3294 LPWSTR deformated_section, deformated_key, deformated_value;
3295 LPWSTR folder, fullname = NULL;
3299 static const WCHAR szWindowsFolder[] =
3300 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3302 component = MSI_RecordGetString(row, 8);
3303 comp = get_loaded_component(package,component);
3305 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3307 TRACE("Skipping ini file due to disabled component %s\n",
3308 debugstr_w(component));
3310 comp->Action = comp->Installed;
3312 return ERROR_SUCCESS;
3315 comp->Action = INSTALLSTATE_LOCAL;
3317 identifier = MSI_RecordGetString(row,1);
3318 filename = MSI_RecordGetString(row,2);
3319 dirproperty = MSI_RecordGetString(row,3);
3320 section = MSI_RecordGetString(row,4);
3321 key = MSI_RecordGetString(row,5);
3322 value = MSI_RecordGetString(row,6);
3323 action = MSI_RecordGetInteger(row,7);
3325 deformat_string(package,section,&deformated_section);
3326 deformat_string(package,key,&deformated_key);
3327 deformat_string(package,value,&deformated_value);
3331 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3333 folder = msi_dup_property( package, dirproperty );
3336 folder = msi_dup_property( package, szWindowsFolder );
3340 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3344 fullname = build_directory_name(2, folder, filename);
3348 TRACE("Adding value %s to section %s in %s\n",
3349 debugstr_w(deformated_key), debugstr_w(deformated_section),
3350 debugstr_w(fullname));
3351 WritePrivateProfileStringW(deformated_section, deformated_key,
3352 deformated_value, fullname);
3354 else if (action == 1)
3357 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3358 returned, 10, fullname);
3359 if (returned[0] == 0)
3361 TRACE("Adding value %s to section %s in %s\n",
3362 debugstr_w(deformated_key), debugstr_w(deformated_section),
3363 debugstr_w(fullname));
3365 WritePrivateProfileStringW(deformated_section, deformated_key,
3366 deformated_value, fullname);
3369 else if (action == 3)
3370 FIXME("Append to existing section not yet implemented\n");
3372 uirow = MSI_CreateRecord(4);
3373 MSI_RecordSetStringW(uirow,1,identifier);
3374 MSI_RecordSetStringW(uirow,2,deformated_section);
3375 MSI_RecordSetStringW(uirow,3,deformated_key);
3376 MSI_RecordSetStringW(uirow,4,deformated_value);
3377 ui_actiondata(package,szWriteIniValues,uirow);
3378 msiobj_release( &uirow->hdr );
3382 msi_free(deformated_key);
3383 msi_free(deformated_value);
3384 msi_free(deformated_section);
3385 return ERROR_SUCCESS;
3388 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3392 static const WCHAR ExecSeqQuery[] =
3393 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3394 '`','I','n','i','F','i','l','e','`',0};
3396 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3397 if (rc != ERROR_SUCCESS)
3399 TRACE("no IniFile table\n");
3400 return ERROR_SUCCESS;
3403 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3404 msiobj_release(&view->hdr);
3408 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3410 MSIPACKAGE *package = (MSIPACKAGE*)param;
3415 static const WCHAR ExeStr[] =
3416 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3417 static const WCHAR close[] = {'\"',0};
3419 PROCESS_INFORMATION info;
3424 memset(&si,0,sizeof(STARTUPINFOW));
3426 filename = MSI_RecordGetString(row,1);
3427 file = get_loaded_file( package, filename );
3431 ERR("Unable to find file id %s\n",debugstr_w(filename));
3432 return ERROR_SUCCESS;
3435 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3437 FullName = msi_alloc(len*sizeof(WCHAR));
3438 strcpyW(FullName,ExeStr);
3439 strcatW( FullName, file->TargetPath );
3440 strcatW(FullName,close);
3442 TRACE("Registering %s\n",debugstr_w(FullName));
3443 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3447 msi_dialog_check_messages(info.hProcess);
3452 uirow = MSI_CreateRecord( 2 );
3453 uipath = strdupW( file->TargetPath );
3454 p = strrchrW(uipath,'\\');
3457 MSI_RecordSetStringW( uirow, 1, &p[2] );
3458 MSI_RecordSetStringW( uirow, 2, uipath);
3459 ui_actiondata( package, szSelfRegModules, uirow);
3460 msiobj_release( &uirow->hdr );
3462 /* FIXME: call ui_progress? */
3464 return ERROR_SUCCESS;
3467 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3471 static const WCHAR ExecSeqQuery[] =
3472 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3473 '`','S','e','l','f','R','e','g','`',0};
3475 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3476 if (rc != ERROR_SUCCESS)
3478 TRACE("no SelfReg table\n");
3479 return ERROR_SUCCESS;
3482 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3483 msiobj_release(&view->hdr);
3485 return ERROR_SUCCESS;
3488 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3490 MSIFEATURE *feature;
3495 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3496 if (rc != ERROR_SUCCESS)
3499 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3500 if (rc != ERROR_SUCCESS)
3503 /* here the guids are base 85 encoded */
3504 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3510 BOOL absent = FALSE;
3513 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3514 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3515 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3519 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3523 if (feature->Feature_Parent)
3524 size += strlenW( feature->Feature_Parent )+2;
3526 data = msi_alloc(size * sizeof(WCHAR));
3529 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3531 MSICOMPONENT* component = cl->component;
3535 if (component->ComponentId)
3537 TRACE("From %s\n",debugstr_w(component->ComponentId));
3538 CLSIDFromString(component->ComponentId, &clsid);
3539 encode_base85_guid(&clsid,buf);
3540 TRACE("to %s\n",debugstr_w(buf));
3544 if (feature->Feature_Parent)
3546 static const WCHAR sep[] = {'\2',0};
3548 strcatW(data,feature->Feature_Parent);
3551 msi_reg_set_val_str( hkey, feature->Feature, data );
3555 if (feature->Feature_Parent)
3556 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3559 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3560 (LPBYTE)feature->Feature_Parent,size);
3564 size += 2*sizeof(WCHAR);
3565 data = msi_alloc(size);
3568 if (feature->Feature_Parent)
3569 strcpyW( &data[1], feature->Feature_Parent );
3570 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3576 uirow = MSI_CreateRecord( 1 );
3577 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3578 ui_actiondata( package, szPublishFeatures, uirow);
3579 msiobj_release( &uirow->hdr );
3580 /* FIXME: call ui_progress? */
3589 static UINT msi_get_local_package_name( LPWSTR path )
3591 static const WCHAR szInstaller[] = {
3592 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3593 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3597 time = GetTickCount();
3598 GetWindowsDirectoryW( path, MAX_PATH );
3599 lstrcatW( path, szInstaller );
3600 CreateDirectoryW( path, NULL );
3602 len = lstrlenW(path);
3603 for (i=0; i<0x10000; i++)
3605 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3606 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3607 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3608 if (handle != INVALID_HANDLE_VALUE)
3610 CloseHandle(handle);
3613 if (GetLastError() != ERROR_FILE_EXISTS &&
3614 GetLastError() != ERROR_SHARING_VIOLATION)
3615 return ERROR_FUNCTION_FAILED;
3618 return ERROR_SUCCESS;
3621 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3623 static const WCHAR szOriginalDatabase[] =
3624 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3625 WCHAR packagefile[MAX_PATH];
3629 r = msi_get_local_package_name( packagefile );
3630 if (r != ERROR_SUCCESS)
3633 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3635 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3636 r = CopyFileW( msiFilePath, packagefile, FALSE);
3637 msi_free( msiFilePath );
3641 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3642 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3643 return ERROR_FUNCTION_FAILED;
3646 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3647 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3648 return ERROR_SUCCESS;
3651 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3653 LPWSTR prop, val, key;
3654 static const LPCSTR propval[] = {
3655 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3656 "ARPCONTACT", "Contact",
3657 "ARPCOMMENTS", "Comments",
3658 "ProductName", "DisplayName",
3659 "ProductVersion", "DisplayVersion",
3660 "ARPHELPLINK", "HelpLink",
3661 "ARPHELPTELEPHONE", "HelpTelephone",
3662 "ARPINSTALLLOCATION", "InstallLocation",
3663 "SourceDir", "InstallSource",
3664 "Manufacturer", "Publisher",
3665 "ARPREADME", "Readme",
3667 "ARPURLINFOABOUT", "URLInfoAbout",
3668 "ARPURLUPDATEINFO", "URLUpdateInfo",
3671 const LPCSTR *p = propval;
3675 prop = strdupAtoW( *p++ );
3676 key = strdupAtoW( *p++ );
3677 val = msi_dup_property( package, prop );
3678 msi_reg_set_val_str( hkey, key, val );
3683 return ERROR_SUCCESS;
3686 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3689 LPWSTR buffer = NULL;
3692 static const WCHAR szWindowsInstaller[] =
3693 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3694 static const WCHAR szUpgradeCode[] =
3695 {'U','p','g','r','a','d','e','C','o','d','e',0};
3696 static const WCHAR modpath_fmt[] =
3697 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3698 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3699 static const WCHAR szModifyPath[] =
3700 {'M','o','d','i','f','y','P','a','t','h',0};
3701 static const WCHAR szUninstallString[] =
3702 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3703 static const WCHAR szEstimatedSize[] =
3704 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3705 static const WCHAR szProductLanguage[] =
3706 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3707 static const WCHAR szProductVersion[] =
3708 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3711 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3712 LPWSTR upgrade_code;
3715 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3716 if (rc != ERROR_SUCCESS)
3719 /* dump all the info i can grab */
3720 /* FIXME: Flesh out more information */
3722 msi_write_uninstall_property_vals( package, hkey );
3724 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3726 msi_make_package_local( package, hkey );
3728 /* do ModifyPath and UninstallString */
3729 size = deformat_string(package,modpath_fmt,&buffer);
3730 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3731 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3734 /* FIXME: Write real Estimated Size when we have it */
3735 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3737 GetLocalTime(&systime);
3738 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3739 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3741 langid = msi_get_property_int( package, szProductLanguage, 0 );
3742 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3744 buffer = msi_dup_property( package, szProductVersion );
3747 DWORD verdword = msi_version_str_to_dword(buffer);
3749 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3750 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3751 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3755 /* Handle Upgrade Codes */
3756 upgrade_code = msi_dup_property( package, szUpgradeCode );
3761 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3762 squash_guid(package->ProductCode,squashed);
3763 msi_reg_set_val_str( hkey2, squashed, NULL );
3765 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3766 squash_guid(package->ProductCode,squashed);
3767 msi_reg_set_val_str( hkey2, squashed, NULL );
3770 msi_free(upgrade_code);
3775 /* FIXME: call ui_actiondata */
3777 return ERROR_SUCCESS;
3780 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3782 return execute_script(package,INSTALL_SCRIPT);
3785 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3789 /* turn off scheduleing */
3790 package->script->CurrentlyScripting= FALSE;
3792 /* first do the same as an InstallExecute */
3793 rc = ACTION_InstallExecute(package);
3794 if (rc != ERROR_SUCCESS)
3797 /* then handle Commit Actions */
3798 rc = execute_script(package,COMMIT_SCRIPT);
3803 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3805 static const WCHAR RunOnce[] = {
3806 'S','o','f','t','w','a','r','e','\\',
3807 'M','i','c','r','o','s','o','f','t','\\',
3808 'W','i','n','d','o','w','s','\\',
3809 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3810 'R','u','n','O','n','c','e',0};
3811 static const WCHAR InstallRunOnce[] = {
3812 'S','o','f','t','w','a','r','e','\\',
3813 'M','i','c','r','o','s','o','f','t','\\',
3814 'W','i','n','d','o','w','s','\\',
3815 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3816 'I','n','s','t','a','l','l','e','r','\\',
3817 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3819 static const WCHAR msiexec_fmt[] = {
3821 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3822 '\"','%','s','\"',0};
3823 static const WCHAR install_fmt[] = {
3824 '/','I',' ','\"','%','s','\"',' ',
3825 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3826 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3827 WCHAR buffer[256], sysdir[MAX_PATH];
3829 WCHAR squished_pc[100];
3831 squash_guid(package->ProductCode,squished_pc);
3833 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3834 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3835 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3838 msi_reg_set_val_str( hkey, squished_pc, buffer );
3841 TRACE("Reboot command %s\n",debugstr_w(buffer));
3843 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3844 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3846 msi_reg_set_val_str( hkey, squished_pc, buffer );
3849 return ERROR_INSTALL_SUSPEND;
3852 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3857 * we are currently doing what should be done here in the top level Install
3858 * however for Adminastrative and uninstalls this step will be needed
3860 if (!package->PackagePath)
3861 return ERROR_SUCCESS;
3863 attrib = GetFileAttributesW(package->PackagePath);
3864 if (attrib == INVALID_FILE_ATTRIBUTES)
3870 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3871 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3872 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3873 if (rc == ERROR_MORE_DATA)
3875 prompt = msi_alloc(size * sizeof(WCHAR));
3876 MsiSourceListGetInfoW(package->ProductCode, NULL,
3877 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3878 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3881 prompt = strdupW(package->PackagePath);
3883 msg = generate_error_string(package,1302,1,prompt);
3884 while(attrib == INVALID_FILE_ATTRIBUTES)
3886 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3889 rc = ERROR_INSTALL_USEREXIT;
3892 attrib = GetFileAttributesW(package->PackagePath);
3898 return ERROR_SUCCESS;
3903 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3910 static const WCHAR szPropKeys[][80] =
3912 {'P','r','o','d','u','c','t','I','D',0},
3913 {'U','S','E','R','N','A','M','E',0},
3914 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3918 static const WCHAR szRegKeys[][80] =
3920 {'P','r','o','d','u','c','t','I','D',0},
3921 {'R','e','g','O','w','n','e','r',0},
3922 {'R','e','g','C','o','m','p','a','n','y',0},
3926 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3928 return ERROR_SUCCESS;
3930 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3931 if (rc != ERROR_SUCCESS)
3934 for( i = 0; szPropKeys[i][0]; i++ )
3936 buffer = msi_dup_property( package, szPropKeys[i] );
3937 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3942 msi_free(productid);
3945 /* FIXME: call ui_actiondata */
3947 return ERROR_SUCCESS;
3951 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3955 package->script->InWhatSequence |= SEQUENCE_EXEC;
3956 rc = ACTION_ProcessExecSequence(package,FALSE);
3961 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3963 MSIPACKAGE *package = (MSIPACKAGE*)param;
3964 LPCWSTR compgroupid=NULL;
3965 LPCWSTR feature=NULL;
3966 LPCWSTR text = NULL;
3967 LPCWSTR qualifier = NULL;
3968 LPCWSTR component = NULL;
3969 LPWSTR advertise = NULL;
3970 LPWSTR output = NULL;
3972 UINT rc = ERROR_SUCCESS;
3977 component = MSI_RecordGetString(rec,3);
3978 comp = get_loaded_component(package,component);
3980 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3981 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3982 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3984 TRACE("Skipping: Component %s not scheduled for install\n",
3985 debugstr_w(component));
3987 return ERROR_SUCCESS;
3990 compgroupid = MSI_RecordGetString(rec,1);
3991 qualifier = MSI_RecordGetString(rec,2);
3993 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
3994 if (rc != ERROR_SUCCESS)
3997 text = MSI_RecordGetString(rec,4);
3998 feature = MSI_RecordGetString(rec,5);
4000 advertise = create_component_advertise_string(package, comp, feature);
4002 sz = strlenW(advertise);
4005 sz += lstrlenW(text);
4008 sz *= sizeof(WCHAR);
4010 output = msi_alloc_zero(sz);
4011 strcpyW(output,advertise);
4012 msi_free(advertise);
4015 strcatW(output,text);
4017 msi_reg_set_val_multi_str( hkey, qualifier, output );
4024 uirow = MSI_CreateRecord( 2 );
4025 MSI_RecordSetStringW( uirow, 1, compgroupid );
4026 MSI_RecordSetStringW( uirow, 2, qualifier);
4027 ui_actiondata( package, szPublishComponents, uirow);
4028 msiobj_release( &uirow->hdr );
4029 /* FIXME: call ui_progress? */
4035 * At present I am ignorning the advertised components part of this and only
4036 * focusing on the qualified component sets
4038 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4042 static const WCHAR ExecSeqQuery[] =
4043 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4044 '`','P','u','b','l','i','s','h',
4045 'C','o','m','p','o','n','e','n','t','`',0};
4047 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4048 if (rc != ERROR_SUCCESS)
4049 return ERROR_SUCCESS;
4051 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4052 msiobj_release(&view->hdr);
4057 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4058 LPCSTR action, LPCWSTR table )
4060 static const WCHAR query[] = {
4061 'S','E','L','E','C','T',' ','*',' ',
4062 'F','R','O','M',' ','`','%','s','`',0 };
4063 MSIQUERY *view = NULL;
4067 r = MSI_OpenQuery( package->db, &view, query, table );
4068 if (r == ERROR_SUCCESS)
4070 r = MSI_IterateRecords(view, &count, NULL, package);
4071 msiobj_release(&view->hdr);
4075 FIXME("%s -> %u ignored %s table values\n",
4076 action, count, debugstr_w(table));
4078 return ERROR_SUCCESS;
4081 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4083 TRACE("%p\n", package);
4084 return ERROR_SUCCESS;
4087 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4089 static const WCHAR table[] =
4090 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4091 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4094 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4096 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4097 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4100 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4102 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4103 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4106 static UINT ACTION_BindImage( MSIPACKAGE *package )
4108 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4109 return msi_unimplemented_action_stub( package, "BindImage", table );
4112 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4114 static const WCHAR table[] = {
4115 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4116 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4119 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4121 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4122 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4125 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4127 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4128 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4131 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4133 static const WCHAR table[] = {
4134 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4135 return msi_unimplemented_action_stub( package, "InstallServices", table );
4138 static UINT ACTION_StartServices( MSIPACKAGE *package )
4140 static const WCHAR table[] = {
4141 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4142 return msi_unimplemented_action_stub( package, "StartServices", table );
4145 static UINT ACTION_StopServices( MSIPACKAGE *package )
4147 static const WCHAR table[] = {
4148 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4149 return msi_unimplemented_action_stub( package, "StopServices", table );
4152 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4154 static const WCHAR table[] = {
4155 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4156 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4159 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4161 static const WCHAR table[] = {
4162 'E','n','v','i','r','o','n','m','e','n','t',0 };
4163 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4166 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4168 static const WCHAR table[] = {
4169 'E','n','v','i','r','o','n','m','e','n','t',0 };
4170 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4173 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4175 static const WCHAR table[] = {
4176 'M','s','i','A','s','s','e','m','b','l','y',0 };
4177 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4180 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4182 static const WCHAR table[] = {
4183 'M','s','i','A','s','s','e','m','b','l','y',0 };
4184 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4187 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4189 static const WCHAR table[] = { 'F','o','n','t',0 };
4190 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4193 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4195 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4196 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4199 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4201 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4202 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4205 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4207 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4208 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4211 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4213 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4214 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4217 static struct _actions StandardActions[] = {
4218 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4219 { szAppSearch, ACTION_AppSearch },
4220 { szBindImage, ACTION_BindImage },
4221 { szCCPSearch, ACTION_CCPSearch},
4222 { szCostFinalize, ACTION_CostFinalize },
4223 { szCostInitialize, ACTION_CostInitialize },
4224 { szCreateFolders, ACTION_CreateFolders },
4225 { szCreateShortcuts, ACTION_CreateShortcuts },
4226 { szDeleteServices, ACTION_DeleteServices },
4227 { szDisableRollback, NULL},
4228 { szDuplicateFiles, ACTION_DuplicateFiles },
4229 { szExecuteAction, ACTION_ExecuteAction },
4230 { szFileCost, ACTION_FileCost },
4231 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4232 { szForceReboot, ACTION_ForceReboot },
4233 { szInstallAdminPackage, NULL},
4234 { szInstallExecute, ACTION_InstallExecute },
4235 { szInstallExecuteAgain, ACTION_InstallExecute },
4236 { szInstallFiles, ACTION_InstallFiles},
4237 { szInstallFinalize, ACTION_InstallFinalize },
4238 { szInstallInitialize, ACTION_InstallInitialize },
4239 { szInstallSFPCatalogFile, NULL},
4240 { szInstallValidate, ACTION_InstallValidate },
4241 { szIsolateComponents, ACTION_IsolateComponents },
4242 { szLaunchConditions, ACTION_LaunchConditions },
4243 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4244 { szMoveFiles, ACTION_MoveFiles },
4245 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4246 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4247 { szInstallODBC, NULL},
4248 { szInstallServices, ACTION_InstallServices },
4249 { szPatchFiles, ACTION_PatchFiles },
4250 { szProcessComponents, ACTION_ProcessComponents },
4251 { szPublishComponents, ACTION_PublishComponents },
4252 { szPublishFeatures, ACTION_PublishFeatures },
4253 { szPublishProduct, ACTION_PublishProduct },
4254 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4255 { szRegisterComPlus, ACTION_RegisterComPlus},
4256 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4257 { szRegisterFonts, ACTION_RegisterFonts },
4258 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4259 { szRegisterProduct, ACTION_RegisterProduct },
4260 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4261 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4262 { szRegisterUser, ACTION_RegisterUser},
4263 { szRemoveDuplicateFiles, NULL},
4264 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4265 { szRemoveExistingProducts, NULL},
4266 { szRemoveFiles, ACTION_RemoveFiles},
4267 { szRemoveFolders, NULL},
4268 { szRemoveIniValues, ACTION_RemoveIniValues },
4269 { szRemoveODBC, NULL},
4270 { szRemoveRegistryValues, NULL},
4271 { szRemoveShortcuts, NULL},
4272 { szResolveSource, ACTION_ResolveSource},
4273 { szRMCCPSearch, ACTION_RMCCPSearch},
4274 { szScheduleReboot, NULL},
4275 { szSelfRegModules, ACTION_SelfRegModules },
4276 { szSelfUnregModules, ACTION_SelfUnregModules },
4277 { szSetODBCFolders, NULL},
4278 { szStartServices, ACTION_StartServices },
4279 { szStopServices, ACTION_StopServices },
4280 { szUnpublishComponents, NULL},
4281 { szUnpublishFeatures, NULL},
4282 { szUnregisterClassInfo, NULL},
4283 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4284 { szUnregisterExtensionInfo, NULL},
4285 { szUnregisterFonts, ACTION_UnregisterFonts },
4286 { szUnregisterMIMEInfo, NULL},
4287 { szUnregisterProgIdInfo, NULL},
4288 { szUnregisterTypeLibraries, NULL},
4289 { szValidateProductID, NULL},
4290 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4291 { szWriteIniValues, ACTION_WriteIniValues },
4292 { szWriteRegistryValues, ACTION_WriteRegistryValues},