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 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;
635 dir = strdupW(szPackagePath);
636 p = strrchrW(dir, '\\');
640 file = szPackagePath + (p - dir);
645 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
646 GetCurrentDirectoryW(MAX_PATH, dir);
647 lstrcatW(dir, cszbs);
648 file = szPackagePath;
651 msi_free( package->PackagePath );
652 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
653 if (!package->PackagePath)
656 return ERROR_OUTOFMEMORY;
659 lstrcpyW(package->PackagePath, dir);
660 lstrcatW(package->PackagePath, file);
662 check = msi_dup_property( package, cszSourceDir );
664 MSI_SetPropertyW(package, cszSourceDir, dir);
667 check = msi_dup_property( package, cszSOURCEDIR );
669 MSI_SetPropertyW(package, cszSOURCEDIR, dir);
675 msi_parse_command_line( package, szCommandLine );
677 msi_apply_transforms( package );
678 msi_apply_patches( package );
680 /* properties may have been added by a transform */
681 msi_clone_properties( package );
683 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
685 package->script->InWhatSequence |= SEQUENCE_UI;
686 rc = ACTION_ProcessUISequence(package);
688 ui_exists = ui_sequence_exists(package);
689 if (rc == ERROR_SUCCESS || !ui_exists)
691 package->script->InWhatSequence |= SEQUENCE_EXEC;
692 rc = ACTION_ProcessExecSequence(package,ui_exists);
696 rc = ACTION_ProcessExecSequence(package,FALSE);
700 /* install was halted but should be considered a success */
704 package->script->CurrentlyScripting= FALSE;
706 /* process the ending type action */
707 if (rc == ERROR_SUCCESS)
708 ACTION_PerformActionSequence(package,-1,ui);
709 else if (rc == ERROR_INSTALL_USEREXIT)
710 ACTION_PerformActionSequence(package,-2,ui);
711 else if (rc == ERROR_INSTALL_SUSPEND)
712 ACTION_PerformActionSequence(package,-4,ui);
714 ACTION_PerformActionSequence(package,-3,ui);
716 /* finish up running custom actions */
717 ACTION_FinishCustomActions(package);
722 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
724 UINT rc = ERROR_SUCCESS;
726 static const WCHAR ExecSeqQuery[] =
727 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
728 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
729 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
730 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
732 static const WCHAR UISeqQuery[] =
733 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
734 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
735 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
736 ' ', '=',' ','%','i',0};
739 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
741 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
745 LPCWSTR action, cond;
747 TRACE("Running the actions\n");
749 /* check conditions */
750 cond = MSI_RecordGetString(row,2);
752 /* this is a hack to skip errors in the condition code */
753 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
756 action = MSI_RecordGetString(row,1);
759 ERR("failed to fetch action\n");
760 rc = ERROR_FUNCTION_FAILED;
765 rc = ACTION_PerformUIAction(package,action,-1);
767 rc = ACTION_PerformAction(package,action,-1,FALSE);
769 msiobj_release(&row->hdr);
780 } iterate_action_param;
782 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
784 iterate_action_param *iap= (iterate_action_param*)param;
786 LPCWSTR cond, action;
788 action = MSI_RecordGetString(row,1);
791 ERR("Error is retrieving action name\n");
792 return ERROR_FUNCTION_FAILED;
795 /* check conditions */
796 cond = MSI_RecordGetString(row,2);
798 /* this is a hack to skip errors in the condition code */
799 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
801 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
802 return ERROR_SUCCESS;
806 rc = ACTION_PerformUIAction(iap->package,action,-1);
808 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
810 msi_dialog_check_messages( NULL );
812 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
813 rc = iap->package->CurrentInstallState;
815 if (rc == ERROR_FUNCTION_NOT_CALLED)
818 if (rc != ERROR_SUCCESS)
819 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
824 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
828 static const WCHAR query[] =
829 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
831 ' ','W','H','E','R','E',' ',
832 '`','S','e','q','u','e','n','c','e','`',' ',
833 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
834 '`','S','e','q','u','e','n','c','e','`',0};
835 iterate_action_param iap;
838 * FIXME: probably should be checking UILevel in the
839 * ACTION_PerformUIAction/ACTION_PerformAction
840 * rather than saving the UI level here. Those
841 * two functions can be merged too.
843 iap.package = package;
846 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
848 r = MSI_OpenQuery( package->db, &view, query, szTable );
849 if (r == ERROR_SUCCESS)
851 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
852 msiobj_release(&view->hdr);
858 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
862 static const WCHAR ExecSeqQuery[] =
863 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
864 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
865 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
866 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
867 'O','R','D','E','R',' ', 'B','Y',' ',
868 '`','S','e','q','u','e','n','c','e','`',0 };
870 static const WCHAR IVQuery[] =
871 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
872 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
873 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
874 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
875 ' ','\'', 'I','n','s','t','a','l','l',
876 'V','a','l','i','d','a','t','e','\'', 0};
878 iterate_action_param iap;
880 iap.package = package;
883 if (package->script->ExecuteSequenceRun)
885 TRACE("Execute Sequence already Run\n");
886 return ERROR_SUCCESS;
889 package->script->ExecuteSequenceRun = TRUE;
891 /* get the sequence number */
894 row = MSI_QueryGetRecord(package->db, IVQuery);
896 return ERROR_FUNCTION_FAILED;
897 seq = MSI_RecordGetInteger(row,1);
898 msiobj_release(&row->hdr);
901 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
902 if (rc == ERROR_SUCCESS)
904 TRACE("Running the actions\n");
906 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
907 msiobj_release(&view->hdr);
913 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
917 static const WCHAR ExecSeqQuery [] =
918 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
919 '`','I','n','s','t','a','l','l',
920 'U','I','S','e','q','u','e','n','c','e','`',
921 ' ','W','H','E','R','E',' ',
922 '`','S','e','q','u','e','n','c','e','`',' ',
923 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
924 '`','S','e','q','u','e','n','c','e','`',0};
925 iterate_action_param iap;
927 iap.package = package;
930 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
932 if (rc == ERROR_SUCCESS)
934 TRACE("Running the actions\n");
936 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
937 msiobj_release(&view->hdr);
943 /********************************************************
944 * ACTION helper functions and functions that perform the actions
945 *******************************************************/
946 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
947 UINT* rc, BOOL force )
953 if (!run && !package->script->CurrentlyScripting)
958 if (strcmpW(action,szInstallFinalize) == 0 ||
959 strcmpW(action,szInstallExecute) == 0 ||
960 strcmpW(action,szInstallExecuteAgain) == 0)
965 while (StandardActions[i].action != NULL)
967 if (strcmpW(StandardActions[i].action, action)==0)
971 ui_actioninfo(package, action, TRUE, 0);
972 *rc = schedule_action(package,INSTALL_SCRIPT,action);
973 ui_actioninfo(package, action, FALSE, *rc);
977 ui_actionstart(package, action);
978 if (StandardActions[i].handler)
980 *rc = StandardActions[i].handler(package);
984 FIXME("unhandled standard action %s\n",debugstr_w(action));
996 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
997 UINT* rc, UINT script, BOOL force )
1002 arc = ACTION_CustomAction(package, action, script, force);
1004 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1013 * A lot of actions are really important even if they don't do anything
1014 * explicit... Lots of properties are set at the beginning of the installation
1015 * CostFinalize does a bunch of work to translate the directories and such
1017 * But until I get write access to the database that is hard, so I am going to
1018 * hack it to see if I can get something to run.
1020 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1022 UINT rc = ERROR_SUCCESS;
1025 TRACE("Performing action (%s)\n",debugstr_w(action));
1027 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1030 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1034 FIXME("unhandled msi action %s\n",debugstr_w(action));
1035 rc = ERROR_FUNCTION_NOT_CALLED;
1041 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1043 UINT rc = ERROR_SUCCESS;
1044 BOOL handled = FALSE;
1046 TRACE("Performing action (%s)\n",debugstr_w(action));
1048 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1051 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1053 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1058 FIXME("unhandled msi action %s\n",debugstr_w(action));
1059 rc = ERROR_FUNCTION_NOT_CALLED;
1067 * Actual Action Handlers
1070 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1072 MSIPACKAGE *package = (MSIPACKAGE*)param;
1078 dir = MSI_RecordGetString(row,1);
1081 ERR("Unable to get folder id\n");
1082 return ERROR_SUCCESS;
1085 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1088 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1089 return ERROR_SUCCESS;
1092 TRACE("Folder is %s\n",debugstr_w(full_path));
1095 uirow = MSI_CreateRecord(1);
1096 MSI_RecordSetStringW(uirow,1,full_path);
1097 ui_actiondata(package,szCreateFolders,uirow);
1098 msiobj_release( &uirow->hdr );
1100 if (folder->State == 0)
1101 create_full_pathW(full_path);
1105 msi_free(full_path);
1106 return ERROR_SUCCESS;
1109 /* FIXME: probably should merge this with the above function */
1110 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1112 UINT rc = ERROR_SUCCESS;
1114 LPWSTR install_path;
1116 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1118 return ERROR_FUNCTION_FAILED;
1120 /* create the path */
1121 if (folder->State == 0)
1123 create_full_pathW(install_path);
1126 msi_free(install_path);
1131 UINT msi_create_component_directories( MSIPACKAGE *package )
1135 /* create all the folders required by the components are going to install */
1136 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1138 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1140 msi_create_directory( package, comp->Directory );
1143 return ERROR_SUCCESS;
1147 * Also we cannot enable/disable components either, so for now I am just going
1148 * to do all the directories for all the components.
1150 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1152 static const WCHAR ExecSeqQuery[] =
1153 {'S','E','L','E','C','T',' ',
1154 '`','D','i','r','e','c','t','o','r','y','_','`',
1155 ' ','F','R','O','M',' ',
1156 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1160 /* create all the empty folders specified in the CreateFolder table */
1161 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1162 if (rc != ERROR_SUCCESS)
1163 return ERROR_SUCCESS;
1165 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1166 msiobj_release(&view->hdr);
1168 msi_create_component_directories( package );
1173 static UINT load_component( MSIRECORD *row, LPVOID param )
1175 MSIPACKAGE *package = param;
1178 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1180 return ERROR_FUNCTION_FAILED;
1182 list_add_tail( &package->components, &comp->entry );
1184 /* fill in the data */
1185 comp->Component = msi_dup_record_field( row, 1 );
1187 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1189 comp->ComponentId = msi_dup_record_field( row, 2 );
1190 comp->Directory = msi_dup_record_field( row, 3 );
1191 comp->Attributes = MSI_RecordGetInteger(row,4);
1192 comp->Condition = msi_dup_record_field( row, 5 );
1193 comp->KeyPath = msi_dup_record_field( row, 6 );
1195 comp->Installed = INSTALLSTATE_UNKNOWN;
1196 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1198 return ERROR_SUCCESS;
1201 static UINT load_all_components( MSIPACKAGE *package )
1203 static const WCHAR query[] = {
1204 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1205 '`','C','o','m','p','o','n','e','n','t','`',0 };
1209 if (!list_empty(&package->components))
1210 return ERROR_SUCCESS;
1212 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1213 if (r != ERROR_SUCCESS)
1216 r = MSI_IterateRecords(view, NULL, load_component, package);
1217 msiobj_release(&view->hdr);
1222 MSIPACKAGE *package;
1223 MSIFEATURE *feature;
1226 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1230 cl = msi_alloc( sizeof (*cl) );
1232 return ERROR_NOT_ENOUGH_MEMORY;
1233 cl->component = comp;
1234 list_add_tail( &feature->Components, &cl->entry );
1236 return ERROR_SUCCESS;
1239 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1243 fl = msi_alloc( sizeof(*fl) );
1245 return ERROR_NOT_ENOUGH_MEMORY;
1246 fl->feature = child;
1247 list_add_tail( &parent->Children, &fl->entry );
1249 return ERROR_SUCCESS;
1252 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1254 _ilfs* ilfs= (_ilfs*)param;
1258 component = MSI_RecordGetString(row,1);
1260 /* check to see if the component is already loaded */
1261 comp = get_loaded_component( ilfs->package, component );
1264 ERR("unknown component %s\n", debugstr_w(component));
1265 return ERROR_FUNCTION_FAILED;
1268 add_feature_component( ilfs->feature, comp );
1269 comp->Enabled = TRUE;
1271 return ERROR_SUCCESS;
1274 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1276 MSIFEATURE *feature;
1278 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1280 if ( !lstrcmpW( feature->Feature, name ) )
1287 static UINT load_feature(MSIRECORD * row, LPVOID param)
1289 MSIPACKAGE* package = (MSIPACKAGE*)param;
1290 MSIFEATURE* feature;
1291 static const WCHAR Query1[] =
1292 {'S','E','L','E','C','T',' ',
1293 '`','C','o','m','p','o','n','e','n','t','_','`',
1294 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1295 'C','o','m','p','o','n','e','n','t','s','`',' ',
1296 'W','H','E','R','E',' ',
1297 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1302 /* fill in the data */
1304 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1306 return ERROR_NOT_ENOUGH_MEMORY;
1308 list_init( &feature->Children );
1309 list_init( &feature->Components );
1311 feature->Feature = msi_dup_record_field( row, 1 );
1313 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1315 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1316 feature->Title = msi_dup_record_field( row, 3 );
1317 feature->Description = msi_dup_record_field( row, 4 );
1319 if (!MSI_RecordIsNull(row,5))
1320 feature->Display = MSI_RecordGetInteger(row,5);
1322 feature->Level= MSI_RecordGetInteger(row,6);
1323 feature->Directory = msi_dup_record_field( row, 7 );
1324 feature->Attributes = MSI_RecordGetInteger(row,8);
1326 feature->Installed = INSTALLSTATE_UNKNOWN;
1327 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1329 list_add_tail( &package->features, &feature->entry );
1331 /* load feature components */
1333 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1334 if (rc != ERROR_SUCCESS)
1335 return ERROR_SUCCESS;
1337 ilfs.package = package;
1338 ilfs.feature = feature;
1340 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1341 msiobj_release(&view->hdr);
1343 return ERROR_SUCCESS;
1346 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1348 MSIPACKAGE* package = (MSIPACKAGE*)param;
1349 MSIFEATURE *parent, *child;
1351 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1353 return ERROR_FUNCTION_FAILED;
1355 if (!child->Feature_Parent)
1356 return ERROR_SUCCESS;
1358 parent = find_feature_by_name( package, child->Feature_Parent );
1360 return ERROR_FUNCTION_FAILED;
1362 add_feature_child( parent, child );
1363 return ERROR_SUCCESS;
1366 static UINT load_all_features( MSIPACKAGE *package )
1368 static const WCHAR query[] = {
1369 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1370 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1371 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1375 if (!list_empty(&package->features))
1376 return ERROR_SUCCESS;
1378 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1379 if (r != ERROR_SUCCESS)
1382 r = MSI_IterateRecords( view, NULL, load_feature, package );
1383 if (r != ERROR_SUCCESS)
1386 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1387 msiobj_release( &view->hdr );
1392 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1403 static UINT load_file(MSIRECORD *row, LPVOID param)
1405 MSIPACKAGE* package = (MSIPACKAGE*)param;
1409 /* fill in the data */
1411 file = msi_alloc_zero( sizeof (MSIFILE) );
1413 return ERROR_NOT_ENOUGH_MEMORY;
1415 file->File = msi_dup_record_field( row, 1 );
1417 component = MSI_RecordGetString( row, 2 );
1418 file->Component = get_loaded_component( package, component );
1420 if (!file->Component)
1421 ERR("Unfound Component %s\n",debugstr_w(component));
1423 file->FileName = msi_dup_record_field( row, 3 );
1424 reduce_to_longfilename( file->FileName );
1426 file->ShortName = msi_dup_record_field( row, 3 );
1427 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1429 file->FileSize = MSI_RecordGetInteger( row, 4 );
1430 file->Version = msi_dup_record_field( row, 5 );
1431 file->Language = msi_dup_record_field( row, 6 );
1432 file->Attributes = MSI_RecordGetInteger( row, 7 );
1433 file->Sequence = MSI_RecordGetInteger( row, 8 );
1435 file->state = msifs_invalid;
1437 /* if the compressed bits are not set in the file attributes,
1438 * then read the information from the package word count property
1440 if (file->Attributes & msidbFileAttributesCompressed)
1442 file->IsCompressed = TRUE;
1444 else if (file->Attributes & msidbFileAttributesNoncompressed)
1446 file->IsCompressed = FALSE;
1450 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1453 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1455 list_add_tail( &package->files, &file->entry );
1457 return ERROR_SUCCESS;
1460 static UINT load_all_files(MSIPACKAGE *package)
1464 static const WCHAR Query[] =
1465 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1466 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1467 '`','S','e','q','u','e','n','c','e','`', 0};
1469 if (!list_empty(&package->files))
1470 return ERROR_SUCCESS;
1472 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1473 if (rc != ERROR_SUCCESS)
1474 return ERROR_SUCCESS;
1476 rc = MSI_IterateRecords(view, NULL, load_file, package);
1477 msiobj_release(&view->hdr);
1479 return ERROR_SUCCESS;
1482 static UINT load_folder( MSIRECORD *row, LPVOID param )
1484 MSIPACKAGE *package = param;
1485 static const WCHAR szDot[] = { '.',0 };
1486 static WCHAR szEmpty[] = { 0 };
1487 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1490 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1492 return ERROR_NOT_ENOUGH_MEMORY;
1494 folder->Directory = msi_dup_record_field( row, 1 );
1496 TRACE("%s\n", debugstr_w(folder->Directory));
1498 p = msi_dup_record_field(row, 3);
1500 /* split src and target dir */
1502 src_short = folder_split_path( p, ':' );
1504 /* split the long and short paths */
1505 tgt_long = folder_split_path( tgt_short, '|' );
1506 src_long = folder_split_path( src_short, '|' );
1508 /* check for no-op dirs */
1509 if (!lstrcmpW(szDot, tgt_short))
1510 tgt_short = szEmpty;
1511 if (!lstrcmpW(szDot, src_short))
1512 src_short = szEmpty;
1515 tgt_long = tgt_short;
1518 src_short = tgt_short;
1519 src_long = tgt_long;
1523 src_long = src_short;
1525 /* FIXME: use the target short path too */
1526 folder->TargetDefault = strdupW(tgt_long);
1527 folder->SourceShortPath = strdupW(src_short);
1528 folder->SourceLongPath = strdupW(src_long);
1531 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1532 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1533 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1535 folder->Parent = msi_dup_record_field( row, 2 );
1537 folder->Property = msi_dup_property( package, folder->Directory );
1539 list_add_tail( &package->folders, &folder->entry );
1541 TRACE("returning %p\n", folder);
1543 return ERROR_SUCCESS;
1546 static UINT load_all_folders( MSIPACKAGE *package )
1548 static const WCHAR query[] = {
1549 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1550 '`','D','i','r','e','c','t','o','r','y','`',0 };
1554 if (!list_empty(&package->folders))
1555 return ERROR_SUCCESS;
1557 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1558 if (r != ERROR_SUCCESS)
1561 r = MSI_IterateRecords(view, NULL, load_folder, package);
1562 msiobj_release(&view->hdr);
1567 * I am not doing any of the costing functionality yet.
1568 * Mostly looking at doing the Component and Feature loading
1570 * The native MSI does A LOT of modification to tables here. Mostly adding
1571 * a lot of temporary columns to the Feature and Component tables.
1573 * note: Native msi also tracks the short filename. But I am only going to
1574 * track the long ones. Also looking at this directory table
1575 * it appears that the directory table does not get the parents
1576 * resolved base on property only based on their entries in the
1579 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1581 static const WCHAR szCosting[] =
1582 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1583 static const WCHAR szZero[] = { '0', 0 };
1585 MSI_SetPropertyW(package, szCosting, szZero);
1586 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1588 load_all_components( package );
1589 load_all_features( package );
1590 load_all_files( package );
1591 load_all_folders( package );
1593 return ERROR_SUCCESS;
1596 static UINT execute_script(MSIPACKAGE *package, UINT script )
1599 UINT rc = ERROR_SUCCESS;
1601 TRACE("Executing Script %i\n",script);
1603 if (!package->script)
1605 ERR("no script!\n");
1606 return ERROR_FUNCTION_FAILED;
1609 for (i = 0; i < package->script->ActionCount[script]; i++)
1612 action = package->script->Actions[script][i];
1613 ui_actionstart(package, action);
1614 TRACE("Executing Action (%s)\n",debugstr_w(action));
1615 rc = ACTION_PerformAction(package, action, script, TRUE);
1616 if (rc != ERROR_SUCCESS)
1619 msi_free_action_script(package, script);
1623 static UINT ACTION_FileCost(MSIPACKAGE *package)
1625 return ERROR_SUCCESS;
1628 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1632 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1636 if (!comp->ComponentId)
1639 res = MsiGetComponentPathW( package->ProductCode,
1640 comp->ComponentId, NULL, NULL);
1642 res = INSTALLSTATE_ABSENT;
1643 comp->Installed = res;
1647 /* scan for and update current install states */
1648 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1651 MSIFEATURE *feature;
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1656 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1658 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1660 comp= cl->component;
1662 if (!comp->ComponentId)
1664 res = INSTALLSTATE_ABSENT;
1668 if (res == INSTALLSTATE_ABSENT)
1669 res = comp->Installed;
1672 if (res == comp->Installed)
1675 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1676 res != INSTALLSTATE_SOURCE)
1678 res = INSTALLSTATE_INCOMPLETE;
1682 feature->Installed = res;
1686 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1689 static const WCHAR all[]={'A','L','L',0};
1691 MSIFEATURE *feature;
1693 override = msi_dup_property( package, property );
1697 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1699 if (strcmpiW(override,all)==0)
1700 msi_feature_set_state( feature, state );
1703 LPWSTR ptr = override;
1704 LPWSTR ptr2 = strchrW(override,',');
1708 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1709 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1711 msi_feature_set_state( feature, state );
1717 ptr2 = strchrW(ptr,',');
1729 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1732 static const WCHAR szlevel[] =
1733 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1734 static const WCHAR szAddLocal[] =
1735 {'A','D','D','L','O','C','A','L',0};
1736 static const WCHAR szRemove[] =
1737 {'R','E','M','O','V','E',0};
1738 static const WCHAR szReinstall[] =
1739 {'R','E','I','N','S','T','A','L','L',0};
1740 BOOL override = FALSE;
1741 MSICOMPONENT* component;
1742 MSIFEATURE *feature;
1745 /* I do not know if this is where it should happen.. but */
1747 TRACE("Checking Install Level\n");
1749 install_level = msi_get_property_int( package, szlevel, 1 );
1751 /* ok here is the _real_ rub
1752 * all these activation/deactivation things happen in order and things
1753 * later on the list override things earlier on the list.
1754 * 1) INSTALLLEVEL processing
1764 * 11) FILEADDDEFAULT
1765 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1766 * ignored for all the features. seems strange, especially since it is not
1767 * documented anywhere, but it is how it works.
1769 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1770 * REMOVE are the big ones, since we don't handle administrative installs
1773 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1774 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1775 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1779 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1781 BOOL feature_state = ((feature->Level > 0) &&
1782 (feature->Level <= install_level));
1784 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1786 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1787 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1788 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1789 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1791 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1795 /* disable child features of unselected parent features */
1796 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1800 if (feature->Level > 0 && feature->Level <= install_level)
1803 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1804 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1809 /* set the Preselected Property */
1810 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1811 static const WCHAR szOne[] = { '1', 0 };
1813 MSI_SetPropertyW(package,szPreselected,szOne);
1817 * now we want to enable or disable components base on feature
1820 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1824 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1825 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1827 /* features with components that have compressed files are made local */
1828 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1830 if (cl->component->Enabled &&
1831 cl->component->ForceLocalState &&
1832 feature->Action == INSTALLSTATE_SOURCE)
1834 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1839 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1841 component = cl->component;
1843 if (!component->Enabled)
1846 switch (feature->Action)
1848 case INSTALLSTATE_ADVERTISED:
1849 component->hasAdvertiseFeature = 1;
1851 case INSTALLSTATE_SOURCE:
1852 component->hasSourceFeature = 1;
1854 case INSTALLSTATE_LOCAL:
1855 component->hasLocalFeature = 1;
1857 case INSTALLSTATE_DEFAULT:
1858 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1859 component->hasAdvertiseFeature = 1;
1860 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1861 component->hasSourceFeature = 1;
1863 component->hasLocalFeature = 1;
1871 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1873 /* if the component isn't enabled, leave it alone */
1874 if (!component->Enabled)
1877 /* check if it's local or source */
1878 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1879 (component->hasLocalFeature || component->hasSourceFeature))
1881 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1882 !component->ForceLocalState)
1883 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1885 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1889 /* if any feature is local, the component must be local too */
1890 if (component->hasLocalFeature)
1892 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1896 if (component->hasSourceFeature)
1898 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1902 if (component->hasAdvertiseFeature)
1904 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1908 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1911 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1913 if (component->Action == INSTALLSTATE_DEFAULT)
1915 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1916 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1919 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1920 debugstr_w(component->Component), component->Installed, component->Action);
1924 return ERROR_SUCCESS;
1927 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1929 MSIPACKAGE *package = (MSIPACKAGE*)param;
1934 name = MSI_RecordGetString(row,1);
1936 f = get_loaded_folder(package, name);
1937 if (!f) return ERROR_SUCCESS;
1939 /* reset the ResolvedTarget */
1940 msi_free(f->ResolvedTarget);
1941 f->ResolvedTarget = NULL;
1943 /* This helper function now does ALL the work */
1944 TRACE("Dir %s ...\n",debugstr_w(name));
1945 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1946 TRACE("resolves to %s\n",debugstr_w(path));
1949 return ERROR_SUCCESS;
1952 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1954 MSIPACKAGE *package = (MSIPACKAGE*)param;
1956 MSIFEATURE *feature;
1958 name = MSI_RecordGetString( row, 1 );
1960 feature = get_loaded_feature( package, name );
1962 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1966 Condition = MSI_RecordGetString(row,3);
1968 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1970 int level = MSI_RecordGetInteger(row,2);
1971 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1972 feature->Level = level;
1975 return ERROR_SUCCESS;
1978 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1980 static const WCHAR name_fmt[] =
1981 {'%','u','.','%','u','.','%','u','.','%','u',0};
1982 static WCHAR name[] = {'\\',0};
1983 VS_FIXEDFILEINFO *lpVer;
1984 WCHAR filever[0x100];
1990 TRACE("%s\n", debugstr_w(filename));
1992 versize = GetFileVersionInfoSizeW( filename, &handle );
1996 version = msi_alloc( versize );
1997 GetFileVersionInfoW( filename, 0, versize, version );
1999 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2001 msi_free( version );
2005 sprintfW( filever, name_fmt,
2006 HIWORD(lpVer->dwFileVersionMS),
2007 LOWORD(lpVer->dwFileVersionMS),
2008 HIWORD(lpVer->dwFileVersionLS),
2009 LOWORD(lpVer->dwFileVersionLS));
2011 msi_free( version );
2013 return strdupW( filever );
2016 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2018 LPWSTR file_version;
2021 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2023 MSICOMPONENT* comp = file->Component;
2029 if (file->IsCompressed)
2030 comp->ForceLocalState = TRUE;
2032 /* calculate target */
2033 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2035 msi_free(file->TargetPath);
2037 TRACE("file %s is named %s\n",
2038 debugstr_w(file->File), debugstr_w(file->FileName));
2040 file->TargetPath = build_directory_name(2, p, file->FileName);
2044 TRACE("file %s resolves to %s\n",
2045 debugstr_w(file->File), debugstr_w(file->TargetPath));
2047 /* don't check files of components that aren't installed */
2048 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2049 comp->Installed == INSTALLSTATE_ABSENT)
2051 file->state = msifs_missing; /* assume files are missing */
2055 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2057 file->state = msifs_missing;
2058 comp->Cost += file->FileSize;
2059 comp->Installed = INSTALLSTATE_INCOMPLETE;
2063 if (file->Version &&
2064 (file_version = msi_get_disk_file_version( file->TargetPath )))
2066 TRACE("new %s old %s\n", debugstr_w(file->Version),
2067 debugstr_w(file_version));
2068 /* FIXME: seems like a bad way to compare version numbers */
2069 if (lstrcmpiW(file_version, file->Version)<0)
2071 file->state = msifs_overwrite;
2072 comp->Cost += file->FileSize;
2073 comp->Installed = INSTALLSTATE_INCOMPLETE;
2076 file->state = msifs_present;
2077 msi_free( file_version );
2080 file->state = msifs_present;
2083 return ERROR_SUCCESS;
2087 * A lot is done in this function aside from just the costing.
2088 * The costing needs to be implemented at some point but for now I am going
2089 * to focus on the directory building
2092 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2094 static const WCHAR ExecSeqQuery[] =
2095 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2096 '`','D','i','r','e','c','t','o','r','y','`',0};
2097 static const WCHAR ConditionQuery[] =
2098 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2099 '`','C','o','n','d','i','t','i','o','n','`',0};
2100 static const WCHAR szCosting[] =
2101 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2102 static const WCHAR szlevel[] =
2103 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2104 static const WCHAR szOne[] = { '1', 0 };
2110 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2111 return ERROR_SUCCESS;
2113 TRACE("Building Directory properties\n");
2115 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2116 if (rc == ERROR_SUCCESS)
2118 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2120 msiobj_release(&view->hdr);
2123 /* read components states from the registry */
2124 ACTION_GetComponentInstallStates(package);
2126 TRACE("File calculations\n");
2127 msi_check_file_install_states( package );
2129 TRACE("Evaluating Condition Table\n");
2131 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2132 if (rc == ERROR_SUCCESS)
2134 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2136 msiobj_release(&view->hdr);
2139 TRACE("Enabling or Disabling Components\n");
2140 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2142 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2144 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2145 comp->Enabled = FALSE;
2149 MSI_SetPropertyW(package,szCosting,szOne);
2150 /* set default run level if not set */
2151 level = msi_dup_property( package, szlevel );
2153 MSI_SetPropertyW(package,szlevel, szOne);
2156 ACTION_UpdateFeatureInstallStates(package);
2158 return MSI_SetFeatureStates(package);
2161 /* OK this value is "interpreted" and then formatted based on the
2162 first few characters */
2163 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2167 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2173 LPWSTR deformated = NULL;
2176 deformat_string(package, &value[2], &deformated);
2178 /* binary value type */
2182 *size = (strlenW(ptr)/2)+1;
2184 *size = strlenW(ptr)/2;
2186 data = msi_alloc(*size);
2192 /* if uneven pad with a zero in front */
2198 data[count] = (BYTE)strtol(byte,NULL,0);
2200 TRACE("Uneven byte count\n");
2208 data[count] = (BYTE)strtol(byte,NULL,0);
2211 msi_free(deformated);
2213 TRACE("Data %i bytes(%i)\n",*size,count);
2220 deformat_string(package, &value[1], &deformated);
2223 *size = sizeof(DWORD);
2224 data = msi_alloc(*size);
2230 if ( (*p < '0') || (*p > '9') )
2236 if (deformated[0] == '-')
2239 TRACE("DWORD %i\n",*(LPDWORD)data);
2241 msi_free(deformated);
2246 static const WCHAR szMulti[] = {'[','~',']',0};
2255 *type=REG_EXPAND_SZ;
2263 if (strstrW(value,szMulti))
2264 *type = REG_MULTI_SZ;
2266 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2271 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2273 MSIPACKAGE *package = (MSIPACKAGE*)param;
2274 static const WCHAR szHCR[] =
2275 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2276 'R','O','O','T','\\',0};
2277 static const WCHAR szHCU[] =
2278 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2279 'U','S','E','R','\\',0};
2280 static const WCHAR szHLM[] =
2281 {'H','K','E','Y','_','L','O','C','A','L','_',
2282 'M','A','C','H','I','N','E','\\',0};
2283 static const WCHAR szHU[] =
2284 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2286 LPSTR value_data = NULL;
2287 HKEY root_key, hkey;
2290 LPCWSTR szRoot, component, name, key, value;
2295 BOOL check_first = FALSE;
2298 ui_progress(package,2,0,0,0);
2305 component = MSI_RecordGetString(row, 6);
2306 comp = get_loaded_component(package,component);
2308 return ERROR_SUCCESS;
2310 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2312 TRACE("Skipping write due to disabled component %s\n",
2313 debugstr_w(component));
2315 comp->Action = comp->Installed;
2317 return ERROR_SUCCESS;
2320 comp->Action = INSTALLSTATE_LOCAL;
2322 name = MSI_RecordGetString(row, 4);
2323 if( MSI_RecordIsNull(row,5) && name )
2325 /* null values can have special meanings */
2326 if (name[0]=='-' && name[1] == 0)
2327 return ERROR_SUCCESS;
2328 else if ((name[0]=='+' && name[1] == 0) ||
2329 (name[0] == '*' && name[1] == 0))
2334 root = MSI_RecordGetInteger(row,2);
2335 key = MSI_RecordGetString(row, 3);
2337 /* get the root key */
2342 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2343 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2344 if (all_users && all_users[0] == '1')
2346 root_key = HKEY_LOCAL_MACHINE;
2351 root_key = HKEY_CURRENT_USER;
2354 msi_free(all_users);
2357 case 0: root_key = HKEY_CLASSES_ROOT;
2360 case 1: root_key = HKEY_CURRENT_USER;
2363 case 2: root_key = HKEY_LOCAL_MACHINE;
2366 case 3: root_key = HKEY_USERS;
2370 ERR("Unknown root %i\n",root);
2376 return ERROR_SUCCESS;
2378 deformat_string(package, key , &deformated);
2379 size = strlenW(deformated) + strlenW(szRoot) + 1;
2380 uikey = msi_alloc(size*sizeof(WCHAR));
2381 strcpyW(uikey,szRoot);
2382 strcatW(uikey,deformated);
2384 if (RegCreateKeyW( root_key, deformated, &hkey))
2386 ERR("Could not create key %s\n",debugstr_w(deformated));
2387 msi_free(deformated);
2389 return ERROR_SUCCESS;
2391 msi_free(deformated);
2393 value = MSI_RecordGetString(row,5);
2395 value_data = parse_value(package, value, &type, &size);
2398 static const WCHAR szEmpty[] = {0};
2399 value_data = (LPSTR)strdupW(szEmpty);
2404 deformat_string(package, name, &deformated);
2406 /* get the double nulls to terminate SZ_MULTI */
2407 if (type == REG_MULTI_SZ)
2408 size +=sizeof(WCHAR);
2412 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2414 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2419 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2420 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2422 TRACE("value %s of %s checked already exists\n",
2423 debugstr_w(deformated), debugstr_w(uikey));
2427 TRACE("Checked and setting value %s of %s\n",
2428 debugstr_w(deformated), debugstr_w(uikey));
2429 if (deformated || size)
2430 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2435 uirow = MSI_CreateRecord(3);
2436 MSI_RecordSetStringW(uirow,2,deformated);
2437 MSI_RecordSetStringW(uirow,1,uikey);
2440 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2442 MSI_RecordSetStringW(uirow,3,value);
2444 ui_actiondata(package,szWriteRegistryValues,uirow);
2445 msiobj_release( &uirow->hdr );
2447 msi_free(value_data);
2448 msi_free(deformated);
2451 return ERROR_SUCCESS;
2454 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2458 static const WCHAR ExecSeqQuery[] =
2459 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2460 '`','R','e','g','i','s','t','r','y','`',0 };
2462 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2463 if (rc != ERROR_SUCCESS)
2464 return ERROR_SUCCESS;
2466 /* increment progress bar each time action data is sent */
2467 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2469 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2471 msiobj_release(&view->hdr);
2475 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2477 package->script->CurrentlyScripting = TRUE;
2479 return ERROR_SUCCESS;
2483 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2488 static const WCHAR q1[]=
2489 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2490 '`','R','e','g','i','s','t','r','y','`',0};
2493 MSIFEATURE *feature;
2496 TRACE("InstallValidate\n");
2498 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2499 if (rc == ERROR_SUCCESS)
2501 MSI_IterateRecords( view, &progress, NULL, package );
2502 msiobj_release( &view->hdr );
2503 total += progress * REG_PROGRESS_VALUE;
2506 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2507 total += COMPONENT_PROGRESS_VALUE;
2509 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2510 total += file->FileSize;
2512 ui_progress(package,0,total,0,0);
2514 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2516 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2517 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2518 feature->ActionRequest);
2521 return ERROR_SUCCESS;
2524 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2526 MSIPACKAGE* package = (MSIPACKAGE*)param;
2527 LPCWSTR cond = NULL;
2528 LPCWSTR message = NULL;
2531 static const WCHAR title[]=
2532 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2534 cond = MSI_RecordGetString(row,1);
2536 r = MSI_EvaluateConditionW(package,cond);
2537 if (r == MSICONDITION_FALSE)
2539 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2542 message = MSI_RecordGetString(row,2);
2543 deformat_string(package,message,&deformated);
2544 MessageBoxW(NULL,deformated,title,MB_OK);
2545 msi_free(deformated);
2548 return ERROR_INSTALL_FAILURE;
2551 return ERROR_SUCCESS;
2554 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2557 MSIQUERY * view = NULL;
2558 static const WCHAR ExecSeqQuery[] =
2559 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2560 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2562 TRACE("Checking launch conditions\n");
2564 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2565 if (rc != ERROR_SUCCESS)
2566 return ERROR_SUCCESS;
2568 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2569 msiobj_release(&view->hdr);
2574 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2578 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2580 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2582 MSIRECORD * row = 0;
2584 LPWSTR deformated,buffer,deformated_name;
2586 static const WCHAR ExecSeqQuery[] =
2587 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2588 '`','R','e','g','i','s','t','r','y','`',' ',
2589 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2590 ' ','=',' ' ,'\'','%','s','\'',0 };
2591 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2592 static const WCHAR fmt2[]=
2593 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2595 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2599 root = MSI_RecordGetInteger(row,2);
2600 key = MSI_RecordGetString(row, 3);
2601 name = MSI_RecordGetString(row, 4);
2602 deformat_string(package, key , &deformated);
2603 deformat_string(package, name, &deformated_name);
2605 len = strlenW(deformated) + 6;
2606 if (deformated_name)
2607 len+=strlenW(deformated_name);
2609 buffer = msi_alloc( len *sizeof(WCHAR));
2611 if (deformated_name)
2612 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2614 sprintfW(buffer,fmt,root,deformated);
2616 msi_free(deformated);
2617 msi_free(deformated_name);
2618 msiobj_release(&row->hdr);
2622 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2624 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2629 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2632 return strdupW( file->TargetPath );
2637 static HKEY openSharedDLLsKey(void)
2640 static const WCHAR path[] =
2641 {'S','o','f','t','w','a','r','e','\\',
2642 'M','i','c','r','o','s','o','f','t','\\',
2643 'W','i','n','d','o','w','s','\\',
2644 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2645 'S','h','a','r','e','d','D','L','L','s',0};
2647 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2651 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2656 DWORD sz = sizeof(count);
2659 hkey = openSharedDLLsKey();
2660 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2661 if (rc != ERROR_SUCCESS)
2667 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2671 hkey = openSharedDLLsKey();
2673 msi_reg_set_val_dword( hkey, path, count );
2675 RegDeleteValueW(hkey,path);
2681 * Return TRUE if the count should be written out and FALSE if not
2683 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2685 MSIFEATURE *feature;
2689 /* only refcount DLLs */
2690 if (comp->KeyPath == NULL ||
2691 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2692 comp->Attributes & msidbComponentAttributesODBCDataSource)
2696 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2697 write = (count > 0);
2699 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2703 /* increment counts */
2704 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2708 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2711 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2713 if ( cl->component == comp )
2718 /* decrement counts */
2719 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2723 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2726 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2728 if ( cl->component == comp )
2733 /* ref count all the files in the component */
2738 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2740 if (file->Component == comp)
2741 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2745 /* add a count for permenent */
2746 if (comp->Attributes & msidbComponentAttributesPermanent)
2749 comp->RefCount = count;
2752 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2756 * Ok further analysis makes me think that this work is
2757 * actually done in the PublishComponents and PublishFeatures
2758 * step, and not here. It appears like the keypath and all that is
2759 * resolved in this step, however actually written in the Publish steps.
2760 * But we will leave it here for now because it is unclear
2762 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2764 WCHAR squished_pc[GUID_SIZE];
2765 WCHAR squished_cc[GUID_SIZE];
2768 HKEY hkey=0,hkey2=0;
2770 /* writes the Component and Features values to the registry */
2772 rc = MSIREG_OpenComponents(&hkey);
2773 if (rc != ERROR_SUCCESS)
2776 squash_guid(package->ProductCode,squished_pc);
2777 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2779 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2783 ui_progress(package,2,0,0,0);
2784 if (!comp->ComponentId)
2787 squash_guid(comp->ComponentId,squished_cc);
2789 msi_free(comp->FullKeypath);
2790 comp->FullKeypath = resolve_keypath( package, comp );
2792 /* do the refcounting */
2793 ACTION_RefCountComponent( package, comp );
2795 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2796 debugstr_w(comp->Component),
2797 debugstr_w(squished_cc),
2798 debugstr_w(comp->FullKeypath),
2801 * Write the keypath out if the component is to be registered
2802 * and delete the key if the component is to be deregistered
2804 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2806 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2807 if (rc != ERROR_SUCCESS)
2810 if (!comp->FullKeypath)
2813 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2815 if (comp->Attributes & msidbComponentAttributesPermanent)
2817 static const WCHAR szPermKey[] =
2818 { '0','0','0','0','0','0','0','0','0','0','0','0',
2819 '0','0','0','0','0','0','0','0','0','0','0','0',
2820 '0','0','0','0','0','0','0','0',0 };
2822 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2827 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2831 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2832 if (rc != ERROR_SUCCESS)
2835 RegDeleteValueW(hkey2,squished_pc);
2837 /* if the key is empty delete it */
2838 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2840 if (res == ERROR_NO_MORE_ITEMS)
2841 RegDeleteKeyW(hkey,squished_cc);
2846 uirow = MSI_CreateRecord(3);
2847 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2848 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2849 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2850 ui_actiondata(package,szProcessComponents,uirow);
2851 msiobj_release( &uirow->hdr );
2865 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2866 LPWSTR lpszName, LONG_PTR lParam)
2869 typelib_struct *tl_struct = (typelib_struct*) lParam;
2870 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2874 if (!IS_INTRESOURCE(lpszName))
2876 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2880 sz = strlenW(tl_struct->source)+4;
2881 sz *= sizeof(WCHAR);
2883 if ((INT_PTR)lpszName == 1)
2884 tl_struct->path = strdupW(tl_struct->source);
2887 tl_struct->path = msi_alloc(sz);
2888 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2891 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2892 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2893 if (!SUCCEEDED(res))
2895 msi_free(tl_struct->path);
2896 tl_struct->path = NULL;
2901 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2902 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2904 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2908 msi_free(tl_struct->path);
2909 tl_struct->path = NULL;
2911 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2912 ITypeLib_Release(tl_struct->ptLib);
2917 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2919 MSIPACKAGE* package = (MSIPACKAGE*)param;
2923 typelib_struct tl_struct;
2925 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2927 component = MSI_RecordGetString(row,3);
2928 comp = get_loaded_component(package,component);
2930 return ERROR_SUCCESS;
2932 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2934 TRACE("Skipping typelib reg due to disabled component\n");
2936 comp->Action = comp->Installed;
2938 return ERROR_SUCCESS;
2941 comp->Action = INSTALLSTATE_LOCAL;
2943 file = get_loaded_file( package, comp->KeyPath );
2945 return ERROR_SUCCESS;
2947 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2951 guid = MSI_RecordGetString(row,1);
2952 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2953 tl_struct.source = strdupW( file->TargetPath );
2954 tl_struct.path = NULL;
2956 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2957 (LONG_PTR)&tl_struct);
2965 helpid = MSI_RecordGetString(row,6);
2968 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2969 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2972 if (!SUCCEEDED(res))
2973 ERR("Failed to register type library %s\n",
2974 debugstr_w(tl_struct.path));
2977 ui_actiondata(package,szRegisterTypeLibraries,row);
2979 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2982 ITypeLib_Release(tl_struct.ptLib);
2983 msi_free(tl_struct.path);
2986 ERR("Failed to load type library %s\n",
2987 debugstr_w(tl_struct.source));
2989 FreeLibrary(module);
2990 msi_free(tl_struct.source);
2993 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2995 return ERROR_SUCCESS;
2998 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3001 * OK this is a bit confusing.. I am given a _Component key and I believe
3002 * that the file that is being registered as a type library is the "key file
3003 * of that component" which I interpret to mean "The file in the KeyPath of
3008 static const WCHAR Query[] =
3009 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3010 '`','T','y','p','e','L','i','b','`',0};
3012 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3013 if (rc != ERROR_SUCCESS)
3014 return ERROR_SUCCESS;
3016 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3017 msiobj_release(&view->hdr);
3021 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3023 MSIPACKAGE *package = (MSIPACKAGE*)param;
3024 LPWSTR target_file, target_folder, filename;
3025 LPCWSTR buffer, extension;
3027 static const WCHAR szlnk[]={'.','l','n','k',0};
3028 IShellLinkW *sl = NULL;
3029 IPersistFile *pf = NULL;
3032 buffer = MSI_RecordGetString(row,4);
3033 comp = get_loaded_component(package,buffer);
3035 return ERROR_SUCCESS;
3037 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3039 TRACE("Skipping shortcut creation due to disabled component\n");
3041 comp->Action = comp->Installed;
3043 return ERROR_SUCCESS;
3046 comp->Action = INSTALLSTATE_LOCAL;
3048 ui_actiondata(package,szCreateShortcuts,row);
3050 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3051 &IID_IShellLinkW, (LPVOID *) &sl );
3055 ERR("CLSID_ShellLink not available\n");
3059 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3062 ERR("QueryInterface(IID_IPersistFile) failed\n");
3066 buffer = MSI_RecordGetString(row,2);
3067 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3069 /* may be needed because of a bug somehwere else */
3070 create_full_pathW(target_folder);
3072 filename = msi_dup_record_field( row, 3 );
3073 reduce_to_longfilename(filename);
3075 extension = strchrW(filename,'.');
3076 if (!extension || strcmpiW(extension,szlnk))
3078 int len = strlenW(filename);
3079 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3080 memcpy(filename + len, szlnk, sizeof(szlnk));
3082 target_file = build_directory_name(2, target_folder, filename);
3083 msi_free(target_folder);
3086 buffer = MSI_RecordGetString(row,5);
3087 if (strchrW(buffer,'['))
3090 deformat_string(package,buffer,&deformated);
3091 IShellLinkW_SetPath(sl,deformated);
3092 msi_free(deformated);
3096 FIXME("poorly handled shortcut format, advertised shortcut\n");
3097 IShellLinkW_SetPath(sl,comp->FullKeypath);
3100 if (!MSI_RecordIsNull(row,6))
3103 buffer = MSI_RecordGetString(row,6);
3104 deformat_string(package,buffer,&deformated);
3105 IShellLinkW_SetArguments(sl,deformated);
3106 msi_free(deformated);
3109 if (!MSI_RecordIsNull(row,7))
3111 buffer = MSI_RecordGetString(row,7);
3112 IShellLinkW_SetDescription(sl,buffer);
3115 if (!MSI_RecordIsNull(row,8))
3116 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3118 if (!MSI_RecordIsNull(row,9))
3123 buffer = MSI_RecordGetString(row,9);
3125 Path = build_icon_path(package,buffer);
3126 index = MSI_RecordGetInteger(row,10);
3128 /* no value means 0 */
3129 if (index == MSI_NULL_INTEGER)
3132 IShellLinkW_SetIconLocation(sl,Path,index);
3136 if (!MSI_RecordIsNull(row,11))
3137 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3139 if (!MSI_RecordIsNull(row,12))
3142 buffer = MSI_RecordGetString(row,12);
3143 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3145 IShellLinkW_SetWorkingDirectory(sl,Path);
3149 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3150 IPersistFile_Save(pf,target_file,FALSE);
3152 msi_free(target_file);
3156 IPersistFile_Release( pf );
3158 IShellLinkW_Release( sl );
3160 return ERROR_SUCCESS;
3163 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3168 static const WCHAR Query[] =
3169 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3170 '`','S','h','o','r','t','c','u','t','`',0};
3172 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3173 if (rc != ERROR_SUCCESS)
3174 return ERROR_SUCCESS;
3176 res = CoInitialize( NULL );
3179 ERR("CoInitialize failed\n");
3180 return ERROR_FUNCTION_FAILED;
3183 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3184 msiobj_release(&view->hdr);
3191 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3193 MSIPACKAGE* package = (MSIPACKAGE*)param;
3202 FileName = MSI_RecordGetString(row,1);
3205 ERR("Unable to get FileName\n");
3206 return ERROR_SUCCESS;
3209 FilePath = build_icon_path(package,FileName);
3211 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3213 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3214 FILE_ATTRIBUTE_NORMAL, NULL);
3216 if (the_file == INVALID_HANDLE_VALUE)
3218 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3220 return ERROR_SUCCESS;
3227 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3228 if (rc != ERROR_SUCCESS)
3230 ERR("Failed to get stream\n");
3231 CloseHandle(the_file);
3232 DeleteFileW(FilePath);
3235 WriteFile(the_file,buffer,sz,&write,NULL);
3236 } while (sz == 1024);
3240 CloseHandle(the_file);
3242 uirow = MSI_CreateRecord(1);
3243 MSI_RecordSetStringW(uirow,1,FileName);
3244 ui_actiondata(package,szPublishProduct,uirow);
3245 msiobj_release( &uirow->hdr );
3247 return ERROR_SUCCESS;
3250 static BOOL msi_check_publish(MSIPACKAGE *package)
3252 MSIFEATURE *feature;
3254 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3256 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3264 * 99% of the work done here is only done for
3265 * advertised installs. However this is where the
3266 * Icon table is processed and written out
3267 * so that is what I am going to do here.
3269 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3273 MSISOURCELISTINFO *info;
3275 static const WCHAR Query[]=
3276 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3277 '`','I','c','o','n','`',0};
3278 /* for registry stuff */
3281 HKEY hudkey=0, props=0;
3282 static const WCHAR szProductLanguage[] =
3283 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3284 static const WCHAR szARPProductIcon[] =
3285 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3286 static const WCHAR szProductVersion[] =
3287 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3291 MSIHANDLE hDb, hSumInfo;
3293 /* FIXME: also need to publish if the product is in advertise mode */
3294 if (!msi_check_publish(package))
3295 return ERROR_SUCCESS;
3297 /* write out icon files */
3299 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3300 if (rc == ERROR_SUCCESS)
3302 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3303 msiobj_release(&view->hdr);
3306 /* ok there is a lot more done here but i need to figure out what */
3308 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3309 if (rc != ERROR_SUCCESS)
3312 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3313 if (rc != ERROR_SUCCESS)
3316 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3317 if (rc != ERROR_SUCCESS)
3320 rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode,&props,TRUE);
3321 if (rc != ERROR_SUCCESS)
3324 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3325 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3328 langid = msi_get_property_int( package, szProductLanguage, 0 );
3329 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3331 buffer = msi_dup_property( package, szARPProductIcon );
3334 LPWSTR path = build_icon_path(package,buffer);
3335 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3340 buffer = msi_dup_property( package, szProductVersion );
3343 DWORD verdword = msi_version_str_to_dword(buffer);
3344 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3348 /* FIXME: Need to write more keys to the user registry */
3350 hDb= alloc_msihandle( &package->db->hdr );
3352 rc = ERROR_NOT_ENOUGH_MEMORY;
3355 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3356 MsiCloseHandle(hDb);
3357 if (rc == ERROR_SUCCESS)
3359 WCHAR guidbuffer[0x200];
3361 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3363 if (rc == ERROR_SUCCESS)
3365 WCHAR squashed[GUID_SIZE];
3366 /* for now we only care about the first guid */
3367 LPWSTR ptr = strchrW(guidbuffer,';');
3369 squash_guid(guidbuffer,squashed);
3370 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3374 ERR("Unable to query Revision_Number...\n");
3377 MsiCloseHandle(hSumInfo);
3381 ERR("Unable to open Summary Information\n");
3385 /* publish the SourceList info */
3386 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3388 MsiSourceListSetInfoW(package->ProductCode, NULL,
3389 info->context, info->options,
3390 info->property, info->value);
3393 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3395 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3396 disk->context, disk->options,
3397 disk->disk_id, disk->volume_label, disk->disk_prompt);
3403 RegCloseKey(hudkey);
3409 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3411 MSIPACKAGE *package = (MSIPACKAGE*)param;
3412 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3413 LPWSTR deformated_section, deformated_key, deformated_value;
3414 LPWSTR folder, fullname = NULL;
3418 static const WCHAR szWindowsFolder[] =
3419 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3421 component = MSI_RecordGetString(row, 8);
3422 comp = get_loaded_component(package,component);
3424 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3426 TRACE("Skipping ini file due to disabled component %s\n",
3427 debugstr_w(component));
3429 comp->Action = comp->Installed;
3431 return ERROR_SUCCESS;
3434 comp->Action = INSTALLSTATE_LOCAL;
3436 identifier = MSI_RecordGetString(row,1);
3437 filename = MSI_RecordGetString(row,2);
3438 dirproperty = MSI_RecordGetString(row,3);
3439 section = MSI_RecordGetString(row,4);
3440 key = MSI_RecordGetString(row,5);
3441 value = MSI_RecordGetString(row,6);
3442 action = MSI_RecordGetInteger(row,7);
3444 deformat_string(package,section,&deformated_section);
3445 deformat_string(package,key,&deformated_key);
3446 deformat_string(package,value,&deformated_value);
3450 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3452 folder = msi_dup_property( package, dirproperty );
3455 folder = msi_dup_property( package, szWindowsFolder );
3459 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3463 fullname = build_directory_name(2, folder, filename);
3467 TRACE("Adding value %s to section %s in %s\n",
3468 debugstr_w(deformated_key), debugstr_w(deformated_section),
3469 debugstr_w(fullname));
3470 WritePrivateProfileStringW(deformated_section, deformated_key,
3471 deformated_value, fullname);
3473 else if (action == 1)
3476 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3477 returned, 10, fullname);
3478 if (returned[0] == 0)
3480 TRACE("Adding value %s to section %s in %s\n",
3481 debugstr_w(deformated_key), debugstr_w(deformated_section),
3482 debugstr_w(fullname));
3484 WritePrivateProfileStringW(deformated_section, deformated_key,
3485 deformated_value, fullname);
3488 else if (action == 3)
3489 FIXME("Append to existing section not yet implemented\n");
3491 uirow = MSI_CreateRecord(4);
3492 MSI_RecordSetStringW(uirow,1,identifier);
3493 MSI_RecordSetStringW(uirow,2,deformated_section);
3494 MSI_RecordSetStringW(uirow,3,deformated_key);
3495 MSI_RecordSetStringW(uirow,4,deformated_value);
3496 ui_actiondata(package,szWriteIniValues,uirow);
3497 msiobj_release( &uirow->hdr );
3501 msi_free(deformated_key);
3502 msi_free(deformated_value);
3503 msi_free(deformated_section);
3504 return ERROR_SUCCESS;
3507 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3511 static const WCHAR ExecSeqQuery[] =
3512 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3513 '`','I','n','i','F','i','l','e','`',0};
3515 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3516 if (rc != ERROR_SUCCESS)
3518 TRACE("no IniFile table\n");
3519 return ERROR_SUCCESS;
3522 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3523 msiobj_release(&view->hdr);
3527 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3529 MSIPACKAGE *package = (MSIPACKAGE*)param;
3534 static const WCHAR ExeStr[] =
3535 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3536 static const WCHAR close[] = {'\"',0};
3538 PROCESS_INFORMATION info;
3543 memset(&si,0,sizeof(STARTUPINFOW));
3545 filename = MSI_RecordGetString(row,1);
3546 file = get_loaded_file( package, filename );
3550 ERR("Unable to find file id %s\n",debugstr_w(filename));
3551 return ERROR_SUCCESS;
3554 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3556 FullName = msi_alloc(len*sizeof(WCHAR));
3557 strcpyW(FullName,ExeStr);
3558 strcatW( FullName, file->TargetPath );
3559 strcatW(FullName,close);
3561 TRACE("Registering %s\n",debugstr_w(FullName));
3562 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3566 msi_dialog_check_messages(info.hProcess);
3571 uirow = MSI_CreateRecord( 2 );
3572 uipath = strdupW( file->TargetPath );
3573 p = strrchrW(uipath,'\\');
3576 MSI_RecordSetStringW( uirow, 1, &p[1] );
3577 MSI_RecordSetStringW( uirow, 2, uipath);
3578 ui_actiondata( package, szSelfRegModules, uirow);
3579 msiobj_release( &uirow->hdr );
3581 /* FIXME: call ui_progress? */
3583 return ERROR_SUCCESS;
3586 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3590 static const WCHAR ExecSeqQuery[] =
3591 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3592 '`','S','e','l','f','R','e','g','`',0};
3594 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3595 if (rc != ERROR_SUCCESS)
3597 TRACE("no SelfReg table\n");
3598 return ERROR_SUCCESS;
3601 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3602 msiobj_release(&view->hdr);
3604 return ERROR_SUCCESS;
3607 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3609 MSIFEATURE *feature;
3614 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3615 if (rc != ERROR_SUCCESS)
3618 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3619 if (rc != ERROR_SUCCESS)
3622 /* here the guids are base 85 encoded */
3623 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3629 BOOL absent = FALSE;
3632 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3633 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3634 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3638 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3642 if (feature->Feature_Parent)
3643 size += strlenW( feature->Feature_Parent )+2;
3645 data = msi_alloc(size * sizeof(WCHAR));
3648 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3650 MSICOMPONENT* component = cl->component;
3654 if (component->ComponentId)
3656 TRACE("From %s\n",debugstr_w(component->ComponentId));
3657 CLSIDFromString(component->ComponentId, &clsid);
3658 encode_base85_guid(&clsid,buf);
3659 TRACE("to %s\n",debugstr_w(buf));
3663 if (feature->Feature_Parent)
3665 static const WCHAR sep[] = {'\2',0};
3667 strcatW(data,feature->Feature_Parent);
3670 msi_reg_set_val_str( hkey, feature->Feature, data );
3674 if (feature->Feature_Parent)
3675 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3678 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3679 (LPBYTE)feature->Feature_Parent,size);
3683 size += 2*sizeof(WCHAR);
3684 data = msi_alloc(size);
3687 if (feature->Feature_Parent)
3688 strcpyW( &data[1], feature->Feature_Parent );
3689 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3695 uirow = MSI_CreateRecord( 1 );
3696 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3697 ui_actiondata( package, szPublishFeatures, uirow);
3698 msiobj_release( &uirow->hdr );
3699 /* FIXME: call ui_progress? */
3708 static UINT msi_get_local_package_name( LPWSTR path )
3710 static const WCHAR szInstaller[] = {
3711 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3712 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3716 time = GetTickCount();
3717 GetWindowsDirectoryW( path, MAX_PATH );
3718 lstrcatW( path, szInstaller );
3719 CreateDirectoryW( path, NULL );
3721 len = lstrlenW(path);
3722 for (i=0; i<0x10000; i++)
3724 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3725 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3726 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3727 if (handle != INVALID_HANDLE_VALUE)
3729 CloseHandle(handle);
3732 if (GetLastError() != ERROR_FILE_EXISTS &&
3733 GetLastError() != ERROR_SHARING_VIOLATION)
3734 return ERROR_FUNCTION_FAILED;
3737 return ERROR_SUCCESS;
3740 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3742 static const WCHAR szOriginalDatabase[] =
3743 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3744 WCHAR packagefile[MAX_PATH];
3748 r = msi_get_local_package_name( packagefile );
3749 if (r != ERROR_SUCCESS)
3752 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3754 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3755 r = CopyFileW( msiFilePath, packagefile, FALSE);
3759 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3760 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3761 msi_free( msiFilePath );
3762 return ERROR_FUNCTION_FAILED;
3764 msi_free( msiFilePath );
3766 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3767 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3768 return ERROR_SUCCESS;
3771 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3773 LPWSTR prop, val, key;
3774 static const LPCSTR propval[] = {
3775 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3776 "ARPCONTACT", "Contact",
3777 "ARPCOMMENTS", "Comments",
3778 "ProductName", "DisplayName",
3779 "ProductVersion", "DisplayVersion",
3780 "ARPHELPLINK", "HelpLink",
3781 "ARPHELPTELEPHONE", "HelpTelephone",
3782 "ARPINSTALLLOCATION", "InstallLocation",
3783 "SourceDir", "InstallSource",
3784 "Manufacturer", "Publisher",
3785 "ARPREADME", "Readme",
3787 "ARPURLINFOABOUT", "URLInfoAbout",
3788 "ARPURLUPDATEINFO", "URLUpdateInfo",
3791 const LPCSTR *p = propval;
3795 prop = strdupAtoW( *p++ );
3796 key = strdupAtoW( *p++ );
3797 val = msi_dup_property( package, prop );
3798 msi_reg_set_val_str( hkey, key, val );
3803 return ERROR_SUCCESS;
3806 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3809 HKEY hudkey=0, props=0;
3810 LPWSTR buffer = NULL;
3813 static const WCHAR szWindowsInstaller[] =
3814 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3815 static const WCHAR szUpgradeCode[] =
3816 {'U','p','g','r','a','d','e','C','o','d','e',0};
3817 static const WCHAR modpath_fmt[] =
3818 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3819 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3820 static const WCHAR szModifyPath[] =
3821 {'M','o','d','i','f','y','P','a','t','h',0};
3822 static const WCHAR szUninstallString[] =
3823 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3824 static const WCHAR szEstimatedSize[] =
3825 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3826 static const WCHAR szProductLanguage[] =
3827 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3828 static const WCHAR szProductVersion[] =
3829 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3832 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3833 LPWSTR upgrade_code;
3836 /* FIXME: also need to publish if the product is in advertise mode */
3837 if (!msi_check_publish(package))
3838 return ERROR_SUCCESS;
3840 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3841 if (rc != ERROR_SUCCESS)
3844 /* dump all the info i can grab */
3845 /* FIXME: Flesh out more information */
3847 msi_write_uninstall_property_vals( package, hkey );
3849 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3851 msi_make_package_local( package, hkey );
3853 /* do ModifyPath and UninstallString */
3854 size = deformat_string(package,modpath_fmt,&buffer);
3855 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3856 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3859 /* FIXME: Write real Estimated Size when we have it */
3860 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3862 GetLocalTime(&systime);
3863 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3864 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3866 langid = msi_get_property_int( package, szProductLanguage, 0 );
3867 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3869 buffer = msi_dup_property( package, szProductVersion );
3872 DWORD verdword = msi_version_str_to_dword(buffer);
3874 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3875 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3876 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3880 /* Handle Upgrade Codes */
3881 upgrade_code = msi_dup_property( package, szUpgradeCode );
3886 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3887 squash_guid(package->ProductCode,squashed);
3888 msi_reg_set_val_str( hkey2, squashed, NULL );
3890 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3891 squash_guid(package->ProductCode,squashed);
3892 msi_reg_set_val_str( hkey2, squashed, NULL );
3895 msi_free(upgrade_code);
3900 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
3901 if (rc != ERROR_SUCCESS)
3904 RegCloseKey(hudkey);
3906 rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode, &props, TRUE);
3907 if (rc != ERROR_SUCCESS)
3910 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
3913 return ERROR_SUCCESS;
3916 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3918 return execute_script(package,INSTALL_SCRIPT);
3921 static UINT msi_unpublish_product(MSIPACKAGE *package)
3923 LPWSTR remove = NULL;
3924 LPWSTR *features = NULL;
3925 BOOL full_uninstall = TRUE;
3926 MSIFEATURE *feature;
3928 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
3929 static const WCHAR szAll[] = {'A','L','L',0};
3931 remove = msi_dup_property(package, szRemove);
3933 return ERROR_SUCCESS;
3935 features = msi_split_string(remove, ',');
3939 ERR("REMOVE feature list is empty!\n");
3940 return ERROR_FUNCTION_FAILED;
3943 if (!lstrcmpW(features[0], szAll))
3944 full_uninstall = TRUE;
3947 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3949 if (feature->Action != INSTALLSTATE_ABSENT)
3950 full_uninstall = FALSE;
3954 if (!full_uninstall)
3957 MSIREG_DeleteProductKey(package->ProductCode);
3958 MSIREG_DeleteUserProductKey(package->ProductCode);
3959 MSIREG_DeleteUserDataProductKey(package->ProductCode);
3964 return ERROR_SUCCESS;
3967 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3971 rc = msi_unpublish_product(package);
3972 if (rc != ERROR_SUCCESS)
3975 /* turn off scheduling */
3976 package->script->CurrentlyScripting= FALSE;
3978 /* first do the same as an InstallExecute */
3979 rc = ACTION_InstallExecute(package);
3980 if (rc != ERROR_SUCCESS)
3983 /* then handle Commit Actions */
3984 rc = execute_script(package,COMMIT_SCRIPT);
3989 UINT ACTION_ForceReboot(MSIPACKAGE *package)
3991 static const WCHAR RunOnce[] = {
3992 'S','o','f','t','w','a','r','e','\\',
3993 'M','i','c','r','o','s','o','f','t','\\',
3994 'W','i','n','d','o','w','s','\\',
3995 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3996 'R','u','n','O','n','c','e',0};
3997 static const WCHAR InstallRunOnce[] = {
3998 'S','o','f','t','w','a','r','e','\\',
3999 'M','i','c','r','o','s','o','f','t','\\',
4000 'W','i','n','d','o','w','s','\\',
4001 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4002 'I','n','s','t','a','l','l','e','r','\\',
4003 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4005 static const WCHAR msiexec_fmt[] = {
4007 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4008 '\"','%','s','\"',0};
4009 static const WCHAR install_fmt[] = {
4010 '/','I',' ','\"','%','s','\"',' ',
4011 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4012 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4013 WCHAR buffer[256], sysdir[MAX_PATH];
4015 WCHAR squished_pc[100];
4017 squash_guid(package->ProductCode,squished_pc);
4019 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4020 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4021 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4024 msi_reg_set_val_str( hkey, squished_pc, buffer );
4027 TRACE("Reboot command %s\n",debugstr_w(buffer));
4029 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4030 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4032 msi_reg_set_val_str( hkey, squished_pc, buffer );
4035 return ERROR_INSTALL_SUSPEND;
4038 static UINT msi_set_sourcedir_props(MSIPACKAGE *package)
4043 p = strrchrW( package->PackagePath, '\\' );
4045 return ERROR_SUCCESS;
4047 len = p - package->PackagePath + 2;
4048 source = msi_alloc( len * sizeof(WCHAR) );
4049 lstrcpynW( source, package->PackagePath, len );
4051 MSI_SetPropertyW( package, cszSourceDir, source );
4052 MSI_SetPropertyW( package, cszSOURCEDIR, source );
4056 return ERROR_SUCCESS;
4059 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4065 * We are currently doing what should be done here in the top level Install
4066 * however for Administrative and uninstalls this step will be needed
4068 if (!package->PackagePath)
4069 return ERROR_SUCCESS;
4071 msi_set_sourcedir_props(package);
4073 attrib = GetFileAttributesW(package->PackagePath);
4074 if (attrib == INVALID_FILE_ATTRIBUTES)
4080 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4081 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
4082 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4083 if (rc == ERROR_MORE_DATA)
4085 prompt = msi_alloc(size * sizeof(WCHAR));
4086 MsiSourceListGetInfoW(package->ProductCode, NULL,
4087 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
4088 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4091 prompt = strdupW(package->PackagePath);
4093 msg = generate_error_string(package,1302,1,prompt);
4094 while(attrib == INVALID_FILE_ATTRIBUTES)
4096 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4099 rc = ERROR_INSTALL_USEREXIT;
4102 attrib = GetFileAttributesW(package->PackagePath);
4108 return ERROR_SUCCESS;
4113 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4120 static const WCHAR szPropKeys[][80] =
4122 {'P','r','o','d','u','c','t','I','D',0},
4123 {'U','S','E','R','N','A','M','E',0},
4124 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4128 static const WCHAR szRegKeys[][80] =
4130 {'P','r','o','d','u','c','t','I','D',0},
4131 {'R','e','g','O','w','n','e','r',0},
4132 {'R','e','g','C','o','m','p','a','n','y',0},
4136 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4138 return ERROR_SUCCESS;
4140 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
4141 if (rc != ERROR_SUCCESS)
4144 for( i = 0; szPropKeys[i][0]; i++ )
4146 buffer = msi_dup_property( package, szPropKeys[i] );
4147 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4152 msi_free(productid);
4155 /* FIXME: call ui_actiondata */
4157 return ERROR_SUCCESS;
4161 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4165 package->script->InWhatSequence |= SEQUENCE_EXEC;
4166 rc = ACTION_ProcessExecSequence(package,FALSE);
4171 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4173 MSIPACKAGE *package = (MSIPACKAGE*)param;
4174 LPCWSTR compgroupid=NULL;
4175 LPCWSTR feature=NULL;
4176 LPCWSTR text = NULL;
4177 LPCWSTR qualifier = NULL;
4178 LPCWSTR component = NULL;
4179 LPWSTR advertise = NULL;
4180 LPWSTR output = NULL;
4182 UINT rc = ERROR_SUCCESS;
4187 component = MSI_RecordGetString(rec,3);
4188 comp = get_loaded_component(package,component);
4190 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4191 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4192 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4194 TRACE("Skipping: Component %s not scheduled for install\n",
4195 debugstr_w(component));
4197 return ERROR_SUCCESS;
4200 compgroupid = MSI_RecordGetString(rec,1);
4201 qualifier = MSI_RecordGetString(rec,2);
4203 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4204 if (rc != ERROR_SUCCESS)
4207 text = MSI_RecordGetString(rec,4);
4208 feature = MSI_RecordGetString(rec,5);
4210 advertise = create_component_advertise_string(package, comp, feature);
4212 sz = strlenW(advertise);
4215 sz += lstrlenW(text);
4218 sz *= sizeof(WCHAR);
4220 output = msi_alloc_zero(sz);
4221 strcpyW(output,advertise);
4222 msi_free(advertise);
4225 strcatW(output,text);
4227 msi_reg_set_val_multi_str( hkey, qualifier, output );
4234 uirow = MSI_CreateRecord( 2 );
4235 MSI_RecordSetStringW( uirow, 1, compgroupid );
4236 MSI_RecordSetStringW( uirow, 2, qualifier);
4237 ui_actiondata( package, szPublishComponents, uirow);
4238 msiobj_release( &uirow->hdr );
4239 /* FIXME: call ui_progress? */
4245 * At present I am ignorning the advertised components part of this and only
4246 * focusing on the qualified component sets
4248 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4252 static const WCHAR ExecSeqQuery[] =
4253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4254 '`','P','u','b','l','i','s','h',
4255 'C','o','m','p','o','n','e','n','t','`',0};
4257 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4258 if (rc != ERROR_SUCCESS)
4259 return ERROR_SUCCESS;
4261 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4262 msiobj_release(&view->hdr);
4267 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4269 MSIPACKAGE *package = (MSIPACKAGE*)param;
4272 SC_HANDLE hscm, service = NULL;
4273 LPCWSTR name, disp, comp, depends, pass;
4274 LPCWSTR load_order, serv_name, key;
4275 DWORD serv_type, start_type;
4278 static const WCHAR query[] =
4279 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4280 '`','C','o','m','p','o','n','e','n','t','`',' ',
4281 'W','H','E','R','E',' ',
4282 '`','C','o','m','p','o','n','e','n','t','`',' ',
4283 '=','\'','%','s','\'',0};
4285 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4288 ERR("Failed to open the SC Manager!\n");
4292 start_type = MSI_RecordGetInteger(rec, 5);
4293 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4296 depends = MSI_RecordGetString(rec, 8);
4297 if (depends && *depends)
4298 FIXME("Dependency list unhandled!\n");
4300 name = MSI_RecordGetString(rec, 2);
4301 disp = MSI_RecordGetString(rec, 3);
4302 serv_type = MSI_RecordGetInteger(rec, 4);
4303 err_control = MSI_RecordGetInteger(rec, 6);
4304 load_order = MSI_RecordGetString(rec, 7);
4305 serv_name = MSI_RecordGetString(rec, 9);
4306 pass = MSI_RecordGetString(rec, 10);
4307 comp = MSI_RecordGetString(rec, 12);
4309 /* fetch the service path */
4310 row = MSI_QueryGetRecord(package->db, query, comp);
4313 ERR("Control query failed!\n");
4317 key = MSI_RecordGetString(row, 6);
4318 msiobj_release(&row->hdr);
4320 file = get_loaded_file(package, key);
4323 ERR("Failed to load the service file\n");
4327 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4328 start_type, err_control, file->TargetPath,
4329 load_order, NULL, NULL, serv_name, pass);
4332 if (GetLastError() != ERROR_SERVICE_EXISTS)
4333 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4337 CloseServiceHandle(service);
4338 CloseServiceHandle(hscm);
4340 return ERROR_SUCCESS;
4343 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4347 static const WCHAR ExecSeqQuery[] =
4348 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4349 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4351 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4352 if (rc != ERROR_SUCCESS)
4353 return ERROR_SUCCESS;
4355 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4356 msiobj_release(&view->hdr);
4361 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4362 static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs)
4368 static const WCHAR separator[] = {'[','~',']',0};
4371 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4376 vector = msi_alloc(sizeof(LPWSTR));
4384 vector[*numargs - 1] = p;
4386 if ((q = strstrW(p, separator)))
4390 vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4401 static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component )
4405 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
4407 if (!lstrcmpW(comp->Component, component))
4414 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4416 MSIPACKAGE *package = (MSIPACKAGE *)param;
4418 SC_HANDLE scm, service = NULL;
4419 LPCWSTR name, *vector = NULL;
4421 DWORD event, numargs;
4422 UINT r = ERROR_FUNCTION_FAILED;
4424 comp = msi_find_component(package, MSI_RecordGetString(rec, 6));
4425 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4426 return ERROR_SUCCESS;
4428 name = MSI_RecordGetString(rec, 2);
4429 event = MSI_RecordGetInteger(rec, 3);
4430 args = strdupW(MSI_RecordGetString(rec, 4));
4432 if (!(event & msidbServiceControlEventStart))
4433 return ERROR_SUCCESS;
4435 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4438 ERR("Failed to open the service control manager\n");
4442 service = OpenServiceW(scm, name, SERVICE_START);
4445 ERR("Failed to open service %s\n", debugstr_w(name));
4449 vector = msi_service_args_to_vector(name, args, &numargs);
4451 if (!StartServiceW(service, numargs, vector))
4453 ERR("Failed to start service %s\n", debugstr_w(name));
4460 CloseServiceHandle(service);
4461 CloseServiceHandle(scm);
4468 static UINT ACTION_StartServices( MSIPACKAGE *package )
4473 static const WCHAR query[] = {
4474 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4475 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4477 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4478 if (rc != ERROR_SUCCESS)
4479 return ERROR_SUCCESS;
4481 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4482 msiobj_release(&view->hdr);
4487 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4491 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4493 if (!lstrcmpW(file->File, filename))
4500 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4502 MSIPACKAGE *package = (MSIPACKAGE*)param;
4503 LPWSTR driver, driver_path, ptr;
4504 WCHAR outpath[MAX_PATH];
4505 MSIFILE *driver_file, *setup_file;
4508 UINT r = ERROR_SUCCESS;
4510 static const WCHAR driver_fmt[] = {
4511 'D','r','i','v','e','r','=','%','s',0};
4512 static const WCHAR setup_fmt[] = {
4513 'S','e','t','u','p','=','%','s',0};
4514 static const WCHAR usage_fmt[] = {
4515 'F','i','l','e','U','s','a','g','e','=','1',0};
4517 desc = MSI_RecordGetString(rec, 3);
4519 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4520 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4522 if (!driver_file || !setup_file)
4524 ERR("ODBC Driver entry not found!\n");
4525 return ERROR_FUNCTION_FAILED;
4528 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4529 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4530 lstrlenW(usage_fmt) + 1;
4531 driver = msi_alloc(len * sizeof(WCHAR));
4533 return ERROR_OUTOFMEMORY;
4536 lstrcpyW(ptr, desc);
4537 ptr += lstrlenW(ptr) + 1;
4539 sprintfW(ptr, driver_fmt, driver_file->FileName);
4540 ptr += lstrlenW(ptr) + 1;
4542 sprintfW(ptr, setup_fmt, setup_file->FileName);
4543 ptr += lstrlenW(ptr) + 1;
4545 lstrcpyW(ptr, usage_fmt);
4546 ptr += lstrlenW(ptr) + 1;
4549 driver_path = strdupW(driver_file->TargetPath);
4550 ptr = strrchrW(driver_path, '\\');
4551 if (ptr) *ptr = '\0';
4553 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4554 NULL, ODBC_INSTALL_COMPLETE, &usage))
4556 ERR("Failed to install SQL driver!\n");
4557 r = ERROR_FUNCTION_FAILED;
4561 msi_free(driver_path);
4566 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4568 MSIPACKAGE *package = (MSIPACKAGE*)param;
4569 LPWSTR translator, translator_path, ptr;
4570 WCHAR outpath[MAX_PATH];
4571 MSIFILE *translator_file, *setup_file;
4574 UINT r = ERROR_SUCCESS;
4576 static const WCHAR translator_fmt[] = {
4577 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4578 static const WCHAR setup_fmt[] = {
4579 'S','e','t','u','p','=','%','s',0};
4581 desc = MSI_RecordGetString(rec, 3);
4583 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4584 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4586 if (!translator_file || !setup_file)
4588 ERR("ODBC Translator entry not found!\n");
4589 return ERROR_FUNCTION_FAILED;
4592 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4593 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4594 translator = msi_alloc(len * sizeof(WCHAR));
4596 return ERROR_OUTOFMEMORY;
4599 lstrcpyW(ptr, desc);
4600 ptr += lstrlenW(ptr) + 1;
4602 sprintfW(ptr, translator_fmt, translator_file->FileName);
4603 ptr += lstrlenW(ptr) + 1;
4605 sprintfW(ptr, setup_fmt, setup_file->FileName);
4606 ptr += lstrlenW(ptr) + 1;
4609 translator_path = strdupW(translator_file->TargetPath);
4610 ptr = strrchrW(translator_path, '\\');
4611 if (ptr) *ptr = '\0';
4613 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4614 NULL, ODBC_INSTALL_COMPLETE, &usage))
4616 ERR("Failed to install SQL translator!\n");
4617 r = ERROR_FUNCTION_FAILED;
4620 msi_free(translator);
4621 msi_free(translator_path);
4626 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4629 LPCWSTR desc, driver;
4630 WORD request = ODBC_ADD_SYS_DSN;
4633 UINT r = ERROR_SUCCESS;
4635 static const WCHAR attrs_fmt[] = {
4636 'D','S','N','=','%','s',0 };
4638 desc = MSI_RecordGetString(rec, 3);
4639 driver = MSI_RecordGetString(rec, 4);
4640 registration = MSI_RecordGetInteger(rec, 5);
4642 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4643 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4645 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4646 attrs = msi_alloc(len * sizeof(WCHAR));
4648 return ERROR_OUTOFMEMORY;
4650 sprintfW(attrs, attrs_fmt, desc);
4651 attrs[len - 1] = '\0';
4653 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4655 ERR("Failed to install SQL data source!\n");
4656 r = ERROR_FUNCTION_FAILED;
4664 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4669 static const WCHAR driver_query[] = {
4670 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4671 'O','D','B','C','D','r','i','v','e','r',0 };
4673 static const WCHAR translator_query[] = {
4674 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4675 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4677 static const WCHAR source_query[] = {
4678 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4679 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4681 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4682 if (rc != ERROR_SUCCESS)
4683 return ERROR_SUCCESS;
4685 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4686 msiobj_release(&view->hdr);
4688 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4689 if (rc != ERROR_SUCCESS)
4690 return ERROR_SUCCESS;
4692 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4693 msiobj_release(&view->hdr);
4695 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4696 if (rc != ERROR_SUCCESS)
4697 return ERROR_SUCCESS;
4699 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4700 msiobj_release(&view->hdr);
4705 #define ENV_ACT_SETALWAYS 0x1
4706 #define ENV_ACT_SETABSENT 0x2
4707 #define ENV_ACT_REMOVE 0x4
4708 #define ENV_ACT_REMOVEMATCH 0x8
4710 #define ENV_MOD_MACHINE 0x20000000
4711 #define ENV_MOD_APPEND 0x40000000
4712 #define ENV_MOD_PREFIX 0x80000000
4713 #define ENV_MOD_MASK 0xC0000000
4715 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4717 static LONG env_set_flags( LPCWSTR *name, LPWSTR *value, DWORD *flags )
4719 LPCWSTR cptr = *name;
4720 LPWSTR ptr = *value;
4722 static const WCHAR prefix[] = {'[','~',']',0};
4728 *flags |= ENV_ACT_SETALWAYS;
4729 else if (*cptr == '+')
4730 *flags |= ENV_ACT_SETABSENT;
4731 else if (*cptr == '-')
4732 *flags |= ENV_ACT_REMOVE;
4733 else if (*cptr == '!')
4734 *flags |= ENV_ACT_REMOVEMATCH;
4735 else if (*cptr == '*')
4736 *flags |= ENV_MOD_MACHINE;
4746 ERR("Missing environment variable\n");
4747 return ERROR_FUNCTION_FAILED;
4750 if (!strncmpW(ptr, prefix, lstrlenW(prefix)))
4752 *flags |= ENV_MOD_PREFIX;
4753 *value += lstrlenW(prefix);
4757 ptr += lstrlenW(ptr) - lstrlenW(prefix) - 1;
4758 if (!lstrcmpW(ptr, prefix))
4760 *flags |= ENV_MOD_APPEND;
4766 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4767 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4768 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4769 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4771 ERR("Invalid flags: %08x\n", *flags);
4772 return ERROR_FUNCTION_FAILED;
4775 return ERROR_SUCCESS;
4778 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4780 MSIPACKAGE *package = param;
4781 LPCWSTR name, value, comp;
4782 LPWSTR data = NULL, newval = NULL;
4783 LPWSTR deformatted, ptr;
4784 DWORD flags, type, size;
4786 HKEY env = NULL, root = HKEY_CURRENT_USER;
4788 static const WCHAR environment[] =
4789 {'S','y','s','t','e','m','\\',
4790 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4791 'C','o','n','t','r','o','l','\\',
4792 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4793 'E','n','v','i','r','o','n','m','e','n','t',0};
4794 static const WCHAR semicolon[] = {';',0};
4796 name = MSI_RecordGetString(rec, 2);
4797 value = MSI_RecordGetString(rec, 3);
4798 comp = MSI_RecordGetString(rec, 4);
4800 deformat_string(package, value, &deformatted);
4802 return ERROR_OUTOFMEMORY;
4804 res = env_set_flags(&name, &deformatted, &flags);
4805 if (res != ERROR_SUCCESS)
4808 value = deformatted;
4810 if (flags & ENV_MOD_MACHINE)
4811 root = HKEY_LOCAL_MACHINE;
4813 res = RegOpenKeyExW(root, environment, 0, KEY_ALL_ACCESS, &env);
4814 if (res != ERROR_SUCCESS)
4817 if (flags & ENV_ACT_REMOVE)
4818 FIXME("Not removing environment variable on uninstall!\n");
4821 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
4822 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
4823 (res == ERROR_SUCCESS && type != REG_SZ))
4826 if (res != ERROR_FILE_NOT_FOUND)
4828 if (flags & ENV_ACT_SETABSENT)
4830 res = ERROR_SUCCESS;
4834 data = msi_alloc(size);
4838 return ERROR_OUTOFMEMORY;
4841 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
4842 if (res != ERROR_SUCCESS)
4845 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
4847 res = RegDeleteKeyW(env, name);
4851 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
4852 newval = msi_alloc(size);
4856 res = ERROR_OUTOFMEMORY;
4860 if (!(flags & ENV_MOD_MASK))
4861 lstrcpyW(newval, value);
4864 if (flags & ENV_MOD_PREFIX)
4866 lstrcpyW(newval, value);
4867 lstrcatW(newval, semicolon);
4868 ptr = newval + lstrlenW(value) + 1;
4871 lstrcpyW(ptr, data);
4873 if (flags & ENV_MOD_APPEND)
4875 lstrcatW(newval, semicolon);
4876 lstrcatW(newval, value);
4882 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
4883 newval = msi_alloc(size);
4886 res = ERROR_OUTOFMEMORY;
4890 lstrcpyW(newval, value);
4893 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
4894 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
4897 if (env) RegCloseKey(env);
4898 msi_free(deformatted);
4904 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4908 static const WCHAR ExecSeqQuery[] =
4909 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4910 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
4911 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4912 if (rc != ERROR_SUCCESS)
4913 return ERROR_SUCCESS;
4915 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
4916 msiobj_release(&view->hdr);
4921 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4922 LPCSTR action, LPCWSTR table )
4924 static const WCHAR query[] = {
4925 'S','E','L','E','C','T',' ','*',' ',
4926 'F','R','O','M',' ','`','%','s','`',0 };
4927 MSIQUERY *view = NULL;
4931 r = MSI_OpenQuery( package->db, &view, query, table );
4932 if (r == ERROR_SUCCESS)
4934 r = MSI_IterateRecords(view, &count, NULL, package);
4935 msiobj_release(&view->hdr);
4939 FIXME("%s -> %u ignored %s table values\n",
4940 action, count, debugstr_w(table));
4942 return ERROR_SUCCESS;
4945 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4947 TRACE("%p\n", package);
4948 return ERROR_SUCCESS;
4951 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4953 static const WCHAR table[] =
4954 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4955 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4958 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4960 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4961 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4964 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4966 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4967 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4970 static UINT ACTION_BindImage( MSIPACKAGE *package )
4972 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4973 return msi_unimplemented_action_stub( package, "BindImage", table );
4976 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4978 static const WCHAR table[] = {
4979 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4980 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4983 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4985 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4986 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4989 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4991 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4992 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4995 static UINT ACTION_StopServices( MSIPACKAGE *package )
4997 static const WCHAR table[] = {
4998 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4999 return msi_unimplemented_action_stub( package, "StopServices", table );
5002 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5004 static const WCHAR table[] = {
5005 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5006 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5008 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5010 static const WCHAR table[] = {
5011 'P','r','o','d','u','c','t','I','D',0 };
5012 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5015 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5017 static const WCHAR table[] = {
5018 'E','n','v','i','r','o','n','m','e','n','t',0 };
5019 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5022 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5024 static const WCHAR table[] = {
5025 'M','s','i','A','s','s','e','m','b','l','y',0 };
5026 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
5029 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5031 static const WCHAR table[] = {
5032 'M','s','i','A','s','s','e','m','b','l','y',0 };
5033 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5036 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5038 static const WCHAR table[] = { 'F','o','n','t',0 };
5039 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5042 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
5044 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5045 return msi_unimplemented_action_stub( package, "CCPSearch", table );
5048 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5050 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5051 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5054 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5056 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5057 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5060 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5062 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5063 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5066 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5068 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5069 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5072 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5074 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5075 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5078 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5080 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5081 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5084 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5086 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5087 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5090 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5092 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5093 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5096 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5098 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5099 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5102 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5104 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5105 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5108 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5110 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5111 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5114 static UINT ACTION_UnpublishFeatures( MSIPACKAGE *package )
5116 static const WCHAR table[] = { 'F','e','a','t','u','r','e','C','o','m','p','o','n','e','n','t','s',0 };
5117 return msi_unimplemented_action_stub( package, "UnpublishFeatures", table );
5120 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5122 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5123 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5126 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5128 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5129 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5132 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5134 static const WCHAR table[] = { 'M','I','M','E',0 };
5135 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5138 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5140 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5141 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5144 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5146 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5147 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5150 static const struct _actions StandardActions[] = {
5151 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5152 { szAppSearch, ACTION_AppSearch },
5153 { szBindImage, ACTION_BindImage },
5154 { szCCPSearch, ACTION_CCPSearch },
5155 { szCostFinalize, ACTION_CostFinalize },
5156 { szCostInitialize, ACTION_CostInitialize },
5157 { szCreateFolders, ACTION_CreateFolders },
5158 { szCreateShortcuts, ACTION_CreateShortcuts },
5159 { szDeleteServices, ACTION_DeleteServices },
5160 { szDisableRollback, NULL },
5161 { szDuplicateFiles, ACTION_DuplicateFiles },
5162 { szExecuteAction, ACTION_ExecuteAction },
5163 { szFileCost, ACTION_FileCost },
5164 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5165 { szForceReboot, ACTION_ForceReboot },
5166 { szInstallAdminPackage, NULL },
5167 { szInstallExecute, ACTION_InstallExecute },
5168 { szInstallExecuteAgain, ACTION_InstallExecute },
5169 { szInstallFiles, ACTION_InstallFiles},
5170 { szInstallFinalize, ACTION_InstallFinalize },
5171 { szInstallInitialize, ACTION_InstallInitialize },
5172 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5173 { szInstallValidate, ACTION_InstallValidate },
5174 { szIsolateComponents, ACTION_IsolateComponents },
5175 { szLaunchConditions, ACTION_LaunchConditions },
5176 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5177 { szMoveFiles, ACTION_MoveFiles },
5178 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5179 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5180 { szInstallODBC, ACTION_InstallODBC },
5181 { szInstallServices, ACTION_InstallServices },
5182 { szPatchFiles, ACTION_PatchFiles },
5183 { szProcessComponents, ACTION_ProcessComponents },
5184 { szPublishComponents, ACTION_PublishComponents },
5185 { szPublishFeatures, ACTION_PublishFeatures },
5186 { szPublishProduct, ACTION_PublishProduct },
5187 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5188 { szRegisterComPlus, ACTION_RegisterComPlus},
5189 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5190 { szRegisterFonts, ACTION_RegisterFonts },
5191 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5192 { szRegisterProduct, ACTION_RegisterProduct },
5193 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5194 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5195 { szRegisterUser, ACTION_RegisterUser },
5196 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5197 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5198 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5199 { szRemoveFiles, ACTION_RemoveFiles },
5200 { szRemoveFolders, ACTION_RemoveFolders },
5201 { szRemoveIniValues, ACTION_RemoveIniValues },
5202 { szRemoveODBC, ACTION_RemoveODBC },
5203 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5204 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5205 { szResolveSource, ACTION_ResolveSource },
5206 { szRMCCPSearch, ACTION_RMCCPSearch },
5207 { szScheduleReboot, NULL },
5208 { szSelfRegModules, ACTION_SelfRegModules },
5209 { szSelfUnregModules, ACTION_SelfUnregModules },
5210 { szSetODBCFolders, NULL },
5211 { szStartServices, ACTION_StartServices },
5212 { szStopServices, ACTION_StopServices },
5213 { szUnpublishComponents, ACTION_UnpublishComponents },
5214 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5215 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5216 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5217 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5218 { szUnregisterFonts, ACTION_UnregisterFonts },
5219 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5220 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5221 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5222 { szValidateProductID, ACTION_ValidateProductID },
5223 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5224 { szWriteIniValues, ACTION_WriteIniValues },
5225 { szWriteRegistryValues, ACTION_WriteRegistryValues },