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 szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
458 LPWSTR guid_list, *guids, product_id;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
461 product_id = msi_dup_property( package, szProdID );
464 /* FIXME: the property ProductID should be written into the DB somewhere */
465 ERR("no product ID 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_id ))
477 msi_free( guid_list );
478 msi_free( product_id );
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);
753 rc = ACTION_PerformAction(package,action,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);
794 rc = ACTION_PerformAction(iap->package,action,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, BOOL force )
988 arc = ACTION_CustomAction(package,action, 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, 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, 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)
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, 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, 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 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1986 msi_free( version );
1988 sprintfW( filever, name_fmt,
1989 HIWORD(lpVer->dwFileVersionMS),
1990 LOWORD(lpVer->dwFileVersionMS),
1991 HIWORD(lpVer->dwFileVersionLS),
1992 LOWORD(lpVer->dwFileVersionLS));
1994 return strdupW( filever );
1997 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1999 LPWSTR file_version;
2002 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2004 MSICOMPONENT* comp = file->Component;
2010 if (file->IsCompressed)
2011 comp->ForceLocalState = TRUE;
2013 /* calculate target */
2014 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2016 msi_free(file->TargetPath);
2018 TRACE("file %s is named %s\n",
2019 debugstr_w(file->File), debugstr_w(file->FileName));
2021 file->TargetPath = build_directory_name(2, p, file->FileName);
2025 TRACE("file %s resolves to %s\n",
2026 debugstr_w(file->File), debugstr_w(file->TargetPath));
2028 /* don't check files of components that aren't installed */
2029 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2030 comp->Installed == INSTALLSTATE_ABSENT)
2032 file->state = msifs_missing; /* assume files are missing */
2036 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2038 file->state = msifs_missing;
2039 comp->Cost += file->FileSize;
2040 comp->Installed = INSTALLSTATE_INCOMPLETE;
2044 if (file->Version &&
2045 (file_version = msi_get_disk_file_version( file->TargetPath )))
2047 TRACE("new %s old %s\n", debugstr_w(file->Version),
2048 debugstr_w(file_version));
2049 /* FIXME: seems like a bad way to compare version numbers */
2050 if (lstrcmpiW(file_version, file->Version)<0)
2052 file->state = msifs_overwrite;
2053 comp->Cost += file->FileSize;
2054 comp->Installed = INSTALLSTATE_INCOMPLETE;
2057 file->state = msifs_present;
2058 msi_free( file_version );
2061 file->state = msifs_present;
2064 return ERROR_SUCCESS;
2068 * A lot is done in this function aside from just the costing.
2069 * The costing needs to be implemented at some point but for now I am going
2070 * to focus on the directory building
2073 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2075 static const WCHAR ExecSeqQuery[] =
2076 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2077 '`','D','i','r','e','c','t','o','r','y','`',0};
2078 static const WCHAR ConditionQuery[] =
2079 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2080 '`','C','o','n','d','i','t','i','o','n','`',0};
2081 static const WCHAR szCosting[] =
2082 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2083 static const WCHAR szlevel[] =
2084 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2085 static const WCHAR szOne[] = { '1', 0 };
2091 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2092 return ERROR_SUCCESS;
2094 TRACE("Building Directory properties\n");
2096 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2097 if (rc == ERROR_SUCCESS)
2099 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2101 msiobj_release(&view->hdr);
2104 /* read components states from the registry */
2105 ACTION_GetComponentInstallStates(package);
2107 TRACE("File calculations\n");
2108 msi_check_file_install_states( package );
2110 TRACE("Evaluating Condition Table\n");
2112 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2113 if (rc == ERROR_SUCCESS)
2115 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2117 msiobj_release(&view->hdr);
2120 TRACE("Enabling or Disabling Components\n");
2121 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2123 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2125 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2126 comp->Enabled = FALSE;
2130 MSI_SetPropertyW(package,szCosting,szOne);
2131 /* set default run level if not set */
2132 level = msi_dup_property( package, szlevel );
2134 MSI_SetPropertyW(package,szlevel, szOne);
2137 ACTION_UpdateFeatureInstallStates(package);
2139 return MSI_SetFeatureStates(package);
2142 /* OK this value is "interpreted" and then formatted based on the
2143 first few characters */
2144 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2148 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2154 LPWSTR deformated = NULL;
2157 deformat_string(package, &value[2], &deformated);
2159 /* binary value type */
2163 *size = (strlenW(ptr)/2)+1;
2165 *size = strlenW(ptr)/2;
2167 data = msi_alloc(*size);
2173 /* if uneven pad with a zero in front */
2179 data[count] = (BYTE)strtol(byte,NULL,0);
2181 TRACE("Uneven byte count\n");
2189 data[count] = (BYTE)strtol(byte,NULL,0);
2192 msi_free(deformated);
2194 TRACE("Data %i bytes(%i)\n",*size,count);
2201 deformat_string(package, &value[1], &deformated);
2204 *size = sizeof(DWORD);
2205 data = msi_alloc(*size);
2211 if ( (*p < '0') || (*p > '9') )
2217 if (deformated[0] == '-')
2220 TRACE("DWORD %i\n",*(LPDWORD)data);
2222 msi_free(deformated);
2227 static const WCHAR szMulti[] = {'[','~',']',0};
2236 *type=REG_EXPAND_SZ;
2244 if (strstrW(value,szMulti))
2245 *type = REG_MULTI_SZ;
2247 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2252 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2254 MSIPACKAGE *package = (MSIPACKAGE*)param;
2255 static const WCHAR szHCR[] =
2256 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2257 'R','O','O','T','\\',0};
2258 static const WCHAR szHCU[] =
2259 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2260 'U','S','E','R','\\',0};
2261 static const WCHAR szHLM[] =
2262 {'H','K','E','Y','_','L','O','C','A','L','_',
2263 'M','A','C','H','I','N','E','\\',0};
2264 static const WCHAR szHU[] =
2265 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2267 LPSTR value_data = NULL;
2268 HKEY root_key, hkey;
2271 LPCWSTR szRoot, component, name, key, value;
2276 BOOL check_first = FALSE;
2279 ui_progress(package,2,0,0,0);
2286 component = MSI_RecordGetString(row, 6);
2287 comp = get_loaded_component(package,component);
2289 return ERROR_SUCCESS;
2291 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2293 TRACE("Skipping write due to disabled component %s\n",
2294 debugstr_w(component));
2296 comp->Action = comp->Installed;
2298 return ERROR_SUCCESS;
2301 comp->Action = INSTALLSTATE_LOCAL;
2303 name = MSI_RecordGetString(row, 4);
2304 if( MSI_RecordIsNull(row,5) && name )
2306 /* null values can have special meanings */
2307 if (name[0]=='-' && name[1] == 0)
2308 return ERROR_SUCCESS;
2309 else if ((name[0]=='+' && name[1] == 0) ||
2310 (name[0] == '*' && name[1] == 0))
2315 root = MSI_RecordGetInteger(row,2);
2316 key = MSI_RecordGetString(row, 3);
2318 /* get the root key */
2323 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2324 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2325 if (all_users && all_users[0] == '1')
2327 root_key = HKEY_LOCAL_MACHINE;
2332 root_key = HKEY_CURRENT_USER;
2335 msi_free(all_users);
2338 case 0: root_key = HKEY_CLASSES_ROOT;
2341 case 1: root_key = HKEY_CURRENT_USER;
2344 case 2: root_key = HKEY_LOCAL_MACHINE;
2347 case 3: root_key = HKEY_USERS;
2351 ERR("Unknown root %i\n",root);
2357 return ERROR_SUCCESS;
2359 deformat_string(package, key , &deformated);
2360 size = strlenW(deformated) + strlenW(szRoot) + 1;
2361 uikey = msi_alloc(size*sizeof(WCHAR));
2362 strcpyW(uikey,szRoot);
2363 strcatW(uikey,deformated);
2365 if (RegCreateKeyW( root_key, deformated, &hkey))
2367 ERR("Could not create key %s\n",debugstr_w(deformated));
2368 msi_free(deformated);
2370 return ERROR_SUCCESS;
2372 msi_free(deformated);
2374 value = MSI_RecordGetString(row,5);
2376 value_data = parse_value(package, value, &type, &size);
2379 static const WCHAR szEmpty[] = {0};
2380 value_data = (LPSTR)strdupW(szEmpty);
2385 deformat_string(package, name, &deformated);
2387 /* get the double nulls to terminate SZ_MULTI */
2388 if (type == REG_MULTI_SZ)
2389 size +=sizeof(WCHAR);
2393 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2395 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2400 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2401 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2403 TRACE("value %s of %s checked already exists\n",
2404 debugstr_w(deformated), debugstr_w(uikey));
2408 TRACE("Checked and setting value %s of %s\n",
2409 debugstr_w(deformated), debugstr_w(uikey));
2410 if (deformated || size)
2411 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2416 uirow = MSI_CreateRecord(3);
2417 MSI_RecordSetStringW(uirow,2,deformated);
2418 MSI_RecordSetStringW(uirow,1,uikey);
2421 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2423 MSI_RecordSetStringW(uirow,3,value);
2425 ui_actiondata(package,szWriteRegistryValues,uirow);
2426 msiobj_release( &uirow->hdr );
2428 msi_free(value_data);
2429 msi_free(deformated);
2432 return ERROR_SUCCESS;
2435 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2439 static const WCHAR ExecSeqQuery[] =
2440 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2441 '`','R','e','g','i','s','t','r','y','`',0 };
2443 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2444 if (rc != ERROR_SUCCESS)
2445 return ERROR_SUCCESS;
2447 /* increment progress bar each time action data is sent */
2448 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2450 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2452 msiobj_release(&view->hdr);
2456 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2458 package->script->CurrentlyScripting = TRUE;
2460 return ERROR_SUCCESS;
2464 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2469 static const WCHAR q1[]=
2470 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2471 '`','R','e','g','i','s','t','r','y','`',0};
2474 MSIFEATURE *feature;
2477 TRACE("InstallValidate\n");
2479 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2480 if (rc == ERROR_SUCCESS)
2482 MSI_IterateRecords( view, &progress, NULL, package );
2483 msiobj_release( &view->hdr );
2484 total += progress * REG_PROGRESS_VALUE;
2487 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2488 total += COMPONENT_PROGRESS_VALUE;
2490 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2491 total += file->FileSize;
2493 ui_progress(package,0,total,0,0);
2495 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2497 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2498 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2499 feature->ActionRequest);
2502 return ERROR_SUCCESS;
2505 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2507 MSIPACKAGE* package = (MSIPACKAGE*)param;
2508 LPCWSTR cond = NULL;
2509 LPCWSTR message = NULL;
2510 static const WCHAR title[]=
2511 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2513 cond = MSI_RecordGetString(row,1);
2515 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2518 message = MSI_RecordGetString(row,2);
2519 deformat_string(package,message,&deformated);
2520 MessageBoxW(NULL,deformated,title,MB_OK);
2521 msi_free(deformated);
2522 return ERROR_FUNCTION_FAILED;
2525 return ERROR_SUCCESS;
2528 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2531 MSIQUERY * view = NULL;
2532 static const WCHAR ExecSeqQuery[] =
2533 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2534 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2536 TRACE("Checking launch conditions\n");
2538 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2539 if (rc != ERROR_SUCCESS)
2540 return ERROR_SUCCESS;
2542 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2543 msiobj_release(&view->hdr);
2548 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2552 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2554 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2556 MSIRECORD * row = 0;
2558 LPWSTR deformated,buffer,deformated_name;
2560 static const WCHAR ExecSeqQuery[] =
2561 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2562 '`','R','e','g','i','s','t','r','y','`',' ',
2563 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2564 ' ','=',' ' ,'\'','%','s','\'',0 };
2565 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2566 static const WCHAR fmt2[]=
2567 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2569 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2573 root = MSI_RecordGetInteger(row,2);
2574 key = MSI_RecordGetString(row, 3);
2575 name = MSI_RecordGetString(row, 4);
2576 deformat_string(package, key , &deformated);
2577 deformat_string(package, name, &deformated_name);
2579 len = strlenW(deformated) + 6;
2580 if (deformated_name)
2581 len+=strlenW(deformated_name);
2583 buffer = msi_alloc( len *sizeof(WCHAR));
2585 if (deformated_name)
2586 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2588 sprintfW(buffer,fmt,root,deformated);
2590 msi_free(deformated);
2591 msi_free(deformated_name);
2592 msiobj_release(&row->hdr);
2596 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2598 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2603 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2606 return strdupW( file->TargetPath );
2611 static HKEY openSharedDLLsKey(void)
2614 static const WCHAR path[] =
2615 {'S','o','f','t','w','a','r','e','\\',
2616 'M','i','c','r','o','s','o','f','t','\\',
2617 'W','i','n','d','o','w','s','\\',
2618 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2619 'S','h','a','r','e','d','D','L','L','s',0};
2621 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2625 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2630 DWORD sz = sizeof(count);
2633 hkey = openSharedDLLsKey();
2634 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2635 if (rc != ERROR_SUCCESS)
2641 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2645 hkey = openSharedDLLsKey();
2647 msi_reg_set_val_dword( hkey, path, count );
2649 RegDeleteValueW(hkey,path);
2655 * Return TRUE if the count should be written out and FALSE if not
2657 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2659 MSIFEATURE *feature;
2663 /* only refcount DLLs */
2664 if (comp->KeyPath == NULL ||
2665 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2666 comp->Attributes & msidbComponentAttributesODBCDataSource)
2670 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2671 write = (count > 0);
2673 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2677 /* increment counts */
2678 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2682 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2685 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2687 if ( cl->component == comp )
2692 /* decrement counts */
2693 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2697 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2700 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2702 if ( cl->component == comp )
2707 /* ref count all the files in the component */
2712 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2714 if (file->Component == comp)
2715 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2719 /* add a count for permenent */
2720 if (comp->Attributes & msidbComponentAttributesPermanent)
2723 comp->RefCount = count;
2726 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2730 * Ok further analysis makes me think that this work is
2731 * actually done in the PublishComponents and PublishFeatures
2732 * step, and not here. It appears like the keypath and all that is
2733 * resolved in this step, however actually written in the Publish steps.
2734 * But we will leave it here for now because it is unclear
2736 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2738 WCHAR squished_pc[GUID_SIZE];
2739 WCHAR squished_cc[GUID_SIZE];
2742 HKEY hkey=0,hkey2=0;
2744 /* writes the Component and Features values to the registry */
2746 rc = MSIREG_OpenComponents(&hkey);
2747 if (rc != ERROR_SUCCESS)
2750 squash_guid(package->ProductCode,squished_pc);
2751 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2753 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2757 ui_progress(package,2,0,0,0);
2758 if (!comp->ComponentId)
2761 squash_guid(comp->ComponentId,squished_cc);
2763 msi_free(comp->FullKeypath);
2764 comp->FullKeypath = resolve_keypath( package, comp );
2766 /* do the refcounting */
2767 ACTION_RefCountComponent( package, comp );
2769 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2770 debugstr_w(comp->Component),
2771 debugstr_w(squished_cc),
2772 debugstr_w(comp->FullKeypath),
2775 * Write the keypath out if the component is to be registered
2776 * and delete the key if the component is to be deregistered
2778 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2780 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2781 if (rc != ERROR_SUCCESS)
2784 if (!comp->FullKeypath)
2787 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2789 if (comp->Attributes & msidbComponentAttributesPermanent)
2791 static const WCHAR szPermKey[] =
2792 { '0','0','0','0','0','0','0','0','0','0','0','0',
2793 '0','0','0','0','0','0','0','0','0','0','0','0',
2794 '0','0','0','0','0','0','0','0',0 };
2796 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2801 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2805 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2806 if (rc != ERROR_SUCCESS)
2809 RegDeleteValueW(hkey2,squished_pc);
2811 /* if the key is empty delete it */
2812 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2814 if (res == ERROR_NO_MORE_ITEMS)
2815 RegDeleteKeyW(hkey,squished_cc);
2820 uirow = MSI_CreateRecord(3);
2821 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2822 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2823 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2824 ui_actiondata(package,szProcessComponents,uirow);
2825 msiobj_release( &uirow->hdr );
2839 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2840 LPWSTR lpszName, LONG_PTR lParam)
2843 typelib_struct *tl_struct = (typelib_struct*) lParam;
2844 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2848 if (!IS_INTRESOURCE(lpszName))
2850 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2854 sz = strlenW(tl_struct->source)+4;
2855 sz *= sizeof(WCHAR);
2857 if ((INT_PTR)lpszName == 1)
2858 tl_struct->path = strdupW(tl_struct->source);
2861 tl_struct->path = msi_alloc(sz);
2862 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2865 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2866 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2867 if (!SUCCEEDED(res))
2869 msi_free(tl_struct->path);
2870 tl_struct->path = NULL;
2875 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2876 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2878 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2882 msi_free(tl_struct->path);
2883 tl_struct->path = NULL;
2885 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2886 ITypeLib_Release(tl_struct->ptLib);
2891 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2893 MSIPACKAGE* package = (MSIPACKAGE*)param;
2897 typelib_struct tl_struct;
2899 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2901 component = MSI_RecordGetString(row,3);
2902 comp = get_loaded_component(package,component);
2904 return ERROR_SUCCESS;
2906 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2908 TRACE("Skipping typelib reg due to disabled component\n");
2910 comp->Action = comp->Installed;
2912 return ERROR_SUCCESS;
2915 comp->Action = INSTALLSTATE_LOCAL;
2917 file = get_loaded_file( package, comp->KeyPath );
2919 return ERROR_SUCCESS;
2921 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2925 guid = MSI_RecordGetString(row,1);
2926 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2927 tl_struct.source = strdupW( file->TargetPath );
2928 tl_struct.path = NULL;
2930 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2931 (LONG_PTR)&tl_struct);
2939 helpid = MSI_RecordGetString(row,6);
2942 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2943 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2946 if (!SUCCEEDED(res))
2947 ERR("Failed to register type library %s\n",
2948 debugstr_w(tl_struct.path));
2951 ui_actiondata(package,szRegisterTypeLibraries,row);
2953 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2956 ITypeLib_Release(tl_struct.ptLib);
2957 msi_free(tl_struct.path);
2960 ERR("Failed to load type library %s\n",
2961 debugstr_w(tl_struct.source));
2963 FreeLibrary(module);
2964 msi_free(tl_struct.source);
2967 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2969 return ERROR_SUCCESS;
2972 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2975 * OK this is a bit confusing.. I am given a _Component key and I believe
2976 * that the file that is being registered as a type library is the "key file
2977 * of that component" which I interpret to mean "The file in the KeyPath of
2982 static const WCHAR Query[] =
2983 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2984 '`','T','y','p','e','L','i','b','`',0};
2986 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2987 if (rc != ERROR_SUCCESS)
2988 return ERROR_SUCCESS;
2990 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2991 msiobj_release(&view->hdr);
2995 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2997 MSIPACKAGE *package = (MSIPACKAGE*)param;
2998 LPWSTR target_file, target_folder, filename;
2999 LPCWSTR buffer, extension;
3001 static const WCHAR szlnk[]={'.','l','n','k',0};
3002 IShellLinkW *sl = NULL;
3003 IPersistFile *pf = NULL;
3006 buffer = MSI_RecordGetString(row,4);
3007 comp = get_loaded_component(package,buffer);
3009 return ERROR_SUCCESS;
3011 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3013 TRACE("Skipping shortcut creation due to disabled component\n");
3015 comp->Action = comp->Installed;
3017 return ERROR_SUCCESS;
3020 comp->Action = INSTALLSTATE_LOCAL;
3022 ui_actiondata(package,szCreateShortcuts,row);
3024 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3025 &IID_IShellLinkW, (LPVOID *) &sl );
3029 ERR("CLSID_ShellLink not available\n");
3033 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3036 ERR("QueryInterface(IID_IPersistFile) failed\n");
3040 buffer = MSI_RecordGetString(row,2);
3041 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3043 /* may be needed because of a bug somehwere else */
3044 create_full_pathW(target_folder);
3046 filename = msi_dup_record_field( row, 3 );
3047 reduce_to_longfilename(filename);
3049 extension = strchrW(filename,'.');
3050 if (!extension || strcmpiW(extension,szlnk))
3052 int len = strlenW(filename);
3053 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3054 memcpy(filename + len, szlnk, sizeof(szlnk));
3056 target_file = build_directory_name(2, target_folder, filename);
3057 msi_free(target_folder);
3060 buffer = MSI_RecordGetString(row,5);
3061 if (strchrW(buffer,'['))
3064 deformat_string(package,buffer,&deformated);
3065 IShellLinkW_SetPath(sl,deformated);
3066 msi_free(deformated);
3070 FIXME("poorly handled shortcut format, advertised shortcut\n");
3071 IShellLinkW_SetPath(sl,comp->FullKeypath);
3074 if (!MSI_RecordIsNull(row,6))
3077 buffer = MSI_RecordGetString(row,6);
3078 deformat_string(package,buffer,&deformated);
3079 IShellLinkW_SetArguments(sl,deformated);
3080 msi_free(deformated);
3083 if (!MSI_RecordIsNull(row,7))
3085 buffer = MSI_RecordGetString(row,7);
3086 IShellLinkW_SetDescription(sl,buffer);
3089 if (!MSI_RecordIsNull(row,8))
3090 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3092 if (!MSI_RecordIsNull(row,9))
3097 buffer = MSI_RecordGetString(row,9);
3099 Path = build_icon_path(package,buffer);
3100 index = MSI_RecordGetInteger(row,10);
3102 /* no value means 0 */
3103 if (index == MSI_NULL_INTEGER)
3106 IShellLinkW_SetIconLocation(sl,Path,index);
3110 if (!MSI_RecordIsNull(row,11))
3111 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3113 if (!MSI_RecordIsNull(row,12))
3116 buffer = MSI_RecordGetString(row,12);
3117 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3119 IShellLinkW_SetWorkingDirectory(sl,Path);
3123 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3124 IPersistFile_Save(pf,target_file,FALSE);
3126 msi_free(target_file);
3130 IPersistFile_Release( pf );
3132 IShellLinkW_Release( sl );
3134 return ERROR_SUCCESS;
3137 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3142 static const WCHAR Query[] =
3143 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3144 '`','S','h','o','r','t','c','u','t','`',0};
3146 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3147 if (rc != ERROR_SUCCESS)
3148 return ERROR_SUCCESS;
3150 res = CoInitialize( NULL );
3153 ERR("CoInitialize failed\n");
3154 return ERROR_FUNCTION_FAILED;
3157 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3158 msiobj_release(&view->hdr);
3165 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3167 MSIPACKAGE* package = (MSIPACKAGE*)param;
3176 FileName = MSI_RecordGetString(row,1);
3179 ERR("Unable to get FileName\n");
3180 return ERROR_SUCCESS;
3183 FilePath = build_icon_path(package,FileName);
3185 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3187 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3188 FILE_ATTRIBUTE_NORMAL, NULL);
3190 if (the_file == INVALID_HANDLE_VALUE)
3192 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3194 return ERROR_SUCCESS;
3201 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3202 if (rc != ERROR_SUCCESS)
3204 ERR("Failed to get stream\n");
3205 CloseHandle(the_file);
3206 DeleteFileW(FilePath);
3209 WriteFile(the_file,buffer,sz,&write,NULL);
3210 } while (sz == 1024);
3214 CloseHandle(the_file);
3216 uirow = MSI_CreateRecord(1);
3217 MSI_RecordSetStringW(uirow,1,FileName);
3218 ui_actiondata(package,szPublishProduct,uirow);
3219 msiobj_release( &uirow->hdr );
3221 return ERROR_SUCCESS;
3225 * 99% of the work done here is only done for
3226 * advertised installs. However this is where the
3227 * Icon table is processed and written out
3228 * so that is what I am going to do here.
3230 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3234 static const WCHAR Query[]=
3235 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3236 '`','I','c','o','n','`',0};
3237 /* for registry stuff */
3240 static const WCHAR szProductLanguage[] =
3241 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3242 static const WCHAR szARPProductIcon[] =
3243 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3244 static const WCHAR szProductVersion[] =
3245 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3249 MSIHANDLE hDb, hSumInfo;
3251 /* write out icon files */
3253 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3254 if (rc == ERROR_SUCCESS)
3256 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3257 msiobj_release(&view->hdr);
3260 /* ok there is a lot more done here but i need to figure out what */
3262 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3263 if (rc != ERROR_SUCCESS)
3266 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3267 if (rc != ERROR_SUCCESS)
3271 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3272 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3275 langid = msi_get_property_int( package, szProductLanguage, 0 );
3276 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3278 buffer = msi_dup_property( package, szARPProductIcon );
3281 LPWSTR path = build_icon_path(package,buffer);
3282 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3287 buffer = msi_dup_property( package, szProductVersion );
3290 DWORD verdword = msi_version_str_to_dword(buffer);
3291 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3295 /* FIXME: Need to write more keys to the user registry */
3297 hDb= alloc_msihandle( &package->db->hdr );
3299 rc = ERROR_NOT_ENOUGH_MEMORY;
3302 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3303 MsiCloseHandle(hDb);
3304 if (rc == ERROR_SUCCESS)
3306 WCHAR guidbuffer[0x200];
3308 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3310 if (rc == ERROR_SUCCESS)
3312 WCHAR squashed[GUID_SIZE];
3313 /* for now we only care about the first guid */
3314 LPWSTR ptr = strchrW(guidbuffer,';');
3316 squash_guid(guidbuffer,squashed);
3317 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3321 ERR("Unable to query Revision_Number...\n");
3324 MsiCloseHandle(hSumInfo);
3328 ERR("Unable to open Summary Information\n");
3340 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3342 MSIPACKAGE *package = (MSIPACKAGE*)param;
3343 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3344 LPWSTR deformated_section, deformated_key, deformated_value;
3345 LPWSTR folder, fullname = NULL;
3349 static const WCHAR szWindowsFolder[] =
3350 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3352 component = MSI_RecordGetString(row, 8);
3353 comp = get_loaded_component(package,component);
3355 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3357 TRACE("Skipping ini file due to disabled component %s\n",
3358 debugstr_w(component));
3360 comp->Action = comp->Installed;
3362 return ERROR_SUCCESS;
3365 comp->Action = INSTALLSTATE_LOCAL;
3367 identifier = MSI_RecordGetString(row,1);
3368 filename = MSI_RecordGetString(row,2);
3369 dirproperty = MSI_RecordGetString(row,3);
3370 section = MSI_RecordGetString(row,4);
3371 key = MSI_RecordGetString(row,5);
3372 value = MSI_RecordGetString(row,6);
3373 action = MSI_RecordGetInteger(row,7);
3375 deformat_string(package,section,&deformated_section);
3376 deformat_string(package,key,&deformated_key);
3377 deformat_string(package,value,&deformated_value);
3381 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3383 folder = msi_dup_property( package, dirproperty );
3386 folder = msi_dup_property( package, szWindowsFolder );
3390 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3394 fullname = build_directory_name(2, folder, filename);
3398 TRACE("Adding value %s to section %s in %s\n",
3399 debugstr_w(deformated_key), debugstr_w(deformated_section),
3400 debugstr_w(fullname));
3401 WritePrivateProfileStringW(deformated_section, deformated_key,
3402 deformated_value, fullname);
3404 else if (action == 1)
3407 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3408 returned, 10, fullname);
3409 if (returned[0] == 0)
3411 TRACE("Adding value %s to section %s in %s\n",
3412 debugstr_w(deformated_key), debugstr_w(deformated_section),
3413 debugstr_w(fullname));
3415 WritePrivateProfileStringW(deformated_section, deformated_key,
3416 deformated_value, fullname);
3419 else if (action == 3)
3420 FIXME("Append to existing section not yet implemented\n");
3422 uirow = MSI_CreateRecord(4);
3423 MSI_RecordSetStringW(uirow,1,identifier);
3424 MSI_RecordSetStringW(uirow,2,deformated_section);
3425 MSI_RecordSetStringW(uirow,3,deformated_key);
3426 MSI_RecordSetStringW(uirow,4,deformated_value);
3427 ui_actiondata(package,szWriteIniValues,uirow);
3428 msiobj_release( &uirow->hdr );
3432 msi_free(deformated_key);
3433 msi_free(deformated_value);
3434 msi_free(deformated_section);
3435 return ERROR_SUCCESS;
3438 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3442 static const WCHAR ExecSeqQuery[] =
3443 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3444 '`','I','n','i','F','i','l','e','`',0};
3446 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3447 if (rc != ERROR_SUCCESS)
3449 TRACE("no IniFile table\n");
3450 return ERROR_SUCCESS;
3453 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3454 msiobj_release(&view->hdr);
3458 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3460 MSIPACKAGE *package = (MSIPACKAGE*)param;
3465 static const WCHAR ExeStr[] =
3466 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3467 static const WCHAR close[] = {'\"',0};
3469 PROCESS_INFORMATION info;
3474 memset(&si,0,sizeof(STARTUPINFOW));
3476 filename = MSI_RecordGetString(row,1);
3477 file = get_loaded_file( package, filename );
3481 ERR("Unable to find file id %s\n",debugstr_w(filename));
3482 return ERROR_SUCCESS;
3485 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3487 FullName = msi_alloc(len*sizeof(WCHAR));
3488 strcpyW(FullName,ExeStr);
3489 strcatW( FullName, file->TargetPath );
3490 strcatW(FullName,close);
3492 TRACE("Registering %s\n",debugstr_w(FullName));
3493 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3497 msi_dialog_check_messages(info.hProcess);
3502 uirow = MSI_CreateRecord( 2 );
3503 uipath = strdupW( file->TargetPath );
3504 p = strrchrW(uipath,'\\');
3507 MSI_RecordSetStringW( uirow, 1, &p[1] );
3508 MSI_RecordSetStringW( uirow, 2, uipath);
3509 ui_actiondata( package, szSelfRegModules, uirow);
3510 msiobj_release( &uirow->hdr );
3512 /* FIXME: call ui_progress? */
3514 return ERROR_SUCCESS;
3517 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3521 static const WCHAR ExecSeqQuery[] =
3522 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3523 '`','S','e','l','f','R','e','g','`',0};
3525 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3526 if (rc != ERROR_SUCCESS)
3528 TRACE("no SelfReg table\n");
3529 return ERROR_SUCCESS;
3532 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3533 msiobj_release(&view->hdr);
3535 return ERROR_SUCCESS;
3538 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3540 MSIFEATURE *feature;
3545 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3546 if (rc != ERROR_SUCCESS)
3549 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3550 if (rc != ERROR_SUCCESS)
3553 /* here the guids are base 85 encoded */
3554 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3560 BOOL absent = FALSE;
3563 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3564 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3565 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3569 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3573 if (feature->Feature_Parent)
3574 size += strlenW( feature->Feature_Parent )+2;
3576 data = msi_alloc(size * sizeof(WCHAR));
3579 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3581 MSICOMPONENT* component = cl->component;
3585 if (component->ComponentId)
3587 TRACE("From %s\n",debugstr_w(component->ComponentId));
3588 CLSIDFromString(component->ComponentId, &clsid);
3589 encode_base85_guid(&clsid,buf);
3590 TRACE("to %s\n",debugstr_w(buf));
3594 if (feature->Feature_Parent)
3596 static const WCHAR sep[] = {'\2',0};
3598 strcatW(data,feature->Feature_Parent);
3601 msi_reg_set_val_str( hkey, feature->Feature, data );
3605 if (feature->Feature_Parent)
3606 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3609 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3610 (LPBYTE)feature->Feature_Parent,size);
3614 size += 2*sizeof(WCHAR);
3615 data = msi_alloc(size);
3618 if (feature->Feature_Parent)
3619 strcpyW( &data[1], feature->Feature_Parent );
3620 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3626 uirow = MSI_CreateRecord( 1 );
3627 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3628 ui_actiondata( package, szPublishFeatures, uirow);
3629 msiobj_release( &uirow->hdr );
3630 /* FIXME: call ui_progress? */
3639 static UINT msi_get_local_package_name( LPWSTR path )
3641 static const WCHAR szInstaller[] = {
3642 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3643 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3647 time = GetTickCount();
3648 GetWindowsDirectoryW( path, MAX_PATH );
3649 lstrcatW( path, szInstaller );
3650 CreateDirectoryW( path, NULL );
3652 len = lstrlenW(path);
3653 for (i=0; i<0x10000; i++)
3655 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3656 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3657 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3658 if (handle != INVALID_HANDLE_VALUE)
3660 CloseHandle(handle);
3663 if (GetLastError() != ERROR_FILE_EXISTS &&
3664 GetLastError() != ERROR_SHARING_VIOLATION)
3665 return ERROR_FUNCTION_FAILED;
3668 return ERROR_SUCCESS;
3671 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3673 static const WCHAR szOriginalDatabase[] =
3674 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3675 WCHAR packagefile[MAX_PATH];
3679 r = msi_get_local_package_name( packagefile );
3680 if (r != ERROR_SUCCESS)
3683 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3685 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3686 r = CopyFileW( msiFilePath, packagefile, FALSE);
3690 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3691 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3692 msi_free( msiFilePath );
3693 return ERROR_FUNCTION_FAILED;
3695 msi_free( msiFilePath );
3697 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3698 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3699 return ERROR_SUCCESS;
3702 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3704 LPWSTR prop, val, key;
3705 static const LPCSTR propval[] = {
3706 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3707 "ARPCONTACT", "Contact",
3708 "ARPCOMMENTS", "Comments",
3709 "ProductName", "DisplayName",
3710 "ProductVersion", "DisplayVersion",
3711 "ARPHELPLINK", "HelpLink",
3712 "ARPHELPTELEPHONE", "HelpTelephone",
3713 "ARPINSTALLLOCATION", "InstallLocation",
3714 "SourceDir", "InstallSource",
3715 "Manufacturer", "Publisher",
3716 "ARPREADME", "Readme",
3718 "ARPURLINFOABOUT", "URLInfoAbout",
3719 "ARPURLUPDATEINFO", "URLUpdateInfo",
3722 const LPCSTR *p = propval;
3726 prop = strdupAtoW( *p++ );
3727 key = strdupAtoW( *p++ );
3728 val = msi_dup_property( package, prop );
3729 msi_reg_set_val_str( hkey, key, val );
3734 return ERROR_SUCCESS;
3737 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3740 LPWSTR buffer = NULL;
3743 static const WCHAR szWindowsInstaller[] =
3744 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3745 static const WCHAR szUpgradeCode[] =
3746 {'U','p','g','r','a','d','e','C','o','d','e',0};
3747 static const WCHAR modpath_fmt[] =
3748 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3749 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3750 static const WCHAR szModifyPath[] =
3751 {'M','o','d','i','f','y','P','a','t','h',0};
3752 static const WCHAR szUninstallString[] =
3753 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3754 static const WCHAR szEstimatedSize[] =
3755 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3756 static const WCHAR szProductLanguage[] =
3757 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3758 static const WCHAR szProductVersion[] =
3759 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3762 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3763 LPWSTR upgrade_code;
3766 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3767 if (rc != ERROR_SUCCESS)
3770 /* dump all the info i can grab */
3771 /* FIXME: Flesh out more information */
3773 msi_write_uninstall_property_vals( package, hkey );
3775 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3777 msi_make_package_local( package, hkey );
3779 /* do ModifyPath and UninstallString */
3780 size = deformat_string(package,modpath_fmt,&buffer);
3781 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3782 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3785 /* FIXME: Write real Estimated Size when we have it */
3786 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3788 GetLocalTime(&systime);
3789 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3790 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3792 langid = msi_get_property_int( package, szProductLanguage, 0 );
3793 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3795 buffer = msi_dup_property( package, szProductVersion );
3798 DWORD verdword = msi_version_str_to_dword(buffer);
3800 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3801 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3802 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3806 /* Handle Upgrade Codes */
3807 upgrade_code = msi_dup_property( package, szUpgradeCode );
3812 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3813 squash_guid(package->ProductCode,squashed);
3814 msi_reg_set_val_str( hkey2, squashed, NULL );
3816 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3817 squash_guid(package->ProductCode,squashed);
3818 msi_reg_set_val_str( hkey2, squashed, NULL );
3821 msi_free(upgrade_code);
3826 /* FIXME: call ui_actiondata */
3828 return ERROR_SUCCESS;
3831 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3833 return execute_script(package,INSTALL_SCRIPT);
3836 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3840 /* turn off scheduling */
3841 package->script->CurrentlyScripting= FALSE;
3843 /* first do the same as an InstallExecute */
3844 rc = ACTION_InstallExecute(package);
3845 if (rc != ERROR_SUCCESS)
3848 /* then handle Commit Actions */
3849 rc = execute_script(package,COMMIT_SCRIPT);
3854 UINT ACTION_ForceReboot(MSIPACKAGE *package)
3856 static const WCHAR RunOnce[] = {
3857 'S','o','f','t','w','a','r','e','\\',
3858 'M','i','c','r','o','s','o','f','t','\\',
3859 'W','i','n','d','o','w','s','\\',
3860 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3861 'R','u','n','O','n','c','e',0};
3862 static const WCHAR InstallRunOnce[] = {
3863 'S','o','f','t','w','a','r','e','\\',
3864 'M','i','c','r','o','s','o','f','t','\\',
3865 'W','i','n','d','o','w','s','\\',
3866 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3867 'I','n','s','t','a','l','l','e','r','\\',
3868 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3870 static const WCHAR msiexec_fmt[] = {
3872 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3873 '\"','%','s','\"',0};
3874 static const WCHAR install_fmt[] = {
3875 '/','I',' ','\"','%','s','\"',' ',
3876 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3877 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3878 WCHAR buffer[256], sysdir[MAX_PATH];
3880 WCHAR squished_pc[100];
3882 squash_guid(package->ProductCode,squished_pc);
3884 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3885 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3886 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3889 msi_reg_set_val_str( hkey, squished_pc, buffer );
3892 TRACE("Reboot command %s\n",debugstr_w(buffer));
3894 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3895 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3897 msi_reg_set_val_str( hkey, squished_pc, buffer );
3900 return ERROR_INSTALL_SUSPEND;
3903 static UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3908 p = strrchrW( package->PackagePath, '\\' );
3910 return ERROR_SUCCESS;
3912 len = p - package->PackagePath + 2;
3913 source = msi_alloc( len * sizeof(WCHAR) );
3914 lstrcpynW( source, package->PackagePath, len );
3916 MSI_SetPropertyW( package, cszSourceDir, source );
3917 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3921 return ERROR_SUCCESS;
3924 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3930 * We are currently doing what should be done here in the top level Install
3931 * however for Administrative and uninstalls this step will be needed
3933 if (!package->PackagePath)
3934 return ERROR_SUCCESS;
3936 msi_set_sourcedir_props(package);
3938 attrib = GetFileAttributesW(package->PackagePath);
3939 if (attrib == INVALID_FILE_ATTRIBUTES)
3945 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3946 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3947 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3948 if (rc == ERROR_MORE_DATA)
3950 prompt = msi_alloc(size * sizeof(WCHAR));
3951 MsiSourceListGetInfoW(package->ProductCode, NULL,
3952 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3953 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3956 prompt = strdupW(package->PackagePath);
3958 msg = generate_error_string(package,1302,1,prompt);
3959 while(attrib == INVALID_FILE_ATTRIBUTES)
3961 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3964 rc = ERROR_INSTALL_USEREXIT;
3967 attrib = GetFileAttributesW(package->PackagePath);
3973 return ERROR_SUCCESS;
3978 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3985 static const WCHAR szPropKeys[][80] =
3987 {'P','r','o','d','u','c','t','I','D',0},
3988 {'U','S','E','R','N','A','M','E',0},
3989 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3993 static const WCHAR szRegKeys[][80] =
3995 {'P','r','o','d','u','c','t','I','D',0},
3996 {'R','e','g','O','w','n','e','r',0},
3997 {'R','e','g','C','o','m','p','a','n','y',0},
4001 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4003 return ERROR_SUCCESS;
4005 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
4006 if (rc != ERROR_SUCCESS)
4009 for( i = 0; szPropKeys[i][0]; i++ )
4011 buffer = msi_dup_property( package, szPropKeys[i] );
4012 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4017 msi_free(productid);
4020 /* FIXME: call ui_actiondata */
4022 return ERROR_SUCCESS;
4026 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4030 package->script->InWhatSequence |= SEQUENCE_EXEC;
4031 rc = ACTION_ProcessExecSequence(package,FALSE);
4036 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4038 MSIPACKAGE *package = (MSIPACKAGE*)param;
4039 LPCWSTR compgroupid=NULL;
4040 LPCWSTR feature=NULL;
4041 LPCWSTR text = NULL;
4042 LPCWSTR qualifier = NULL;
4043 LPCWSTR component = NULL;
4044 LPWSTR advertise = NULL;
4045 LPWSTR output = NULL;
4047 UINT rc = ERROR_SUCCESS;
4052 component = MSI_RecordGetString(rec,3);
4053 comp = get_loaded_component(package,component);
4055 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4056 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4057 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4059 TRACE("Skipping: Component %s not scheduled for install\n",
4060 debugstr_w(component));
4062 return ERROR_SUCCESS;
4065 compgroupid = MSI_RecordGetString(rec,1);
4066 qualifier = MSI_RecordGetString(rec,2);
4068 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4069 if (rc != ERROR_SUCCESS)
4072 text = MSI_RecordGetString(rec,4);
4073 feature = MSI_RecordGetString(rec,5);
4075 advertise = create_component_advertise_string(package, comp, feature);
4077 sz = strlenW(advertise);
4080 sz += lstrlenW(text);
4083 sz *= sizeof(WCHAR);
4085 output = msi_alloc_zero(sz);
4086 strcpyW(output,advertise);
4087 msi_free(advertise);
4090 strcatW(output,text);
4092 msi_reg_set_val_multi_str( hkey, qualifier, output );
4099 uirow = MSI_CreateRecord( 2 );
4100 MSI_RecordSetStringW( uirow, 1, compgroupid );
4101 MSI_RecordSetStringW( uirow, 2, qualifier);
4102 ui_actiondata( package, szPublishComponents, uirow);
4103 msiobj_release( &uirow->hdr );
4104 /* FIXME: call ui_progress? */
4110 * At present I am ignorning the advertised components part of this and only
4111 * focusing on the qualified component sets
4113 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4117 static const WCHAR ExecSeqQuery[] =
4118 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4119 '`','P','u','b','l','i','s','h',
4120 'C','o','m','p','o','n','e','n','t','`',0};
4122 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4123 if (rc != ERROR_SUCCESS)
4124 return ERROR_SUCCESS;
4126 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4127 msiobj_release(&view->hdr);
4132 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4134 MSIPACKAGE *package = (MSIPACKAGE*)param;
4137 SC_HANDLE hscm, service = NULL;
4138 LPCWSTR name, disp, comp, depends, pass;
4139 LPCWSTR load_order, serv_name, key;
4140 DWORD serv_type, start_type;
4143 static const WCHAR query[] =
4144 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4145 '`','C','o','m','p','o','n','e','n','t','`',' ',
4146 'W','H','E','R','E',' ',
4147 '`','C','o','m','p','o','n','e','n','t','`',' ',
4148 '=','\'','%','s','\'',0};
4150 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4153 ERR("Failed to open the SC Manager!\n");
4157 start_type = MSI_RecordGetInteger(rec, 5);
4158 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4161 depends = MSI_RecordGetString(rec, 8);
4162 if (depends && *depends)
4163 FIXME("Dependency list unhandled!\n");
4165 name = MSI_RecordGetString(rec, 2);
4166 disp = MSI_RecordGetString(rec, 3);
4167 serv_type = MSI_RecordGetInteger(rec, 4);
4168 err_control = MSI_RecordGetInteger(rec, 6);
4169 load_order = MSI_RecordGetString(rec, 7);
4170 serv_name = MSI_RecordGetString(rec, 9);
4171 pass = MSI_RecordGetString(rec, 10);
4172 comp = MSI_RecordGetString(rec, 12);
4174 /* fetch the service path */
4175 row = MSI_QueryGetRecord(package->db, query, comp);
4178 ERR("Control query failed!\n");
4182 key = MSI_RecordGetString(row, 6);
4183 msiobj_release(&row->hdr);
4185 file = get_loaded_file(package, key);
4188 ERR("Failed to load the service file\n");
4192 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4193 start_type, err_control, file->TargetPath,
4194 load_order, NULL, NULL, serv_name, pass);
4197 if (GetLastError() != ERROR_SERVICE_EXISTS)
4198 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4202 CloseServiceHandle(service);
4203 CloseServiceHandle(hscm);
4205 return ERROR_SUCCESS;
4208 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4212 static const WCHAR ExecSeqQuery[] =
4213 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4214 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4216 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4217 if (rc != ERROR_SUCCESS)
4218 return ERROR_SUCCESS;
4220 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4221 msiobj_release(&view->hdr);
4226 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4227 static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs)
4233 static const WCHAR separator[] = {'[','~',']',0};
4236 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4241 vector = msi_alloc(sizeof(LPWSTR));
4249 vector[*numargs - 1] = p;
4251 if ((q = strstrW(p, separator)))
4255 vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4266 static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component )
4270 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
4272 if (!lstrcmpW(comp->Component, component))
4279 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4281 MSIPACKAGE *package = (MSIPACKAGE *)param;
4283 SC_HANDLE scm, service = NULL;
4284 LPCWSTR name, *vector = NULL;
4286 DWORD event, numargs;
4287 UINT r = ERROR_FUNCTION_FAILED;
4289 comp = msi_find_component(package, MSI_RecordGetString(rec, 6));
4290 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4291 return ERROR_SUCCESS;
4293 name = MSI_RecordGetString(rec, 2);
4294 event = MSI_RecordGetInteger(rec, 3);
4295 args = strdupW(MSI_RecordGetString(rec, 4));
4297 if (!(event & msidbServiceControlEventStart))
4298 return ERROR_SUCCESS;
4300 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4303 ERR("Failed to open the service control manager\n");
4307 service = OpenServiceW(scm, name, SERVICE_START);
4310 ERR("Failed to open service %s\n", debugstr_w(name));
4314 vector = msi_service_args_to_vector(name, args, &numargs);
4316 if (!StartServiceW(service, numargs, vector))
4318 ERR("Failed to start service %s\n", debugstr_w(name));
4325 CloseServiceHandle(service);
4326 CloseServiceHandle(scm);
4333 static UINT ACTION_StartServices( MSIPACKAGE *package )
4338 static const WCHAR query[] = {
4339 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4340 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4342 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4343 if (rc != ERROR_SUCCESS)
4344 return ERROR_SUCCESS;
4346 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4347 msiobj_release(&view->hdr);
4352 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4356 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4358 if (!lstrcmpW(file->File, filename))
4365 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4367 MSIPACKAGE *package = (MSIPACKAGE*)param;
4368 LPWSTR driver, driver_path, ptr;
4369 WCHAR outpath[MAX_PATH];
4370 MSIFILE *driver_file, *setup_file;
4373 UINT r = ERROR_SUCCESS;
4375 static const WCHAR driver_fmt[] = {
4376 'D','r','i','v','e','r','=','%','s',0};
4377 static const WCHAR setup_fmt[] = {
4378 'S','e','t','u','p','=','%','s',0};
4379 static const WCHAR usage_fmt[] = {
4380 'F','i','l','e','U','s','a','g','e','=','1',0};
4382 desc = MSI_RecordGetString(rec, 3);
4384 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4385 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4387 if (!driver_file || !setup_file)
4389 ERR("ODBC Driver entry not found!\n");
4390 return ERROR_FUNCTION_FAILED;
4393 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4394 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4395 lstrlenW(usage_fmt) + 1;
4396 driver = msi_alloc(len * sizeof(WCHAR));
4398 return ERROR_OUTOFMEMORY;
4401 lstrcpyW(ptr, desc);
4402 ptr += lstrlenW(ptr) + 1;
4404 sprintfW(ptr, driver_fmt, driver_file->FileName);
4405 ptr += lstrlenW(ptr) + 1;
4407 sprintfW(ptr, setup_fmt, setup_file->FileName);
4408 ptr += lstrlenW(ptr) + 1;
4410 lstrcpyW(ptr, usage_fmt);
4411 ptr += lstrlenW(ptr) + 1;
4414 driver_path = strdupW(driver_file->TargetPath);
4415 ptr = strrchrW(driver_path, '\\');
4416 if (ptr) *ptr = '\0';
4418 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4419 NULL, ODBC_INSTALL_COMPLETE, &usage))
4421 ERR("Failed to install SQL driver!\n");
4422 r = ERROR_FUNCTION_FAILED;
4426 msi_free(driver_path);
4431 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4433 MSIPACKAGE *package = (MSIPACKAGE*)param;
4434 LPWSTR translator, translator_path, ptr;
4435 WCHAR outpath[MAX_PATH];
4436 MSIFILE *translator_file, *setup_file;
4439 UINT r = ERROR_SUCCESS;
4441 static const WCHAR translator_fmt[] = {
4442 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4443 static const WCHAR setup_fmt[] = {
4444 'S','e','t','u','p','=','%','s',0};
4446 desc = MSI_RecordGetString(rec, 3);
4448 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4449 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4451 if (!translator_file || !setup_file)
4453 ERR("ODBC Translator entry not found!\n");
4454 return ERROR_FUNCTION_FAILED;
4457 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4458 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4459 translator = msi_alloc(len * sizeof(WCHAR));
4461 return ERROR_OUTOFMEMORY;
4464 lstrcpyW(ptr, desc);
4465 ptr += lstrlenW(ptr) + 1;
4467 sprintfW(ptr, translator_fmt, translator_file->FileName);
4468 ptr += lstrlenW(ptr) + 1;
4470 sprintfW(ptr, setup_fmt, setup_file->FileName);
4471 ptr += lstrlenW(ptr) + 1;
4474 translator_path = strdupW(translator_file->TargetPath);
4475 ptr = strrchrW(translator_path, '\\');
4476 if (ptr) *ptr = '\0';
4478 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4479 NULL, ODBC_INSTALL_COMPLETE, &usage))
4481 ERR("Failed to install SQL translator!\n");
4482 r = ERROR_FUNCTION_FAILED;
4485 msi_free(translator);
4486 msi_free(translator_path);
4491 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4494 LPCWSTR desc, driver;
4495 WORD request = ODBC_ADD_SYS_DSN;
4498 UINT r = ERROR_SUCCESS;
4500 static const WCHAR attrs_fmt[] = {
4501 'D','S','N','=','%','s',0 };
4503 desc = MSI_RecordGetString(rec, 3);
4504 driver = MSI_RecordGetString(rec, 4);
4505 registration = MSI_RecordGetInteger(rec, 5);
4507 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4508 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4510 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4511 attrs = msi_alloc(len * sizeof(WCHAR));
4513 return ERROR_OUTOFMEMORY;
4515 sprintfW(attrs, attrs_fmt, desc);
4516 attrs[len - 1] = '\0';
4518 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4520 ERR("Failed to install SQL data source!\n");
4521 r = ERROR_FUNCTION_FAILED;
4529 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4534 static const WCHAR driver_query[] = {
4535 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4536 'O','D','B','C','D','r','i','v','e','r',0 };
4538 static const WCHAR translator_query[] = {
4539 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4540 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4542 static const WCHAR source_query[] = {
4543 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4544 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4546 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4547 if (rc != ERROR_SUCCESS)
4548 return ERROR_SUCCESS;
4550 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4551 msiobj_release(&view->hdr);
4553 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4554 if (rc != ERROR_SUCCESS)
4555 return ERROR_SUCCESS;
4557 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4558 msiobj_release(&view->hdr);
4560 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4561 if (rc != ERROR_SUCCESS)
4562 return ERROR_SUCCESS;
4564 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4565 msiobj_release(&view->hdr);
4570 #define ENV_ACT_SETALWAYS 0x1
4571 #define ENV_ACT_SETABSENT 0x2
4572 #define ENV_ACT_REMOVE 0x4
4573 #define ENV_ACT_REMOVEMATCH 0x8
4575 #define ENV_MOD_MACHINE 0x20000000
4576 #define ENV_MOD_APPEND 0x40000000
4577 #define ENV_MOD_PREFIX 0x80000000
4578 #define ENV_MOD_MASK 0xC0000000
4580 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4582 static LONG env_set_flags( LPCWSTR *name, LPWSTR *value, DWORD *flags )
4584 LPCWSTR cptr = *name;
4585 LPWSTR ptr = *value;
4587 static const WCHAR prefix[] = {'[','~',']',0};
4590 while (*cptr && (*cptr == '=' || *cptr == '+' ||
4591 *cptr == '-' || *cptr == '!' || *cptr == '*'))
4596 *flags |= ENV_ACT_SETALWAYS;
4599 *flags |= ENV_ACT_SETABSENT;
4602 *flags |= ENV_ACT_REMOVE;
4605 *flags |= ENV_ACT_REMOVEMATCH;
4608 *flags |= ENV_MOD_MACHINE;
4611 ERR("Unknown Environment flag: %c\n", *cptr);
4612 return ERROR_FUNCTION_FAILED;
4621 ERR("Missing environment variable\n");
4622 return ERROR_FUNCTION_FAILED;
4625 if (!strncmpW(ptr, prefix, lstrlenW(prefix)))
4627 *flags |= ENV_MOD_PREFIX;
4628 *value += lstrlenW(prefix);
4632 ptr += lstrlenW(ptr) - lstrlenW(prefix) - 1;
4633 if (!lstrcmpW(ptr, prefix))
4635 *flags |= ENV_MOD_APPEND;
4641 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4642 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4643 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4644 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4646 ERR("Invalid flags: %08x\n", *flags);
4647 return ERROR_FUNCTION_FAILED;
4650 return ERROR_SUCCESS;
4653 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4655 MSIPACKAGE *package = param;
4656 LPCWSTR name, value, comp;
4657 LPWSTR data = NULL, newval = NULL;
4658 LPWSTR deformatted, ptr;
4659 DWORD flags, type, size;
4661 HKEY env, root = HKEY_CURRENT_USER;
4663 static const WCHAR environment[] =
4664 {'S','y','s','t','e','m','\\',
4665 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4666 'C','o','n','t','r','o','l','\\',
4667 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4668 'E','n','v','i','r','o','n','m','e','n','t',0};
4669 static const WCHAR semicolon[] = {';',0};
4671 name = MSI_RecordGetString(rec, 2);
4672 value = MSI_RecordGetString(rec, 3);
4673 comp = MSI_RecordGetString(rec, 4);
4675 deformat_string(package, value, &deformatted);
4677 return ERROR_OUTOFMEMORY;
4679 res = env_set_flags(&name, &deformatted, &flags);
4680 if (res != ERROR_SUCCESS)
4683 value = deformatted;
4685 if (flags & ENV_MOD_MACHINE)
4686 root = HKEY_LOCAL_MACHINE;
4688 res = RegOpenKeyExW(root, environment, 0, KEY_ALL_ACCESS, &env);
4689 if (res != ERROR_SUCCESS)
4692 if (flags & ENV_ACT_REMOVE)
4693 FIXME("Not removing environment variable on uninstall!\n");
4696 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
4697 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
4698 (res == ERROR_SUCCESS && type != REG_SZ))
4701 if (res != ERROR_FILE_NOT_FOUND)
4703 if (flags & ENV_ACT_SETABSENT)
4705 res = ERROR_SUCCESS;
4709 data = msi_alloc(size);
4713 return ERROR_OUTOFMEMORY;
4716 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
4717 if (res != ERROR_SUCCESS)
4720 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
4722 res = RegDeleteKeyW(env, name);
4726 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
4727 newval = msi_alloc(size);
4731 res = ERROR_OUTOFMEMORY;
4735 if (!(flags & ENV_MOD_MASK))
4736 lstrcpyW(newval, value);
4739 if (flags & ENV_MOD_PREFIX)
4741 lstrcpyW(newval, value);
4742 lstrcatW(newval, semicolon);
4743 ptr = newval + lstrlenW(value) + 1;
4746 lstrcpyW(ptr, data);
4748 if (flags & ENV_MOD_APPEND)
4750 lstrcatW(newval, semicolon);
4751 lstrcatW(newval, value);
4757 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
4758 newval = msi_alloc(size);
4761 res = ERROR_OUTOFMEMORY;
4765 lstrcpyW(newval, value);
4768 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
4769 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
4773 msi_free(deformatted);
4779 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4783 static const WCHAR ExecSeqQuery[] =
4784 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4785 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
4786 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4787 if (rc != ERROR_SUCCESS)
4788 return ERROR_SUCCESS;
4790 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
4791 msiobj_release(&view->hdr);
4796 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4797 LPCSTR action, LPCWSTR table )
4799 static const WCHAR query[] = {
4800 'S','E','L','E','C','T',' ','*',' ',
4801 'F','R','O','M',' ','`','%','s','`',0 };
4802 MSIQUERY *view = NULL;
4806 r = MSI_OpenQuery( package->db, &view, query, table );
4807 if (r == ERROR_SUCCESS)
4809 r = MSI_IterateRecords(view, &count, NULL, package);
4810 msiobj_release(&view->hdr);
4814 FIXME("%s -> %u ignored %s table values\n",
4815 action, count, debugstr_w(table));
4817 return ERROR_SUCCESS;
4820 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4822 TRACE("%p\n", package);
4823 return ERROR_SUCCESS;
4826 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4828 static const WCHAR table[] =
4829 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4830 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4833 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4835 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4836 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4839 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4841 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4842 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4845 static UINT ACTION_BindImage( MSIPACKAGE *package )
4847 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4848 return msi_unimplemented_action_stub( package, "BindImage", table );
4851 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4853 static const WCHAR table[] = {
4854 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4855 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4858 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4860 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4861 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4864 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4866 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4867 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4870 static UINT ACTION_StopServices( MSIPACKAGE *package )
4872 static const WCHAR table[] = {
4873 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4874 return msi_unimplemented_action_stub( package, "StopServices", table );
4877 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4879 static const WCHAR table[] = {
4880 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4881 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4883 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
4885 static const WCHAR table[] = {
4886 'P','r','o','d','u','c','t','I','D',0 };
4887 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
4890 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4892 static const WCHAR table[] = {
4893 'E','n','v','i','r','o','n','m','e','n','t',0 };
4894 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4897 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4899 static const WCHAR table[] = {
4900 'M','s','i','A','s','s','e','m','b','l','y',0 };
4901 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4904 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4906 static const WCHAR table[] = {
4907 'M','s','i','A','s','s','e','m','b','l','y',0 };
4908 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4911 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4913 static const WCHAR table[] = { 'F','o','n','t',0 };
4914 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4917 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4919 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4920 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4923 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4925 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4926 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4929 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4931 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4932 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4935 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4937 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4938 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4941 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
4943 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
4944 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
4947 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
4949 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
4950 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
4953 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
4955 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4956 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
4959 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
4961 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
4962 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
4965 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
4967 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
4968 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
4971 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
4973 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
4974 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
4977 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4979 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
4980 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
4983 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4985 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
4986 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
4989 static UINT ACTION_UnpublishFeatures( MSIPACKAGE *package )
4991 static const WCHAR table[] = { 'F','e','a','t','u','r','e','C','o','m','p','o','n','e','n','t','s',0 };
4992 return msi_unimplemented_action_stub( package, "UnpublishFeatures", table );
4995 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
4997 static const WCHAR table[] = { 'A','p','p','I','d',0 };
4998 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5001 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5003 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5004 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5007 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5009 static const WCHAR table[] = { 'M','I','M','E',0 };
5010 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5013 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5015 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5016 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5019 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5021 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5022 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5025 static const struct _actions StandardActions[] = {
5026 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5027 { szAppSearch, ACTION_AppSearch },
5028 { szBindImage, ACTION_BindImage },
5029 { szCCPSearch, ACTION_CCPSearch },
5030 { szCostFinalize, ACTION_CostFinalize },
5031 { szCostInitialize, ACTION_CostInitialize },
5032 { szCreateFolders, ACTION_CreateFolders },
5033 { szCreateShortcuts, ACTION_CreateShortcuts },
5034 { szDeleteServices, ACTION_DeleteServices },
5035 { szDisableRollback, NULL },
5036 { szDuplicateFiles, ACTION_DuplicateFiles },
5037 { szExecuteAction, ACTION_ExecuteAction },
5038 { szFileCost, ACTION_FileCost },
5039 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5040 { szForceReboot, ACTION_ForceReboot },
5041 { szInstallAdminPackage, NULL },
5042 { szInstallExecute, ACTION_InstallExecute },
5043 { szInstallExecuteAgain, ACTION_InstallExecute },
5044 { szInstallFiles, ACTION_InstallFiles},
5045 { szInstallFinalize, ACTION_InstallFinalize },
5046 { szInstallInitialize, ACTION_InstallInitialize },
5047 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5048 { szInstallValidate, ACTION_InstallValidate },
5049 { szIsolateComponents, ACTION_IsolateComponents },
5050 { szLaunchConditions, ACTION_LaunchConditions },
5051 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5052 { szMoveFiles, ACTION_MoveFiles },
5053 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5054 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5055 { szInstallODBC, ACTION_InstallODBC },
5056 { szInstallServices, ACTION_InstallServices },
5057 { szPatchFiles, ACTION_PatchFiles },
5058 { szProcessComponents, ACTION_ProcessComponents },
5059 { szPublishComponents, ACTION_PublishComponents },
5060 { szPublishFeatures, ACTION_PublishFeatures },
5061 { szPublishProduct, ACTION_PublishProduct },
5062 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5063 { szRegisterComPlus, ACTION_RegisterComPlus},
5064 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5065 { szRegisterFonts, ACTION_RegisterFonts },
5066 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5067 { szRegisterProduct, ACTION_RegisterProduct },
5068 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5069 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5070 { szRegisterUser, ACTION_RegisterUser },
5071 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5072 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5073 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5074 { szRemoveFiles, ACTION_RemoveFiles },
5075 { szRemoveFolders, ACTION_RemoveFolders },
5076 { szRemoveIniValues, ACTION_RemoveIniValues },
5077 { szRemoveODBC, ACTION_RemoveODBC },
5078 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5079 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5080 { szResolveSource, ACTION_ResolveSource },
5081 { szRMCCPSearch, ACTION_RMCCPSearch },
5082 { szScheduleReboot, NULL },
5083 { szSelfRegModules, ACTION_SelfRegModules },
5084 { szSelfUnregModules, ACTION_SelfUnregModules },
5085 { szSetODBCFolders, NULL },
5086 { szStartServices, ACTION_StartServices },
5087 { szStopServices, ACTION_StopServices },
5088 { szUnpublishComponents, ACTION_UnpublishComponents },
5089 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5090 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5091 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5092 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5093 { szUnregisterFonts, ACTION_UnregisterFonts },
5094 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5095 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5096 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5097 { szValidateProductID, ACTION_ValidateProductID },
5098 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5099 { szWriteIniValues, ACTION_WriteIniValues },
5100 { szWriteRegistryValues, ACTION_WriteRegistryValues },