2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
39 #include "wine/debug.h"
44 #include "wine/unicode.h"
47 #define REG_PROGRESS_VALUE 13200
48 #define COMPONENT_PROGRESS_VALUE 24000
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
55 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
56 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
57 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
60 * consts and values used
62 static const WCHAR c_colon[] = {'C',':','\\',0};
64 static const WCHAR szCreateFolders[] =
65 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
66 static const WCHAR szCostFinalize[] =
67 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
68 const WCHAR szInstallFiles[] =
69 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
70 const WCHAR szDuplicateFiles[] =
71 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
72 static const WCHAR szWriteRegistryValues[] =
73 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
74 'V','a','l','u','e','s',0};
75 static const WCHAR szCostInitialize[] =
76 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
77 static const WCHAR szFileCost[] =
78 {'F','i','l','e','C','o','s','t',0};
79 static const WCHAR szInstallInitialize[] =
80 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
81 static const WCHAR szInstallValidate[] =
82 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
83 static const WCHAR szLaunchConditions[] =
84 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
85 static const WCHAR szProcessComponents[] =
86 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
87 static const WCHAR szRegisterTypeLibraries[] =
88 {'R','e','g','i','s','t','e','r','T','y','p','e',
89 'L','i','b','r','a','r','i','e','s',0};
90 const WCHAR szRegisterClassInfo[] =
91 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
92 const WCHAR szRegisterProgIdInfo[] =
93 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
94 static const WCHAR szCreateShortcuts[] =
95 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
96 static const WCHAR szPublishProduct[] =
97 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
98 static const WCHAR szWriteIniValues[] =
99 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
100 static const WCHAR szSelfRegModules[] =
101 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
102 static const WCHAR szPublishFeatures[] =
103 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
104 static const WCHAR szRegisterProduct[] =
105 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
106 static const WCHAR szInstallExecute[] =
107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
108 static const WCHAR szInstallExecuteAgain[] =
109 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
110 'A','g','a','i','n',0};
111 static const WCHAR szInstallFinalize[] =
112 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
113 static const WCHAR szForceReboot[] =
114 {'F','o','r','c','e','R','e','b','o','o','t',0};
115 static const WCHAR szResolveSource[] =
116 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
117 static const WCHAR szAppSearch[] =
118 {'A','p','p','S','e','a','r','c','h',0};
119 static const WCHAR szAllocateRegistrySpace[] =
120 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
121 'S','p','a','c','e',0};
122 static const WCHAR szBindImage[] =
123 {'B','i','n','d','I','m','a','g','e',0};
124 static const WCHAR szCCPSearch[] =
125 {'C','C','P','S','e','a','r','c','h',0};
126 static const WCHAR szDeleteServices[] =
127 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
128 static const WCHAR szDisableRollback[] =
129 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
130 static const WCHAR szExecuteAction[] =
131 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
132 const WCHAR szFindRelatedProducts[] =
133 {'F','i','n','d','R','e','l','a','t','e','d',
134 'P','r','o','d','u','c','t','s',0};
135 static const WCHAR szInstallAdminPackage[] =
136 {'I','n','s','t','a','l','l','A','d','m','i','n',
137 'P','a','c','k','a','g','e',0};
138 static const WCHAR szInstallSFPCatalogFile[] =
139 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
141 static const WCHAR szIsolateComponents[] =
142 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
143 const WCHAR szMigrateFeatureStates[] =
144 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
145 'S','t','a','t','e','s',0};
146 const WCHAR szMoveFiles[] =
147 {'M','o','v','e','F','i','l','e','s',0};
148 static const WCHAR szMsiPublishAssemblies[] =
149 {'M','s','i','P','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szMsiUnpublishAssemblies[] =
152 {'M','s','i','U','n','p','u','b','l','i','s','h',
153 'A','s','s','e','m','b','l','i','e','s',0};
154 static const WCHAR szInstallODBC[] =
155 {'I','n','s','t','a','l','l','O','D','B','C',0};
156 static const WCHAR szInstallServices[] =
157 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
158 const WCHAR szPatchFiles[] =
159 {'P','a','t','c','h','F','i','l','e','s',0};
160 static const WCHAR szPublishComponents[] =
161 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
162 static const WCHAR szRegisterComPlus[] =
163 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
164 const WCHAR szRegisterExtensionInfo[] =
165 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
167 static const WCHAR szRegisterFonts[] =
168 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 const WCHAR szRegisterMIMEInfo[] =
170 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szRegisterUser[] =
172 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
173 const WCHAR szRemoveDuplicateFiles[] =
174 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
175 'F','i','l','e','s',0};
176 static const WCHAR szRemoveEnvironmentStrings[] =
177 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
178 'S','t','r','i','n','g','s',0};
179 const WCHAR szRemoveExistingProducts[] =
180 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
181 'P','r','o','d','u','c','t','s',0};
182 const WCHAR szRemoveFiles[] =
183 {'R','e','m','o','v','e','F','i','l','e','s',0};
184 static const WCHAR szRemoveFolders[] =
185 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
186 static const WCHAR szRemoveIniValues[] =
187 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
188 static const WCHAR szRemoveODBC[] =
189 {'R','e','m','o','v','e','O','D','B','C',0};
190 static const WCHAR szRemoveRegistryValues[] =
191 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
192 'V','a','l','u','e','s',0};
193 static const WCHAR szRemoveShortcuts[] =
194 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
195 static const WCHAR szRMCCPSearch[] =
196 {'R','M','C','C','P','S','e','a','r','c','h',0};
197 static const WCHAR szScheduleReboot[] =
198 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
199 static const WCHAR szSelfUnregModules[] =
200 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
201 static const WCHAR szSetODBCFolders[] =
202 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
203 static const WCHAR szStartServices[] =
204 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
205 static const WCHAR szStopServices[] =
206 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
207 static const WCHAR szUnpublishComponents[] =
208 {'U','n','p','u','b','l','i','s','h',
209 'C','o','m','p','o','n','e','n','t','s',0};
210 static const WCHAR szUnpublishFeatures[] =
211 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
212 const WCHAR szUnregisterClassInfo[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
215 static const WCHAR szUnregisterComPlus[] =
216 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const WCHAR szUnregisterExtensionInfo[] =
218 {'U','n','r','e','g','i','s','t','e','r',
219 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
220 static const WCHAR szUnregisterFonts[] =
221 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const WCHAR szUnregisterMIMEInfo[] =
223 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const WCHAR szUnregisterProgIdInfo[] =
225 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
227 static const WCHAR szUnregisterTypeLibraries[] =
228 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
229 'L','i','b','r','a','r','i','e','s',0};
230 static const WCHAR szValidateProductID[] =
231 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
232 static const WCHAR szWriteEnvironmentStrings[] =
233 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
234 'S','t','r','i','n','g','s',0};
236 /* action handlers */
237 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
241 STANDARDACTIONHANDLER handler;
244 static const struct _actions StandardActions[];
247 /********************************************************
249 ********************************************************/
251 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
253 static const WCHAR Query_t[] =
254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
255 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
256 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
257 ' ','\'','%','s','\'',0};
260 row = MSI_QueryGetRecord( package->db, Query_t, action );
263 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
264 msiobj_release(&row->hdr);
267 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
271 static const WCHAR template_s[]=
272 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
274 static const WCHAR template_e[]=
275 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
276 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
278 static const WCHAR format[] =
279 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
283 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
285 sprintfW(message,template_s,timet,action);
287 sprintfW(message,template_e,timet,action,rc);
289 row = MSI_CreateRecord(1);
290 MSI_RecordSetStringW(row,1,message);
292 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
293 msiobj_release(&row->hdr);
296 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
301 LPWSTR prop = NULL, val = NULL;
304 return ERROR_SUCCESS;
316 TRACE("Looking at %s\n",debugstr_w(ptr));
318 ptr2 = strchrW(ptr,'=');
321 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
328 prop = msi_alloc((len+1)*sizeof(WCHAR));
329 memcpy(prop,ptr,len*sizeof(WCHAR));
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
352 if (lstrlenW(prop) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
362 return ERROR_SUCCESS;
366 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
369 LPWSTR p, *ret = NULL;
375 /* count the number of substrings */
376 for ( pc = str, count = 0; pc; count++ )
378 pc = strchrW( pc, sep );
383 /* allocate space for an array of substring pointers and the substrings */
384 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
385 (lstrlenW(str)+1) * sizeof(WCHAR) );
389 /* copy the string and set the pointers */
390 p = (LPWSTR) &ret[count+1];
392 for( count = 0; (ret[count] = p); count++ )
394 p = strchrW( p, sep );
402 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
404 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code, patch_product;
408 prod_code = msi_dup_property( package, szProductCode );
409 patch_product = msi_get_suminfo_product( patch );
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
413 if ( strstrW( patch_product, prod_code ) )
416 ret = ERROR_FUNCTION_FAILED;
418 msi_free( patch_product );
419 msi_free( prod_code );
424 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
425 MSIDATABASE *patch_db, LPCWSTR name )
427 UINT ret = ERROR_FUNCTION_FAILED;
428 IStorage *stg = NULL;
431 TRACE("%p %s\n", package, debugstr_w(name) );
435 ERR("expected a colon in %s\n", debugstr_w(name));
436 return ERROR_FUNCTION_FAILED;
439 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
442 ret = msi_check_transform_applicable( package, stg );
443 if (ret == ERROR_SUCCESS)
444 msi_table_apply_transform( package->db, stg );
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
447 IStorage_Release( stg );
450 ERR("failed to open substorage %s\n", debugstr_w(name));
452 return ERROR_SUCCESS;
455 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
457 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list, *guids, product_code;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
461 product_code = msi_dup_property( package, szProdCode );
464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
466 return ERROR_SUCCESS;
469 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
470 guids = msi_split_string( guid_list, ';' );
471 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
473 if (!lstrcmpW( guids[i], product_code ))
477 msi_free( guid_list );
478 msi_free( product_code );
483 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
486 LPWSTR str, *substorage;
487 UINT i, r = ERROR_SUCCESS;
489 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
491 return ERROR_FUNCTION_FAILED;
493 msi_check_patch_applicable( package, si );
495 /* enumerate the substorage */
496 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
497 substorage = msi_split_string( str, ';' );
498 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
499 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
500 msi_free( substorage );
503 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
505 msiobj_release( &si->hdr );
510 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
512 MSIDATABASE *patch_db = NULL;
515 TRACE("%p %s\n", package, debugstr_w( file ) );
518 * We probably want to make sure we only open a patch collection here.
519 * Patch collections (.msp) and databases (.msi) have different GUIDs
520 * but currently MSI_OpenDatabaseW will accept both.
522 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
523 if ( r != ERROR_SUCCESS )
525 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
529 msi_parse_patch_summary( package, patch_db );
532 * There might be a CAB file in the patch package,
533 * so append it to the list of storage to search for streams.
535 append_storage_to_db( package->db, patch_db->storage );
537 msiobj_release( &patch_db->hdr );
539 return ERROR_SUCCESS;
542 /* get the PATCH property, and apply all the patches it specifies */
543 static UINT msi_apply_patches( MSIPACKAGE *package )
545 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
546 LPWSTR patch_list, *patches;
547 UINT i, r = ERROR_SUCCESS;
549 patch_list = msi_dup_property( package, szPatch );
551 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
553 patches = msi_split_string( patch_list, ';' );
554 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
555 r = msi_apply_patch_package( package, patches[i] );
558 msi_free( patch_list );
563 static UINT msi_apply_transforms( MSIPACKAGE *package )
565 static const WCHAR szTransforms[] = {
566 'T','R','A','N','S','F','O','R','M','S',0 };
567 LPWSTR xform_list, *xforms;
568 UINT i, r = ERROR_SUCCESS;
570 xform_list = msi_dup_property( package, szTransforms );
571 xforms = msi_split_string( xform_list, ';' );
573 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
575 if (xforms[i][0] == ':')
576 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
578 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
582 msi_free( xform_list );
587 BOOL ui_sequence_exists( MSIPACKAGE *package )
592 static const WCHAR ExecSeqQuery [] =
593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
594 '`','I','n','s','t','a','l','l',
595 'U','I','S','e','q','u','e','n','c','e','`',
596 ' ','W','H','E','R','E',' ',
597 '`','S','e','q','u','e','n','c','e','`',' ',
598 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
599 '`','S','e','q','u','e','n','c','e','`',0};
601 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
602 if (rc == ERROR_SUCCESS)
604 msiobj_release(&view->hdr);
611 /****************************************************
612 * TOP level entry points
613 *****************************************************/
615 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
616 LPCWSTR szCommandLine )
619 BOOL ui = FALSE, ui_exists;
620 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
621 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
622 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
624 MSI_SetPropertyW(package, szAction, szInstall);
626 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
628 package->script->InWhatSequence = SEQUENCE_INSTALL;
632 LPWSTR p, check, dir;
634 dir = strdupW(szPackagePath);
635 p = strrchrW(dir, '\\');
641 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
642 GetCurrentDirectoryW(MAX_PATH, dir);
643 lstrcatW(dir, cszbs);
644 p = (LPWSTR)szPackagePath;
647 msi_free( package->PackagePath );
648 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(p) + 2) * sizeof(WCHAR));
649 if (!package->PackagePath)
652 return ERROR_OUTOFMEMORY;
655 lstrcpyW(package->PackagePath, dir);
656 lstrcatW(package->PackagePath, cszbs);
657 lstrcatW(package->PackagePath, p);
659 check = msi_dup_property( package, cszSourceDir );
661 MSI_SetPropertyW(package, cszSourceDir, dir);
664 check = msi_dup_property( package, cszSOURCEDIR );
666 MSI_SetPropertyW(package, cszSOURCEDIR, dir);
672 msi_parse_command_line( package, szCommandLine );
674 msi_apply_transforms( package );
675 msi_apply_patches( package );
677 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
679 package->script->InWhatSequence |= SEQUENCE_UI;
680 rc = ACTION_ProcessUISequence(package);
682 ui_exists = ui_sequence_exists(package);
683 if (rc == ERROR_SUCCESS || !ui_exists)
685 package->script->InWhatSequence |= SEQUENCE_EXEC;
686 rc = ACTION_ProcessExecSequence(package,ui_exists);
690 rc = ACTION_ProcessExecSequence(package,FALSE);
694 /* install was halted but should be considered a success */
698 package->script->CurrentlyScripting= FALSE;
700 /* process the ending type action */
701 if (rc == ERROR_SUCCESS)
702 ACTION_PerformActionSequence(package,-1,ui);
703 else if (rc == ERROR_INSTALL_USEREXIT)
704 ACTION_PerformActionSequence(package,-2,ui);
705 else if (rc == ERROR_INSTALL_SUSPEND)
706 ACTION_PerformActionSequence(package,-4,ui);
708 ACTION_PerformActionSequence(package,-3,ui);
710 /* finish up running custom actions */
711 ACTION_FinishCustomActions(package);
716 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
718 UINT rc = ERROR_SUCCESS;
720 static const WCHAR ExecSeqQuery[] =
721 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
722 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
723 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
724 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
726 static const WCHAR UISeqQuery[] =
727 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
728 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
729 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
730 ' ', '=',' ','%','i',0};
733 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
735 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
739 LPCWSTR action, cond;
741 TRACE("Running the actions\n");
743 /* check conditions */
744 cond = MSI_RecordGetString(row,2);
746 /* this is a hack to skip errors in the condition code */
747 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
750 action = MSI_RecordGetString(row,1);
753 ERR("failed to fetch action\n");
754 rc = ERROR_FUNCTION_FAILED;
759 rc = ACTION_PerformUIAction(package,action,-1);
761 rc = ACTION_PerformAction(package,action,-1,FALSE);
763 msiobj_release(&row->hdr);
774 } iterate_action_param;
776 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
778 iterate_action_param *iap= (iterate_action_param*)param;
780 LPCWSTR cond, action;
782 action = MSI_RecordGetString(row,1);
785 ERR("Error is retrieving action name\n");
786 return ERROR_FUNCTION_FAILED;
789 /* check conditions */
790 cond = MSI_RecordGetString(row,2);
792 /* this is a hack to skip errors in the condition code */
793 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
795 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
796 return ERROR_SUCCESS;
800 rc = ACTION_PerformUIAction(iap->package,action,-1);
802 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
804 msi_dialog_check_messages( NULL );
806 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
807 rc = iap->package->CurrentInstallState;
809 if (rc == ERROR_FUNCTION_NOT_CALLED)
812 if (rc != ERROR_SUCCESS)
813 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
818 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
822 static const WCHAR query[] =
823 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
825 ' ','W','H','E','R','E',' ',
826 '`','S','e','q','u','e','n','c','e','`',' ',
827 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
828 '`','S','e','q','u','e','n','c','e','`',0};
829 iterate_action_param iap;
832 * FIXME: probably should be checking UILevel in the
833 * ACTION_PerformUIAction/ACTION_PerformAction
834 * rather than saving the UI level here. Those
835 * two functions can be merged too.
837 iap.package = package;
840 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
842 r = MSI_OpenQuery( package->db, &view, query, szTable );
843 if (r == ERROR_SUCCESS)
845 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
846 msiobj_release(&view->hdr);
852 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
856 static const WCHAR ExecSeqQuery[] =
857 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
858 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
859 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
860 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
861 'O','R','D','E','R',' ', 'B','Y',' ',
862 '`','S','e','q','u','e','n','c','e','`',0 };
864 static const WCHAR IVQuery[] =
865 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
866 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
867 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
868 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
869 ' ','\'', 'I','n','s','t','a','l','l',
870 'V','a','l','i','d','a','t','e','\'', 0};
872 iterate_action_param iap;
874 iap.package = package;
877 if (package->script->ExecuteSequenceRun)
879 TRACE("Execute Sequence already Run\n");
880 return ERROR_SUCCESS;
883 package->script->ExecuteSequenceRun = TRUE;
885 /* get the sequence number */
888 row = MSI_QueryGetRecord(package->db, IVQuery);
890 return ERROR_FUNCTION_FAILED;
891 seq = MSI_RecordGetInteger(row,1);
892 msiobj_release(&row->hdr);
895 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
896 if (rc == ERROR_SUCCESS)
898 TRACE("Running the actions\n");
900 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
901 msiobj_release(&view->hdr);
907 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
911 static const WCHAR ExecSeqQuery [] =
912 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
913 '`','I','n','s','t','a','l','l',
914 'U','I','S','e','q','u','e','n','c','e','`',
915 ' ','W','H','E','R','E',' ',
916 '`','S','e','q','u','e','n','c','e','`',' ',
917 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
918 '`','S','e','q','u','e','n','c','e','`',0};
919 iterate_action_param iap;
921 iap.package = package;
924 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
926 if (rc == ERROR_SUCCESS)
928 TRACE("Running the actions\n");
930 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
931 msiobj_release(&view->hdr);
937 /********************************************************
938 * ACTION helper functions and functions that perform the actions
939 *******************************************************/
940 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
941 UINT* rc, BOOL force )
947 if (!run && !package->script->CurrentlyScripting)
952 if (strcmpW(action,szInstallFinalize) == 0 ||
953 strcmpW(action,szInstallExecute) == 0 ||
954 strcmpW(action,szInstallExecuteAgain) == 0)
959 while (StandardActions[i].action != NULL)
961 if (strcmpW(StandardActions[i].action, action)==0)
965 ui_actioninfo(package, action, TRUE, 0);
966 *rc = schedule_action(package,INSTALL_SCRIPT,action);
967 ui_actioninfo(package, action, FALSE, *rc);
971 ui_actionstart(package, action);
972 if (StandardActions[i].handler)
974 *rc = StandardActions[i].handler(package);
978 FIXME("unhandled standard action %s\n",debugstr_w(action));
990 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
991 UINT* rc, UINT script, BOOL force )
996 arc = ACTION_CustomAction(package, action, script, force);
998 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1007 * A lot of actions are really important even if they don't do anything
1008 * explicit... Lots of properties are set at the beginning of the installation
1009 * CostFinalize does a bunch of work to translate the directories and such
1011 * But until I get write access to the database that is hard, so I am going to
1012 * hack it to see if I can get something to run.
1014 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1016 UINT rc = ERROR_SUCCESS;
1019 TRACE("Performing action (%s)\n",debugstr_w(action));
1021 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1024 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1028 FIXME("unhandled msi action %s\n",debugstr_w(action));
1029 rc = ERROR_FUNCTION_NOT_CALLED;
1035 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1037 UINT rc = ERROR_SUCCESS;
1038 BOOL handled = FALSE;
1040 TRACE("Performing action (%s)\n",debugstr_w(action));
1042 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1045 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1047 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1052 FIXME("unhandled msi action %s\n",debugstr_w(action));
1053 rc = ERROR_FUNCTION_NOT_CALLED;
1061 * Actual Action Handlers
1064 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1066 MSIPACKAGE *package = (MSIPACKAGE*)param;
1072 dir = MSI_RecordGetString(row,1);
1075 ERR("Unable to get folder id\n");
1076 return ERROR_SUCCESS;
1079 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1082 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1083 return ERROR_SUCCESS;
1086 TRACE("Folder is %s\n",debugstr_w(full_path));
1089 uirow = MSI_CreateRecord(1);
1090 MSI_RecordSetStringW(uirow,1,full_path);
1091 ui_actiondata(package,szCreateFolders,uirow);
1092 msiobj_release( &uirow->hdr );
1094 if (folder->State == 0)
1095 create_full_pathW(full_path);
1099 msi_free(full_path);
1100 return ERROR_SUCCESS;
1103 /* FIXME: probably should merge this with the above function */
1104 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1106 UINT rc = ERROR_SUCCESS;
1108 LPWSTR install_path;
1110 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1112 return ERROR_FUNCTION_FAILED;
1114 /* create the path */
1115 if (folder->State == 0)
1117 create_full_pathW(install_path);
1120 msi_free(install_path);
1125 UINT msi_create_component_directories( MSIPACKAGE *package )
1129 /* create all the folders required by the components are going to install */
1130 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1132 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1134 msi_create_directory( package, comp->Directory );
1137 return ERROR_SUCCESS;
1141 * Also we cannot enable/disable components either, so for now I am just going
1142 * to do all the directories for all the components.
1144 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1146 static const WCHAR ExecSeqQuery[] =
1147 {'S','E','L','E','C','T',' ',
1148 '`','D','i','r','e','c','t','o','r','y','_','`',
1149 ' ','F','R','O','M',' ',
1150 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1154 /* create all the empty folders specified in the CreateFolder table */
1155 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1156 if (rc != ERROR_SUCCESS)
1157 return ERROR_SUCCESS;
1159 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1160 msiobj_release(&view->hdr);
1162 msi_create_component_directories( package );
1167 static UINT load_component( MSIRECORD *row, LPVOID param )
1169 MSIPACKAGE *package = param;
1172 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1174 return ERROR_FUNCTION_FAILED;
1176 list_add_tail( &package->components, &comp->entry );
1178 /* fill in the data */
1179 comp->Component = msi_dup_record_field( row, 1 );
1181 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1183 comp->ComponentId = msi_dup_record_field( row, 2 );
1184 comp->Directory = msi_dup_record_field( row, 3 );
1185 comp->Attributes = MSI_RecordGetInteger(row,4);
1186 comp->Condition = msi_dup_record_field( row, 5 );
1187 comp->KeyPath = msi_dup_record_field( row, 6 );
1189 comp->Installed = INSTALLSTATE_UNKNOWN;
1190 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1192 return ERROR_SUCCESS;
1195 static UINT load_all_components( MSIPACKAGE *package )
1197 static const WCHAR query[] = {
1198 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1199 '`','C','o','m','p','o','n','e','n','t','`',0 };
1203 if (!list_empty(&package->components))
1204 return ERROR_SUCCESS;
1206 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1207 if (r != ERROR_SUCCESS)
1210 r = MSI_IterateRecords(view, NULL, load_component, package);
1211 msiobj_release(&view->hdr);
1216 MSIPACKAGE *package;
1217 MSIFEATURE *feature;
1220 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1224 cl = msi_alloc( sizeof (*cl) );
1226 return ERROR_NOT_ENOUGH_MEMORY;
1227 cl->component = comp;
1228 list_add_tail( &feature->Components, &cl->entry );
1230 return ERROR_SUCCESS;
1233 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1237 fl = msi_alloc( sizeof(*fl) );
1239 return ERROR_NOT_ENOUGH_MEMORY;
1240 fl->feature = child;
1241 list_add_tail( &parent->Children, &fl->entry );
1243 return ERROR_SUCCESS;
1246 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1248 _ilfs* ilfs= (_ilfs*)param;
1252 component = MSI_RecordGetString(row,1);
1254 /* check to see if the component is already loaded */
1255 comp = get_loaded_component( ilfs->package, component );
1258 ERR("unknown component %s\n", debugstr_w(component));
1259 return ERROR_FUNCTION_FAILED;
1262 add_feature_component( ilfs->feature, comp );
1263 comp->Enabled = TRUE;
1265 return ERROR_SUCCESS;
1268 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1270 MSIFEATURE *feature;
1272 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1274 if ( !lstrcmpW( feature->Feature, name ) )
1281 static UINT load_feature(MSIRECORD * row, LPVOID param)
1283 MSIPACKAGE* package = (MSIPACKAGE*)param;
1284 MSIFEATURE* feature;
1285 static const WCHAR Query1[] =
1286 {'S','E','L','E','C','T',' ',
1287 '`','C','o','m','p','o','n','e','n','t','_','`',
1288 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1289 'C','o','m','p','o','n','e','n','t','s','`',' ',
1290 'W','H','E','R','E',' ',
1291 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1296 /* fill in the data */
1298 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1300 return ERROR_NOT_ENOUGH_MEMORY;
1302 list_init( &feature->Children );
1303 list_init( &feature->Components );
1305 feature->Feature = msi_dup_record_field( row, 1 );
1307 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1309 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1310 feature->Title = msi_dup_record_field( row, 3 );
1311 feature->Description = msi_dup_record_field( row, 4 );
1313 if (!MSI_RecordIsNull(row,5))
1314 feature->Display = MSI_RecordGetInteger(row,5);
1316 feature->Level= MSI_RecordGetInteger(row,6);
1317 feature->Directory = msi_dup_record_field( row, 7 );
1318 feature->Attributes = MSI_RecordGetInteger(row,8);
1320 feature->Installed = INSTALLSTATE_UNKNOWN;
1321 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1323 list_add_tail( &package->features, &feature->entry );
1325 /* load feature components */
1327 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1328 if (rc != ERROR_SUCCESS)
1329 return ERROR_SUCCESS;
1331 ilfs.package = package;
1332 ilfs.feature = feature;
1334 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1335 msiobj_release(&view->hdr);
1337 return ERROR_SUCCESS;
1340 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1342 MSIPACKAGE* package = (MSIPACKAGE*)param;
1343 MSIFEATURE *parent, *child;
1345 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1347 return ERROR_FUNCTION_FAILED;
1349 if (!child->Feature_Parent)
1350 return ERROR_SUCCESS;
1352 parent = find_feature_by_name( package, child->Feature_Parent );
1354 return ERROR_FUNCTION_FAILED;
1356 add_feature_child( parent, child );
1357 return ERROR_SUCCESS;
1360 static UINT load_all_features( MSIPACKAGE *package )
1362 static const WCHAR query[] = {
1363 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1364 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1365 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1369 if (!list_empty(&package->features))
1370 return ERROR_SUCCESS;
1372 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1373 if (r != ERROR_SUCCESS)
1376 r = MSI_IterateRecords( view, NULL, load_feature, package );
1377 if (r != ERROR_SUCCESS)
1380 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1381 msiobj_release( &view->hdr );
1386 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1397 static UINT load_file(MSIRECORD *row, LPVOID param)
1399 MSIPACKAGE* package = (MSIPACKAGE*)param;
1403 /* fill in the data */
1405 file = msi_alloc_zero( sizeof (MSIFILE) );
1407 return ERROR_NOT_ENOUGH_MEMORY;
1409 file->File = msi_dup_record_field( row, 1 );
1411 component = MSI_RecordGetString( row, 2 );
1412 file->Component = get_loaded_component( package, component );
1414 if (!file->Component)
1415 ERR("Unfound Component %s\n",debugstr_w(component));
1417 file->FileName = msi_dup_record_field( row, 3 );
1418 reduce_to_longfilename( file->FileName );
1420 file->ShortName = msi_dup_record_field( row, 3 );
1421 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1423 file->FileSize = MSI_RecordGetInteger( row, 4 );
1424 file->Version = msi_dup_record_field( row, 5 );
1425 file->Language = msi_dup_record_field( row, 6 );
1426 file->Attributes = MSI_RecordGetInteger( row, 7 );
1427 file->Sequence = MSI_RecordGetInteger( row, 8 );
1429 file->state = msifs_invalid;
1431 /* if the compressed bits are not set in the file attributes,
1432 * then read the information from the package word count property
1434 if (file->Attributes & msidbFileAttributesCompressed)
1436 file->IsCompressed = TRUE;
1438 else if (file->Attributes & msidbFileAttributesNoncompressed)
1440 file->IsCompressed = FALSE;
1444 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1447 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1449 list_add_tail( &package->files, &file->entry );
1451 return ERROR_SUCCESS;
1454 static UINT load_all_files(MSIPACKAGE *package)
1458 static const WCHAR Query[] =
1459 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1460 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1461 '`','S','e','q','u','e','n','c','e','`', 0};
1463 if (!list_empty(&package->files))
1464 return ERROR_SUCCESS;
1466 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1467 if (rc != ERROR_SUCCESS)
1468 return ERROR_SUCCESS;
1470 rc = MSI_IterateRecords(view, NULL, load_file, package);
1471 msiobj_release(&view->hdr);
1473 return ERROR_SUCCESS;
1476 static UINT load_folder( MSIRECORD *row, LPVOID param )
1478 MSIPACKAGE *package = param;
1479 static const WCHAR szDot[] = { '.',0 };
1480 static WCHAR szEmpty[] = { 0 };
1481 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1484 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1486 return ERROR_NOT_ENOUGH_MEMORY;
1488 folder->Directory = msi_dup_record_field( row, 1 );
1490 TRACE("%s\n", debugstr_w(folder->Directory));
1492 p = msi_dup_record_field(row, 3);
1494 /* split src and target dir */
1496 src_short = folder_split_path( p, ':' );
1498 /* split the long and short paths */
1499 tgt_long = folder_split_path( tgt_short, '|' );
1500 src_long = folder_split_path( src_short, '|' );
1502 /* check for no-op dirs */
1503 if (!lstrcmpW(szDot, tgt_short))
1504 tgt_short = szEmpty;
1505 if (!lstrcmpW(szDot, src_short))
1506 src_short = szEmpty;
1509 tgt_long = tgt_short;
1512 src_short = tgt_short;
1513 src_long = tgt_long;
1517 src_long = src_short;
1519 /* FIXME: use the target short path too */
1520 folder->TargetDefault = strdupW(tgt_long);
1521 folder->SourceShortPath = strdupW(src_short);
1522 folder->SourceLongPath = strdupW(src_long);
1525 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1526 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1527 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1529 folder->Parent = msi_dup_record_field( row, 2 );
1531 folder->Property = msi_dup_property( package, folder->Directory );
1533 list_add_tail( &package->folders, &folder->entry );
1535 TRACE("returning %p\n", folder);
1537 return ERROR_SUCCESS;
1540 static UINT load_all_folders( MSIPACKAGE *package )
1542 static const WCHAR query[] = {
1543 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1544 '`','D','i','r','e','c','t','o','r','y','`',0 };
1548 if (!list_empty(&package->folders))
1549 return ERROR_SUCCESS;
1551 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1552 if (r != ERROR_SUCCESS)
1555 r = MSI_IterateRecords(view, NULL, load_folder, package);
1556 msiobj_release(&view->hdr);
1561 * I am not doing any of the costing functionality yet.
1562 * Mostly looking at doing the Component and Feature loading
1564 * The native MSI does A LOT of modification to tables here. Mostly adding
1565 * a lot of temporary columns to the Feature and Component tables.
1567 * note: Native msi also tracks the short filename. But I am only going to
1568 * track the long ones. Also looking at this directory table
1569 * it appears that the directory table does not get the parents
1570 * resolved base on property only based on their entries in the
1573 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1575 static const WCHAR szCosting[] =
1576 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1577 static const WCHAR szZero[] = { '0', 0 };
1579 MSI_SetPropertyW(package, szCosting, szZero);
1580 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1582 load_all_components( package );
1583 load_all_features( package );
1584 load_all_files( package );
1585 load_all_folders( package );
1587 return ERROR_SUCCESS;
1590 static UINT execute_script(MSIPACKAGE *package, UINT script )
1593 UINT rc = ERROR_SUCCESS;
1595 TRACE("Executing Script %i\n",script);
1597 if (!package->script)
1599 ERR("no script!\n");
1600 return ERROR_FUNCTION_FAILED;
1603 for (i = 0; i < package->script->ActionCount[script]; i++)
1606 action = package->script->Actions[script][i];
1607 ui_actionstart(package, action);
1608 TRACE("Executing Action (%s)\n",debugstr_w(action));
1609 rc = ACTION_PerformAction(package, action, script, TRUE);
1610 if (rc != ERROR_SUCCESS)
1613 msi_free_action_script(package, script);
1617 static UINT ACTION_FileCost(MSIPACKAGE *package)
1619 return ERROR_SUCCESS;
1622 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1626 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1630 if (!comp->ComponentId)
1633 res = MsiGetComponentPathW( package->ProductCode,
1634 comp->ComponentId, NULL, NULL);
1636 res = INSTALLSTATE_ABSENT;
1637 comp->Installed = res;
1641 /* scan for and update current install states */
1642 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1645 MSIFEATURE *feature;
1647 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1650 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1652 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1654 comp= cl->component;
1656 if (!comp->ComponentId)
1658 res = INSTALLSTATE_ABSENT;
1662 if (res == INSTALLSTATE_ABSENT)
1663 res = comp->Installed;
1666 if (res == comp->Installed)
1669 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1670 res != INSTALLSTATE_SOURCE)
1672 res = INSTALLSTATE_INCOMPLETE;
1676 feature->Installed = res;
1680 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1683 static const WCHAR all[]={'A','L','L',0};
1685 MSIFEATURE *feature;
1687 override = msi_dup_property( package, property );
1691 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1693 if (strcmpiW(override,all)==0)
1694 msi_feature_set_state( feature, state );
1697 LPWSTR ptr = override;
1698 LPWSTR ptr2 = strchrW(override,',');
1702 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1703 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1705 msi_feature_set_state( feature, state );
1711 ptr2 = strchrW(ptr,',');
1723 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1726 static const WCHAR szlevel[] =
1727 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1728 static const WCHAR szAddLocal[] =
1729 {'A','D','D','L','O','C','A','L',0};
1730 static const WCHAR szRemove[] =
1731 {'R','E','M','O','V','E',0};
1732 static const WCHAR szReinstall[] =
1733 {'R','E','I','N','S','T','A','L','L',0};
1734 BOOL override = FALSE;
1735 MSICOMPONENT* component;
1736 MSIFEATURE *feature;
1739 /* I do not know if this is where it should happen.. but */
1741 TRACE("Checking Install Level\n");
1743 install_level = msi_get_property_int( package, szlevel, 1 );
1745 /* ok here is the _real_ rub
1746 * all these activation/deactivation things happen in order and things
1747 * later on the list override things earlier on the list.
1748 * 1) INSTALLLEVEL processing
1758 * 11) FILEADDDEFAULT
1759 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1760 * ignored for all the features. seems strange, especially since it is not
1761 * documented anywhere, but it is how it works.
1763 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1764 * REMOVE are the big ones, since we don't handle administrative installs
1767 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1768 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1769 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1773 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1775 BOOL feature_state = ((feature->Level > 0) &&
1776 (feature->Level <= install_level));
1778 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1780 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1781 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1782 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1783 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1785 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1789 /* disable child features of unselected parent features */
1790 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1794 if (feature->Level > 0 && feature->Level <= install_level)
1797 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1798 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1803 /* set the Preselected Property */
1804 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1805 static const WCHAR szOne[] = { '1', 0 };
1807 MSI_SetPropertyW(package,szPreselected,szOne);
1811 * now we want to enable or disable components base on feature
1814 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1818 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1819 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1821 /* features with components that have compressed files are made local */
1822 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1824 if (cl->component->Enabled &&
1825 cl->component->ForceLocalState &&
1826 feature->Action == INSTALLSTATE_SOURCE)
1828 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1833 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1835 component = cl->component;
1837 if (!component->Enabled)
1840 switch (feature->Action)
1842 case INSTALLSTATE_ADVERTISED:
1843 component->hasAdvertiseFeature = 1;
1845 case INSTALLSTATE_SOURCE:
1846 component->hasSourceFeature = 1;
1848 case INSTALLSTATE_LOCAL:
1849 component->hasLocalFeature = 1;
1851 case INSTALLSTATE_DEFAULT:
1852 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1853 component->hasAdvertiseFeature = 1;
1854 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1855 component->hasSourceFeature = 1;
1857 component->hasLocalFeature = 1;
1865 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1867 /* if the component isn't enabled, leave it alone */
1868 if (!component->Enabled)
1871 /* check if it's local or source */
1872 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1873 (component->hasLocalFeature || component->hasSourceFeature))
1875 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1876 !component->ForceLocalState)
1877 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1879 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1883 /* if any feature is local, the component must be local too */
1884 if (component->hasLocalFeature)
1886 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1890 if (component->hasSourceFeature)
1892 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1896 if (component->hasAdvertiseFeature)
1898 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1902 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1905 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1907 if (component->Action == INSTALLSTATE_DEFAULT)
1909 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1910 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1913 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1914 debugstr_w(component->Component), component->Installed, component->Action);
1918 return ERROR_SUCCESS;
1921 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1923 MSIPACKAGE *package = (MSIPACKAGE*)param;
1928 name = MSI_RecordGetString(row,1);
1930 f = get_loaded_folder(package, name);
1931 if (!f) return ERROR_SUCCESS;
1933 /* reset the ResolvedTarget */
1934 msi_free(f->ResolvedTarget);
1935 f->ResolvedTarget = NULL;
1937 /* This helper function now does ALL the work */
1938 TRACE("Dir %s ...\n",debugstr_w(name));
1939 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1940 TRACE("resolves to %s\n",debugstr_w(path));
1943 return ERROR_SUCCESS;
1946 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1948 MSIPACKAGE *package = (MSIPACKAGE*)param;
1950 MSIFEATURE *feature;
1952 name = MSI_RecordGetString( row, 1 );
1954 feature = get_loaded_feature( package, name );
1956 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1960 Condition = MSI_RecordGetString(row,3);
1962 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1964 int level = MSI_RecordGetInteger(row,2);
1965 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1966 feature->Level = level;
1969 return ERROR_SUCCESS;
1972 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1974 static const WCHAR name_fmt[] =
1975 {'%','u','.','%','u','.','%','u','.','%','u',0};
1976 static WCHAR name[] = {'\\',0};
1977 VS_FIXEDFILEINFO *lpVer;
1978 WCHAR filever[0x100];
1984 TRACE("%s\n", debugstr_w(filename));
1986 versize = GetFileVersionInfoSizeW( filename, &handle );
1990 version = msi_alloc( versize );
1991 GetFileVersionInfoW( filename, 0, versize, version );
1993 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1995 msi_free( version );
1999 sprintfW( filever, name_fmt,
2000 HIWORD(lpVer->dwFileVersionMS),
2001 LOWORD(lpVer->dwFileVersionMS),
2002 HIWORD(lpVer->dwFileVersionLS),
2003 LOWORD(lpVer->dwFileVersionLS));
2005 msi_free( version );
2007 return strdupW( filever );
2010 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2012 LPWSTR file_version;
2015 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2017 MSICOMPONENT* comp = file->Component;
2023 if (file->IsCompressed)
2024 comp->ForceLocalState = TRUE;
2026 /* calculate target */
2027 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2029 msi_free(file->TargetPath);
2031 TRACE("file %s is named %s\n",
2032 debugstr_w(file->File), debugstr_w(file->FileName));
2034 file->TargetPath = build_directory_name(2, p, file->FileName);
2038 TRACE("file %s resolves to %s\n",
2039 debugstr_w(file->File), debugstr_w(file->TargetPath));
2041 /* don't check files of components that aren't installed */
2042 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2043 comp->Installed == INSTALLSTATE_ABSENT)
2045 file->state = msifs_missing; /* assume files are missing */
2049 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2051 file->state = msifs_missing;
2052 comp->Cost += file->FileSize;
2053 comp->Installed = INSTALLSTATE_INCOMPLETE;
2057 if (file->Version &&
2058 (file_version = msi_get_disk_file_version( file->TargetPath )))
2060 TRACE("new %s old %s\n", debugstr_w(file->Version),
2061 debugstr_w(file_version));
2062 /* FIXME: seems like a bad way to compare version numbers */
2063 if (lstrcmpiW(file_version, file->Version)<0)
2065 file->state = msifs_overwrite;
2066 comp->Cost += file->FileSize;
2067 comp->Installed = INSTALLSTATE_INCOMPLETE;
2070 file->state = msifs_present;
2071 msi_free( file_version );
2074 file->state = msifs_present;
2077 return ERROR_SUCCESS;
2081 * A lot is done in this function aside from just the costing.
2082 * The costing needs to be implemented at some point but for now I am going
2083 * to focus on the directory building
2086 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2088 static const WCHAR ExecSeqQuery[] =
2089 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2090 '`','D','i','r','e','c','t','o','r','y','`',0};
2091 static const WCHAR ConditionQuery[] =
2092 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2093 '`','C','o','n','d','i','t','i','o','n','`',0};
2094 static const WCHAR szCosting[] =
2095 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2096 static const WCHAR szlevel[] =
2097 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2098 static const WCHAR szOne[] = { '1', 0 };
2104 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2105 return ERROR_SUCCESS;
2107 TRACE("Building Directory properties\n");
2109 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2110 if (rc == ERROR_SUCCESS)
2112 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2114 msiobj_release(&view->hdr);
2117 /* read components states from the registry */
2118 ACTION_GetComponentInstallStates(package);
2120 TRACE("File calculations\n");
2121 msi_check_file_install_states( package );
2123 TRACE("Evaluating Condition Table\n");
2125 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2126 if (rc == ERROR_SUCCESS)
2128 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2130 msiobj_release(&view->hdr);
2133 TRACE("Enabling or Disabling Components\n");
2134 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2136 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2138 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2139 comp->Enabled = FALSE;
2143 MSI_SetPropertyW(package,szCosting,szOne);
2144 /* set default run level if not set */
2145 level = msi_dup_property( package, szlevel );
2147 MSI_SetPropertyW(package,szlevel, szOne);
2150 ACTION_UpdateFeatureInstallStates(package);
2152 return MSI_SetFeatureStates(package);
2155 /* OK this value is "interpreted" and then formatted based on the
2156 first few characters */
2157 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2161 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2167 LPWSTR deformated = NULL;
2170 deformat_string(package, &value[2], &deformated);
2172 /* binary value type */
2176 *size = (strlenW(ptr)/2)+1;
2178 *size = strlenW(ptr)/2;
2180 data = msi_alloc(*size);
2186 /* if uneven pad with a zero in front */
2192 data[count] = (BYTE)strtol(byte,NULL,0);
2194 TRACE("Uneven byte count\n");
2202 data[count] = (BYTE)strtol(byte,NULL,0);
2205 msi_free(deformated);
2207 TRACE("Data %i bytes(%i)\n",*size,count);
2214 deformat_string(package, &value[1], &deformated);
2217 *size = sizeof(DWORD);
2218 data = msi_alloc(*size);
2224 if ( (*p < '0') || (*p > '9') )
2230 if (deformated[0] == '-')
2233 TRACE("DWORD %i\n",*(LPDWORD)data);
2235 msi_free(deformated);
2240 static const WCHAR szMulti[] = {'[','~',']',0};
2249 *type=REG_EXPAND_SZ;
2257 if (strstrW(value,szMulti))
2258 *type = REG_MULTI_SZ;
2260 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2265 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2267 MSIPACKAGE *package = (MSIPACKAGE*)param;
2268 static const WCHAR szHCR[] =
2269 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2270 'R','O','O','T','\\',0};
2271 static const WCHAR szHCU[] =
2272 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2273 'U','S','E','R','\\',0};
2274 static const WCHAR szHLM[] =
2275 {'H','K','E','Y','_','L','O','C','A','L','_',
2276 'M','A','C','H','I','N','E','\\',0};
2277 static const WCHAR szHU[] =
2278 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2280 LPSTR value_data = NULL;
2281 HKEY root_key, hkey;
2284 LPCWSTR szRoot, component, name, key, value;
2289 BOOL check_first = FALSE;
2292 ui_progress(package,2,0,0,0);
2299 component = MSI_RecordGetString(row, 6);
2300 comp = get_loaded_component(package,component);
2302 return ERROR_SUCCESS;
2304 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2306 TRACE("Skipping write due to disabled component %s\n",
2307 debugstr_w(component));
2309 comp->Action = comp->Installed;
2311 return ERROR_SUCCESS;
2314 comp->Action = INSTALLSTATE_LOCAL;
2316 name = MSI_RecordGetString(row, 4);
2317 if( MSI_RecordIsNull(row,5) && name )
2319 /* null values can have special meanings */
2320 if (name[0]=='-' && name[1] == 0)
2321 return ERROR_SUCCESS;
2322 else if ((name[0]=='+' && name[1] == 0) ||
2323 (name[0] == '*' && name[1] == 0))
2328 root = MSI_RecordGetInteger(row,2);
2329 key = MSI_RecordGetString(row, 3);
2331 /* get the root key */
2336 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2337 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2338 if (all_users && all_users[0] == '1')
2340 root_key = HKEY_LOCAL_MACHINE;
2345 root_key = HKEY_CURRENT_USER;
2348 msi_free(all_users);
2351 case 0: root_key = HKEY_CLASSES_ROOT;
2354 case 1: root_key = HKEY_CURRENT_USER;
2357 case 2: root_key = HKEY_LOCAL_MACHINE;
2360 case 3: root_key = HKEY_USERS;
2364 ERR("Unknown root %i\n",root);
2370 return ERROR_SUCCESS;
2372 deformat_string(package, key , &deformated);
2373 size = strlenW(deformated) + strlenW(szRoot) + 1;
2374 uikey = msi_alloc(size*sizeof(WCHAR));
2375 strcpyW(uikey,szRoot);
2376 strcatW(uikey,deformated);
2378 if (RegCreateKeyW( root_key, deformated, &hkey))
2380 ERR("Could not create key %s\n",debugstr_w(deformated));
2381 msi_free(deformated);
2383 return ERROR_SUCCESS;
2385 msi_free(deformated);
2387 value = MSI_RecordGetString(row,5);
2389 value_data = parse_value(package, value, &type, &size);
2392 static const WCHAR szEmpty[] = {0};
2393 value_data = (LPSTR)strdupW(szEmpty);
2398 deformat_string(package, name, &deformated);
2400 /* get the double nulls to terminate SZ_MULTI */
2401 if (type == REG_MULTI_SZ)
2402 size +=sizeof(WCHAR);
2406 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2408 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2413 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2414 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2416 TRACE("value %s of %s checked already exists\n",
2417 debugstr_w(deformated), debugstr_w(uikey));
2421 TRACE("Checked and setting value %s of %s\n",
2422 debugstr_w(deformated), debugstr_w(uikey));
2423 if (deformated || size)
2424 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2429 uirow = MSI_CreateRecord(3);
2430 MSI_RecordSetStringW(uirow,2,deformated);
2431 MSI_RecordSetStringW(uirow,1,uikey);
2434 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2436 MSI_RecordSetStringW(uirow,3,value);
2438 ui_actiondata(package,szWriteRegistryValues,uirow);
2439 msiobj_release( &uirow->hdr );
2441 msi_free(value_data);
2442 msi_free(deformated);
2445 return ERROR_SUCCESS;
2448 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2452 static const WCHAR ExecSeqQuery[] =
2453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2454 '`','R','e','g','i','s','t','r','y','`',0 };
2456 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2457 if (rc != ERROR_SUCCESS)
2458 return ERROR_SUCCESS;
2460 /* increment progress bar each time action data is sent */
2461 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2463 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2465 msiobj_release(&view->hdr);
2469 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2471 package->script->CurrentlyScripting = TRUE;
2473 return ERROR_SUCCESS;
2477 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2482 static const WCHAR q1[]=
2483 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2484 '`','R','e','g','i','s','t','r','y','`',0};
2487 MSIFEATURE *feature;
2490 TRACE("InstallValidate\n");
2492 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2493 if (rc == ERROR_SUCCESS)
2495 MSI_IterateRecords( view, &progress, NULL, package );
2496 msiobj_release( &view->hdr );
2497 total += progress * REG_PROGRESS_VALUE;
2500 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2501 total += COMPONENT_PROGRESS_VALUE;
2503 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2504 total += file->FileSize;
2506 ui_progress(package,0,total,0,0);
2508 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2510 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2511 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2512 feature->ActionRequest);
2515 return ERROR_SUCCESS;
2518 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2520 MSIPACKAGE* package = (MSIPACKAGE*)param;
2521 LPCWSTR cond = NULL;
2522 LPCWSTR message = NULL;
2525 static const WCHAR title[]=
2526 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2528 cond = MSI_RecordGetString(row,1);
2530 r = MSI_EvaluateConditionW(package,cond);
2531 if (r == MSICONDITION_FALSE)
2533 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2536 message = MSI_RecordGetString(row,2);
2537 deformat_string(package,message,&deformated);
2538 MessageBoxW(NULL,deformated,title,MB_OK);
2539 msi_free(deformated);
2542 return ERROR_INSTALL_FAILURE;
2545 return ERROR_SUCCESS;
2548 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2551 MSIQUERY * view = NULL;
2552 static const WCHAR ExecSeqQuery[] =
2553 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2554 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2556 TRACE("Checking launch conditions\n");
2558 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2559 if (rc != ERROR_SUCCESS)
2560 return ERROR_SUCCESS;
2562 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2563 msiobj_release(&view->hdr);
2568 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2572 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2574 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2576 MSIRECORD * row = 0;
2578 LPWSTR deformated,buffer,deformated_name;
2580 static const WCHAR ExecSeqQuery[] =
2581 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2582 '`','R','e','g','i','s','t','r','y','`',' ',
2583 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2584 ' ','=',' ' ,'\'','%','s','\'',0 };
2585 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2586 static const WCHAR fmt2[]=
2587 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2589 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2593 root = MSI_RecordGetInteger(row,2);
2594 key = MSI_RecordGetString(row, 3);
2595 name = MSI_RecordGetString(row, 4);
2596 deformat_string(package, key , &deformated);
2597 deformat_string(package, name, &deformated_name);
2599 len = strlenW(deformated) + 6;
2600 if (deformated_name)
2601 len+=strlenW(deformated_name);
2603 buffer = msi_alloc( len *sizeof(WCHAR));
2605 if (deformated_name)
2606 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2608 sprintfW(buffer,fmt,root,deformated);
2610 msi_free(deformated);
2611 msi_free(deformated_name);
2612 msiobj_release(&row->hdr);
2616 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2618 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2623 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2626 return strdupW( file->TargetPath );
2631 static HKEY openSharedDLLsKey(void)
2634 static const WCHAR path[] =
2635 {'S','o','f','t','w','a','r','e','\\',
2636 'M','i','c','r','o','s','o','f','t','\\',
2637 'W','i','n','d','o','w','s','\\',
2638 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2639 'S','h','a','r','e','d','D','L','L','s',0};
2641 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2645 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2650 DWORD sz = sizeof(count);
2653 hkey = openSharedDLLsKey();
2654 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2655 if (rc != ERROR_SUCCESS)
2661 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2665 hkey = openSharedDLLsKey();
2667 msi_reg_set_val_dword( hkey, path, count );
2669 RegDeleteValueW(hkey,path);
2675 * Return TRUE if the count should be written out and FALSE if not
2677 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2679 MSIFEATURE *feature;
2683 /* only refcount DLLs */
2684 if (comp->KeyPath == NULL ||
2685 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2686 comp->Attributes & msidbComponentAttributesODBCDataSource)
2690 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2691 write = (count > 0);
2693 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2697 /* increment counts */
2698 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2702 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2705 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2707 if ( cl->component == comp )
2712 /* decrement counts */
2713 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2717 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2720 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2722 if ( cl->component == comp )
2727 /* ref count all the files in the component */
2732 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2734 if (file->Component == comp)
2735 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2739 /* add a count for permenent */
2740 if (comp->Attributes & msidbComponentAttributesPermanent)
2743 comp->RefCount = count;
2746 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2750 * Ok further analysis makes me think that this work is
2751 * actually done in the PublishComponents and PublishFeatures
2752 * step, and not here. It appears like the keypath and all that is
2753 * resolved in this step, however actually written in the Publish steps.
2754 * But we will leave it here for now because it is unclear
2756 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2758 WCHAR squished_pc[GUID_SIZE];
2759 WCHAR squished_cc[GUID_SIZE];
2762 HKEY hkey=0,hkey2=0;
2764 /* writes the Component and Features values to the registry */
2766 rc = MSIREG_OpenComponents(&hkey);
2767 if (rc != ERROR_SUCCESS)
2770 squash_guid(package->ProductCode,squished_pc);
2771 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2773 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2777 ui_progress(package,2,0,0,0);
2778 if (!comp->ComponentId)
2781 squash_guid(comp->ComponentId,squished_cc);
2783 msi_free(comp->FullKeypath);
2784 comp->FullKeypath = resolve_keypath( package, comp );
2786 /* do the refcounting */
2787 ACTION_RefCountComponent( package, comp );
2789 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2790 debugstr_w(comp->Component),
2791 debugstr_w(squished_cc),
2792 debugstr_w(comp->FullKeypath),
2795 * Write the keypath out if the component is to be registered
2796 * and delete the key if the component is to be deregistered
2798 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2800 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2801 if (rc != ERROR_SUCCESS)
2804 if (!comp->FullKeypath)
2807 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2809 if (comp->Attributes & msidbComponentAttributesPermanent)
2811 static const WCHAR szPermKey[] =
2812 { '0','0','0','0','0','0','0','0','0','0','0','0',
2813 '0','0','0','0','0','0','0','0','0','0','0','0',
2814 '0','0','0','0','0','0','0','0',0 };
2816 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2821 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2825 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2826 if (rc != ERROR_SUCCESS)
2829 RegDeleteValueW(hkey2,squished_pc);
2831 /* if the key is empty delete it */
2832 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2834 if (res == ERROR_NO_MORE_ITEMS)
2835 RegDeleteKeyW(hkey,squished_cc);
2840 uirow = MSI_CreateRecord(3);
2841 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2842 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2843 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2844 ui_actiondata(package,szProcessComponents,uirow);
2845 msiobj_release( &uirow->hdr );
2859 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2860 LPWSTR lpszName, LONG_PTR lParam)
2863 typelib_struct *tl_struct = (typelib_struct*) lParam;
2864 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2868 if (!IS_INTRESOURCE(lpszName))
2870 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2874 sz = strlenW(tl_struct->source)+4;
2875 sz *= sizeof(WCHAR);
2877 if ((INT_PTR)lpszName == 1)
2878 tl_struct->path = strdupW(tl_struct->source);
2881 tl_struct->path = msi_alloc(sz);
2882 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2885 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2886 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2887 if (!SUCCEEDED(res))
2889 msi_free(tl_struct->path);
2890 tl_struct->path = NULL;
2895 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2896 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2898 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2902 msi_free(tl_struct->path);
2903 tl_struct->path = NULL;
2905 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2906 ITypeLib_Release(tl_struct->ptLib);
2911 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2913 MSIPACKAGE* package = (MSIPACKAGE*)param;
2917 typelib_struct tl_struct;
2919 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2921 component = MSI_RecordGetString(row,3);
2922 comp = get_loaded_component(package,component);
2924 return ERROR_SUCCESS;
2926 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2928 TRACE("Skipping typelib reg due to disabled component\n");
2930 comp->Action = comp->Installed;
2932 return ERROR_SUCCESS;
2935 comp->Action = INSTALLSTATE_LOCAL;
2937 file = get_loaded_file( package, comp->KeyPath );
2939 return ERROR_SUCCESS;
2941 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2945 guid = MSI_RecordGetString(row,1);
2946 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2947 tl_struct.source = strdupW( file->TargetPath );
2948 tl_struct.path = NULL;
2950 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2951 (LONG_PTR)&tl_struct);
2959 helpid = MSI_RecordGetString(row,6);
2962 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2963 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2966 if (!SUCCEEDED(res))
2967 ERR("Failed to register type library %s\n",
2968 debugstr_w(tl_struct.path));
2971 ui_actiondata(package,szRegisterTypeLibraries,row);
2973 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2976 ITypeLib_Release(tl_struct.ptLib);
2977 msi_free(tl_struct.path);
2980 ERR("Failed to load type library %s\n",
2981 debugstr_w(tl_struct.source));
2983 FreeLibrary(module);
2984 msi_free(tl_struct.source);
2987 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2989 return ERROR_SUCCESS;
2992 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2995 * OK this is a bit confusing.. I am given a _Component key and I believe
2996 * that the file that is being registered as a type library is the "key file
2997 * of that component" which I interpret to mean "The file in the KeyPath of
3002 static const WCHAR Query[] =
3003 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3004 '`','T','y','p','e','L','i','b','`',0};
3006 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3007 if (rc != ERROR_SUCCESS)
3008 return ERROR_SUCCESS;
3010 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3011 msiobj_release(&view->hdr);
3015 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3017 MSIPACKAGE *package = (MSIPACKAGE*)param;
3018 LPWSTR target_file, target_folder, filename;
3019 LPCWSTR buffer, extension;
3021 static const WCHAR szlnk[]={'.','l','n','k',0};
3022 IShellLinkW *sl = NULL;
3023 IPersistFile *pf = NULL;
3026 buffer = MSI_RecordGetString(row,4);
3027 comp = get_loaded_component(package,buffer);
3029 return ERROR_SUCCESS;
3031 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3033 TRACE("Skipping shortcut creation due to disabled component\n");
3035 comp->Action = comp->Installed;
3037 return ERROR_SUCCESS;
3040 comp->Action = INSTALLSTATE_LOCAL;
3042 ui_actiondata(package,szCreateShortcuts,row);
3044 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3045 &IID_IShellLinkW, (LPVOID *) &sl );
3049 ERR("CLSID_ShellLink not available\n");
3053 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3056 ERR("QueryInterface(IID_IPersistFile) failed\n");
3060 buffer = MSI_RecordGetString(row,2);
3061 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3063 /* may be needed because of a bug somehwere else */
3064 create_full_pathW(target_folder);
3066 filename = msi_dup_record_field( row, 3 );
3067 reduce_to_longfilename(filename);
3069 extension = strchrW(filename,'.');
3070 if (!extension || strcmpiW(extension,szlnk))
3072 int len = strlenW(filename);
3073 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3074 memcpy(filename + len, szlnk, sizeof(szlnk));
3076 target_file = build_directory_name(2, target_folder, filename);
3077 msi_free(target_folder);
3080 buffer = MSI_RecordGetString(row,5);
3081 if (strchrW(buffer,'['))
3084 deformat_string(package,buffer,&deformated);
3085 IShellLinkW_SetPath(sl,deformated);
3086 msi_free(deformated);
3090 FIXME("poorly handled shortcut format, advertised shortcut\n");
3091 IShellLinkW_SetPath(sl,comp->FullKeypath);
3094 if (!MSI_RecordIsNull(row,6))
3097 buffer = MSI_RecordGetString(row,6);
3098 deformat_string(package,buffer,&deformated);
3099 IShellLinkW_SetArguments(sl,deformated);
3100 msi_free(deformated);
3103 if (!MSI_RecordIsNull(row,7))
3105 buffer = MSI_RecordGetString(row,7);
3106 IShellLinkW_SetDescription(sl,buffer);
3109 if (!MSI_RecordIsNull(row,8))
3110 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3112 if (!MSI_RecordIsNull(row,9))
3117 buffer = MSI_RecordGetString(row,9);
3119 Path = build_icon_path(package,buffer);
3120 index = MSI_RecordGetInteger(row,10);
3122 /* no value means 0 */
3123 if (index == MSI_NULL_INTEGER)
3126 IShellLinkW_SetIconLocation(sl,Path,index);
3130 if (!MSI_RecordIsNull(row,11))
3131 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3133 if (!MSI_RecordIsNull(row,12))
3136 buffer = MSI_RecordGetString(row,12);
3137 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3139 IShellLinkW_SetWorkingDirectory(sl,Path);
3143 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3144 IPersistFile_Save(pf,target_file,FALSE);
3146 msi_free(target_file);
3150 IPersistFile_Release( pf );
3152 IShellLinkW_Release( sl );
3154 return ERROR_SUCCESS;
3157 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3162 static const WCHAR Query[] =
3163 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3164 '`','S','h','o','r','t','c','u','t','`',0};
3166 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3167 if (rc != ERROR_SUCCESS)
3168 return ERROR_SUCCESS;
3170 res = CoInitialize( NULL );
3173 ERR("CoInitialize failed\n");
3174 return ERROR_FUNCTION_FAILED;
3177 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3178 msiobj_release(&view->hdr);
3185 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3187 MSIPACKAGE* package = (MSIPACKAGE*)param;
3196 FileName = MSI_RecordGetString(row,1);
3199 ERR("Unable to get FileName\n");
3200 return ERROR_SUCCESS;
3203 FilePath = build_icon_path(package,FileName);
3205 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3207 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3208 FILE_ATTRIBUTE_NORMAL, NULL);
3210 if (the_file == INVALID_HANDLE_VALUE)
3212 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3214 return ERROR_SUCCESS;
3221 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3222 if (rc != ERROR_SUCCESS)
3224 ERR("Failed to get stream\n");
3225 CloseHandle(the_file);
3226 DeleteFileW(FilePath);
3229 WriteFile(the_file,buffer,sz,&write,NULL);
3230 } while (sz == 1024);
3234 CloseHandle(the_file);
3236 uirow = MSI_CreateRecord(1);
3237 MSI_RecordSetStringW(uirow,1,FileName);
3238 ui_actiondata(package,szPublishProduct,uirow);
3239 msiobj_release( &uirow->hdr );
3241 return ERROR_SUCCESS;
3245 * 99% of the work done here is only done for
3246 * advertised installs. However this is where the
3247 * Icon table is processed and written out
3248 * so that is what I am going to do here.
3250 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3254 static const WCHAR Query[]=
3255 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3256 '`','I','c','o','n','`',0};
3257 /* for registry stuff */
3260 HKEY hudkey=0, props=0;
3261 static const WCHAR szProductLanguage[] =
3262 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3263 static const WCHAR szARPProductIcon[] =
3264 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3265 static const WCHAR szProductVersion[] =
3266 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3267 static const WCHAR szInstallProperties[] =
3268 {'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
3269 static const WCHAR szWindowsInstaller[] =
3270 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3274 MSIHANDLE hDb, hSumInfo;
3276 /* write out icon files */
3278 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3279 if (rc == ERROR_SUCCESS)
3281 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3282 msiobj_release(&view->hdr);
3285 /* ok there is a lot more done here but i need to figure out what */
3287 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3288 if (rc != ERROR_SUCCESS)
3291 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3292 if (rc != ERROR_SUCCESS)
3295 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3296 if (rc != ERROR_SUCCESS)
3299 rc = RegCreateKeyW(hudkey, szInstallProperties, &props);
3300 if (rc != ERROR_SUCCESS)
3303 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
3305 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3306 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3309 langid = msi_get_property_int( package, szProductLanguage, 0 );
3310 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3312 buffer = msi_dup_property( package, szARPProductIcon );
3315 LPWSTR path = build_icon_path(package,buffer);
3316 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3321 buffer = msi_dup_property( package, szProductVersion );
3324 DWORD verdword = msi_version_str_to_dword(buffer);
3325 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3329 /* FIXME: Need to write more keys to the user registry */
3331 hDb= alloc_msihandle( &package->db->hdr );
3333 rc = ERROR_NOT_ENOUGH_MEMORY;
3336 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3337 MsiCloseHandle(hDb);
3338 if (rc == ERROR_SUCCESS)
3340 WCHAR guidbuffer[0x200];
3342 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3344 if (rc == ERROR_SUCCESS)
3346 WCHAR squashed[GUID_SIZE];
3347 /* for now we only care about the first guid */
3348 LPWSTR ptr = strchrW(guidbuffer,';');
3350 squash_guid(guidbuffer,squashed);
3351 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3355 ERR("Unable to query Revision_Number...\n");
3358 MsiCloseHandle(hSumInfo);
3362 ERR("Unable to open Summary Information\n");
3369 RegCloseKey(hudkey);
3375 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3377 MSIPACKAGE *package = (MSIPACKAGE*)param;
3378 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3379 LPWSTR deformated_section, deformated_key, deformated_value;
3380 LPWSTR folder, fullname = NULL;
3384 static const WCHAR szWindowsFolder[] =
3385 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3387 component = MSI_RecordGetString(row, 8);
3388 comp = get_loaded_component(package,component);
3390 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3392 TRACE("Skipping ini file due to disabled component %s\n",
3393 debugstr_w(component));
3395 comp->Action = comp->Installed;
3397 return ERROR_SUCCESS;
3400 comp->Action = INSTALLSTATE_LOCAL;
3402 identifier = MSI_RecordGetString(row,1);
3403 filename = MSI_RecordGetString(row,2);
3404 dirproperty = MSI_RecordGetString(row,3);
3405 section = MSI_RecordGetString(row,4);
3406 key = MSI_RecordGetString(row,5);
3407 value = MSI_RecordGetString(row,6);
3408 action = MSI_RecordGetInteger(row,7);
3410 deformat_string(package,section,&deformated_section);
3411 deformat_string(package,key,&deformated_key);
3412 deformat_string(package,value,&deformated_value);
3416 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3418 folder = msi_dup_property( package, dirproperty );
3421 folder = msi_dup_property( package, szWindowsFolder );
3425 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3429 fullname = build_directory_name(2, folder, filename);
3433 TRACE("Adding value %s to section %s in %s\n",
3434 debugstr_w(deformated_key), debugstr_w(deformated_section),
3435 debugstr_w(fullname));
3436 WritePrivateProfileStringW(deformated_section, deformated_key,
3437 deformated_value, fullname);
3439 else if (action == 1)
3442 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3443 returned, 10, fullname);
3444 if (returned[0] == 0)
3446 TRACE("Adding value %s to section %s in %s\n",
3447 debugstr_w(deformated_key), debugstr_w(deformated_section),
3448 debugstr_w(fullname));
3450 WritePrivateProfileStringW(deformated_section, deformated_key,
3451 deformated_value, fullname);
3454 else if (action == 3)
3455 FIXME("Append to existing section not yet implemented\n");
3457 uirow = MSI_CreateRecord(4);
3458 MSI_RecordSetStringW(uirow,1,identifier);
3459 MSI_RecordSetStringW(uirow,2,deformated_section);
3460 MSI_RecordSetStringW(uirow,3,deformated_key);
3461 MSI_RecordSetStringW(uirow,4,deformated_value);
3462 ui_actiondata(package,szWriteIniValues,uirow);
3463 msiobj_release( &uirow->hdr );
3467 msi_free(deformated_key);
3468 msi_free(deformated_value);
3469 msi_free(deformated_section);
3470 return ERROR_SUCCESS;
3473 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3477 static const WCHAR ExecSeqQuery[] =
3478 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3479 '`','I','n','i','F','i','l','e','`',0};
3481 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3482 if (rc != ERROR_SUCCESS)
3484 TRACE("no IniFile table\n");
3485 return ERROR_SUCCESS;
3488 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3489 msiobj_release(&view->hdr);
3493 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3495 MSIPACKAGE *package = (MSIPACKAGE*)param;
3500 static const WCHAR ExeStr[] =
3501 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3502 static const WCHAR close[] = {'\"',0};
3504 PROCESS_INFORMATION info;
3509 memset(&si,0,sizeof(STARTUPINFOW));
3511 filename = MSI_RecordGetString(row,1);
3512 file = get_loaded_file( package, filename );
3516 ERR("Unable to find file id %s\n",debugstr_w(filename));
3517 return ERROR_SUCCESS;
3520 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3522 FullName = msi_alloc(len*sizeof(WCHAR));
3523 strcpyW(FullName,ExeStr);
3524 strcatW( FullName, file->TargetPath );
3525 strcatW(FullName,close);
3527 TRACE("Registering %s\n",debugstr_w(FullName));
3528 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3532 msi_dialog_check_messages(info.hProcess);
3537 uirow = MSI_CreateRecord( 2 );
3538 uipath = strdupW( file->TargetPath );
3539 p = strrchrW(uipath,'\\');
3542 MSI_RecordSetStringW( uirow, 1, &p[1] );
3543 MSI_RecordSetStringW( uirow, 2, uipath);
3544 ui_actiondata( package, szSelfRegModules, uirow);
3545 msiobj_release( &uirow->hdr );
3547 /* FIXME: call ui_progress? */
3549 return ERROR_SUCCESS;
3552 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3556 static const WCHAR ExecSeqQuery[] =
3557 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3558 '`','S','e','l','f','R','e','g','`',0};
3560 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3561 if (rc != ERROR_SUCCESS)
3563 TRACE("no SelfReg table\n");
3564 return ERROR_SUCCESS;
3567 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3568 msiobj_release(&view->hdr);
3570 return ERROR_SUCCESS;
3573 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3575 MSIFEATURE *feature;
3580 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3581 if (rc != ERROR_SUCCESS)
3584 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3585 if (rc != ERROR_SUCCESS)
3588 /* here the guids are base 85 encoded */
3589 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3595 BOOL absent = FALSE;
3598 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3599 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3600 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3604 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3608 if (feature->Feature_Parent)
3609 size += strlenW( feature->Feature_Parent )+2;
3611 data = msi_alloc(size * sizeof(WCHAR));
3614 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3616 MSICOMPONENT* component = cl->component;
3620 if (component->ComponentId)
3622 TRACE("From %s\n",debugstr_w(component->ComponentId));
3623 CLSIDFromString(component->ComponentId, &clsid);
3624 encode_base85_guid(&clsid,buf);
3625 TRACE("to %s\n",debugstr_w(buf));
3629 if (feature->Feature_Parent)
3631 static const WCHAR sep[] = {'\2',0};
3633 strcatW(data,feature->Feature_Parent);
3636 msi_reg_set_val_str( hkey, feature->Feature, data );
3640 if (feature->Feature_Parent)
3641 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3644 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3645 (LPBYTE)feature->Feature_Parent,size);
3649 size += 2*sizeof(WCHAR);
3650 data = msi_alloc(size);
3653 if (feature->Feature_Parent)
3654 strcpyW( &data[1], feature->Feature_Parent );
3655 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3661 uirow = MSI_CreateRecord( 1 );
3662 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3663 ui_actiondata( package, szPublishFeatures, uirow);
3664 msiobj_release( &uirow->hdr );
3665 /* FIXME: call ui_progress? */
3674 static UINT msi_get_local_package_name( LPWSTR path )
3676 static const WCHAR szInstaller[] = {
3677 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3678 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3682 time = GetTickCount();
3683 GetWindowsDirectoryW( path, MAX_PATH );
3684 lstrcatW( path, szInstaller );
3685 CreateDirectoryW( path, NULL );
3687 len = lstrlenW(path);
3688 for (i=0; i<0x10000; i++)
3690 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3691 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3692 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3693 if (handle != INVALID_HANDLE_VALUE)
3695 CloseHandle(handle);
3698 if (GetLastError() != ERROR_FILE_EXISTS &&
3699 GetLastError() != ERROR_SHARING_VIOLATION)
3700 return ERROR_FUNCTION_FAILED;
3703 return ERROR_SUCCESS;
3706 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3708 static const WCHAR szOriginalDatabase[] =
3709 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3710 WCHAR packagefile[MAX_PATH];
3714 r = msi_get_local_package_name( packagefile );
3715 if (r != ERROR_SUCCESS)
3718 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3720 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3721 r = CopyFileW( msiFilePath, packagefile, FALSE);
3725 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3726 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3727 msi_free( msiFilePath );
3728 return ERROR_FUNCTION_FAILED;
3730 msi_free( msiFilePath );
3732 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3733 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3734 return ERROR_SUCCESS;
3737 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3739 LPWSTR prop, val, key;
3740 static const LPCSTR propval[] = {
3741 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3742 "ARPCONTACT", "Contact",
3743 "ARPCOMMENTS", "Comments",
3744 "ProductName", "DisplayName",
3745 "ProductVersion", "DisplayVersion",
3746 "ARPHELPLINK", "HelpLink",
3747 "ARPHELPTELEPHONE", "HelpTelephone",
3748 "ARPINSTALLLOCATION", "InstallLocation",
3749 "SourceDir", "InstallSource",
3750 "Manufacturer", "Publisher",
3751 "ARPREADME", "Readme",
3753 "ARPURLINFOABOUT", "URLInfoAbout",
3754 "ARPURLUPDATEINFO", "URLUpdateInfo",
3757 const LPCSTR *p = propval;
3761 prop = strdupAtoW( *p++ );
3762 key = strdupAtoW( *p++ );
3763 val = msi_dup_property( package, prop );
3764 msi_reg_set_val_str( hkey, key, val );
3769 return ERROR_SUCCESS;
3772 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3775 LPWSTR buffer = NULL;
3778 static const WCHAR szWindowsInstaller[] =
3779 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3780 static const WCHAR szUpgradeCode[] =
3781 {'U','p','g','r','a','d','e','C','o','d','e',0};
3782 static const WCHAR modpath_fmt[] =
3783 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3784 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3785 static const WCHAR szModifyPath[] =
3786 {'M','o','d','i','f','y','P','a','t','h',0};
3787 static const WCHAR szUninstallString[] =
3788 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3789 static const WCHAR szEstimatedSize[] =
3790 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3791 static const WCHAR szProductLanguage[] =
3792 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3793 static const WCHAR szProductVersion[] =
3794 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3797 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3798 LPWSTR upgrade_code;
3801 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3802 if (rc != ERROR_SUCCESS)
3805 /* dump all the info i can grab */
3806 /* FIXME: Flesh out more information */
3808 msi_write_uninstall_property_vals( package, hkey );
3810 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3812 msi_make_package_local( package, hkey );
3814 /* do ModifyPath and UninstallString */
3815 size = deformat_string(package,modpath_fmt,&buffer);
3816 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3817 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3820 /* FIXME: Write real Estimated Size when we have it */
3821 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3823 GetLocalTime(&systime);
3824 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3825 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3827 langid = msi_get_property_int( package, szProductLanguage, 0 );
3828 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3830 buffer = msi_dup_property( package, szProductVersion );
3833 DWORD verdword = msi_version_str_to_dword(buffer);
3835 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3836 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3837 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3841 /* Handle Upgrade Codes */
3842 upgrade_code = msi_dup_property( package, szUpgradeCode );
3847 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3848 squash_guid(package->ProductCode,squashed);
3849 msi_reg_set_val_str( hkey2, squashed, NULL );
3851 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3852 squash_guid(package->ProductCode,squashed);
3853 msi_reg_set_val_str( hkey2, squashed, NULL );
3856 msi_free(upgrade_code);
3861 /* FIXME: call ui_actiondata */
3863 return ERROR_SUCCESS;
3866 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3868 return execute_script(package,INSTALL_SCRIPT);
3871 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3875 /* turn off scheduling */
3876 package->script->CurrentlyScripting= FALSE;
3878 /* first do the same as an InstallExecute */
3879 rc = ACTION_InstallExecute(package);
3880 if (rc != ERROR_SUCCESS)
3883 /* then handle Commit Actions */
3884 rc = execute_script(package,COMMIT_SCRIPT);
3889 UINT ACTION_ForceReboot(MSIPACKAGE *package)
3891 static const WCHAR RunOnce[] = {
3892 'S','o','f','t','w','a','r','e','\\',
3893 'M','i','c','r','o','s','o','f','t','\\',
3894 'W','i','n','d','o','w','s','\\',
3895 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3896 'R','u','n','O','n','c','e',0};
3897 static const WCHAR InstallRunOnce[] = {
3898 'S','o','f','t','w','a','r','e','\\',
3899 'M','i','c','r','o','s','o','f','t','\\',
3900 'W','i','n','d','o','w','s','\\',
3901 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3902 'I','n','s','t','a','l','l','e','r','\\',
3903 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3905 static const WCHAR msiexec_fmt[] = {
3907 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3908 '\"','%','s','\"',0};
3909 static const WCHAR install_fmt[] = {
3910 '/','I',' ','\"','%','s','\"',' ',
3911 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3912 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3913 WCHAR buffer[256], sysdir[MAX_PATH];
3915 WCHAR squished_pc[100];
3917 squash_guid(package->ProductCode,squished_pc);
3919 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3920 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3921 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3924 msi_reg_set_val_str( hkey, squished_pc, buffer );
3927 TRACE("Reboot command %s\n",debugstr_w(buffer));
3929 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3930 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3932 msi_reg_set_val_str( hkey, squished_pc, buffer );
3935 return ERROR_INSTALL_SUSPEND;
3938 static UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3943 p = strrchrW( package->PackagePath, '\\' );
3945 return ERROR_SUCCESS;
3947 len = p - package->PackagePath + 2;
3948 source = msi_alloc( len * sizeof(WCHAR) );
3949 lstrcpynW( source, package->PackagePath, len );
3951 MSI_SetPropertyW( package, cszSourceDir, source );
3952 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3956 return ERROR_SUCCESS;
3959 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3965 * We are currently doing what should be done here in the top level Install
3966 * however for Administrative and uninstalls this step will be needed
3968 if (!package->PackagePath)
3969 return ERROR_SUCCESS;
3971 msi_set_sourcedir_props(package);
3973 attrib = GetFileAttributesW(package->PackagePath);
3974 if (attrib == INVALID_FILE_ATTRIBUTES)
3980 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3981 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3982 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3983 if (rc == ERROR_MORE_DATA)
3985 prompt = msi_alloc(size * sizeof(WCHAR));
3986 MsiSourceListGetInfoW(package->ProductCode, NULL,
3987 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3988 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3991 prompt = strdupW(package->PackagePath);
3993 msg = generate_error_string(package,1302,1,prompt);
3994 while(attrib == INVALID_FILE_ATTRIBUTES)
3996 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3999 rc = ERROR_INSTALL_USEREXIT;
4002 attrib = GetFileAttributesW(package->PackagePath);
4008 return ERROR_SUCCESS;
4013 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4020 static const WCHAR szPropKeys[][80] =
4022 {'P','r','o','d','u','c','t','I','D',0},
4023 {'U','S','E','R','N','A','M','E',0},
4024 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4028 static const WCHAR szRegKeys[][80] =
4030 {'P','r','o','d','u','c','t','I','D',0},
4031 {'R','e','g','O','w','n','e','r',0},
4032 {'R','e','g','C','o','m','p','a','n','y',0},
4036 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4038 return ERROR_SUCCESS;
4040 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
4041 if (rc != ERROR_SUCCESS)
4044 for( i = 0; szPropKeys[i][0]; i++ )
4046 buffer = msi_dup_property( package, szPropKeys[i] );
4047 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4052 msi_free(productid);
4055 /* FIXME: call ui_actiondata */
4057 return ERROR_SUCCESS;
4061 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4065 package->script->InWhatSequence |= SEQUENCE_EXEC;
4066 rc = ACTION_ProcessExecSequence(package,FALSE);
4071 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4073 MSIPACKAGE *package = (MSIPACKAGE*)param;
4074 LPCWSTR compgroupid=NULL;
4075 LPCWSTR feature=NULL;
4076 LPCWSTR text = NULL;
4077 LPCWSTR qualifier = NULL;
4078 LPCWSTR component = NULL;
4079 LPWSTR advertise = NULL;
4080 LPWSTR output = NULL;
4082 UINT rc = ERROR_SUCCESS;
4087 component = MSI_RecordGetString(rec,3);
4088 comp = get_loaded_component(package,component);
4090 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4091 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4092 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4094 TRACE("Skipping: Component %s not scheduled for install\n",
4095 debugstr_w(component));
4097 return ERROR_SUCCESS;
4100 compgroupid = MSI_RecordGetString(rec,1);
4101 qualifier = MSI_RecordGetString(rec,2);
4103 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4104 if (rc != ERROR_SUCCESS)
4107 text = MSI_RecordGetString(rec,4);
4108 feature = MSI_RecordGetString(rec,5);
4110 advertise = create_component_advertise_string(package, comp, feature);
4112 sz = strlenW(advertise);
4115 sz += lstrlenW(text);
4118 sz *= sizeof(WCHAR);
4120 output = msi_alloc_zero(sz);
4121 strcpyW(output,advertise);
4122 msi_free(advertise);
4125 strcatW(output,text);
4127 msi_reg_set_val_multi_str( hkey, qualifier, output );
4134 uirow = MSI_CreateRecord( 2 );
4135 MSI_RecordSetStringW( uirow, 1, compgroupid );
4136 MSI_RecordSetStringW( uirow, 2, qualifier);
4137 ui_actiondata( package, szPublishComponents, uirow);
4138 msiobj_release( &uirow->hdr );
4139 /* FIXME: call ui_progress? */
4145 * At present I am ignorning the advertised components part of this and only
4146 * focusing on the qualified component sets
4148 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4152 static const WCHAR ExecSeqQuery[] =
4153 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4154 '`','P','u','b','l','i','s','h',
4155 'C','o','m','p','o','n','e','n','t','`',0};
4157 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4158 if (rc != ERROR_SUCCESS)
4159 return ERROR_SUCCESS;
4161 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4162 msiobj_release(&view->hdr);
4167 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4169 MSIPACKAGE *package = (MSIPACKAGE*)param;
4172 SC_HANDLE hscm, service = NULL;
4173 LPCWSTR name, disp, comp, depends, pass;
4174 LPCWSTR load_order, serv_name, key;
4175 DWORD serv_type, start_type;
4178 static const WCHAR query[] =
4179 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4180 '`','C','o','m','p','o','n','e','n','t','`',' ',
4181 'W','H','E','R','E',' ',
4182 '`','C','o','m','p','o','n','e','n','t','`',' ',
4183 '=','\'','%','s','\'',0};
4185 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4188 ERR("Failed to open the SC Manager!\n");
4192 start_type = MSI_RecordGetInteger(rec, 5);
4193 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4196 depends = MSI_RecordGetString(rec, 8);
4197 if (depends && *depends)
4198 FIXME("Dependency list unhandled!\n");
4200 name = MSI_RecordGetString(rec, 2);
4201 disp = MSI_RecordGetString(rec, 3);
4202 serv_type = MSI_RecordGetInteger(rec, 4);
4203 err_control = MSI_RecordGetInteger(rec, 6);
4204 load_order = MSI_RecordGetString(rec, 7);
4205 serv_name = MSI_RecordGetString(rec, 9);
4206 pass = MSI_RecordGetString(rec, 10);
4207 comp = MSI_RecordGetString(rec, 12);
4209 /* fetch the service path */
4210 row = MSI_QueryGetRecord(package->db, query, comp);
4213 ERR("Control query failed!\n");
4217 key = MSI_RecordGetString(row, 6);
4218 msiobj_release(&row->hdr);
4220 file = get_loaded_file(package, key);
4223 ERR("Failed to load the service file\n");
4227 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4228 start_type, err_control, file->TargetPath,
4229 load_order, NULL, NULL, serv_name, pass);
4232 if (GetLastError() != ERROR_SERVICE_EXISTS)
4233 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4237 CloseServiceHandle(service);
4238 CloseServiceHandle(hscm);
4240 return ERROR_SUCCESS;
4243 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4247 static const WCHAR ExecSeqQuery[] =
4248 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4249 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4251 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4252 if (rc != ERROR_SUCCESS)
4253 return ERROR_SUCCESS;
4255 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4256 msiobj_release(&view->hdr);
4261 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4262 static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs)
4268 static const WCHAR separator[] = {'[','~',']',0};
4271 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4276 vector = msi_alloc(sizeof(LPWSTR));
4284 vector[*numargs - 1] = p;
4286 if ((q = strstrW(p, separator)))
4290 vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4301 static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component )
4305 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
4307 if (!lstrcmpW(comp->Component, component))
4314 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4316 MSIPACKAGE *package = (MSIPACKAGE *)param;
4318 SC_HANDLE scm, service = NULL;
4319 LPCWSTR name, *vector = NULL;
4321 DWORD event, numargs;
4322 UINT r = ERROR_FUNCTION_FAILED;
4324 comp = msi_find_component(package, MSI_RecordGetString(rec, 6));
4325 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4326 return ERROR_SUCCESS;
4328 name = MSI_RecordGetString(rec, 2);
4329 event = MSI_RecordGetInteger(rec, 3);
4330 args = strdupW(MSI_RecordGetString(rec, 4));
4332 if (!(event & msidbServiceControlEventStart))
4333 return ERROR_SUCCESS;
4335 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4338 ERR("Failed to open the service control manager\n");
4342 service = OpenServiceW(scm, name, SERVICE_START);
4345 ERR("Failed to open service %s\n", debugstr_w(name));
4349 vector = msi_service_args_to_vector(name, args, &numargs);
4351 if (!StartServiceW(service, numargs, vector))
4353 ERR("Failed to start service %s\n", debugstr_w(name));
4360 CloseServiceHandle(service);
4361 CloseServiceHandle(scm);
4368 static UINT ACTION_StartServices( MSIPACKAGE *package )
4373 static const WCHAR query[] = {
4374 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4375 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4377 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4378 if (rc != ERROR_SUCCESS)
4379 return ERROR_SUCCESS;
4381 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4382 msiobj_release(&view->hdr);
4387 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4391 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4393 if (!lstrcmpW(file->File, filename))
4400 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4402 MSIPACKAGE *package = (MSIPACKAGE*)param;
4403 LPWSTR driver, driver_path, ptr;
4404 WCHAR outpath[MAX_PATH];
4405 MSIFILE *driver_file, *setup_file;
4408 UINT r = ERROR_SUCCESS;
4410 static const WCHAR driver_fmt[] = {
4411 'D','r','i','v','e','r','=','%','s',0};
4412 static const WCHAR setup_fmt[] = {
4413 'S','e','t','u','p','=','%','s',0};
4414 static const WCHAR usage_fmt[] = {
4415 'F','i','l','e','U','s','a','g','e','=','1',0};
4417 desc = MSI_RecordGetString(rec, 3);
4419 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4420 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4422 if (!driver_file || !setup_file)
4424 ERR("ODBC Driver entry not found!\n");
4425 return ERROR_FUNCTION_FAILED;
4428 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4429 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4430 lstrlenW(usage_fmt) + 1;
4431 driver = msi_alloc(len * sizeof(WCHAR));
4433 return ERROR_OUTOFMEMORY;
4436 lstrcpyW(ptr, desc);
4437 ptr += lstrlenW(ptr) + 1;
4439 sprintfW(ptr, driver_fmt, driver_file->FileName);
4440 ptr += lstrlenW(ptr) + 1;
4442 sprintfW(ptr, setup_fmt, setup_file->FileName);
4443 ptr += lstrlenW(ptr) + 1;
4445 lstrcpyW(ptr, usage_fmt);
4446 ptr += lstrlenW(ptr) + 1;
4449 driver_path = strdupW(driver_file->TargetPath);
4450 ptr = strrchrW(driver_path, '\\');
4451 if (ptr) *ptr = '\0';
4453 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4454 NULL, ODBC_INSTALL_COMPLETE, &usage))
4456 ERR("Failed to install SQL driver!\n");
4457 r = ERROR_FUNCTION_FAILED;
4461 msi_free(driver_path);
4466 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4468 MSIPACKAGE *package = (MSIPACKAGE*)param;
4469 LPWSTR translator, translator_path, ptr;
4470 WCHAR outpath[MAX_PATH];
4471 MSIFILE *translator_file, *setup_file;
4474 UINT r = ERROR_SUCCESS;
4476 static const WCHAR translator_fmt[] = {
4477 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4478 static const WCHAR setup_fmt[] = {
4479 'S','e','t','u','p','=','%','s',0};
4481 desc = MSI_RecordGetString(rec, 3);
4483 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4484 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4486 if (!translator_file || !setup_file)
4488 ERR("ODBC Translator entry not found!\n");
4489 return ERROR_FUNCTION_FAILED;
4492 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4493 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4494 translator = msi_alloc(len * sizeof(WCHAR));
4496 return ERROR_OUTOFMEMORY;
4499 lstrcpyW(ptr, desc);
4500 ptr += lstrlenW(ptr) + 1;
4502 sprintfW(ptr, translator_fmt, translator_file->FileName);
4503 ptr += lstrlenW(ptr) + 1;
4505 sprintfW(ptr, setup_fmt, setup_file->FileName);
4506 ptr += lstrlenW(ptr) + 1;
4509 translator_path = strdupW(translator_file->TargetPath);
4510 ptr = strrchrW(translator_path, '\\');
4511 if (ptr) *ptr = '\0';
4513 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4514 NULL, ODBC_INSTALL_COMPLETE, &usage))
4516 ERR("Failed to install SQL translator!\n");
4517 r = ERROR_FUNCTION_FAILED;
4520 msi_free(translator);
4521 msi_free(translator_path);
4526 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4529 LPCWSTR desc, driver;
4530 WORD request = ODBC_ADD_SYS_DSN;
4533 UINT r = ERROR_SUCCESS;
4535 static const WCHAR attrs_fmt[] = {
4536 'D','S','N','=','%','s',0 };
4538 desc = MSI_RecordGetString(rec, 3);
4539 driver = MSI_RecordGetString(rec, 4);
4540 registration = MSI_RecordGetInteger(rec, 5);
4542 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4543 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4545 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4546 attrs = msi_alloc(len * sizeof(WCHAR));
4548 return ERROR_OUTOFMEMORY;
4550 sprintfW(attrs, attrs_fmt, desc);
4551 attrs[len - 1] = '\0';
4553 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4555 ERR("Failed to install SQL data source!\n");
4556 r = ERROR_FUNCTION_FAILED;
4564 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4569 static const WCHAR driver_query[] = {
4570 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4571 'O','D','B','C','D','r','i','v','e','r',0 };
4573 static const WCHAR translator_query[] = {
4574 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4575 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4577 static const WCHAR source_query[] = {
4578 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4579 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4581 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4582 if (rc != ERROR_SUCCESS)
4583 return ERROR_SUCCESS;
4585 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4586 msiobj_release(&view->hdr);
4588 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4589 if (rc != ERROR_SUCCESS)
4590 return ERROR_SUCCESS;
4592 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4593 msiobj_release(&view->hdr);
4595 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4596 if (rc != ERROR_SUCCESS)
4597 return ERROR_SUCCESS;
4599 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4600 msiobj_release(&view->hdr);
4605 #define ENV_ACT_SETALWAYS 0x1
4606 #define ENV_ACT_SETABSENT 0x2
4607 #define ENV_ACT_REMOVE 0x4
4608 #define ENV_ACT_REMOVEMATCH 0x8
4610 #define ENV_MOD_MACHINE 0x20000000
4611 #define ENV_MOD_APPEND 0x40000000
4612 #define ENV_MOD_PREFIX 0x80000000
4613 #define ENV_MOD_MASK 0xC0000000
4615 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4617 static LONG env_set_flags( LPCWSTR *name, LPWSTR *value, DWORD *flags )
4619 LPCWSTR cptr = *name;
4620 LPWSTR ptr = *value;
4622 static const WCHAR prefix[] = {'[','~',']',0};
4628 *flags |= ENV_ACT_SETALWAYS;
4629 else if (*cptr == '+')
4630 *flags |= ENV_ACT_SETABSENT;
4631 else if (*cptr == '-')
4632 *flags |= ENV_ACT_REMOVE;
4633 else if (*cptr == '!')
4634 *flags |= ENV_ACT_REMOVEMATCH;
4635 else if (*cptr == '*')
4636 *flags |= ENV_MOD_MACHINE;
4646 ERR("Missing environment variable\n");
4647 return ERROR_FUNCTION_FAILED;
4650 if (!strncmpW(ptr, prefix, lstrlenW(prefix)))
4652 *flags |= ENV_MOD_PREFIX;
4653 *value += lstrlenW(prefix);
4657 ptr += lstrlenW(ptr) - lstrlenW(prefix) - 1;
4658 if (!lstrcmpW(ptr, prefix))
4660 *flags |= ENV_MOD_APPEND;
4666 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4667 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4668 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4669 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4671 ERR("Invalid flags: %08x\n", *flags);
4672 return ERROR_FUNCTION_FAILED;
4675 return ERROR_SUCCESS;
4678 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4680 MSIPACKAGE *package = param;
4681 LPCWSTR name, value, comp;
4682 LPWSTR data = NULL, newval = NULL;
4683 LPWSTR deformatted, ptr;
4684 DWORD flags, type, size;
4686 HKEY env = NULL, root = HKEY_CURRENT_USER;
4688 static const WCHAR environment[] =
4689 {'S','y','s','t','e','m','\\',
4690 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4691 'C','o','n','t','r','o','l','\\',
4692 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4693 'E','n','v','i','r','o','n','m','e','n','t',0};
4694 static const WCHAR semicolon[] = {';',0};
4696 name = MSI_RecordGetString(rec, 2);
4697 value = MSI_RecordGetString(rec, 3);
4698 comp = MSI_RecordGetString(rec, 4);
4700 deformat_string(package, value, &deformatted);
4702 return ERROR_OUTOFMEMORY;
4704 res = env_set_flags(&name, &deformatted, &flags);
4705 if (res != ERROR_SUCCESS)
4708 value = deformatted;
4710 if (flags & ENV_MOD_MACHINE)
4711 root = HKEY_LOCAL_MACHINE;
4713 res = RegOpenKeyExW(root, environment, 0, KEY_ALL_ACCESS, &env);
4714 if (res != ERROR_SUCCESS)
4717 if (flags & ENV_ACT_REMOVE)
4718 FIXME("Not removing environment variable on uninstall!\n");
4721 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
4722 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
4723 (res == ERROR_SUCCESS && type != REG_SZ))
4726 if (res != ERROR_FILE_NOT_FOUND)
4728 if (flags & ENV_ACT_SETABSENT)
4730 res = ERROR_SUCCESS;
4734 data = msi_alloc(size);
4738 return ERROR_OUTOFMEMORY;
4741 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
4742 if (res != ERROR_SUCCESS)
4745 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
4747 res = RegDeleteKeyW(env, name);
4751 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
4752 newval = msi_alloc(size);
4756 res = ERROR_OUTOFMEMORY;
4760 if (!(flags & ENV_MOD_MASK))
4761 lstrcpyW(newval, value);
4764 if (flags & ENV_MOD_PREFIX)
4766 lstrcpyW(newval, value);
4767 lstrcatW(newval, semicolon);
4768 ptr = newval + lstrlenW(value) + 1;
4771 lstrcpyW(ptr, data);
4773 if (flags & ENV_MOD_APPEND)
4775 lstrcatW(newval, semicolon);
4776 lstrcatW(newval, value);
4782 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
4783 newval = msi_alloc(size);
4786 res = ERROR_OUTOFMEMORY;
4790 lstrcpyW(newval, value);
4793 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
4794 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
4797 if (env) RegCloseKey(env);
4798 msi_free(deformatted);
4804 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4808 static const WCHAR ExecSeqQuery[] =
4809 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4810 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
4811 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4812 if (rc != ERROR_SUCCESS)
4813 return ERROR_SUCCESS;
4815 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
4816 msiobj_release(&view->hdr);
4821 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4822 LPCSTR action, LPCWSTR table )
4824 static const WCHAR query[] = {
4825 'S','E','L','E','C','T',' ','*',' ',
4826 'F','R','O','M',' ','`','%','s','`',0 };
4827 MSIQUERY *view = NULL;
4831 r = MSI_OpenQuery( package->db, &view, query, table );
4832 if (r == ERROR_SUCCESS)
4834 r = MSI_IterateRecords(view, &count, NULL, package);
4835 msiobj_release(&view->hdr);
4839 FIXME("%s -> %u ignored %s table values\n",
4840 action, count, debugstr_w(table));
4842 return ERROR_SUCCESS;
4845 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4847 TRACE("%p\n", package);
4848 return ERROR_SUCCESS;
4851 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4853 static const WCHAR table[] =
4854 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4855 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4858 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4860 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4861 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4864 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4866 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4867 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4870 static UINT ACTION_BindImage( MSIPACKAGE *package )
4872 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4873 return msi_unimplemented_action_stub( package, "BindImage", table );
4876 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4878 static const WCHAR table[] = {
4879 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4880 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4883 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4885 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4886 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4889 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4891 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4892 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4895 static UINT ACTION_StopServices( MSIPACKAGE *package )
4897 static const WCHAR table[] = {
4898 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4899 return msi_unimplemented_action_stub( package, "StopServices", table );
4902 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4904 static const WCHAR table[] = {
4905 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4906 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4908 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
4910 static const WCHAR table[] = {
4911 'P','r','o','d','u','c','t','I','D',0 };
4912 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
4915 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4917 static const WCHAR table[] = {
4918 'E','n','v','i','r','o','n','m','e','n','t',0 };
4919 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4922 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4924 static const WCHAR table[] = {
4925 'M','s','i','A','s','s','e','m','b','l','y',0 };
4926 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4929 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4931 static const WCHAR table[] = {
4932 'M','s','i','A','s','s','e','m','b','l','y',0 };
4933 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4936 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4938 static const WCHAR table[] = { 'F','o','n','t',0 };
4939 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4942 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4944 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4945 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4948 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4950 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4951 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4954 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4956 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4957 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4960 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4962 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4963 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4966 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
4968 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
4969 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
4972 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
4974 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
4975 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
4978 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
4980 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4981 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
4984 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
4986 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
4987 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
4990 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
4992 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
4993 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
4996 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
4998 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
4999 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5002 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5004 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5005 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5008 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5010 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5011 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5014 static UINT ACTION_UnpublishFeatures( MSIPACKAGE *package )
5016 static const WCHAR table[] = { 'F','e','a','t','u','r','e','C','o','m','p','o','n','e','n','t','s',0 };
5017 return msi_unimplemented_action_stub( package, "UnpublishFeatures", table );
5020 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5022 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5023 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5026 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5028 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5029 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5032 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5034 static const WCHAR table[] = { 'M','I','M','E',0 };
5035 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5038 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5040 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5041 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5044 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5046 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5047 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5050 static const struct _actions StandardActions[] = {
5051 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5052 { szAppSearch, ACTION_AppSearch },
5053 { szBindImage, ACTION_BindImage },
5054 { szCCPSearch, ACTION_CCPSearch },
5055 { szCostFinalize, ACTION_CostFinalize },
5056 { szCostInitialize, ACTION_CostInitialize },
5057 { szCreateFolders, ACTION_CreateFolders },
5058 { szCreateShortcuts, ACTION_CreateShortcuts },
5059 { szDeleteServices, ACTION_DeleteServices },
5060 { szDisableRollback, NULL },
5061 { szDuplicateFiles, ACTION_DuplicateFiles },
5062 { szExecuteAction, ACTION_ExecuteAction },
5063 { szFileCost, ACTION_FileCost },
5064 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5065 { szForceReboot, ACTION_ForceReboot },
5066 { szInstallAdminPackage, NULL },
5067 { szInstallExecute, ACTION_InstallExecute },
5068 { szInstallExecuteAgain, ACTION_InstallExecute },
5069 { szInstallFiles, ACTION_InstallFiles},
5070 { szInstallFinalize, ACTION_InstallFinalize },
5071 { szInstallInitialize, ACTION_InstallInitialize },
5072 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5073 { szInstallValidate, ACTION_InstallValidate },
5074 { szIsolateComponents, ACTION_IsolateComponents },
5075 { szLaunchConditions, ACTION_LaunchConditions },
5076 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5077 { szMoveFiles, ACTION_MoveFiles },
5078 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5079 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5080 { szInstallODBC, ACTION_InstallODBC },
5081 { szInstallServices, ACTION_InstallServices },
5082 { szPatchFiles, ACTION_PatchFiles },
5083 { szProcessComponents, ACTION_ProcessComponents },
5084 { szPublishComponents, ACTION_PublishComponents },
5085 { szPublishFeatures, ACTION_PublishFeatures },
5086 { szPublishProduct, ACTION_PublishProduct },
5087 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5088 { szRegisterComPlus, ACTION_RegisterComPlus},
5089 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5090 { szRegisterFonts, ACTION_RegisterFonts },
5091 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5092 { szRegisterProduct, ACTION_RegisterProduct },
5093 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5094 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5095 { szRegisterUser, ACTION_RegisterUser },
5096 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5097 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5098 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5099 { szRemoveFiles, ACTION_RemoveFiles },
5100 { szRemoveFolders, ACTION_RemoveFolders },
5101 { szRemoveIniValues, ACTION_RemoveIniValues },
5102 { szRemoveODBC, ACTION_RemoveODBC },
5103 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5104 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5105 { szResolveSource, ACTION_ResolveSource },
5106 { szRMCCPSearch, ACTION_RMCCPSearch },
5107 { szScheduleReboot, NULL },
5108 { szSelfRegModules, ACTION_SelfRegModules },
5109 { szSelfUnregModules, ACTION_SelfUnregModules },
5110 { szSetODBCFolders, NULL },
5111 { szStartServices, ACTION_StartServices },
5112 { szStopServices, ACTION_StopServices },
5113 { szUnpublishComponents, ACTION_UnpublishComponents },
5114 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5115 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5116 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5117 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5118 { szUnregisterFonts, ACTION_UnregisterFonts },
5119 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5120 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5121 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5122 { szValidateProductID, ACTION_ValidateProductID },
5123 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5124 { szWriteIniValues, ACTION_WriteIniValues },
5125 { szWriteRegistryValues, ACTION_WriteRegistryValues },