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
39 #include "wine/debug.h"
44 #include "wine/unicode.h"
47 #define REG_PROGRESS_VALUE 13200
48 #define COMPONENT_PROGRESS_VALUE 24000
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
55 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
56 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
57 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
60 * consts and values used
62 static const WCHAR c_colon[] = {'C',':','\\',0};
64 static const WCHAR szCreateFolders[] =
65 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
66 static const WCHAR szCostFinalize[] =
67 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
68 const WCHAR szInstallFiles[] =
69 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
70 const WCHAR szDuplicateFiles[] =
71 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
72 static const WCHAR szWriteRegistryValues[] =
73 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
74 'V','a','l','u','e','s',0};
75 static const WCHAR szCostInitialize[] =
76 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
77 static const WCHAR szFileCost[] =
78 {'F','i','l','e','C','o','s','t',0};
79 static const WCHAR szInstallInitialize[] =
80 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
81 static const WCHAR szInstallValidate[] =
82 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
83 static const WCHAR szLaunchConditions[] =
84 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
85 static const WCHAR szProcessComponents[] =
86 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
87 static const WCHAR szRegisterTypeLibraries[] =
88 {'R','e','g','i','s','t','e','r','T','y','p','e',
89 'L','i','b','r','a','r','i','e','s',0};
90 const WCHAR szRegisterClassInfo[] =
91 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
92 const WCHAR szRegisterProgIdInfo[] =
93 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
94 static const WCHAR szCreateShortcuts[] =
95 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
96 static const WCHAR szPublishProduct[] =
97 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
98 static const WCHAR szWriteIniValues[] =
99 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
100 static const WCHAR szSelfRegModules[] =
101 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
102 static const WCHAR szPublishFeatures[] =
103 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
104 static const WCHAR szRegisterProduct[] =
105 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
106 static const WCHAR szInstallExecute[] =
107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
108 static const WCHAR szInstallExecuteAgain[] =
109 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
110 'A','g','a','i','n',0};
111 static const WCHAR szInstallFinalize[] =
112 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
113 static const WCHAR szForceReboot[] =
114 {'F','o','r','c','e','R','e','b','o','o','t',0};
115 static const WCHAR szResolveSource[] =
116 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
117 static const WCHAR szAppSearch[] =
118 {'A','p','p','S','e','a','r','c','h',0};
119 static const WCHAR szAllocateRegistrySpace[] =
120 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
121 'S','p','a','c','e',0};
122 static const WCHAR szBindImage[] =
123 {'B','i','n','d','I','m','a','g','e',0};
124 static const WCHAR szCCPSearch[] =
125 {'C','C','P','S','e','a','r','c','h',0};
126 static const WCHAR szDeleteServices[] =
127 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
128 static const WCHAR szDisableRollback[] =
129 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
130 static const WCHAR szExecuteAction[] =
131 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
132 const WCHAR szFindRelatedProducts[] =
133 {'F','i','n','d','R','e','l','a','t','e','d',
134 'P','r','o','d','u','c','t','s',0};
135 static const WCHAR szInstallAdminPackage[] =
136 {'I','n','s','t','a','l','l','A','d','m','i','n',
137 'P','a','c','k','a','g','e',0};
138 static const WCHAR szInstallSFPCatalogFile[] =
139 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
141 static const WCHAR szIsolateComponents[] =
142 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
143 const WCHAR szMigrateFeatureStates[] =
144 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
145 'S','t','a','t','e','s',0};
146 const WCHAR szMoveFiles[] =
147 {'M','o','v','e','F','i','l','e','s',0};
148 static const WCHAR szMsiPublishAssemblies[] =
149 {'M','s','i','P','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szMsiUnpublishAssemblies[] =
152 {'M','s','i','U','n','p','u','b','l','i','s','h',
153 'A','s','s','e','m','b','l','i','e','s',0};
154 static const WCHAR szInstallODBC[] =
155 {'I','n','s','t','a','l','l','O','D','B','C',0};
156 static const WCHAR szInstallServices[] =
157 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
158 const WCHAR szPatchFiles[] =
159 {'P','a','t','c','h','F','i','l','e','s',0};
160 static const WCHAR szPublishComponents[] =
161 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
162 static const WCHAR szRegisterComPlus[] =
163 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
164 const WCHAR szRegisterExtensionInfo[] =
165 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
167 static const WCHAR szRegisterFonts[] =
168 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 const WCHAR szRegisterMIMEInfo[] =
170 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szRegisterUser[] =
172 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
173 const WCHAR szRemoveDuplicateFiles[] =
174 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
175 'F','i','l','e','s',0};
176 static const WCHAR szRemoveEnvironmentStrings[] =
177 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
178 'S','t','r','i','n','g','s',0};
179 const WCHAR szRemoveExistingProducts[] =
180 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
181 'P','r','o','d','u','c','t','s',0};
182 const WCHAR szRemoveFiles[] =
183 {'R','e','m','o','v','e','F','i','l','e','s',0};
184 static const WCHAR szRemoveFolders[] =
185 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
186 static const WCHAR szRemoveIniValues[] =
187 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
188 static const WCHAR szRemoveODBC[] =
189 {'R','e','m','o','v','e','O','D','B','C',0};
190 static const WCHAR szRemoveRegistryValues[] =
191 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
192 'V','a','l','u','e','s',0};
193 static const WCHAR szRemoveShortcuts[] =
194 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
195 static const WCHAR szRMCCPSearch[] =
196 {'R','M','C','C','P','S','e','a','r','c','h',0};
197 static const WCHAR szScheduleReboot[] =
198 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
199 static const WCHAR szSelfUnregModules[] =
200 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
201 static const WCHAR szSetODBCFolders[] =
202 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
203 static const WCHAR szStartServices[] =
204 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
205 static const WCHAR szStopServices[] =
206 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
207 static const WCHAR szUnpublishComponents[] =
208 {'U','n','p','u','b','l','i','s','h',
209 'C','o','m','p','o','n','e','n','t','s',0};
210 static const WCHAR szUnpublishFeatures[] =
211 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
212 const WCHAR szUnregisterClassInfo[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
215 static const WCHAR szUnregisterComPlus[] =
216 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const WCHAR szUnregisterExtensionInfo[] =
218 {'U','n','r','e','g','i','s','t','e','r',
219 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
220 static const WCHAR szUnregisterFonts[] =
221 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const WCHAR szUnregisterMIMEInfo[] =
223 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const WCHAR szUnregisterProgIdInfo[] =
225 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
227 static const WCHAR szUnregisterTypeLibraries[] =
228 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
229 'L','i','b','r','a','r','i','e','s',0};
230 static const WCHAR szValidateProductID[] =
231 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
232 static const WCHAR szWriteEnvironmentStrings[] =
233 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
234 'S','t','r','i','n','g','s',0};
236 /* action handlers */
237 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
241 STANDARDACTIONHANDLER handler;
244 static const struct _actions StandardActions[];
247 /********************************************************
249 ********************************************************/
251 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
253 static const WCHAR Query_t[] =
254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
255 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
256 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
257 ' ','\'','%','s','\'',0};
260 row = MSI_QueryGetRecord( package->db, Query_t, action );
263 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
264 msiobj_release(&row->hdr);
267 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
271 static const WCHAR template_s[]=
272 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
274 static const WCHAR template_e[]=
275 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
276 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
278 static const WCHAR format[] =
279 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
283 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
285 sprintfW(message,template_s,timet,action);
287 sprintfW(message,template_e,timet,action,rc);
289 row = MSI_CreateRecord(1);
290 MSI_RecordSetStringW(row,1,message);
292 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
293 msiobj_release(&row->hdr);
296 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
301 LPWSTR prop = NULL, val = NULL;
304 return ERROR_SUCCESS;
316 TRACE("Looking at %s\n",debugstr_w(ptr));
318 ptr2 = strchrW(ptr,'=');
321 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
328 prop = msi_alloc((len+1)*sizeof(WCHAR));
329 memcpy(prop,ptr,len*sizeof(WCHAR));
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
352 if (lstrlenW(prop) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
362 return ERROR_SUCCESS;
366 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
369 LPWSTR p, *ret = NULL;
375 /* count the number of substrings */
376 for ( pc = str, count = 0; pc; count++ )
378 pc = strchrW( pc, sep );
383 /* allocate space for an array of substring pointers and the substrings */
384 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
385 (lstrlenW(str)+1) * sizeof(WCHAR) );
389 /* copy the string and set the pointers */
390 p = (LPWSTR) &ret[count+1];
392 for( count = 0; (ret[count] = p); count++ )
394 p = strchrW( p, sep );
402 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
404 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code, patch_product;
408 prod_code = msi_dup_property( package, szProductCode );
409 patch_product = msi_get_suminfo_product( patch );
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
413 if ( strstrW( patch_product, prod_code ) )
416 ret = ERROR_FUNCTION_FAILED;
418 msi_free( patch_product );
419 msi_free( prod_code );
424 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
425 MSIDATABASE *patch_db, LPCWSTR name )
427 UINT ret = ERROR_FUNCTION_FAILED;
428 IStorage *stg = NULL;
431 TRACE("%p %s\n", package, debugstr_w(name) );
435 ERR("expected a colon in %s\n", debugstr_w(name));
436 return ERROR_FUNCTION_FAILED;
439 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
442 ret = msi_check_transform_applicable( package, stg );
443 if (ret == ERROR_SUCCESS)
444 msi_table_apply_transform( package->db, stg );
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
447 IStorage_Release( stg );
450 ERR("failed to open substorage %s\n", debugstr_w(name));
452 return ERROR_SUCCESS;
455 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
457 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list, *guids, product_code;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
461 product_code = msi_dup_property( package, szProdCode );
464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
466 return ERROR_SUCCESS;
469 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
470 guids = msi_split_string( guid_list, ';' );
471 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
473 if (!lstrcmpW( guids[i], product_code ))
477 msi_free( guid_list );
478 msi_free( product_code );
483 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
486 LPWSTR str, *substorage;
487 UINT i, r = ERROR_SUCCESS;
489 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
491 return ERROR_FUNCTION_FAILED;
493 msi_check_patch_applicable( package, si );
495 /* enumerate the substorage */
496 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
497 substorage = msi_split_string( str, ';' );
498 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
499 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
500 msi_free( substorage );
503 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
505 msiobj_release( &si->hdr );
510 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
512 MSIDATABASE *patch_db = NULL;
515 TRACE("%p %s\n", package, debugstr_w( file ) );
518 * We probably want to make sure we only open a patch collection here.
519 * Patch collections (.msp) and databases (.msi) have different GUIDs
520 * but currently MSI_OpenDatabaseW will accept both.
522 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
523 if ( r != ERROR_SUCCESS )
525 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
529 msi_parse_patch_summary( package, patch_db );
532 * There might be a CAB file in the patch package,
533 * so append it to the list of storage to search for streams.
535 append_storage_to_db( package->db, patch_db->storage );
537 msiobj_release( &patch_db->hdr );
539 return ERROR_SUCCESS;
542 /* get the PATCH property, and apply all the patches it specifies */
543 static UINT msi_apply_patches( MSIPACKAGE *package )
545 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
546 LPWSTR patch_list, *patches;
547 UINT i, r = ERROR_SUCCESS;
549 patch_list = msi_dup_property( package, szPatch );
551 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
553 patches = msi_split_string( patch_list, ';' );
554 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
555 r = msi_apply_patch_package( package, patches[i] );
558 msi_free( patch_list );
563 static UINT msi_apply_transforms( MSIPACKAGE *package )
565 static const WCHAR szTransforms[] = {
566 'T','R','A','N','S','F','O','R','M','S',0 };
567 LPWSTR xform_list, *xforms;
568 UINT i, r = ERROR_SUCCESS;
570 xform_list = msi_dup_property( package, szTransforms );
571 xforms = msi_split_string( xform_list, ';' );
573 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
575 if (xforms[i][0] == ':')
576 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
578 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
582 msi_free( xform_list );
587 BOOL ui_sequence_exists( MSIPACKAGE *package )
592 static const WCHAR ExecSeqQuery [] =
593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
594 '`','I','n','s','t','a','l','l',
595 'U','I','S','e','q','u','e','n','c','e','`',
596 ' ','W','H','E','R','E',' ',
597 '`','S','e','q','u','e','n','c','e','`',' ',
598 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
599 '`','S','e','q','u','e','n','c','e','`',0};
601 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
602 if (rc == ERROR_SUCCESS)
604 msiobj_release(&view->hdr);
611 /****************************************************
612 * TOP level entry points
613 *****************************************************/
615 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
616 LPCWSTR szCommandLine )
619 BOOL ui = FALSE, ui_exists;
620 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
621 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
622 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
624 MSI_SetPropertyW(package, szAction, szInstall);
626 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
628 package->script->InWhatSequence = SEQUENCE_INSTALL;
632 LPWSTR p, check, path;
634 path = strdupW(szPackagePath);
635 p = strrchrW(path,'\\');
644 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
645 GetCurrentDirectoryW(MAX_PATH,path);
649 check = msi_dup_property( package, cszSourceDir );
651 MSI_SetPropertyW(package, cszSourceDir, path);
654 check = msi_dup_property( package, cszSOURCEDIR );
656 MSI_SetPropertyW(package, cszSOURCEDIR, path);
658 msi_free( package->PackagePath );
659 package->PackagePath = path;
664 msi_parse_command_line( package, szCommandLine );
666 msi_apply_transforms( package );
667 msi_apply_patches( package );
669 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
671 package->script->InWhatSequence |= SEQUENCE_UI;
672 rc = ACTION_ProcessUISequence(package);
674 ui_exists = ui_sequence_exists(package);
675 if (rc == ERROR_SUCCESS || !ui_exists)
677 package->script->InWhatSequence |= SEQUENCE_EXEC;
678 rc = ACTION_ProcessExecSequence(package,ui_exists);
682 rc = ACTION_ProcessExecSequence(package,FALSE);
686 /* install was halted but should be considered a success */
690 package->script->CurrentlyScripting= FALSE;
692 /* process the ending type action */
693 if (rc == ERROR_SUCCESS)
694 ACTION_PerformActionSequence(package,-1,ui);
695 else if (rc == ERROR_INSTALL_USEREXIT)
696 ACTION_PerformActionSequence(package,-2,ui);
697 else if (rc == ERROR_INSTALL_SUSPEND)
698 ACTION_PerformActionSequence(package,-4,ui);
700 ACTION_PerformActionSequence(package,-3,ui);
702 /* finish up running custom actions */
703 ACTION_FinishCustomActions(package);
708 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
710 UINT rc = ERROR_SUCCESS;
712 static const WCHAR ExecSeqQuery[] =
713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
714 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
715 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
716 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
718 static const WCHAR UISeqQuery[] =
719 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
720 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
721 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
722 ' ', '=',' ','%','i',0};
725 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
727 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
731 LPCWSTR action, cond;
733 TRACE("Running the actions\n");
735 /* check conditions */
736 cond = MSI_RecordGetString(row,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
742 action = MSI_RecordGetString(row,1);
745 ERR("failed to fetch action\n");
746 rc = ERROR_FUNCTION_FAILED;
751 rc = ACTION_PerformUIAction(package,action,-1);
753 rc = ACTION_PerformAction(package,action,-1,FALSE);
755 msiobj_release(&row->hdr);
766 } iterate_action_param;
768 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
770 iterate_action_param *iap= (iterate_action_param*)param;
772 LPCWSTR cond, action;
774 action = MSI_RecordGetString(row,1);
777 ERR("Error is retrieving action name\n");
778 return ERROR_FUNCTION_FAILED;
781 /* check conditions */
782 cond = MSI_RecordGetString(row,2);
784 /* this is a hack to skip errors in the condition code */
785 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
787 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
788 return ERROR_SUCCESS;
792 rc = ACTION_PerformUIAction(iap->package,action,-1);
794 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
796 msi_dialog_check_messages( NULL );
798 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
799 rc = iap->package->CurrentInstallState;
801 if (rc == ERROR_FUNCTION_NOT_CALLED)
804 if (rc != ERROR_SUCCESS)
805 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
810 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
814 static const WCHAR query[] =
815 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
817 ' ','W','H','E','R','E',' ',
818 '`','S','e','q','u','e','n','c','e','`',' ',
819 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
820 '`','S','e','q','u','e','n','c','e','`',0};
821 iterate_action_param iap;
824 * FIXME: probably should be checking UILevel in the
825 * ACTION_PerformUIAction/ACTION_PerformAction
826 * rather than saving the UI level here. Those
827 * two functions can be merged too.
829 iap.package = package;
832 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
834 r = MSI_OpenQuery( package->db, &view, query, szTable );
835 if (r == ERROR_SUCCESS)
837 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
838 msiobj_release(&view->hdr);
844 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
848 static const WCHAR ExecSeqQuery[] =
849 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
850 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
851 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
852 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
853 'O','R','D','E','R',' ', 'B','Y',' ',
854 '`','S','e','q','u','e','n','c','e','`',0 };
856 static const WCHAR IVQuery[] =
857 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
858 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
859 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
860 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
861 ' ','\'', 'I','n','s','t','a','l','l',
862 'V','a','l','i','d','a','t','e','\'', 0};
864 iterate_action_param iap;
866 iap.package = package;
869 if (package->script->ExecuteSequenceRun)
871 TRACE("Execute Sequence already Run\n");
872 return ERROR_SUCCESS;
875 package->script->ExecuteSequenceRun = TRUE;
877 /* get the sequence number */
880 row = MSI_QueryGetRecord(package->db, IVQuery);
882 return ERROR_FUNCTION_FAILED;
883 seq = MSI_RecordGetInteger(row,1);
884 msiobj_release(&row->hdr);
887 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
888 if (rc == ERROR_SUCCESS)
890 TRACE("Running the actions\n");
892 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
893 msiobj_release(&view->hdr);
899 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
903 static const WCHAR ExecSeqQuery [] =
904 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
905 '`','I','n','s','t','a','l','l',
906 'U','I','S','e','q','u','e','n','c','e','`',
907 ' ','W','H','E','R','E',' ',
908 '`','S','e','q','u','e','n','c','e','`',' ',
909 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
910 '`','S','e','q','u','e','n','c','e','`',0};
911 iterate_action_param iap;
913 iap.package = package;
916 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
918 if (rc == ERROR_SUCCESS)
920 TRACE("Running the actions\n");
922 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
923 msiobj_release(&view->hdr);
929 /********************************************************
930 * ACTION helper functions and functions that perform the actions
931 *******************************************************/
932 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
933 UINT* rc, BOOL force )
939 if (!run && !package->script->CurrentlyScripting)
944 if (strcmpW(action,szInstallFinalize) == 0 ||
945 strcmpW(action,szInstallExecute) == 0 ||
946 strcmpW(action,szInstallExecuteAgain) == 0)
951 while (StandardActions[i].action != NULL)
953 if (strcmpW(StandardActions[i].action, action)==0)
957 ui_actioninfo(package, action, TRUE, 0);
958 *rc = schedule_action(package,INSTALL_SCRIPT,action);
959 ui_actioninfo(package, action, FALSE, *rc);
963 ui_actionstart(package, action);
964 if (StandardActions[i].handler)
966 *rc = StandardActions[i].handler(package);
970 FIXME("unhandled standard action %s\n",debugstr_w(action));
982 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
983 UINT* rc, UINT script, BOOL force )
988 arc = ACTION_CustomAction(package, action, script, force);
990 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
999 * A lot of actions are really important even if they don't do anything
1000 * explicit... Lots of properties are set at the beginning of the installation
1001 * CostFinalize does a bunch of work to translate the directories and such
1003 * But until I get write access to the database that is hard, so I am going to
1004 * hack it to see if I can get something to run.
1006 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1008 UINT rc = ERROR_SUCCESS;
1011 TRACE("Performing action (%s)\n",debugstr_w(action));
1013 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1016 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1020 FIXME("unhandled msi action %s\n",debugstr_w(action));
1021 rc = ERROR_FUNCTION_NOT_CALLED;
1027 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1029 UINT rc = ERROR_SUCCESS;
1030 BOOL handled = FALSE;
1032 TRACE("Performing action (%s)\n",debugstr_w(action));
1034 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1037 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1039 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1044 FIXME("unhandled msi action %s\n",debugstr_w(action));
1045 rc = ERROR_FUNCTION_NOT_CALLED;
1053 * Actual Action Handlers
1056 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1058 MSIPACKAGE *package = (MSIPACKAGE*)param;
1064 dir = MSI_RecordGetString(row,1);
1067 ERR("Unable to get folder id\n");
1068 return ERROR_SUCCESS;
1071 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1074 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1075 return ERROR_SUCCESS;
1078 TRACE("Folder is %s\n",debugstr_w(full_path));
1081 uirow = MSI_CreateRecord(1);
1082 MSI_RecordSetStringW(uirow,1,full_path);
1083 ui_actiondata(package,szCreateFolders,uirow);
1084 msiobj_release( &uirow->hdr );
1086 if (folder->State == 0)
1087 create_full_pathW(full_path);
1091 msi_free(full_path);
1092 return ERROR_SUCCESS;
1095 /* FIXME: probably should merge this with the above function */
1096 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1098 UINT rc = ERROR_SUCCESS;
1100 LPWSTR install_path;
1102 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1104 return ERROR_FUNCTION_FAILED;
1106 /* create the path */
1107 if (folder->State == 0)
1109 create_full_pathW(install_path);
1112 msi_free(install_path);
1117 UINT msi_create_component_directories( MSIPACKAGE *package )
1121 /* create all the folders required by the components are going to install */
1122 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1124 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1126 msi_create_directory( package, comp->Directory );
1129 return ERROR_SUCCESS;
1133 * Also we cannot enable/disable components either, so for now I am just going
1134 * to do all the directories for all the components.
1136 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1138 static const WCHAR ExecSeqQuery[] =
1139 {'S','E','L','E','C','T',' ',
1140 '`','D','i','r','e','c','t','o','r','y','_','`',
1141 ' ','F','R','O','M',' ',
1142 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1146 /* create all the empty folders specified in the CreateFolder table */
1147 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1148 if (rc != ERROR_SUCCESS)
1149 return ERROR_SUCCESS;
1151 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1152 msiobj_release(&view->hdr);
1154 msi_create_component_directories( package );
1159 static UINT load_component( MSIRECORD *row, LPVOID param )
1161 MSIPACKAGE *package = param;
1164 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1166 return ERROR_FUNCTION_FAILED;
1168 list_add_tail( &package->components, &comp->entry );
1170 /* fill in the data */
1171 comp->Component = msi_dup_record_field( row, 1 );
1173 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1175 comp->ComponentId = msi_dup_record_field( row, 2 );
1176 comp->Directory = msi_dup_record_field( row, 3 );
1177 comp->Attributes = MSI_RecordGetInteger(row,4);
1178 comp->Condition = msi_dup_record_field( row, 5 );
1179 comp->KeyPath = msi_dup_record_field( row, 6 );
1181 comp->Installed = INSTALLSTATE_UNKNOWN;
1182 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1184 return ERROR_SUCCESS;
1187 static UINT load_all_components( MSIPACKAGE *package )
1189 static const WCHAR query[] = {
1190 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1191 '`','C','o','m','p','o','n','e','n','t','`',0 };
1195 if (!list_empty(&package->components))
1196 return ERROR_SUCCESS;
1198 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1199 if (r != ERROR_SUCCESS)
1202 r = MSI_IterateRecords(view, NULL, load_component, package);
1203 msiobj_release(&view->hdr);
1208 MSIPACKAGE *package;
1209 MSIFEATURE *feature;
1212 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1216 cl = msi_alloc( sizeof (*cl) );
1218 return ERROR_NOT_ENOUGH_MEMORY;
1219 cl->component = comp;
1220 list_add_tail( &feature->Components, &cl->entry );
1222 return ERROR_SUCCESS;
1225 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1229 fl = msi_alloc( sizeof(*fl) );
1231 return ERROR_NOT_ENOUGH_MEMORY;
1232 fl->feature = child;
1233 list_add_tail( &parent->Children, &fl->entry );
1235 return ERROR_SUCCESS;
1238 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1240 _ilfs* ilfs= (_ilfs*)param;
1244 component = MSI_RecordGetString(row,1);
1246 /* check to see if the component is already loaded */
1247 comp = get_loaded_component( ilfs->package, component );
1250 ERR("unknown component %s\n", debugstr_w(component));
1251 return ERROR_FUNCTION_FAILED;
1254 add_feature_component( ilfs->feature, comp );
1255 comp->Enabled = TRUE;
1257 return ERROR_SUCCESS;
1260 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1262 MSIFEATURE *feature;
1264 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1266 if ( !lstrcmpW( feature->Feature, name ) )
1273 static UINT load_feature(MSIRECORD * row, LPVOID param)
1275 MSIPACKAGE* package = (MSIPACKAGE*)param;
1276 MSIFEATURE* feature;
1277 static const WCHAR Query1[] =
1278 {'S','E','L','E','C','T',' ',
1279 '`','C','o','m','p','o','n','e','n','t','_','`',
1280 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1281 'C','o','m','p','o','n','e','n','t','s','`',' ',
1282 'W','H','E','R','E',' ',
1283 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1288 /* fill in the data */
1290 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1292 return ERROR_NOT_ENOUGH_MEMORY;
1294 list_init( &feature->Children );
1295 list_init( &feature->Components );
1297 feature->Feature = msi_dup_record_field( row, 1 );
1299 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1301 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1302 feature->Title = msi_dup_record_field( row, 3 );
1303 feature->Description = msi_dup_record_field( row, 4 );
1305 if (!MSI_RecordIsNull(row,5))
1306 feature->Display = MSI_RecordGetInteger(row,5);
1308 feature->Level= MSI_RecordGetInteger(row,6);
1309 feature->Directory = msi_dup_record_field( row, 7 );
1310 feature->Attributes = MSI_RecordGetInteger(row,8);
1312 feature->Installed = INSTALLSTATE_UNKNOWN;
1313 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1315 list_add_tail( &package->features, &feature->entry );
1317 /* load feature components */
1319 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1320 if (rc != ERROR_SUCCESS)
1321 return ERROR_SUCCESS;
1323 ilfs.package = package;
1324 ilfs.feature = feature;
1326 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1327 msiobj_release(&view->hdr);
1329 return ERROR_SUCCESS;
1332 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1334 MSIPACKAGE* package = (MSIPACKAGE*)param;
1335 MSIFEATURE *parent, *child;
1337 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1339 return ERROR_FUNCTION_FAILED;
1341 if (!child->Feature_Parent)
1342 return ERROR_SUCCESS;
1344 parent = find_feature_by_name( package, child->Feature_Parent );
1346 return ERROR_FUNCTION_FAILED;
1348 add_feature_child( parent, child );
1349 return ERROR_SUCCESS;
1352 static UINT load_all_features( MSIPACKAGE *package )
1354 static const WCHAR query[] = {
1355 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1356 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1357 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1361 if (!list_empty(&package->features))
1362 return ERROR_SUCCESS;
1364 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1365 if (r != ERROR_SUCCESS)
1368 r = MSI_IterateRecords( view, NULL, load_feature, package );
1369 if (r != ERROR_SUCCESS)
1372 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1373 msiobj_release( &view->hdr );
1378 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1389 static UINT load_file(MSIRECORD *row, LPVOID param)
1391 MSIPACKAGE* package = (MSIPACKAGE*)param;
1395 /* fill in the data */
1397 file = msi_alloc_zero( sizeof (MSIFILE) );
1399 return ERROR_NOT_ENOUGH_MEMORY;
1401 file->File = msi_dup_record_field( row, 1 );
1403 component = MSI_RecordGetString( row, 2 );
1404 file->Component = get_loaded_component( package, component );
1406 if (!file->Component)
1407 ERR("Unfound Component %s\n",debugstr_w(component));
1409 file->FileName = msi_dup_record_field( row, 3 );
1410 reduce_to_longfilename( file->FileName );
1412 file->ShortName = msi_dup_record_field( row, 3 );
1413 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1415 file->FileSize = MSI_RecordGetInteger( row, 4 );
1416 file->Version = msi_dup_record_field( row, 5 );
1417 file->Language = msi_dup_record_field( row, 6 );
1418 file->Attributes = MSI_RecordGetInteger( row, 7 );
1419 file->Sequence = MSI_RecordGetInteger( row, 8 );
1421 file->state = msifs_invalid;
1423 /* if the compressed bits are not set in the file attributes,
1424 * then read the information from the package word count property
1426 if (file->Attributes & msidbFileAttributesCompressed)
1428 file->IsCompressed = TRUE;
1430 else if (file->Attributes & msidbFileAttributesNoncompressed)
1432 file->IsCompressed = FALSE;
1436 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1439 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1441 list_add_tail( &package->files, &file->entry );
1443 return ERROR_SUCCESS;
1446 static UINT load_all_files(MSIPACKAGE *package)
1450 static const WCHAR Query[] =
1451 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1452 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1453 '`','S','e','q','u','e','n','c','e','`', 0};
1455 if (!list_empty(&package->files))
1456 return ERROR_SUCCESS;
1458 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1459 if (rc != ERROR_SUCCESS)
1460 return ERROR_SUCCESS;
1462 rc = MSI_IterateRecords(view, NULL, load_file, package);
1463 msiobj_release(&view->hdr);
1465 return ERROR_SUCCESS;
1468 static UINT load_folder( MSIRECORD *row, LPVOID param )
1470 MSIPACKAGE *package = param;
1471 static const WCHAR szDot[] = { '.',0 };
1472 static WCHAR szEmpty[] = { 0 };
1473 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1476 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1478 return ERROR_NOT_ENOUGH_MEMORY;
1480 folder->Directory = msi_dup_record_field( row, 1 );
1482 TRACE("%s\n", debugstr_w(folder->Directory));
1484 p = msi_dup_record_field(row, 3);
1486 /* split src and target dir */
1488 src_short = folder_split_path( p, ':' );
1490 /* split the long and short paths */
1491 tgt_long = folder_split_path( tgt_short, '|' );
1492 src_long = folder_split_path( src_short, '|' );
1494 /* check for no-op dirs */
1495 if (!lstrcmpW(szDot, tgt_short))
1496 tgt_short = szEmpty;
1497 if (!lstrcmpW(szDot, src_short))
1498 src_short = szEmpty;
1501 tgt_long = tgt_short;
1504 src_short = tgt_short;
1505 src_long = tgt_long;
1509 src_long = src_short;
1511 /* FIXME: use the target short path too */
1512 folder->TargetDefault = strdupW(tgt_long);
1513 folder->SourceShortPath = strdupW(src_short);
1514 folder->SourceLongPath = strdupW(src_long);
1517 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1518 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1519 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1521 folder->Parent = msi_dup_record_field( row, 2 );
1523 folder->Property = msi_dup_property( package, folder->Directory );
1525 list_add_tail( &package->folders, &folder->entry );
1527 TRACE("returning %p\n", folder);
1529 return ERROR_SUCCESS;
1532 static UINT load_all_folders( MSIPACKAGE *package )
1534 static const WCHAR query[] = {
1535 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1536 '`','D','i','r','e','c','t','o','r','y','`',0 };
1540 if (!list_empty(&package->folders))
1541 return ERROR_SUCCESS;
1543 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1544 if (r != ERROR_SUCCESS)
1547 r = MSI_IterateRecords(view, NULL, load_folder, package);
1548 msiobj_release(&view->hdr);
1553 * I am not doing any of the costing functionality yet.
1554 * Mostly looking at doing the Component and Feature loading
1556 * The native MSI does A LOT of modification to tables here. Mostly adding
1557 * a lot of temporary columns to the Feature and Component tables.
1559 * note: Native msi also tracks the short filename. But I am only going to
1560 * track the long ones. Also looking at this directory table
1561 * it appears that the directory table does not get the parents
1562 * resolved base on property only based on their entries in the
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1567 static const WCHAR szCosting[] =
1568 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1569 static const WCHAR szZero[] = { '0', 0 };
1571 MSI_SetPropertyW(package, szCosting, szZero);
1572 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1574 load_all_components( package );
1575 load_all_features( package );
1576 load_all_files( package );
1577 load_all_folders( package );
1579 return ERROR_SUCCESS;
1582 static UINT execute_script(MSIPACKAGE *package, UINT script )
1585 UINT rc = ERROR_SUCCESS;
1587 TRACE("Executing Script %i\n",script);
1589 if (!package->script)
1591 ERR("no script!\n");
1592 return ERROR_FUNCTION_FAILED;
1595 for (i = 0; i < package->script->ActionCount[script]; i++)
1598 action = package->script->Actions[script][i];
1599 ui_actionstart(package, action);
1600 TRACE("Executing Action (%s)\n",debugstr_w(action));
1601 rc = ACTION_PerformAction(package, action, script, TRUE);
1602 if (rc != ERROR_SUCCESS)
1605 msi_free_action_script(package, script);
1609 static UINT ACTION_FileCost(MSIPACKAGE *package)
1611 return ERROR_SUCCESS;
1614 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1618 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1622 if (!comp->ComponentId)
1625 res = MsiGetComponentPathW( package->ProductCode,
1626 comp->ComponentId, NULL, NULL);
1628 res = INSTALLSTATE_ABSENT;
1629 comp->Installed = res;
1633 /* scan for and update current install states */
1634 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1637 MSIFEATURE *feature;
1639 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1642 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1644 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1646 comp= cl->component;
1648 if (!comp->ComponentId)
1650 res = INSTALLSTATE_ABSENT;
1654 if (res == INSTALLSTATE_ABSENT)
1655 res = comp->Installed;
1658 if (res == comp->Installed)
1661 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1662 res != INSTALLSTATE_SOURCE)
1664 res = INSTALLSTATE_INCOMPLETE;
1668 feature->Installed = res;
1672 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1675 static const WCHAR all[]={'A','L','L',0};
1677 MSIFEATURE *feature;
1679 override = msi_dup_property( package, property );
1683 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1685 if (strcmpiW(override,all)==0)
1686 msi_feature_set_state( feature, state );
1689 LPWSTR ptr = override;
1690 LPWSTR ptr2 = strchrW(override,',');
1694 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1695 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1697 msi_feature_set_state( feature, state );
1703 ptr2 = strchrW(ptr,',');
1715 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1718 static const WCHAR szlevel[] =
1719 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1720 static const WCHAR szAddLocal[] =
1721 {'A','D','D','L','O','C','A','L',0};
1722 static const WCHAR szRemove[] =
1723 {'R','E','M','O','V','E',0};
1724 static const WCHAR szReinstall[] =
1725 {'R','E','I','N','S','T','A','L','L',0};
1726 BOOL override = FALSE;
1727 MSICOMPONENT* component;
1728 MSIFEATURE *feature;
1731 /* I do not know if this is where it should happen.. but */
1733 TRACE("Checking Install Level\n");
1735 install_level = msi_get_property_int( package, szlevel, 1 );
1737 /* ok here is the _real_ rub
1738 * all these activation/deactivation things happen in order and things
1739 * later on the list override things earlier on the list.
1740 * 1) INSTALLLEVEL processing
1750 * 11) FILEADDDEFAULT
1751 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1752 * ignored for all the features. seems strange, especially since it is not
1753 * documented anywhere, but it is how it works.
1755 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1756 * REMOVE are the big ones, since we don't handle administrative installs
1759 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1760 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1761 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1765 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1767 BOOL feature_state = ((feature->Level > 0) &&
1768 (feature->Level <= install_level));
1770 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1772 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1773 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1774 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1775 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1777 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1781 /* disable child features of unselected parent features */
1782 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1786 if (feature->Level > 0 && feature->Level <= install_level)
1789 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1790 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1795 /* set the Preselected Property */
1796 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1797 static const WCHAR szOne[] = { '1', 0 };
1799 MSI_SetPropertyW(package,szPreselected,szOne);
1803 * now we want to enable or disable components base on feature
1806 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1810 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1811 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1813 /* features with components that have compressed files are made local */
1814 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1816 if (cl->component->Enabled &&
1817 cl->component->ForceLocalState &&
1818 feature->Action == INSTALLSTATE_SOURCE)
1820 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1825 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1827 component = cl->component;
1829 if (!component->Enabled)
1832 switch (feature->Action)
1834 case INSTALLSTATE_ADVERTISED:
1835 component->hasAdvertiseFeature = 1;
1837 case INSTALLSTATE_SOURCE:
1838 component->hasSourceFeature = 1;
1840 case INSTALLSTATE_LOCAL:
1841 component->hasLocalFeature = 1;
1843 case INSTALLSTATE_DEFAULT:
1844 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1845 component->hasAdvertiseFeature = 1;
1846 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1847 component->hasSourceFeature = 1;
1849 component->hasLocalFeature = 1;
1857 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1859 /* if the component isn't enabled, leave it alone */
1860 if (!component->Enabled)
1863 /* check if it's local or source */
1864 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1865 (component->hasLocalFeature || component->hasSourceFeature))
1867 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1868 !component->ForceLocalState)
1869 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1871 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1875 /* if any feature is local, the component must be local too */
1876 if (component->hasLocalFeature)
1878 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1882 if (component->hasSourceFeature)
1884 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1888 if (component->hasAdvertiseFeature)
1890 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1894 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1897 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1899 if (component->Action == INSTALLSTATE_DEFAULT)
1901 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1902 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1905 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1906 debugstr_w(component->Component), component->Installed, component->Action);
1910 return ERROR_SUCCESS;
1913 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1915 MSIPACKAGE *package = (MSIPACKAGE*)param;
1920 name = MSI_RecordGetString(row,1);
1922 f = get_loaded_folder(package, name);
1923 if (!f) return ERROR_SUCCESS;
1925 /* reset the ResolvedTarget */
1926 msi_free(f->ResolvedTarget);
1927 f->ResolvedTarget = NULL;
1929 /* This helper function now does ALL the work */
1930 TRACE("Dir %s ...\n",debugstr_w(name));
1931 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1932 TRACE("resolves to %s\n",debugstr_w(path));
1935 return ERROR_SUCCESS;
1938 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1940 MSIPACKAGE *package = (MSIPACKAGE*)param;
1942 MSIFEATURE *feature;
1944 name = MSI_RecordGetString( row, 1 );
1946 feature = get_loaded_feature( package, name );
1948 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1952 Condition = MSI_RecordGetString(row,3);
1954 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1956 int level = MSI_RecordGetInteger(row,2);
1957 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1958 feature->Level = level;
1961 return ERROR_SUCCESS;
1964 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1966 static const WCHAR name_fmt[] =
1967 {'%','u','.','%','u','.','%','u','.','%','u',0};
1968 static WCHAR name[] = {'\\',0};
1969 VS_FIXEDFILEINFO *lpVer;
1970 WCHAR filever[0x100];
1976 TRACE("%s\n", debugstr_w(filename));
1978 versize = GetFileVersionInfoSizeW( filename, &handle );
1982 version = msi_alloc( versize );
1983 GetFileVersionInfoW( filename, 0, versize, version );
1985 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1987 msi_free( version );
1991 sprintfW( filever, name_fmt,
1992 HIWORD(lpVer->dwFileVersionMS),
1993 LOWORD(lpVer->dwFileVersionMS),
1994 HIWORD(lpVer->dwFileVersionLS),
1995 LOWORD(lpVer->dwFileVersionLS));
1997 msi_free( version );
1999 return strdupW( filever );
2002 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2004 LPWSTR file_version;
2007 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2009 MSICOMPONENT* comp = file->Component;
2015 if (file->IsCompressed)
2016 comp->ForceLocalState = TRUE;
2018 /* calculate target */
2019 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2021 msi_free(file->TargetPath);
2023 TRACE("file %s is named %s\n",
2024 debugstr_w(file->File), debugstr_w(file->FileName));
2026 file->TargetPath = build_directory_name(2, p, file->FileName);
2030 TRACE("file %s resolves to %s\n",
2031 debugstr_w(file->File), debugstr_w(file->TargetPath));
2033 /* don't check files of components that aren't installed */
2034 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2035 comp->Installed == INSTALLSTATE_ABSENT)
2037 file->state = msifs_missing; /* assume files are missing */
2041 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2043 file->state = msifs_missing;
2044 comp->Cost += file->FileSize;
2045 comp->Installed = INSTALLSTATE_INCOMPLETE;
2049 if (file->Version &&
2050 (file_version = msi_get_disk_file_version( file->TargetPath )))
2052 TRACE("new %s old %s\n", debugstr_w(file->Version),
2053 debugstr_w(file_version));
2054 /* FIXME: seems like a bad way to compare version numbers */
2055 if (lstrcmpiW(file_version, file->Version)<0)
2057 file->state = msifs_overwrite;
2058 comp->Cost += file->FileSize;
2059 comp->Installed = INSTALLSTATE_INCOMPLETE;
2062 file->state = msifs_present;
2063 msi_free( file_version );
2066 file->state = msifs_present;
2069 return ERROR_SUCCESS;
2073 * A lot is done in this function aside from just the costing.
2074 * The costing needs to be implemented at some point but for now I am going
2075 * to focus on the directory building
2078 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2080 static const WCHAR ExecSeqQuery[] =
2081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2082 '`','D','i','r','e','c','t','o','r','y','`',0};
2083 static const WCHAR ConditionQuery[] =
2084 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2085 '`','C','o','n','d','i','t','i','o','n','`',0};
2086 static const WCHAR szCosting[] =
2087 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2088 static const WCHAR szlevel[] =
2089 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2090 static const WCHAR szOne[] = { '1', 0 };
2096 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2097 return ERROR_SUCCESS;
2099 TRACE("Building Directory properties\n");
2101 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2102 if (rc == ERROR_SUCCESS)
2104 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2106 msiobj_release(&view->hdr);
2109 /* read components states from the registry */
2110 ACTION_GetComponentInstallStates(package);
2112 TRACE("File calculations\n");
2113 msi_check_file_install_states( package );
2115 TRACE("Evaluating Condition Table\n");
2117 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2118 if (rc == ERROR_SUCCESS)
2120 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2122 msiobj_release(&view->hdr);
2125 TRACE("Enabling or Disabling Components\n");
2126 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2128 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2130 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2131 comp->Enabled = FALSE;
2135 MSI_SetPropertyW(package,szCosting,szOne);
2136 /* set default run level if not set */
2137 level = msi_dup_property( package, szlevel );
2139 MSI_SetPropertyW(package,szlevel, szOne);
2142 ACTION_UpdateFeatureInstallStates(package);
2144 return MSI_SetFeatureStates(package);
2147 /* OK this value is "interpreted" and then formatted based on the
2148 first few characters */
2149 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2153 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2159 LPWSTR deformated = NULL;
2162 deformat_string(package, &value[2], &deformated);
2164 /* binary value type */
2168 *size = (strlenW(ptr)/2)+1;
2170 *size = strlenW(ptr)/2;
2172 data = msi_alloc(*size);
2178 /* if uneven pad with a zero in front */
2184 data[count] = (BYTE)strtol(byte,NULL,0);
2186 TRACE("Uneven byte count\n");
2194 data[count] = (BYTE)strtol(byte,NULL,0);
2197 msi_free(deformated);
2199 TRACE("Data %i bytes(%i)\n",*size,count);
2206 deformat_string(package, &value[1], &deformated);
2209 *size = sizeof(DWORD);
2210 data = msi_alloc(*size);
2216 if ( (*p < '0') || (*p > '9') )
2222 if (deformated[0] == '-')
2225 TRACE("DWORD %i\n",*(LPDWORD)data);
2227 msi_free(deformated);
2232 static const WCHAR szMulti[] = {'[','~',']',0};
2241 *type=REG_EXPAND_SZ;
2249 if (strstrW(value,szMulti))
2250 *type = REG_MULTI_SZ;
2252 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2257 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2259 MSIPACKAGE *package = (MSIPACKAGE*)param;
2260 static const WCHAR szHCR[] =
2261 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2262 'R','O','O','T','\\',0};
2263 static const WCHAR szHCU[] =
2264 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2265 'U','S','E','R','\\',0};
2266 static const WCHAR szHLM[] =
2267 {'H','K','E','Y','_','L','O','C','A','L','_',
2268 'M','A','C','H','I','N','E','\\',0};
2269 static const WCHAR szHU[] =
2270 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2272 LPSTR value_data = NULL;
2273 HKEY root_key, hkey;
2276 LPCWSTR szRoot, component, name, key, value;
2281 BOOL check_first = FALSE;
2284 ui_progress(package,2,0,0,0);
2291 component = MSI_RecordGetString(row, 6);
2292 comp = get_loaded_component(package,component);
2294 return ERROR_SUCCESS;
2296 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2298 TRACE("Skipping write due to disabled component %s\n",
2299 debugstr_w(component));
2301 comp->Action = comp->Installed;
2303 return ERROR_SUCCESS;
2306 comp->Action = INSTALLSTATE_LOCAL;
2308 name = MSI_RecordGetString(row, 4);
2309 if( MSI_RecordIsNull(row,5) && name )
2311 /* null values can have special meanings */
2312 if (name[0]=='-' && name[1] == 0)
2313 return ERROR_SUCCESS;
2314 else if ((name[0]=='+' && name[1] == 0) ||
2315 (name[0] == '*' && name[1] == 0))
2320 root = MSI_RecordGetInteger(row,2);
2321 key = MSI_RecordGetString(row, 3);
2323 /* get the root key */
2328 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2329 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2330 if (all_users && all_users[0] == '1')
2332 root_key = HKEY_LOCAL_MACHINE;
2337 root_key = HKEY_CURRENT_USER;
2340 msi_free(all_users);
2343 case 0: root_key = HKEY_CLASSES_ROOT;
2346 case 1: root_key = HKEY_CURRENT_USER;
2349 case 2: root_key = HKEY_LOCAL_MACHINE;
2352 case 3: root_key = HKEY_USERS;
2356 ERR("Unknown root %i\n",root);
2362 return ERROR_SUCCESS;
2364 deformat_string(package, key , &deformated);
2365 size = strlenW(deformated) + strlenW(szRoot) + 1;
2366 uikey = msi_alloc(size*sizeof(WCHAR));
2367 strcpyW(uikey,szRoot);
2368 strcatW(uikey,deformated);
2370 if (RegCreateKeyW( root_key, deformated, &hkey))
2372 ERR("Could not create key %s\n",debugstr_w(deformated));
2373 msi_free(deformated);
2375 return ERROR_SUCCESS;
2377 msi_free(deformated);
2379 value = MSI_RecordGetString(row,5);
2381 value_data = parse_value(package, value, &type, &size);
2384 static const WCHAR szEmpty[] = {0};
2385 value_data = (LPSTR)strdupW(szEmpty);
2390 deformat_string(package, name, &deformated);
2392 /* get the double nulls to terminate SZ_MULTI */
2393 if (type == REG_MULTI_SZ)
2394 size +=sizeof(WCHAR);
2398 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2400 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2405 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2406 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2408 TRACE("value %s of %s checked already exists\n",
2409 debugstr_w(deformated), debugstr_w(uikey));
2413 TRACE("Checked and setting value %s of %s\n",
2414 debugstr_w(deformated), debugstr_w(uikey));
2415 if (deformated || size)
2416 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2421 uirow = MSI_CreateRecord(3);
2422 MSI_RecordSetStringW(uirow,2,deformated);
2423 MSI_RecordSetStringW(uirow,1,uikey);
2426 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2428 MSI_RecordSetStringW(uirow,3,value);
2430 ui_actiondata(package,szWriteRegistryValues,uirow);
2431 msiobj_release( &uirow->hdr );
2433 msi_free(value_data);
2434 msi_free(deformated);
2437 return ERROR_SUCCESS;
2440 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2444 static const WCHAR ExecSeqQuery[] =
2445 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2446 '`','R','e','g','i','s','t','r','y','`',0 };
2448 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2449 if (rc != ERROR_SUCCESS)
2450 return ERROR_SUCCESS;
2452 /* increment progress bar each time action data is sent */
2453 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2455 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2457 msiobj_release(&view->hdr);
2461 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2463 package->script->CurrentlyScripting = TRUE;
2465 return ERROR_SUCCESS;
2469 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2474 static const WCHAR q1[]=
2475 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2476 '`','R','e','g','i','s','t','r','y','`',0};
2479 MSIFEATURE *feature;
2482 TRACE("InstallValidate\n");
2484 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2485 if (rc == ERROR_SUCCESS)
2487 MSI_IterateRecords( view, &progress, NULL, package );
2488 msiobj_release( &view->hdr );
2489 total += progress * REG_PROGRESS_VALUE;
2492 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2493 total += COMPONENT_PROGRESS_VALUE;
2495 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2496 total += file->FileSize;
2498 ui_progress(package,0,total,0,0);
2500 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2502 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2503 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2504 feature->ActionRequest);
2507 return ERROR_SUCCESS;
2510 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2512 MSIPACKAGE* package = (MSIPACKAGE*)param;
2513 LPCWSTR cond = NULL;
2514 LPCWSTR message = NULL;
2517 static const WCHAR title[]=
2518 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2520 cond = MSI_RecordGetString(row,1);
2522 r = MSI_EvaluateConditionW(package,cond);
2523 if (r == MSICONDITION_FALSE)
2525 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2528 message = MSI_RecordGetString(row,2);
2529 deformat_string(package,message,&deformated);
2530 MessageBoxW(NULL,deformated,title,MB_OK);
2531 msi_free(deformated);
2534 return ERROR_INSTALL_FAILURE;
2537 return ERROR_SUCCESS;
2540 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2543 MSIQUERY * view = NULL;
2544 static const WCHAR ExecSeqQuery[] =
2545 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2546 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2548 TRACE("Checking launch conditions\n");
2550 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2551 if (rc != ERROR_SUCCESS)
2552 return ERROR_SUCCESS;
2554 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2555 msiobj_release(&view->hdr);
2560 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2564 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2566 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2568 MSIRECORD * row = 0;
2570 LPWSTR deformated,buffer,deformated_name;
2572 static const WCHAR ExecSeqQuery[] =
2573 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2574 '`','R','e','g','i','s','t','r','y','`',' ',
2575 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2576 ' ','=',' ' ,'\'','%','s','\'',0 };
2577 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2578 static const WCHAR fmt2[]=
2579 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2581 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2585 root = MSI_RecordGetInteger(row,2);
2586 key = MSI_RecordGetString(row, 3);
2587 name = MSI_RecordGetString(row, 4);
2588 deformat_string(package, key , &deformated);
2589 deformat_string(package, name, &deformated_name);
2591 len = strlenW(deformated) + 6;
2592 if (deformated_name)
2593 len+=strlenW(deformated_name);
2595 buffer = msi_alloc( len *sizeof(WCHAR));
2597 if (deformated_name)
2598 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2600 sprintfW(buffer,fmt,root,deformated);
2602 msi_free(deformated);
2603 msi_free(deformated_name);
2604 msiobj_release(&row->hdr);
2608 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2610 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2615 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2618 return strdupW( file->TargetPath );
2623 static HKEY openSharedDLLsKey(void)
2626 static const WCHAR path[] =
2627 {'S','o','f','t','w','a','r','e','\\',
2628 'M','i','c','r','o','s','o','f','t','\\',
2629 'W','i','n','d','o','w','s','\\',
2630 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2631 'S','h','a','r','e','d','D','L','L','s',0};
2633 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2637 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2642 DWORD sz = sizeof(count);
2645 hkey = openSharedDLLsKey();
2646 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2647 if (rc != ERROR_SUCCESS)
2653 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2657 hkey = openSharedDLLsKey();
2659 msi_reg_set_val_dword( hkey, path, count );
2661 RegDeleteValueW(hkey,path);
2667 * Return TRUE if the count should be written out and FALSE if not
2669 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2671 MSIFEATURE *feature;
2675 /* only refcount DLLs */
2676 if (comp->KeyPath == NULL ||
2677 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2678 comp->Attributes & msidbComponentAttributesODBCDataSource)
2682 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2683 write = (count > 0);
2685 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2689 /* increment counts */
2690 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2694 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2697 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2699 if ( cl->component == comp )
2704 /* decrement counts */
2705 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2709 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2712 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2714 if ( cl->component == comp )
2719 /* ref count all the files in the component */
2724 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2726 if (file->Component == comp)
2727 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2731 /* add a count for permenent */
2732 if (comp->Attributes & msidbComponentAttributesPermanent)
2735 comp->RefCount = count;
2738 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2742 * Ok further analysis makes me think that this work is
2743 * actually done in the PublishComponents and PublishFeatures
2744 * step, and not here. It appears like the keypath and all that is
2745 * resolved in this step, however actually written in the Publish steps.
2746 * But we will leave it here for now because it is unclear
2748 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2750 WCHAR squished_pc[GUID_SIZE];
2751 WCHAR squished_cc[GUID_SIZE];
2754 HKEY hkey=0,hkey2=0;
2756 /* writes the Component and Features values to the registry */
2758 rc = MSIREG_OpenComponents(&hkey);
2759 if (rc != ERROR_SUCCESS)
2762 squash_guid(package->ProductCode,squished_pc);
2763 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2765 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2769 ui_progress(package,2,0,0,0);
2770 if (!comp->ComponentId)
2773 squash_guid(comp->ComponentId,squished_cc);
2775 msi_free(comp->FullKeypath);
2776 comp->FullKeypath = resolve_keypath( package, comp );
2778 /* do the refcounting */
2779 ACTION_RefCountComponent( package, comp );
2781 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2782 debugstr_w(comp->Component),
2783 debugstr_w(squished_cc),
2784 debugstr_w(comp->FullKeypath),
2787 * Write the keypath out if the component is to be registered
2788 * and delete the key if the component is to be deregistered
2790 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2792 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2793 if (rc != ERROR_SUCCESS)
2796 if (!comp->FullKeypath)
2799 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2801 if (comp->Attributes & msidbComponentAttributesPermanent)
2803 static const WCHAR szPermKey[] =
2804 { '0','0','0','0','0','0','0','0','0','0','0','0',
2805 '0','0','0','0','0','0','0','0','0','0','0','0',
2806 '0','0','0','0','0','0','0','0',0 };
2808 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2813 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2817 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2818 if (rc != ERROR_SUCCESS)
2821 RegDeleteValueW(hkey2,squished_pc);
2823 /* if the key is empty delete it */
2824 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2826 if (res == ERROR_NO_MORE_ITEMS)
2827 RegDeleteKeyW(hkey,squished_cc);
2832 uirow = MSI_CreateRecord(3);
2833 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2834 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2835 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2836 ui_actiondata(package,szProcessComponents,uirow);
2837 msiobj_release( &uirow->hdr );
2851 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2852 LPWSTR lpszName, LONG_PTR lParam)
2855 typelib_struct *tl_struct = (typelib_struct*) lParam;
2856 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2860 if (!IS_INTRESOURCE(lpszName))
2862 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2866 sz = strlenW(tl_struct->source)+4;
2867 sz *= sizeof(WCHAR);
2869 if ((INT_PTR)lpszName == 1)
2870 tl_struct->path = strdupW(tl_struct->source);
2873 tl_struct->path = msi_alloc(sz);
2874 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2877 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2878 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2879 if (!SUCCEEDED(res))
2881 msi_free(tl_struct->path);
2882 tl_struct->path = NULL;
2887 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2888 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2890 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2894 msi_free(tl_struct->path);
2895 tl_struct->path = NULL;
2897 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2898 ITypeLib_Release(tl_struct->ptLib);
2903 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2905 MSIPACKAGE* package = (MSIPACKAGE*)param;
2909 typelib_struct tl_struct;
2911 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2913 component = MSI_RecordGetString(row,3);
2914 comp = get_loaded_component(package,component);
2916 return ERROR_SUCCESS;
2918 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2920 TRACE("Skipping typelib reg due to disabled component\n");
2922 comp->Action = comp->Installed;
2924 return ERROR_SUCCESS;
2927 comp->Action = INSTALLSTATE_LOCAL;
2929 file = get_loaded_file( package, comp->KeyPath );
2931 return ERROR_SUCCESS;
2933 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2937 guid = MSI_RecordGetString(row,1);
2938 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2939 tl_struct.source = strdupW( file->TargetPath );
2940 tl_struct.path = NULL;
2942 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2943 (LONG_PTR)&tl_struct);
2951 helpid = MSI_RecordGetString(row,6);
2954 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2955 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2958 if (!SUCCEEDED(res))
2959 ERR("Failed to register type library %s\n",
2960 debugstr_w(tl_struct.path));
2963 ui_actiondata(package,szRegisterTypeLibraries,row);
2965 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2968 ITypeLib_Release(tl_struct.ptLib);
2969 msi_free(tl_struct.path);
2972 ERR("Failed to load type library %s\n",
2973 debugstr_w(tl_struct.source));
2975 FreeLibrary(module);
2976 msi_free(tl_struct.source);
2979 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2981 return ERROR_SUCCESS;
2984 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2987 * OK this is a bit confusing.. I am given a _Component key and I believe
2988 * that the file that is being registered as a type library is the "key file
2989 * of that component" which I interpret to mean "The file in the KeyPath of
2994 static const WCHAR Query[] =
2995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2996 '`','T','y','p','e','L','i','b','`',0};
2998 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2999 if (rc != ERROR_SUCCESS)
3000 return ERROR_SUCCESS;
3002 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3003 msiobj_release(&view->hdr);
3007 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3009 MSIPACKAGE *package = (MSIPACKAGE*)param;
3010 LPWSTR target_file, target_folder, filename;
3011 LPCWSTR buffer, extension;
3013 static const WCHAR szlnk[]={'.','l','n','k',0};
3014 IShellLinkW *sl = NULL;
3015 IPersistFile *pf = NULL;
3018 buffer = MSI_RecordGetString(row,4);
3019 comp = get_loaded_component(package,buffer);
3021 return ERROR_SUCCESS;
3023 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3025 TRACE("Skipping shortcut creation due to disabled component\n");
3027 comp->Action = comp->Installed;
3029 return ERROR_SUCCESS;
3032 comp->Action = INSTALLSTATE_LOCAL;
3034 ui_actiondata(package,szCreateShortcuts,row);
3036 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3037 &IID_IShellLinkW, (LPVOID *) &sl );
3041 ERR("CLSID_ShellLink not available\n");
3045 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3048 ERR("QueryInterface(IID_IPersistFile) failed\n");
3052 buffer = MSI_RecordGetString(row,2);
3053 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3055 /* may be needed because of a bug somehwere else */
3056 create_full_pathW(target_folder);
3058 filename = msi_dup_record_field( row, 3 );
3059 reduce_to_longfilename(filename);
3061 extension = strchrW(filename,'.');
3062 if (!extension || strcmpiW(extension,szlnk))
3064 int len = strlenW(filename);
3065 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3066 memcpy(filename + len, szlnk, sizeof(szlnk));
3068 target_file = build_directory_name(2, target_folder, filename);
3069 msi_free(target_folder);
3072 buffer = MSI_RecordGetString(row,5);
3073 if (strchrW(buffer,'['))
3076 deformat_string(package,buffer,&deformated);
3077 IShellLinkW_SetPath(sl,deformated);
3078 msi_free(deformated);
3082 FIXME("poorly handled shortcut format, advertised shortcut\n");
3083 IShellLinkW_SetPath(sl,comp->FullKeypath);
3086 if (!MSI_RecordIsNull(row,6))
3089 buffer = MSI_RecordGetString(row,6);
3090 deformat_string(package,buffer,&deformated);
3091 IShellLinkW_SetArguments(sl,deformated);
3092 msi_free(deformated);
3095 if (!MSI_RecordIsNull(row,7))
3097 buffer = MSI_RecordGetString(row,7);
3098 IShellLinkW_SetDescription(sl,buffer);
3101 if (!MSI_RecordIsNull(row,8))
3102 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3104 if (!MSI_RecordIsNull(row,9))
3109 buffer = MSI_RecordGetString(row,9);
3111 Path = build_icon_path(package,buffer);
3112 index = MSI_RecordGetInteger(row,10);
3114 /* no value means 0 */
3115 if (index == MSI_NULL_INTEGER)
3118 IShellLinkW_SetIconLocation(sl,Path,index);
3122 if (!MSI_RecordIsNull(row,11))
3123 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3125 if (!MSI_RecordIsNull(row,12))
3128 buffer = MSI_RecordGetString(row,12);
3129 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3131 IShellLinkW_SetWorkingDirectory(sl,Path);
3135 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3136 IPersistFile_Save(pf,target_file,FALSE);
3138 msi_free(target_file);
3142 IPersistFile_Release( pf );
3144 IShellLinkW_Release( sl );
3146 return ERROR_SUCCESS;
3149 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3154 static const WCHAR Query[] =
3155 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3156 '`','S','h','o','r','t','c','u','t','`',0};
3158 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3159 if (rc != ERROR_SUCCESS)
3160 return ERROR_SUCCESS;
3162 res = CoInitialize( NULL );
3165 ERR("CoInitialize failed\n");
3166 return ERROR_FUNCTION_FAILED;
3169 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3170 msiobj_release(&view->hdr);
3177 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3179 MSIPACKAGE* package = (MSIPACKAGE*)param;
3188 FileName = MSI_RecordGetString(row,1);
3191 ERR("Unable to get FileName\n");
3192 return ERROR_SUCCESS;
3195 FilePath = build_icon_path(package,FileName);
3197 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3199 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3200 FILE_ATTRIBUTE_NORMAL, NULL);
3202 if (the_file == INVALID_HANDLE_VALUE)
3204 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3206 return ERROR_SUCCESS;
3213 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3214 if (rc != ERROR_SUCCESS)
3216 ERR("Failed to get stream\n");
3217 CloseHandle(the_file);
3218 DeleteFileW(FilePath);
3221 WriteFile(the_file,buffer,sz,&write,NULL);
3222 } while (sz == 1024);
3226 CloseHandle(the_file);
3228 uirow = MSI_CreateRecord(1);
3229 MSI_RecordSetStringW(uirow,1,FileName);
3230 ui_actiondata(package,szPublishProduct,uirow);
3231 msiobj_release( &uirow->hdr );
3233 return ERROR_SUCCESS;
3237 * 99% of the work done here is only done for
3238 * advertised installs. However this is where the
3239 * Icon table is processed and written out
3240 * so that is what I am going to do here.
3242 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3246 static const WCHAR Query[]=
3247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3248 '`','I','c','o','n','`',0};
3249 /* for registry stuff */
3252 HKEY hudkey=0, props=0;
3253 static const WCHAR szProductLanguage[] =
3254 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3255 static const WCHAR szARPProductIcon[] =
3256 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3257 static const WCHAR szProductVersion[] =
3258 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3259 static const WCHAR szInstallProperties[] =
3260 {'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
3261 static const WCHAR szWindowsInstaller[] =
3262 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3266 MSIHANDLE hDb, hSumInfo;
3268 /* write out icon files */
3270 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3271 if (rc == ERROR_SUCCESS)
3273 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3274 msiobj_release(&view->hdr);
3277 /* ok there is a lot more done here but i need to figure out what */
3279 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3280 if (rc != ERROR_SUCCESS)
3283 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3284 if (rc != ERROR_SUCCESS)
3287 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3288 if (rc != ERROR_SUCCESS)
3291 rc = RegCreateKeyW(hudkey, szInstallProperties, &props);
3292 if (rc != ERROR_SUCCESS)
3295 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
3297 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3298 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3301 langid = msi_get_property_int( package, szProductLanguage, 0 );
3302 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3304 buffer = msi_dup_property( package, szARPProductIcon );
3307 LPWSTR path = build_icon_path(package,buffer);
3308 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3313 buffer = msi_dup_property( package, szProductVersion );
3316 DWORD verdword = msi_version_str_to_dword(buffer);
3317 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3321 /* FIXME: Need to write more keys to the user registry */
3323 hDb= alloc_msihandle( &package->db->hdr );
3325 rc = ERROR_NOT_ENOUGH_MEMORY;
3328 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3329 MsiCloseHandle(hDb);
3330 if (rc == ERROR_SUCCESS)
3332 WCHAR guidbuffer[0x200];
3334 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3336 if (rc == ERROR_SUCCESS)
3338 WCHAR squashed[GUID_SIZE];
3339 /* for now we only care about the first guid */
3340 LPWSTR ptr = strchrW(guidbuffer,';');
3342 squash_guid(guidbuffer,squashed);
3343 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3347 ERR("Unable to query Revision_Number...\n");
3350 MsiCloseHandle(hSumInfo);
3354 ERR("Unable to open Summary Information\n");
3361 RegCloseKey(hudkey);
3367 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3369 MSIPACKAGE *package = (MSIPACKAGE*)param;
3370 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3371 LPWSTR deformated_section, deformated_key, deformated_value;
3372 LPWSTR folder, fullname = NULL;
3376 static const WCHAR szWindowsFolder[] =
3377 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3379 component = MSI_RecordGetString(row, 8);
3380 comp = get_loaded_component(package,component);
3382 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3384 TRACE("Skipping ini file due to disabled component %s\n",
3385 debugstr_w(component));
3387 comp->Action = comp->Installed;
3389 return ERROR_SUCCESS;
3392 comp->Action = INSTALLSTATE_LOCAL;
3394 identifier = MSI_RecordGetString(row,1);
3395 filename = MSI_RecordGetString(row,2);
3396 dirproperty = MSI_RecordGetString(row,3);
3397 section = MSI_RecordGetString(row,4);
3398 key = MSI_RecordGetString(row,5);
3399 value = MSI_RecordGetString(row,6);
3400 action = MSI_RecordGetInteger(row,7);
3402 deformat_string(package,section,&deformated_section);
3403 deformat_string(package,key,&deformated_key);
3404 deformat_string(package,value,&deformated_value);
3408 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3410 folder = msi_dup_property( package, dirproperty );
3413 folder = msi_dup_property( package, szWindowsFolder );
3417 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3421 fullname = build_directory_name(2, folder, filename);
3425 TRACE("Adding value %s to section %s in %s\n",
3426 debugstr_w(deformated_key), debugstr_w(deformated_section),
3427 debugstr_w(fullname));
3428 WritePrivateProfileStringW(deformated_section, deformated_key,
3429 deformated_value, fullname);
3431 else if (action == 1)
3434 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3435 returned, 10, fullname);
3436 if (returned[0] == 0)
3438 TRACE("Adding value %s to section %s in %s\n",
3439 debugstr_w(deformated_key), debugstr_w(deformated_section),
3440 debugstr_w(fullname));
3442 WritePrivateProfileStringW(deformated_section, deformated_key,
3443 deformated_value, fullname);
3446 else if (action == 3)
3447 FIXME("Append to existing section not yet implemented\n");
3449 uirow = MSI_CreateRecord(4);
3450 MSI_RecordSetStringW(uirow,1,identifier);
3451 MSI_RecordSetStringW(uirow,2,deformated_section);
3452 MSI_RecordSetStringW(uirow,3,deformated_key);
3453 MSI_RecordSetStringW(uirow,4,deformated_value);
3454 ui_actiondata(package,szWriteIniValues,uirow);
3455 msiobj_release( &uirow->hdr );
3459 msi_free(deformated_key);
3460 msi_free(deformated_value);
3461 msi_free(deformated_section);
3462 return ERROR_SUCCESS;
3465 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3469 static const WCHAR ExecSeqQuery[] =
3470 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3471 '`','I','n','i','F','i','l','e','`',0};
3473 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3474 if (rc != ERROR_SUCCESS)
3476 TRACE("no IniFile table\n");
3477 return ERROR_SUCCESS;
3480 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3481 msiobj_release(&view->hdr);
3485 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3487 MSIPACKAGE *package = (MSIPACKAGE*)param;
3492 static const WCHAR ExeStr[] =
3493 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3494 static const WCHAR close[] = {'\"',0};
3496 PROCESS_INFORMATION info;
3501 memset(&si,0,sizeof(STARTUPINFOW));
3503 filename = MSI_RecordGetString(row,1);
3504 file = get_loaded_file( package, filename );
3508 ERR("Unable to find file id %s\n",debugstr_w(filename));
3509 return ERROR_SUCCESS;
3512 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3514 FullName = msi_alloc(len*sizeof(WCHAR));
3515 strcpyW(FullName,ExeStr);
3516 strcatW( FullName, file->TargetPath );
3517 strcatW(FullName,close);
3519 TRACE("Registering %s\n",debugstr_w(FullName));
3520 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3524 msi_dialog_check_messages(info.hProcess);
3529 uirow = MSI_CreateRecord( 2 );
3530 uipath = strdupW( file->TargetPath );
3531 p = strrchrW(uipath,'\\');
3534 MSI_RecordSetStringW( uirow, 1, &p[1] );
3535 MSI_RecordSetStringW( uirow, 2, uipath);
3536 ui_actiondata( package, szSelfRegModules, uirow);
3537 msiobj_release( &uirow->hdr );
3539 /* FIXME: call ui_progress? */
3541 return ERROR_SUCCESS;
3544 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3548 static const WCHAR ExecSeqQuery[] =
3549 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3550 '`','S','e','l','f','R','e','g','`',0};
3552 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3553 if (rc != ERROR_SUCCESS)
3555 TRACE("no SelfReg table\n");
3556 return ERROR_SUCCESS;
3559 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3560 msiobj_release(&view->hdr);
3562 return ERROR_SUCCESS;
3565 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3567 MSIFEATURE *feature;
3572 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3573 if (rc != ERROR_SUCCESS)
3576 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3577 if (rc != ERROR_SUCCESS)
3580 /* here the guids are base 85 encoded */
3581 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3587 BOOL absent = FALSE;
3590 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3591 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3592 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3596 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3600 if (feature->Feature_Parent)
3601 size += strlenW( feature->Feature_Parent )+2;
3603 data = msi_alloc(size * sizeof(WCHAR));
3606 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3608 MSICOMPONENT* component = cl->component;
3612 if (component->ComponentId)
3614 TRACE("From %s\n",debugstr_w(component->ComponentId));
3615 CLSIDFromString(component->ComponentId, &clsid);
3616 encode_base85_guid(&clsid,buf);
3617 TRACE("to %s\n",debugstr_w(buf));
3621 if (feature->Feature_Parent)
3623 static const WCHAR sep[] = {'\2',0};
3625 strcatW(data,feature->Feature_Parent);
3628 msi_reg_set_val_str( hkey, feature->Feature, data );
3632 if (feature->Feature_Parent)
3633 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3636 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3637 (LPBYTE)feature->Feature_Parent,size);
3641 size += 2*sizeof(WCHAR);
3642 data = msi_alloc(size);
3645 if (feature->Feature_Parent)
3646 strcpyW( &data[1], feature->Feature_Parent );
3647 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3653 uirow = MSI_CreateRecord( 1 );
3654 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3655 ui_actiondata( package, szPublishFeatures, uirow);
3656 msiobj_release( &uirow->hdr );
3657 /* FIXME: call ui_progress? */
3666 static UINT msi_get_local_package_name( LPWSTR path )
3668 static const WCHAR szInstaller[] = {
3669 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3670 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3674 time = GetTickCount();
3675 GetWindowsDirectoryW( path, MAX_PATH );
3676 lstrcatW( path, szInstaller );
3677 CreateDirectoryW( path, NULL );
3679 len = lstrlenW(path);
3680 for (i=0; i<0x10000; i++)
3682 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3683 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3684 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3685 if (handle != INVALID_HANDLE_VALUE)
3687 CloseHandle(handle);
3690 if (GetLastError() != ERROR_FILE_EXISTS &&
3691 GetLastError() != ERROR_SHARING_VIOLATION)
3692 return ERROR_FUNCTION_FAILED;
3695 return ERROR_SUCCESS;
3698 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3700 static const WCHAR szOriginalDatabase[] =
3701 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3702 WCHAR packagefile[MAX_PATH];
3706 r = msi_get_local_package_name( packagefile );
3707 if (r != ERROR_SUCCESS)
3710 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3712 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3713 r = CopyFileW( msiFilePath, packagefile, FALSE);
3717 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3718 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3719 msi_free( msiFilePath );
3720 return ERROR_FUNCTION_FAILED;
3722 msi_free( msiFilePath );
3724 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3725 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3726 return ERROR_SUCCESS;
3729 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3731 LPWSTR prop, val, key;
3732 static const LPCSTR propval[] = {
3733 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3734 "ARPCONTACT", "Contact",
3735 "ARPCOMMENTS", "Comments",
3736 "ProductName", "DisplayName",
3737 "ProductVersion", "DisplayVersion",
3738 "ARPHELPLINK", "HelpLink",
3739 "ARPHELPTELEPHONE", "HelpTelephone",
3740 "ARPINSTALLLOCATION", "InstallLocation",
3741 "SourceDir", "InstallSource",
3742 "Manufacturer", "Publisher",
3743 "ARPREADME", "Readme",
3745 "ARPURLINFOABOUT", "URLInfoAbout",
3746 "ARPURLUPDATEINFO", "URLUpdateInfo",
3749 const LPCSTR *p = propval;
3753 prop = strdupAtoW( *p++ );
3754 key = strdupAtoW( *p++ );
3755 val = msi_dup_property( package, prop );
3756 msi_reg_set_val_str( hkey, key, val );
3761 return ERROR_SUCCESS;
3764 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3767 LPWSTR buffer = NULL;
3770 static const WCHAR szWindowsInstaller[] =
3771 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3772 static const WCHAR szUpgradeCode[] =
3773 {'U','p','g','r','a','d','e','C','o','d','e',0};
3774 static const WCHAR modpath_fmt[] =
3775 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3776 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3777 static const WCHAR szModifyPath[] =
3778 {'M','o','d','i','f','y','P','a','t','h',0};
3779 static const WCHAR szUninstallString[] =
3780 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3781 static const WCHAR szEstimatedSize[] =
3782 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3783 static const WCHAR szProductLanguage[] =
3784 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3785 static const WCHAR szProductVersion[] =
3786 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3789 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3790 LPWSTR upgrade_code;
3793 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3794 if (rc != ERROR_SUCCESS)
3797 /* dump all the info i can grab */
3798 /* FIXME: Flesh out more information */
3800 msi_write_uninstall_property_vals( package, hkey );
3802 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3804 msi_make_package_local( package, hkey );
3806 /* do ModifyPath and UninstallString */
3807 size = deformat_string(package,modpath_fmt,&buffer);
3808 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3809 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3812 /* FIXME: Write real Estimated Size when we have it */
3813 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3815 GetLocalTime(&systime);
3816 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3817 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3819 langid = msi_get_property_int( package, szProductLanguage, 0 );
3820 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3822 buffer = msi_dup_property( package, szProductVersion );
3825 DWORD verdword = msi_version_str_to_dword(buffer);
3827 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3828 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3829 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3833 /* Handle Upgrade Codes */
3834 upgrade_code = msi_dup_property( package, szUpgradeCode );
3839 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3840 squash_guid(package->ProductCode,squashed);
3841 msi_reg_set_val_str( hkey2, squashed, NULL );
3843 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3844 squash_guid(package->ProductCode,squashed);
3845 msi_reg_set_val_str( hkey2, squashed, NULL );
3848 msi_free(upgrade_code);
3853 /* FIXME: call ui_actiondata */
3855 return ERROR_SUCCESS;
3858 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3860 return execute_script(package,INSTALL_SCRIPT);
3863 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3867 /* turn off scheduling */
3868 package->script->CurrentlyScripting= FALSE;
3870 /* first do the same as an InstallExecute */
3871 rc = ACTION_InstallExecute(package);
3872 if (rc != ERROR_SUCCESS)
3875 /* then handle Commit Actions */
3876 rc = execute_script(package,COMMIT_SCRIPT);
3881 UINT ACTION_ForceReboot(MSIPACKAGE *package)
3883 static const WCHAR RunOnce[] = {
3884 'S','o','f','t','w','a','r','e','\\',
3885 'M','i','c','r','o','s','o','f','t','\\',
3886 'W','i','n','d','o','w','s','\\',
3887 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3888 'R','u','n','O','n','c','e',0};
3889 static const WCHAR InstallRunOnce[] = {
3890 'S','o','f','t','w','a','r','e','\\',
3891 'M','i','c','r','o','s','o','f','t','\\',
3892 'W','i','n','d','o','w','s','\\',
3893 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3894 'I','n','s','t','a','l','l','e','r','\\',
3895 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3897 static const WCHAR msiexec_fmt[] = {
3899 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3900 '\"','%','s','\"',0};
3901 static const WCHAR install_fmt[] = {
3902 '/','I',' ','\"','%','s','\"',' ',
3903 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3904 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3905 WCHAR buffer[256], sysdir[MAX_PATH];
3907 WCHAR squished_pc[100];
3909 squash_guid(package->ProductCode,squished_pc);
3911 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3912 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3913 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3916 msi_reg_set_val_str( hkey, squished_pc, buffer );
3919 TRACE("Reboot command %s\n",debugstr_w(buffer));
3921 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3922 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3924 msi_reg_set_val_str( hkey, squished_pc, buffer );
3927 return ERROR_INSTALL_SUSPEND;
3930 static UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3935 p = strrchrW( package->PackagePath, '\\' );
3937 return ERROR_SUCCESS;
3939 len = p - package->PackagePath + 2;
3940 source = msi_alloc( len * sizeof(WCHAR) );
3941 lstrcpynW( source, package->PackagePath, len );
3943 MSI_SetPropertyW( package, cszSourceDir, source );
3944 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3948 return ERROR_SUCCESS;
3951 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3957 * We are currently doing what should be done here in the top level Install
3958 * however for Administrative and uninstalls this step will be needed
3960 if (!package->PackagePath)
3961 return ERROR_SUCCESS;
3963 msi_set_sourcedir_props(package);
3965 attrib = GetFileAttributesW(package->PackagePath);
3966 if (attrib == INVALID_FILE_ATTRIBUTES)
3972 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3973 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3974 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3975 if (rc == ERROR_MORE_DATA)
3977 prompt = msi_alloc(size * sizeof(WCHAR));
3978 MsiSourceListGetInfoW(package->ProductCode, NULL,
3979 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3980 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3983 prompt = strdupW(package->PackagePath);
3985 msg = generate_error_string(package,1302,1,prompt);
3986 while(attrib == INVALID_FILE_ATTRIBUTES)
3988 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3991 rc = ERROR_INSTALL_USEREXIT;
3994 attrib = GetFileAttributesW(package->PackagePath);
4000 return ERROR_SUCCESS;
4005 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4012 static const WCHAR szPropKeys[][80] =
4014 {'P','r','o','d','u','c','t','I','D',0},
4015 {'U','S','E','R','N','A','M','E',0},
4016 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4020 static const WCHAR szRegKeys[][80] =
4022 {'P','r','o','d','u','c','t','I','D',0},
4023 {'R','e','g','O','w','n','e','r',0},
4024 {'R','e','g','C','o','m','p','a','n','y',0},
4028 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4030 return ERROR_SUCCESS;
4032 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
4033 if (rc != ERROR_SUCCESS)
4036 for( i = 0; szPropKeys[i][0]; i++ )
4038 buffer = msi_dup_property( package, szPropKeys[i] );
4039 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4044 msi_free(productid);
4047 /* FIXME: call ui_actiondata */
4049 return ERROR_SUCCESS;
4053 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4057 package->script->InWhatSequence |= SEQUENCE_EXEC;
4058 rc = ACTION_ProcessExecSequence(package,FALSE);
4063 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4065 MSIPACKAGE *package = (MSIPACKAGE*)param;
4066 LPCWSTR compgroupid=NULL;
4067 LPCWSTR feature=NULL;
4068 LPCWSTR text = NULL;
4069 LPCWSTR qualifier = NULL;
4070 LPCWSTR component = NULL;
4071 LPWSTR advertise = NULL;
4072 LPWSTR output = NULL;
4074 UINT rc = ERROR_SUCCESS;
4079 component = MSI_RecordGetString(rec,3);
4080 comp = get_loaded_component(package,component);
4082 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4083 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4084 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4086 TRACE("Skipping: Component %s not scheduled for install\n",
4087 debugstr_w(component));
4089 return ERROR_SUCCESS;
4092 compgroupid = MSI_RecordGetString(rec,1);
4093 qualifier = MSI_RecordGetString(rec,2);
4095 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4096 if (rc != ERROR_SUCCESS)
4099 text = MSI_RecordGetString(rec,4);
4100 feature = MSI_RecordGetString(rec,5);
4102 advertise = create_component_advertise_string(package, comp, feature);
4104 sz = strlenW(advertise);
4107 sz += lstrlenW(text);
4110 sz *= sizeof(WCHAR);
4112 output = msi_alloc_zero(sz);
4113 strcpyW(output,advertise);
4114 msi_free(advertise);
4117 strcatW(output,text);
4119 msi_reg_set_val_multi_str( hkey, qualifier, output );
4126 uirow = MSI_CreateRecord( 2 );
4127 MSI_RecordSetStringW( uirow, 1, compgroupid );
4128 MSI_RecordSetStringW( uirow, 2, qualifier);
4129 ui_actiondata( package, szPublishComponents, uirow);
4130 msiobj_release( &uirow->hdr );
4131 /* FIXME: call ui_progress? */
4137 * At present I am ignorning the advertised components part of this and only
4138 * focusing on the qualified component sets
4140 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4144 static const WCHAR ExecSeqQuery[] =
4145 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4146 '`','P','u','b','l','i','s','h',
4147 'C','o','m','p','o','n','e','n','t','`',0};
4149 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4150 if (rc != ERROR_SUCCESS)
4151 return ERROR_SUCCESS;
4153 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4154 msiobj_release(&view->hdr);
4159 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4161 MSIPACKAGE *package = (MSIPACKAGE*)param;
4164 SC_HANDLE hscm, service = NULL;
4165 LPCWSTR name, disp, comp, depends, pass;
4166 LPCWSTR load_order, serv_name, key;
4167 DWORD serv_type, start_type;
4170 static const WCHAR query[] =
4171 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4172 '`','C','o','m','p','o','n','e','n','t','`',' ',
4173 'W','H','E','R','E',' ',
4174 '`','C','o','m','p','o','n','e','n','t','`',' ',
4175 '=','\'','%','s','\'',0};
4177 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4180 ERR("Failed to open the SC Manager!\n");
4184 start_type = MSI_RecordGetInteger(rec, 5);
4185 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4188 depends = MSI_RecordGetString(rec, 8);
4189 if (depends && *depends)
4190 FIXME("Dependency list unhandled!\n");
4192 name = MSI_RecordGetString(rec, 2);
4193 disp = MSI_RecordGetString(rec, 3);
4194 serv_type = MSI_RecordGetInteger(rec, 4);
4195 err_control = MSI_RecordGetInteger(rec, 6);
4196 load_order = MSI_RecordGetString(rec, 7);
4197 serv_name = MSI_RecordGetString(rec, 9);
4198 pass = MSI_RecordGetString(rec, 10);
4199 comp = MSI_RecordGetString(rec, 12);
4201 /* fetch the service path */
4202 row = MSI_QueryGetRecord(package->db, query, comp);
4205 ERR("Control query failed!\n");
4209 key = MSI_RecordGetString(row, 6);
4210 msiobj_release(&row->hdr);
4212 file = get_loaded_file(package, key);
4215 ERR("Failed to load the service file\n");
4219 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4220 start_type, err_control, file->TargetPath,
4221 load_order, NULL, NULL, serv_name, pass);
4224 if (GetLastError() != ERROR_SERVICE_EXISTS)
4225 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4229 CloseServiceHandle(service);
4230 CloseServiceHandle(hscm);
4232 return ERROR_SUCCESS;
4235 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4239 static const WCHAR ExecSeqQuery[] =
4240 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4241 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4243 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4244 if (rc != ERROR_SUCCESS)
4245 return ERROR_SUCCESS;
4247 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4248 msiobj_release(&view->hdr);
4253 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4254 static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs)
4260 static const WCHAR separator[] = {'[','~',']',0};
4263 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4268 vector = msi_alloc(sizeof(LPWSTR));
4276 vector[*numargs - 1] = p;
4278 if ((q = strstrW(p, separator)))
4282 vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4293 static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component )
4297 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
4299 if (!lstrcmpW(comp->Component, component))
4306 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4308 MSIPACKAGE *package = (MSIPACKAGE *)param;
4310 SC_HANDLE scm, service = NULL;
4311 LPCWSTR name, *vector = NULL;
4313 DWORD event, numargs;
4314 UINT r = ERROR_FUNCTION_FAILED;
4316 comp = msi_find_component(package, MSI_RecordGetString(rec, 6));
4317 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4318 return ERROR_SUCCESS;
4320 name = MSI_RecordGetString(rec, 2);
4321 event = MSI_RecordGetInteger(rec, 3);
4322 args = strdupW(MSI_RecordGetString(rec, 4));
4324 if (!(event & msidbServiceControlEventStart))
4325 return ERROR_SUCCESS;
4327 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4330 ERR("Failed to open the service control manager\n");
4334 service = OpenServiceW(scm, name, SERVICE_START);
4337 ERR("Failed to open service %s\n", debugstr_w(name));
4341 vector = msi_service_args_to_vector(name, args, &numargs);
4343 if (!StartServiceW(service, numargs, vector))
4345 ERR("Failed to start service %s\n", debugstr_w(name));
4352 CloseServiceHandle(service);
4353 CloseServiceHandle(scm);
4360 static UINT ACTION_StartServices( MSIPACKAGE *package )
4365 static const WCHAR query[] = {
4366 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4367 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4369 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4370 if (rc != ERROR_SUCCESS)
4371 return ERROR_SUCCESS;
4373 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4374 msiobj_release(&view->hdr);
4379 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4383 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4385 if (!lstrcmpW(file->File, filename))
4392 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4394 MSIPACKAGE *package = (MSIPACKAGE*)param;
4395 LPWSTR driver, driver_path, ptr;
4396 WCHAR outpath[MAX_PATH];
4397 MSIFILE *driver_file, *setup_file;
4400 UINT r = ERROR_SUCCESS;
4402 static const WCHAR driver_fmt[] = {
4403 'D','r','i','v','e','r','=','%','s',0};
4404 static const WCHAR setup_fmt[] = {
4405 'S','e','t','u','p','=','%','s',0};
4406 static const WCHAR usage_fmt[] = {
4407 'F','i','l','e','U','s','a','g','e','=','1',0};
4409 desc = MSI_RecordGetString(rec, 3);
4411 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4412 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4414 if (!driver_file || !setup_file)
4416 ERR("ODBC Driver entry not found!\n");
4417 return ERROR_FUNCTION_FAILED;
4420 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4421 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4422 lstrlenW(usage_fmt) + 1;
4423 driver = msi_alloc(len * sizeof(WCHAR));
4425 return ERROR_OUTOFMEMORY;
4428 lstrcpyW(ptr, desc);
4429 ptr += lstrlenW(ptr) + 1;
4431 sprintfW(ptr, driver_fmt, driver_file->FileName);
4432 ptr += lstrlenW(ptr) + 1;
4434 sprintfW(ptr, setup_fmt, setup_file->FileName);
4435 ptr += lstrlenW(ptr) + 1;
4437 lstrcpyW(ptr, usage_fmt);
4438 ptr += lstrlenW(ptr) + 1;
4441 driver_path = strdupW(driver_file->TargetPath);
4442 ptr = strrchrW(driver_path, '\\');
4443 if (ptr) *ptr = '\0';
4445 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4446 NULL, ODBC_INSTALL_COMPLETE, &usage))
4448 ERR("Failed to install SQL driver!\n");
4449 r = ERROR_FUNCTION_FAILED;
4453 msi_free(driver_path);
4458 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4460 MSIPACKAGE *package = (MSIPACKAGE*)param;
4461 LPWSTR translator, translator_path, ptr;
4462 WCHAR outpath[MAX_PATH];
4463 MSIFILE *translator_file, *setup_file;
4466 UINT r = ERROR_SUCCESS;
4468 static const WCHAR translator_fmt[] = {
4469 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4470 static const WCHAR setup_fmt[] = {
4471 'S','e','t','u','p','=','%','s',0};
4473 desc = MSI_RecordGetString(rec, 3);
4475 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4476 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4478 if (!translator_file || !setup_file)
4480 ERR("ODBC Translator entry not found!\n");
4481 return ERROR_FUNCTION_FAILED;
4484 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4485 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4486 translator = msi_alloc(len * sizeof(WCHAR));
4488 return ERROR_OUTOFMEMORY;
4491 lstrcpyW(ptr, desc);
4492 ptr += lstrlenW(ptr) + 1;
4494 sprintfW(ptr, translator_fmt, translator_file->FileName);
4495 ptr += lstrlenW(ptr) + 1;
4497 sprintfW(ptr, setup_fmt, setup_file->FileName);
4498 ptr += lstrlenW(ptr) + 1;
4501 translator_path = strdupW(translator_file->TargetPath);
4502 ptr = strrchrW(translator_path, '\\');
4503 if (ptr) *ptr = '\0';
4505 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4506 NULL, ODBC_INSTALL_COMPLETE, &usage))
4508 ERR("Failed to install SQL translator!\n");
4509 r = ERROR_FUNCTION_FAILED;
4512 msi_free(translator);
4513 msi_free(translator_path);
4518 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4521 LPCWSTR desc, driver;
4522 WORD request = ODBC_ADD_SYS_DSN;
4525 UINT r = ERROR_SUCCESS;
4527 static const WCHAR attrs_fmt[] = {
4528 'D','S','N','=','%','s',0 };
4530 desc = MSI_RecordGetString(rec, 3);
4531 driver = MSI_RecordGetString(rec, 4);
4532 registration = MSI_RecordGetInteger(rec, 5);
4534 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4535 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4537 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4538 attrs = msi_alloc(len * sizeof(WCHAR));
4540 return ERROR_OUTOFMEMORY;
4542 sprintfW(attrs, attrs_fmt, desc);
4543 attrs[len - 1] = '\0';
4545 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4547 ERR("Failed to install SQL data source!\n");
4548 r = ERROR_FUNCTION_FAILED;
4556 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4561 static const WCHAR driver_query[] = {
4562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4563 'O','D','B','C','D','r','i','v','e','r',0 };
4565 static const WCHAR translator_query[] = {
4566 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4567 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4569 static const WCHAR source_query[] = {
4570 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4571 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4573 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4574 if (rc != ERROR_SUCCESS)
4575 return ERROR_SUCCESS;
4577 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4578 msiobj_release(&view->hdr);
4580 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4581 if (rc != ERROR_SUCCESS)
4582 return ERROR_SUCCESS;
4584 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4585 msiobj_release(&view->hdr);
4587 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4588 if (rc != ERROR_SUCCESS)
4589 return ERROR_SUCCESS;
4591 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4592 msiobj_release(&view->hdr);
4597 #define ENV_ACT_SETALWAYS 0x1
4598 #define ENV_ACT_SETABSENT 0x2
4599 #define ENV_ACT_REMOVE 0x4
4600 #define ENV_ACT_REMOVEMATCH 0x8
4602 #define ENV_MOD_MACHINE 0x20000000
4603 #define ENV_MOD_APPEND 0x40000000
4604 #define ENV_MOD_PREFIX 0x80000000
4605 #define ENV_MOD_MASK 0xC0000000
4607 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4609 static LONG env_set_flags( LPCWSTR *name, LPWSTR *value, DWORD *flags )
4611 LPCWSTR cptr = *name;
4612 LPWSTR ptr = *value;
4614 static const WCHAR prefix[] = {'[','~',']',0};
4620 *flags |= ENV_ACT_SETALWAYS;
4621 else if (*cptr == '+')
4622 *flags |= ENV_ACT_SETABSENT;
4623 else if (*cptr == '-')
4624 *flags |= ENV_ACT_REMOVE;
4625 else if (*cptr == '!')
4626 *flags |= ENV_ACT_REMOVEMATCH;
4627 else if (*cptr == '*')
4628 *flags |= ENV_MOD_MACHINE;
4638 ERR("Missing environment variable\n");
4639 return ERROR_FUNCTION_FAILED;
4642 if (!strncmpW(ptr, prefix, lstrlenW(prefix)))
4644 *flags |= ENV_MOD_PREFIX;
4645 *value += lstrlenW(prefix);
4649 ptr += lstrlenW(ptr) - lstrlenW(prefix) - 1;
4650 if (!lstrcmpW(ptr, prefix))
4652 *flags |= ENV_MOD_APPEND;
4658 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4659 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4660 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4661 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4663 ERR("Invalid flags: %08x\n", *flags);
4664 return ERROR_FUNCTION_FAILED;
4667 return ERROR_SUCCESS;
4670 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4672 MSIPACKAGE *package = param;
4673 LPCWSTR name, value, comp;
4674 LPWSTR data = NULL, newval = NULL;
4675 LPWSTR deformatted, ptr;
4676 DWORD flags, type, size;
4678 HKEY env = NULL, root = HKEY_CURRENT_USER;
4680 static const WCHAR environment[] =
4681 {'S','y','s','t','e','m','\\',
4682 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4683 'C','o','n','t','r','o','l','\\',
4684 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4685 'E','n','v','i','r','o','n','m','e','n','t',0};
4686 static const WCHAR semicolon[] = {';',0};
4688 name = MSI_RecordGetString(rec, 2);
4689 value = MSI_RecordGetString(rec, 3);
4690 comp = MSI_RecordGetString(rec, 4);
4692 deformat_string(package, value, &deformatted);
4694 return ERROR_OUTOFMEMORY;
4696 res = env_set_flags(&name, &deformatted, &flags);
4697 if (res != ERROR_SUCCESS)
4700 value = deformatted;
4702 if (flags & ENV_MOD_MACHINE)
4703 root = HKEY_LOCAL_MACHINE;
4705 res = RegOpenKeyExW(root, environment, 0, KEY_ALL_ACCESS, &env);
4706 if (res != ERROR_SUCCESS)
4709 if (flags & ENV_ACT_REMOVE)
4710 FIXME("Not removing environment variable on uninstall!\n");
4713 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
4714 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
4715 (res == ERROR_SUCCESS && type != REG_SZ))
4718 if (res != ERROR_FILE_NOT_FOUND)
4720 if (flags & ENV_ACT_SETABSENT)
4722 res = ERROR_SUCCESS;
4726 data = msi_alloc(size);
4730 return ERROR_OUTOFMEMORY;
4733 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
4734 if (res != ERROR_SUCCESS)
4737 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
4739 res = RegDeleteKeyW(env, name);
4743 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
4744 newval = msi_alloc(size);
4748 res = ERROR_OUTOFMEMORY;
4752 if (!(flags & ENV_MOD_MASK))
4753 lstrcpyW(newval, value);
4756 if (flags & ENV_MOD_PREFIX)
4758 lstrcpyW(newval, value);
4759 lstrcatW(newval, semicolon);
4760 ptr = newval + lstrlenW(value) + 1;
4763 lstrcpyW(ptr, data);
4765 if (flags & ENV_MOD_APPEND)
4767 lstrcatW(newval, semicolon);
4768 lstrcatW(newval, value);
4774 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
4775 newval = msi_alloc(size);
4778 res = ERROR_OUTOFMEMORY;
4782 lstrcpyW(newval, value);
4785 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
4786 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
4789 if (env) RegCloseKey(env);
4790 msi_free(deformatted);
4796 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4800 static const WCHAR ExecSeqQuery[] =
4801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4802 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
4803 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4804 if (rc != ERROR_SUCCESS)
4805 return ERROR_SUCCESS;
4807 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
4808 msiobj_release(&view->hdr);
4813 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4814 LPCSTR action, LPCWSTR table )
4816 static const WCHAR query[] = {
4817 'S','E','L','E','C','T',' ','*',' ',
4818 'F','R','O','M',' ','`','%','s','`',0 };
4819 MSIQUERY *view = NULL;
4823 r = MSI_OpenQuery( package->db, &view, query, table );
4824 if (r == ERROR_SUCCESS)
4826 r = MSI_IterateRecords(view, &count, NULL, package);
4827 msiobj_release(&view->hdr);
4831 FIXME("%s -> %u ignored %s table values\n",
4832 action, count, debugstr_w(table));
4834 return ERROR_SUCCESS;
4837 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4839 TRACE("%p\n", package);
4840 return ERROR_SUCCESS;
4843 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4845 static const WCHAR table[] =
4846 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4847 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4850 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4852 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4853 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4856 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4858 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4859 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4862 static UINT ACTION_BindImage( MSIPACKAGE *package )
4864 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4865 return msi_unimplemented_action_stub( package, "BindImage", table );
4868 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4870 static const WCHAR table[] = {
4871 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4872 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4875 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4877 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4878 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4881 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4883 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4884 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4887 static UINT ACTION_StopServices( MSIPACKAGE *package )
4889 static const WCHAR table[] = {
4890 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4891 return msi_unimplemented_action_stub( package, "StopServices", table );
4894 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4896 static const WCHAR table[] = {
4897 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4898 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4900 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
4902 static const WCHAR table[] = {
4903 'P','r','o','d','u','c','t','I','D',0 };
4904 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
4907 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4909 static const WCHAR table[] = {
4910 'E','n','v','i','r','o','n','m','e','n','t',0 };
4911 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4914 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4916 static const WCHAR table[] = {
4917 'M','s','i','A','s','s','e','m','b','l','y',0 };
4918 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4921 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4923 static const WCHAR table[] = {
4924 'M','s','i','A','s','s','e','m','b','l','y',0 };
4925 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4928 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4930 static const WCHAR table[] = { 'F','o','n','t',0 };
4931 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4934 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4936 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4937 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4940 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4942 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4943 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4946 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4948 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4949 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4952 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4954 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4955 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4958 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
4960 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
4961 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
4964 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
4966 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
4967 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
4970 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
4972 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4973 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
4976 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
4978 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
4979 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
4982 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
4984 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
4985 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
4988 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
4990 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
4991 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
4994 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4996 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
4997 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5000 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5002 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5003 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5006 static UINT ACTION_UnpublishFeatures( MSIPACKAGE *package )
5008 static const WCHAR table[] = { 'F','e','a','t','u','r','e','C','o','m','p','o','n','e','n','t','s',0 };
5009 return msi_unimplemented_action_stub( package, "UnpublishFeatures", table );
5012 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5014 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5015 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5018 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5020 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5021 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5024 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5026 static const WCHAR table[] = { 'M','I','M','E',0 };
5027 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5030 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5032 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5033 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5036 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5038 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5039 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5042 static const struct _actions StandardActions[] = {
5043 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5044 { szAppSearch, ACTION_AppSearch },
5045 { szBindImage, ACTION_BindImage },
5046 { szCCPSearch, ACTION_CCPSearch },
5047 { szCostFinalize, ACTION_CostFinalize },
5048 { szCostInitialize, ACTION_CostInitialize },
5049 { szCreateFolders, ACTION_CreateFolders },
5050 { szCreateShortcuts, ACTION_CreateShortcuts },
5051 { szDeleteServices, ACTION_DeleteServices },
5052 { szDisableRollback, NULL },
5053 { szDuplicateFiles, ACTION_DuplicateFiles },
5054 { szExecuteAction, ACTION_ExecuteAction },
5055 { szFileCost, ACTION_FileCost },
5056 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5057 { szForceReboot, ACTION_ForceReboot },
5058 { szInstallAdminPackage, NULL },
5059 { szInstallExecute, ACTION_InstallExecute },
5060 { szInstallExecuteAgain, ACTION_InstallExecute },
5061 { szInstallFiles, ACTION_InstallFiles},
5062 { szInstallFinalize, ACTION_InstallFinalize },
5063 { szInstallInitialize, ACTION_InstallInitialize },
5064 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5065 { szInstallValidate, ACTION_InstallValidate },
5066 { szIsolateComponents, ACTION_IsolateComponents },
5067 { szLaunchConditions, ACTION_LaunchConditions },
5068 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5069 { szMoveFiles, ACTION_MoveFiles },
5070 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5071 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5072 { szInstallODBC, ACTION_InstallODBC },
5073 { szInstallServices, ACTION_InstallServices },
5074 { szPatchFiles, ACTION_PatchFiles },
5075 { szProcessComponents, ACTION_ProcessComponents },
5076 { szPublishComponents, ACTION_PublishComponents },
5077 { szPublishFeatures, ACTION_PublishFeatures },
5078 { szPublishProduct, ACTION_PublishProduct },
5079 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5080 { szRegisterComPlus, ACTION_RegisterComPlus},
5081 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5082 { szRegisterFonts, ACTION_RegisterFonts },
5083 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5084 { szRegisterProduct, ACTION_RegisterProduct },
5085 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5086 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5087 { szRegisterUser, ACTION_RegisterUser },
5088 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5089 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5090 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5091 { szRemoveFiles, ACTION_RemoveFiles },
5092 { szRemoveFolders, ACTION_RemoveFolders },
5093 { szRemoveIniValues, ACTION_RemoveIniValues },
5094 { szRemoveODBC, ACTION_RemoveODBC },
5095 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5096 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5097 { szResolveSource, ACTION_ResolveSource },
5098 { szRMCCPSearch, ACTION_RMCCPSearch },
5099 { szScheduleReboot, NULL },
5100 { szSelfRegModules, ACTION_SelfRegModules },
5101 { szSelfUnregModules, ACTION_SelfUnregModules },
5102 { szSetODBCFolders, NULL },
5103 { szStartServices, ACTION_StartServices },
5104 { szStopServices, ACTION_StopServices },
5105 { szUnpublishComponents, ACTION_UnpublishComponents },
5106 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5107 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5108 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5109 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5110 { szUnregisterFonts, ACTION_UnregisterFonts },
5111 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5112 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5113 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5114 { szValidateProductID, ACTION_ValidateProductID },
5115 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5116 { szWriteIniValues, ACTION_WriteIniValues },
5117 { szWriteRegistryValues, ACTION_WriteRegistryValues },