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
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAppSearch[] =
96 {'A','p','p','S','e','a','r','c','h',0};
97 static const WCHAR szAllocateRegistrySpace[] =
98 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
99 static const WCHAR szBindImage[] =
100 {'B','i','n','d','I','m','a','g','e',0};
101 static const WCHAR szCCPSearch[] =
102 {'C','C','P','S','e','a','r','c','h',0};
103 static const WCHAR szDeleteServices[] =
104 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
105 static const WCHAR szDisableRollback[] =
106 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
107 static const WCHAR szExecuteAction[] =
108 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
109 static const WCHAR szInstallAdminPackage[] =
110 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
111 static const WCHAR szInstallSFPCatalogFile[] =
112 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
113 static const WCHAR szIsolateComponents[] =
114 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
115 static const WCHAR szMigrateFeatureStates[] =
116 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
117 static const WCHAR szMoveFiles[] =
118 {'M','o','v','e','F','i','l','e','s',0};
119 static const WCHAR szMsiPublishAssemblies[] =
120 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
121 static const WCHAR szMsiUnpublishAssemblies[] =
122 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
123 static const WCHAR szInstallODBC[] =
124 {'I','n','s','t','a','l','l','O','D','B','C',0};
125 static const WCHAR szInstallServices[] =
126 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szPatchFiles[] =
128 {'P','a','t','c','h','F','i','l','e','s',0};
129 static const WCHAR szPublishComponents[] =
130 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
131 static const WCHAR szRegisterComPlus[] =
132 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
133 static const WCHAR szRegisterFonts[] =
134 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
135 static const WCHAR szRegisterUser[] =
136 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
137 static const WCHAR szRemoveEnvironmentStrings[] =
138 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
139 static const WCHAR szRemoveExistingProducts[] =
140 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
141 static const WCHAR szRemoveFolders[] =
142 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
143 static const WCHAR szRemoveIniValues[] =
144 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
145 static const WCHAR szRemoveODBC[] =
146 {'R','e','m','o','v','e','O','D','B','C',0};
147 static const WCHAR szRemoveRegistryValues[] =
148 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
149 static const WCHAR szRemoveShortcuts[] =
150 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
151 static const WCHAR szRMCCPSearch[] =
152 {'R','M','C','C','P','S','e','a','r','c','h',0};
153 static const WCHAR szScheduleReboot[] =
154 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
155 static const WCHAR szSelfUnregModules[] =
156 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
157 static const WCHAR szSetODBCFolders[] =
158 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
159 static const WCHAR szStartServices[] =
160 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
161 static const WCHAR szStopServices[] =
162 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
163 static const WCHAR szUnpublishComponents[] =
164 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
165 static const WCHAR szUnpublishFeatures[] =
166 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
167 static const WCHAR szUnregisterClassInfo[] =
168 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
169 static const WCHAR szUnregisterComPlus[] =
170 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
171 static const WCHAR szUnregisterExtensionInfo[] =
172 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
173 static const WCHAR szUnregisterFonts[] =
174 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
175 static const WCHAR szUnregisterMIMEInfo[] =
176 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
177 static const WCHAR szUnregisterProgIdInfo[] =
178 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
179 static const WCHAR szUnregisterTypeLibraries[] =
180 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
181 static const WCHAR szValidateProductID[] =
182 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
183 static const WCHAR szWriteEnvironmentStrings[] =
184 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
186 /********************************************************
188 ********************************************************/
190 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
192 static const WCHAR Query_t[] =
193 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
194 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
195 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
196 ' ','\'','%','s','\'',0};
199 row = MSI_QueryGetRecord( package->db, Query_t, action );
202 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
203 msiobj_release(&row->hdr);
206 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
210 static const WCHAR template_s[]=
211 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
213 static const WCHAR template_e[]=
214 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
215 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
217 static const WCHAR format[] =
218 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
222 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
224 sprintfW(message,template_s,timet,action);
226 sprintfW(message,template_e,timet,action,rc);
228 row = MSI_CreateRecord(1);
229 MSI_RecordSetStringW(row,1,message);
231 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
232 msiobj_release(&row->hdr);
235 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
241 LPWSTR prop = NULL, val = NULL;
244 return ERROR_SUCCESS;
256 TRACE("Looking at %s\n",debugstr_w(ptr));
258 ptr2 = strchrW(ptr,'=');
261 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
268 prop = msi_alloc((len+1)*sizeof(WCHAR));
269 memcpy(prop,ptr,len*sizeof(WCHAR));
279 while (*ptr && (quote || (!quote && *ptr!=' ')))
292 val = msi_alloc((len+1)*sizeof(WCHAR));
293 memcpy(val,ptr2,len*sizeof(WCHAR));
296 if (lstrlenW(prop) > 0)
298 TRACE("Found commandline property (%s) = (%s)\n",
299 debugstr_w(prop), debugstr_w(val));
300 MSI_SetPropertyW(package,prop,val);
306 return ERROR_SUCCESS;
310 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
313 LPWSTR p, *ret = NULL;
319 /* count the number of substrings */
320 for ( pc = str, count = 0; pc; count++ )
322 pc = strchrW( pc, sep );
327 /* allocate space for an array of substring pointers and the substrings */
328 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
329 (lstrlenW(str)+1) * sizeof(WCHAR) );
333 /* copy the string and set the pointers */
334 p = (LPWSTR) &ret[count+1];
336 for( count = 0; (ret[count] = p); count++ )
338 p = strchrW( p, sep );
346 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
348 static const WCHAR szSystemLanguageID[] =
349 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
351 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
352 UINT ret = ERROR_FUNCTION_FAILED;
354 prod_code = msi_dup_property( package, szProductCode );
355 patch_product = msi_get_suminfo_product( patch );
357 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
359 if ( strstrW( patch_product, prod_code ) )
364 si = MSI_GetSummaryInformationW( patch, 0 );
367 ERR("no summary information!\n");
371 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
374 ERR("no template property!\n");
375 msiobj_release( &si->hdr );
382 msiobj_release( &si->hdr );
386 langid = msi_dup_property( package, szSystemLanguageID );
389 msiobj_release( &si->hdr );
393 p = strchrW( template, ';' );
394 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
396 TRACE("applicable transform\n");
400 /* FIXME: check platform */
402 msiobj_release( &si->hdr );
406 msi_free( patch_product );
407 msi_free( prod_code );
408 msi_free( template );
414 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
415 MSIDATABASE *patch_db, LPCWSTR name )
417 UINT ret = ERROR_FUNCTION_FAILED;
418 IStorage *stg = NULL;
421 TRACE("%p %s\n", package, debugstr_w(name) );
425 ERR("expected a colon in %s\n", debugstr_w(name));
426 return ERROR_FUNCTION_FAILED;
429 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
432 ret = msi_check_transform_applicable( package, stg );
433 if (ret == ERROR_SUCCESS)
434 msi_table_apply_transform( package->db, stg );
436 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
437 IStorage_Release( stg );
440 ERR("failed to open substorage %s\n", debugstr_w(name));
442 return ERROR_SUCCESS;
445 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
447 LPWSTR guid_list, *guids, product_code;
448 UINT i, ret = ERROR_FUNCTION_FAILED;
450 product_code = msi_dup_property( package, szProductCode );
453 /* FIXME: the property ProductCode should be written into the DB somewhere */
454 ERR("no product code to check\n");
455 return ERROR_SUCCESS;
458 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
459 guids = msi_split_string( guid_list, ';' );
460 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
462 if (!lstrcmpW( guids[i], product_code ))
466 msi_free( guid_list );
467 msi_free( product_code );
472 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
475 MSIRECORD *rec = NULL;
480 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
481 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
482 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
483 '`','S','o','u','r','c','e','`',' ','I','S',' ',
484 'N','O','T',' ','N','U','L','L',0};
486 r = MSI_DatabaseOpenViewW(package->db, query, &view);
487 if (r != ERROR_SUCCESS)
490 r = MSI_ViewExecute(view, 0);
491 if (r != ERROR_SUCCESS)
494 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
496 prop = MSI_RecordGetString(rec, 1);
497 patch = msi_dup_property(package, szPatch);
498 MSI_SetPropertyW(package, prop, patch);
503 if (rec) msiobj_release(&rec->hdr);
504 msiobj_release(&view->hdr);
509 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
512 LPWSTR str, *substorage;
513 UINT i, r = ERROR_SUCCESS;
515 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
517 return ERROR_FUNCTION_FAILED;
519 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
521 TRACE("Patch not applicable\n");
522 return ERROR_SUCCESS;
525 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
527 return ERROR_OUTOFMEMORY;
529 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
530 if (!package->patch->patchcode)
531 return ERROR_OUTOFMEMORY;
533 /* enumerate the substorage */
534 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
535 package->patch->transforms = str;
537 substorage = msi_split_string( str, ';' );
538 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
539 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
541 msi_free( substorage );
542 msiobj_release( &si->hdr );
544 msi_set_media_source_prop(package);
549 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
551 MSIDATABASE *patch_db = NULL;
554 TRACE("%p %s\n", package, debugstr_w( file ) );
557 * We probably want to make sure we only open a patch collection here.
558 * Patch collections (.msp) and databases (.msi) have different GUIDs
559 * but currently MSI_OpenDatabaseW will accept both.
561 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
562 if ( r != ERROR_SUCCESS )
564 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
568 msi_parse_patch_summary( package, patch_db );
571 * There might be a CAB file in the patch package,
572 * so append it to the list of storage to search for streams.
574 append_storage_to_db( package->db, patch_db->storage );
576 msiobj_release( &patch_db->hdr );
578 return ERROR_SUCCESS;
581 /* get the PATCH property, and apply all the patches it specifies */
582 static UINT msi_apply_patches( MSIPACKAGE *package )
584 LPWSTR patch_list, *patches;
585 UINT i, r = ERROR_SUCCESS;
587 patch_list = msi_dup_property( package, szPatch );
589 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
591 patches = msi_split_string( patch_list, ';' );
592 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
593 r = msi_apply_patch_package( package, patches[i] );
596 msi_free( patch_list );
601 static UINT msi_apply_transforms( MSIPACKAGE *package )
603 static const WCHAR szTransforms[] = {
604 'T','R','A','N','S','F','O','R','M','S',0 };
605 LPWSTR xform_list, *xforms;
606 UINT i, r = ERROR_SUCCESS;
608 xform_list = msi_dup_property( package, szTransforms );
609 xforms = msi_split_string( xform_list, ';' );
611 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
613 if (xforms[i][0] == ':')
614 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
616 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
620 msi_free( xform_list );
625 static BOOL ui_sequence_exists( MSIPACKAGE *package )
630 static const WCHAR ExecSeqQuery [] =
631 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
632 '`','I','n','s','t','a','l','l',
633 'U','I','S','e','q','u','e','n','c','e','`',
634 ' ','W','H','E','R','E',' ',
635 '`','S','e','q','u','e','n','c','e','`',' ',
636 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
637 '`','S','e','q','u','e','n','c','e','`',0};
639 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
640 if (rc == ERROR_SUCCESS)
642 msiobj_release(&view->hdr);
649 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
652 LPWSTR source, check;
655 static const WCHAR szOriginalDatabase[] =
656 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
658 db = msi_dup_property( package, szOriginalDatabase );
660 return ERROR_OUTOFMEMORY;
662 p = strrchrW( db, '\\' );
665 p = strrchrW( db, '/' );
669 return ERROR_SUCCESS;
674 source = msi_alloc( len * sizeof(WCHAR) );
675 lstrcpynW( source, db, len );
677 check = msi_dup_property( package, cszSourceDir );
678 if (!check || replace)
679 MSI_SetPropertyW( package, cszSourceDir, source );
683 check = msi_dup_property( package, cszSOURCEDIR );
684 if (!check || replace)
685 MSI_SetPropertyW( package, cszSOURCEDIR, source );
691 return ERROR_SUCCESS;
694 static BOOL needs_ui_sequence(MSIPACKAGE *package)
696 INT level = msi_get_property_int(package, szUILevel, 0);
697 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
700 static UINT msi_set_context(MSIPACKAGE *package)
707 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
709 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
710 if (r == ERROR_SUCCESS)
713 if (num == 1 || num == 2)
714 package->Context = MSIINSTALLCONTEXT_MACHINE;
717 return ERROR_SUCCESS;
720 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
723 LPCWSTR cond, action;
724 MSIPACKAGE *package = param;
726 action = MSI_RecordGetString(row,1);
729 ERR("Error is retrieving action name\n");
730 return ERROR_FUNCTION_FAILED;
733 /* check conditions */
734 cond = MSI_RecordGetString(row,2);
736 /* this is a hack to skip errors in the condition code */
737 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
739 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
740 return ERROR_SUCCESS;
743 if (needs_ui_sequence(package))
744 rc = ACTION_PerformUIAction(package, action, -1);
746 rc = ACTION_PerformAction(package, action, -1, FALSE);
748 msi_dialog_check_messages( NULL );
750 if (package->CurrentInstallState != ERROR_SUCCESS)
751 rc = package->CurrentInstallState;
753 if (rc == ERROR_FUNCTION_NOT_CALLED)
756 if (rc != ERROR_SUCCESS)
757 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
762 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
766 static const WCHAR query[] =
767 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
769 ' ','W','H','E','R','E',' ',
770 '`','S','e','q','u','e','n','c','e','`',' ',
771 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
772 '`','S','e','q','u','e','n','c','e','`',0};
774 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
776 r = MSI_OpenQuery( package->db, &view, query, szTable );
777 if (r == ERROR_SUCCESS)
779 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
780 msiobj_release(&view->hdr);
786 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
790 static const WCHAR ExecSeqQuery[] =
791 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
792 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
793 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
794 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
795 'O','R','D','E','R',' ', 'B','Y',' ',
796 '`','S','e','q','u','e','n','c','e','`',0 };
797 static const WCHAR IVQuery[] =
798 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
799 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
800 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
801 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
802 ' ','\'', 'I','n','s','t','a','l','l',
803 'V','a','l','i','d','a','t','e','\'', 0};
806 if (package->script->ExecuteSequenceRun)
808 TRACE("Execute Sequence already Run\n");
809 return ERROR_SUCCESS;
812 package->script->ExecuteSequenceRun = TRUE;
814 /* get the sequence number */
817 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
819 return ERROR_FUNCTION_FAILED;
820 seq = MSI_RecordGetInteger(row,1);
821 msiobj_release(&row->hdr);
824 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
825 if (rc == ERROR_SUCCESS)
827 TRACE("Running the actions\n");
829 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
830 msiobj_release(&view->hdr);
836 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
840 static const WCHAR ExecSeqQuery [] =
841 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
842 '`','I','n','s','t','a','l','l',
843 'U','I','S','e','q','u','e','n','c','e','`',
844 ' ','W','H','E','R','E',' ',
845 '`','S','e','q','u','e','n','c','e','`',' ',
846 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
847 '`','S','e','q','u','e','n','c','e','`',0};
849 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
850 if (rc == ERROR_SUCCESS)
852 TRACE("Running the actions\n");
854 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
855 msiobj_release(&view->hdr);
861 /********************************************************
862 * ACTION helper functions and functions that perform the actions
863 *******************************************************/
864 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
865 UINT* rc, UINT script, BOOL force )
870 arc = ACTION_CustomAction(package, action, script, force);
872 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
881 * Actual Action Handlers
884 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
886 MSIPACKAGE *package = param;
887 LPCWSTR dir, component;
893 component = MSI_RecordGetString(row, 2);
894 comp = get_loaded_component(package, component);
896 return ERROR_SUCCESS;
898 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
900 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
901 comp->Action = comp->Installed;
902 return ERROR_SUCCESS;
904 comp->Action = INSTALLSTATE_LOCAL;
906 dir = MSI_RecordGetString(row,1);
909 ERR("Unable to get folder id\n");
910 return ERROR_SUCCESS;
913 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
916 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
917 return ERROR_SUCCESS;
920 TRACE("Folder is %s\n",debugstr_w(full_path));
923 uirow = MSI_CreateRecord(1);
924 MSI_RecordSetStringW(uirow,1,full_path);
925 ui_actiondata(package,szCreateFolders,uirow);
926 msiobj_release( &uirow->hdr );
928 if (folder->State == 0)
929 create_full_pathW(full_path);
934 return ERROR_SUCCESS;
937 /* FIXME: probably should merge this with the above function */
938 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
940 UINT rc = ERROR_SUCCESS;
944 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
946 return ERROR_FUNCTION_FAILED;
948 /* create the path */
949 if (folder->State == 0)
951 create_full_pathW(install_path);
954 msi_free(install_path);
959 UINT msi_create_component_directories( MSIPACKAGE *package )
963 /* create all the folders required by the components are going to install */
964 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
966 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
968 msi_create_directory( package, comp->Directory );
971 return ERROR_SUCCESS;
974 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
976 static const WCHAR ExecSeqQuery[] =
977 {'S','E','L','E','C','T',' ',
978 '`','D','i','r','e','c','t','o','r','y','_','`',
979 ' ','F','R','O','M',' ',
980 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
984 /* create all the empty folders specified in the CreateFolder table */
985 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
986 if (rc != ERROR_SUCCESS)
987 return ERROR_SUCCESS;
989 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
990 msiobj_release(&view->hdr);
995 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
997 MSIPACKAGE *package = param;
998 LPCWSTR dir, component;
1004 component = MSI_RecordGetString(row, 2);
1005 comp = get_loaded_component(package, component);
1007 return ERROR_SUCCESS;
1009 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1011 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1012 comp->Action = comp->Installed;
1013 return ERROR_SUCCESS;
1015 comp->Action = INSTALLSTATE_ABSENT;
1017 dir = MSI_RecordGetString( row, 1 );
1020 ERR("Unable to get folder id\n");
1021 return ERROR_SUCCESS;
1024 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1027 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1028 return ERROR_SUCCESS;
1031 TRACE("folder is %s\n", debugstr_w(full_path));
1033 uirow = MSI_CreateRecord( 1 );
1034 MSI_RecordSetStringW( uirow, 1, full_path );
1035 ui_actiondata( package, szRemoveFolders, uirow );
1036 msiobj_release( &uirow->hdr );
1038 RemoveDirectoryW( full_path );
1041 msi_free( full_path );
1042 return ERROR_SUCCESS;
1045 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1047 static const WCHAR query[] =
1048 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1049 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1054 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1055 if (rc != ERROR_SUCCESS)
1056 return ERROR_SUCCESS;
1058 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1059 msiobj_release( &view->hdr );
1064 static UINT load_component( MSIRECORD *row, LPVOID param )
1066 MSIPACKAGE *package = param;
1069 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1071 return ERROR_FUNCTION_FAILED;
1073 list_add_tail( &package->components, &comp->entry );
1075 /* fill in the data */
1076 comp->Component = msi_dup_record_field( row, 1 );
1078 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1080 comp->ComponentId = msi_dup_record_field( row, 2 );
1081 comp->Directory = msi_dup_record_field( row, 3 );
1082 comp->Attributes = MSI_RecordGetInteger(row,4);
1083 comp->Condition = msi_dup_record_field( row, 5 );
1084 comp->KeyPath = msi_dup_record_field( row, 6 );
1086 comp->Installed = INSTALLSTATE_UNKNOWN;
1087 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1089 return ERROR_SUCCESS;
1092 static UINT load_all_components( MSIPACKAGE *package )
1094 static const WCHAR query[] = {
1095 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1096 '`','C','o','m','p','o','n','e','n','t','`',0 };
1100 if (!list_empty(&package->components))
1101 return ERROR_SUCCESS;
1103 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1104 if (r != ERROR_SUCCESS)
1107 r = MSI_IterateRecords(view, NULL, load_component, package);
1108 msiobj_release(&view->hdr);
1113 MSIPACKAGE *package;
1114 MSIFEATURE *feature;
1117 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1121 cl = msi_alloc( sizeof (*cl) );
1123 return ERROR_NOT_ENOUGH_MEMORY;
1124 cl->component = comp;
1125 list_add_tail( &feature->Components, &cl->entry );
1127 return ERROR_SUCCESS;
1130 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1134 fl = msi_alloc( sizeof(*fl) );
1136 return ERROR_NOT_ENOUGH_MEMORY;
1137 fl->feature = child;
1138 list_add_tail( &parent->Children, &fl->entry );
1140 return ERROR_SUCCESS;
1143 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1145 _ilfs* ilfs = param;
1149 component = MSI_RecordGetString(row,1);
1151 /* check to see if the component is already loaded */
1152 comp = get_loaded_component( ilfs->package, component );
1155 ERR("unknown component %s\n", debugstr_w(component));
1156 return ERROR_FUNCTION_FAILED;
1159 add_feature_component( ilfs->feature, comp );
1160 comp->Enabled = TRUE;
1162 return ERROR_SUCCESS;
1165 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1167 MSIFEATURE *feature;
1172 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1174 if ( !lstrcmpW( feature->Feature, name ) )
1181 static UINT load_feature(MSIRECORD * row, LPVOID param)
1183 MSIPACKAGE* package = param;
1184 MSIFEATURE* feature;
1185 static const WCHAR Query1[] =
1186 {'S','E','L','E','C','T',' ',
1187 '`','C','o','m','p','o','n','e','n','t','_','`',
1188 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1189 'C','o','m','p','o','n','e','n','t','s','`',' ',
1190 'W','H','E','R','E',' ',
1191 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1196 /* fill in the data */
1198 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1200 return ERROR_NOT_ENOUGH_MEMORY;
1202 list_init( &feature->Children );
1203 list_init( &feature->Components );
1205 feature->Feature = msi_dup_record_field( row, 1 );
1207 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1209 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1210 feature->Title = msi_dup_record_field( row, 3 );
1211 feature->Description = msi_dup_record_field( row, 4 );
1213 if (!MSI_RecordIsNull(row,5))
1214 feature->Display = MSI_RecordGetInteger(row,5);
1216 feature->Level= MSI_RecordGetInteger(row,6);
1217 feature->Directory = msi_dup_record_field( row, 7 );
1218 feature->Attributes = MSI_RecordGetInteger(row,8);
1220 feature->Installed = INSTALLSTATE_UNKNOWN;
1221 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1223 list_add_tail( &package->features, &feature->entry );
1225 /* load feature components */
1227 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1228 if (rc != ERROR_SUCCESS)
1229 return ERROR_SUCCESS;
1231 ilfs.package = package;
1232 ilfs.feature = feature;
1234 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1235 msiobj_release(&view->hdr);
1237 return ERROR_SUCCESS;
1240 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1242 MSIPACKAGE* package = param;
1243 MSIFEATURE *parent, *child;
1245 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1247 return ERROR_FUNCTION_FAILED;
1249 if (!child->Feature_Parent)
1250 return ERROR_SUCCESS;
1252 parent = find_feature_by_name( package, child->Feature_Parent );
1254 return ERROR_FUNCTION_FAILED;
1256 add_feature_child( parent, child );
1257 return ERROR_SUCCESS;
1260 static UINT load_all_features( MSIPACKAGE *package )
1262 static const WCHAR query[] = {
1263 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1264 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1265 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1269 if (!list_empty(&package->features))
1270 return ERROR_SUCCESS;
1272 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1273 if (r != ERROR_SUCCESS)
1276 r = MSI_IterateRecords( view, NULL, load_feature, package );
1277 if (r != ERROR_SUCCESS)
1280 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1281 msiobj_release( &view->hdr );
1286 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1297 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1299 static const WCHAR query[] = {
1300 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1301 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1302 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1303 MSIQUERY *view = NULL;
1304 MSIRECORD *row = NULL;
1307 TRACE("%s\n", debugstr_w(file->File));
1309 r = MSI_OpenQuery(package->db, &view, query, file->File);
1310 if (r != ERROR_SUCCESS)
1313 r = MSI_ViewExecute(view, NULL);
1314 if (r != ERROR_SUCCESS)
1317 r = MSI_ViewFetch(view, &row);
1318 if (r != ERROR_SUCCESS)
1321 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1322 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1323 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1324 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1325 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1328 if (view) msiobj_release(&view->hdr);
1329 if (row) msiobj_release(&row->hdr);
1333 static UINT load_file(MSIRECORD *row, LPVOID param)
1335 MSIPACKAGE* package = param;
1339 /* fill in the data */
1341 file = msi_alloc_zero( sizeof (MSIFILE) );
1343 return ERROR_NOT_ENOUGH_MEMORY;
1345 file->File = msi_dup_record_field( row, 1 );
1347 component = MSI_RecordGetString( row, 2 );
1348 file->Component = get_loaded_component( package, component );
1350 if (!file->Component)
1352 WARN("Component not found: %s\n", debugstr_w(component));
1353 msi_free(file->File);
1355 return ERROR_SUCCESS;
1358 file->FileName = msi_dup_record_field( row, 3 );
1359 reduce_to_longfilename( file->FileName );
1361 file->ShortName = msi_dup_record_field( row, 3 );
1362 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1364 file->FileSize = MSI_RecordGetInteger( row, 4 );
1365 file->Version = msi_dup_record_field( row, 5 );
1366 file->Language = msi_dup_record_field( row, 6 );
1367 file->Attributes = MSI_RecordGetInteger( row, 7 );
1368 file->Sequence = MSI_RecordGetInteger( row, 8 );
1370 file->state = msifs_invalid;
1372 /* if the compressed bits are not set in the file attributes,
1373 * then read the information from the package word count property
1375 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1377 file->IsCompressed = FALSE;
1379 else if (file->Attributes &
1380 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1382 file->IsCompressed = TRUE;
1384 else if (file->Attributes & msidbFileAttributesNoncompressed)
1386 file->IsCompressed = FALSE;
1390 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1393 load_file_hash(package, file);
1395 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1397 list_add_tail( &package->files, &file->entry );
1399 return ERROR_SUCCESS;
1402 static UINT load_all_files(MSIPACKAGE *package)
1406 static const WCHAR Query[] =
1407 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1408 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1409 '`','S','e','q','u','e','n','c','e','`', 0};
1411 if (!list_empty(&package->files))
1412 return ERROR_SUCCESS;
1414 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1415 if (rc != ERROR_SUCCESS)
1416 return ERROR_SUCCESS;
1418 rc = MSI_IterateRecords(view, NULL, load_file, package);
1419 msiobj_release(&view->hdr);
1421 return ERROR_SUCCESS;
1424 static UINT load_folder( MSIRECORD *row, LPVOID param )
1426 MSIPACKAGE *package = param;
1427 static WCHAR szEmpty[] = { 0 };
1428 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1431 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1433 return ERROR_NOT_ENOUGH_MEMORY;
1435 folder->Directory = msi_dup_record_field( row, 1 );
1437 TRACE("%s\n", debugstr_w(folder->Directory));
1439 p = msi_dup_record_field(row, 3);
1441 /* split src and target dir */
1443 src_short = folder_split_path( p, ':' );
1445 /* split the long and short paths */
1446 tgt_long = folder_split_path( tgt_short, '|' );
1447 src_long = folder_split_path( src_short, '|' );
1449 /* check for no-op dirs */
1450 if (!lstrcmpW(szDot, tgt_short))
1451 tgt_short = szEmpty;
1452 if (!lstrcmpW(szDot, src_short))
1453 src_short = szEmpty;
1456 tgt_long = tgt_short;
1459 src_short = tgt_short;
1460 src_long = tgt_long;
1464 src_long = src_short;
1466 /* FIXME: use the target short path too */
1467 folder->TargetDefault = strdupW(tgt_long);
1468 folder->SourceShortPath = strdupW(src_short);
1469 folder->SourceLongPath = strdupW(src_long);
1472 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1473 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1474 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1476 folder->Parent = msi_dup_record_field( row, 2 );
1478 folder->Property = msi_dup_property( package, folder->Directory );
1480 list_add_tail( &package->folders, &folder->entry );
1482 TRACE("returning %p\n", folder);
1484 return ERROR_SUCCESS;
1487 static UINT load_all_folders( MSIPACKAGE *package )
1489 static const WCHAR query[] = {
1490 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1491 '`','D','i','r','e','c','t','o','r','y','`',0 };
1495 if (!list_empty(&package->folders))
1496 return ERROR_SUCCESS;
1498 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1499 if (r != ERROR_SUCCESS)
1502 r = MSI_IterateRecords(view, NULL, load_folder, package);
1503 msiobj_release(&view->hdr);
1508 * I am not doing any of the costing functionality yet.
1509 * Mostly looking at doing the Component and Feature loading
1511 * The native MSI does A LOT of modification to tables here. Mostly adding
1512 * a lot of temporary columns to the Feature and Component tables.
1514 * note: Native msi also tracks the short filename. But I am only going to
1515 * track the long ones. Also looking at this directory table
1516 * it appears that the directory table does not get the parents
1517 * resolved base on property only based on their entries in the
1520 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1522 static const WCHAR szCosting[] =
1523 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1525 MSI_SetPropertyW(package, szCosting, szZero);
1526 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1528 load_all_folders( package );
1529 load_all_components( package );
1530 load_all_features( package );
1531 load_all_files( package );
1533 return ERROR_SUCCESS;
1536 static UINT execute_script(MSIPACKAGE *package, UINT script )
1539 UINT rc = ERROR_SUCCESS;
1541 TRACE("Executing Script %i\n",script);
1543 if (!package->script)
1545 ERR("no script!\n");
1546 return ERROR_FUNCTION_FAILED;
1549 for (i = 0; i < package->script->ActionCount[script]; i++)
1552 action = package->script->Actions[script][i];
1553 ui_actionstart(package, action);
1554 TRACE("Executing Action (%s)\n",debugstr_w(action));
1555 rc = ACTION_PerformAction(package, action, script, TRUE);
1556 if (rc != ERROR_SUCCESS)
1559 msi_free_action_script(package, script);
1563 static UINT ACTION_FileCost(MSIPACKAGE *package)
1565 return ERROR_SUCCESS;
1568 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1574 state = MsiQueryProductStateW(package->ProductCode);
1576 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1578 if (!comp->ComponentId)
1581 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1582 comp->Installed = INSTALLSTATE_ABSENT;
1585 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1586 package->Context, comp->ComponentId,
1588 if (r != ERROR_SUCCESS)
1589 comp->Installed = INSTALLSTATE_ABSENT;
1594 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1596 MSIFEATURE *feature;
1599 state = MsiQueryProductStateW(package->ProductCode);
1601 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1603 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1604 feature->Installed = INSTALLSTATE_ABSENT;
1607 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1613 static BOOL process_state_property(MSIPACKAGE* package, int level,
1614 LPCWSTR property, INSTALLSTATE state)
1617 MSIFEATURE *feature;
1619 override = msi_dup_property( package, property );
1623 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1625 if (lstrcmpW(property, szRemove) &&
1626 (feature->Level <= 0 || feature->Level > level))
1629 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1631 if (strcmpiW(override, szAll)==0)
1632 msi_feature_set_state(package, feature, state);
1635 LPWSTR ptr = override;
1636 LPWSTR ptr2 = strchrW(override,',');
1640 int len = ptr2 - ptr;
1642 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1643 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1645 msi_feature_set_state(package, feature, state);
1651 ptr2 = strchrW(ptr,',');
1663 static BOOL process_overrides( MSIPACKAGE *package, int level )
1665 static const WCHAR szAddLocal[] =
1666 {'A','D','D','L','O','C','A','L',0};
1667 static const WCHAR szAddSource[] =
1668 {'A','D','D','S','O','U','R','C','E',0};
1669 static const WCHAR szAdvertise[] =
1670 {'A','D','V','E','R','T','I','S','E',0};
1673 /* all these activation/deactivation things happen in order and things
1674 * later on the list override things earlier on the list.
1676 * 0 INSTALLLEVEL processing
1689 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1690 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1691 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1692 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1693 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1696 MSI_SetPropertyW( package, szPreselected, szOne );
1701 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1704 static const WCHAR szlevel[] =
1705 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1706 MSICOMPONENT* component;
1707 MSIFEATURE *feature;
1709 TRACE("Checking Install Level\n");
1711 level = msi_get_property_int(package, szlevel, 1);
1713 if (!msi_get_property_int( package, szPreselected, 0 ))
1715 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1717 BOOL feature_state = ((feature->Level > 0) &&
1718 (feature->Level <= level));
1720 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1722 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1723 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1724 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1725 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1727 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1731 /* disable child features of unselected parent features */
1732 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1736 if (feature->Level > 0 && feature->Level <= level)
1739 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1740 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1745 * now we want to enable or disable components base on feature
1748 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1752 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1753 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1755 if (!feature->Level)
1758 /* features with components that have compressed files are made local */
1759 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1761 if (cl->component->Enabled &&
1762 cl->component->ForceLocalState &&
1763 feature->Action == INSTALLSTATE_SOURCE)
1765 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1770 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1772 component = cl->component;
1774 if (!component->Enabled)
1777 switch (feature->Action)
1779 case INSTALLSTATE_ABSENT:
1780 component->anyAbsent = 1;
1782 case INSTALLSTATE_ADVERTISED:
1783 component->hasAdvertiseFeature = 1;
1785 case INSTALLSTATE_SOURCE:
1786 component->hasSourceFeature = 1;
1788 case INSTALLSTATE_LOCAL:
1789 component->hasLocalFeature = 1;
1791 case INSTALLSTATE_DEFAULT:
1792 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1793 component->hasAdvertiseFeature = 1;
1794 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1795 component->hasSourceFeature = 1;
1797 component->hasLocalFeature = 1;
1805 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1807 /* if the component isn't enabled, leave it alone */
1808 if (!component->Enabled)
1811 /* check if it's local or source */
1812 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1813 (component->hasLocalFeature || component->hasSourceFeature))
1815 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1816 !component->ForceLocalState)
1817 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1819 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1823 /* if any feature is local, the component must be local too */
1824 if (component->hasLocalFeature)
1826 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1830 if (component->hasSourceFeature)
1832 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1836 if (component->hasAdvertiseFeature)
1838 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1842 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1843 if (component->anyAbsent)
1844 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1847 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1849 if (component->Action == INSTALLSTATE_DEFAULT)
1851 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1852 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1855 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1856 debugstr_w(component->Component), component->Installed, component->Action);
1860 return ERROR_SUCCESS;
1863 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1865 MSIPACKAGE *package = param;
1870 name = MSI_RecordGetString(row,1);
1872 f = get_loaded_folder(package, name);
1873 if (!f) return ERROR_SUCCESS;
1875 /* reset the ResolvedTarget */
1876 msi_free(f->ResolvedTarget);
1877 f->ResolvedTarget = NULL;
1879 /* This helper function now does ALL the work */
1880 TRACE("Dir %s ...\n",debugstr_w(name));
1881 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1882 TRACE("resolves to %s\n",debugstr_w(path));
1885 return ERROR_SUCCESS;
1888 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1890 MSIPACKAGE *package = param;
1892 MSIFEATURE *feature;
1894 name = MSI_RecordGetString( row, 1 );
1896 feature = get_loaded_feature( package, name );
1898 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1902 Condition = MSI_RecordGetString(row,3);
1904 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1906 int level = MSI_RecordGetInteger(row,2);
1907 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1908 feature->Level = level;
1911 return ERROR_SUCCESS;
1914 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1916 static const WCHAR name_fmt[] =
1917 {'%','u','.','%','u','.','%','u','.','%','u',0};
1918 static const WCHAR name[] = {'\\',0};
1919 VS_FIXEDFILEINFO *lpVer;
1920 WCHAR filever[0x100];
1926 TRACE("%s\n", debugstr_w(filename));
1928 versize = GetFileVersionInfoSizeW( filename, &handle );
1932 version = msi_alloc( versize );
1933 GetFileVersionInfoW( filename, 0, versize, version );
1935 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1937 msi_free( version );
1941 sprintfW( filever, name_fmt,
1942 HIWORD(lpVer->dwFileVersionMS),
1943 LOWORD(lpVer->dwFileVersionMS),
1944 HIWORD(lpVer->dwFileVersionLS),
1945 LOWORD(lpVer->dwFileVersionLS));
1947 msi_free( version );
1949 return strdupW( filever );
1952 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1954 LPWSTR file_version;
1957 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1959 MSICOMPONENT* comp = file->Component;
1965 if (file->IsCompressed)
1966 comp->ForceLocalState = TRUE;
1968 /* calculate target */
1969 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1971 msi_free(file->TargetPath);
1973 TRACE("file %s is named %s\n",
1974 debugstr_w(file->File), debugstr_w(file->FileName));
1976 file->TargetPath = build_directory_name(2, p, file->FileName);
1980 TRACE("file %s resolves to %s\n",
1981 debugstr_w(file->File), debugstr_w(file->TargetPath));
1983 /* don't check files of components that aren't installed */
1984 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1985 comp->Installed == INSTALLSTATE_ABSENT)
1987 file->state = msifs_missing; /* assume files are missing */
1991 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1993 file->state = msifs_missing;
1994 comp->Cost += file->FileSize;
1998 if (file->Version &&
1999 (file_version = msi_get_disk_file_version( file->TargetPath )))
2001 TRACE("new %s old %s\n", debugstr_w(file->Version),
2002 debugstr_w(file_version));
2003 /* FIXME: seems like a bad way to compare version numbers */
2004 if (lstrcmpiW(file_version, file->Version)<0)
2006 file->state = msifs_overwrite;
2007 comp->Cost += file->FileSize;
2010 file->state = msifs_present;
2011 msi_free( file_version );
2014 file->state = msifs_present;
2017 return ERROR_SUCCESS;
2021 * A lot is done in this function aside from just the costing.
2022 * The costing needs to be implemented at some point but for now I am going
2023 * to focus on the directory building
2026 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2028 static const WCHAR ExecSeqQuery[] =
2029 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2030 '`','D','i','r','e','c','t','o','r','y','`',0};
2031 static const WCHAR ConditionQuery[] =
2032 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2033 '`','C','o','n','d','i','t','i','o','n','`',0};
2034 static const WCHAR szCosting[] =
2035 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2036 static const WCHAR szlevel[] =
2037 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2038 static const WCHAR szOutOfDiskSpace[] =
2039 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2041 UINT rc = ERROR_SUCCESS;
2045 TRACE("Building Directory properties\n");
2047 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2048 if (rc == ERROR_SUCCESS)
2050 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2052 msiobj_release(&view->hdr);
2055 /* read components states from the registry */
2056 ACTION_GetComponentInstallStates(package);
2057 ACTION_GetFeatureInstallStates(package);
2059 TRACE("File calculations\n");
2060 msi_check_file_install_states( package );
2062 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2064 TRACE("Evaluating Condition Table\n");
2066 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2067 if (rc == ERROR_SUCCESS)
2069 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2070 msiobj_release( &view->hdr );
2073 TRACE("Enabling or Disabling Components\n");
2074 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2076 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2078 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2079 comp->Enabled = FALSE;
2082 comp->Enabled = TRUE;
2086 MSI_SetPropertyW(package,szCosting,szOne);
2087 /* set default run level if not set */
2088 level = msi_dup_property( package, szlevel );
2090 MSI_SetPropertyW(package,szlevel, szOne);
2093 /* FIXME: check volume disk space */
2094 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2096 return MSI_SetFeatureStates(package);
2099 /* OK this value is "interpreted" and then formatted based on the
2100 first few characters */
2101 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2106 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2112 LPWSTR deformated = NULL;
2115 deformat_string(package, &value[2], &deformated);
2117 /* binary value type */
2121 *size = (strlenW(ptr)/2)+1;
2123 *size = strlenW(ptr)/2;
2125 data = msi_alloc(*size);
2131 /* if uneven pad with a zero in front */
2137 data[count] = (BYTE)strtol(byte,NULL,0);
2139 TRACE("Uneven byte count\n");
2147 data[count] = (BYTE)strtol(byte,NULL,0);
2150 msi_free(deformated);
2152 TRACE("Data %i bytes(%i)\n",*size,count);
2159 deformat_string(package, &value[1], &deformated);
2162 *size = sizeof(DWORD);
2163 data = msi_alloc(*size);
2169 if ( (*p < '0') || (*p > '9') )
2175 if (deformated[0] == '-')
2178 TRACE("DWORD %i\n",*(LPDWORD)data);
2180 msi_free(deformated);
2185 static const WCHAR szMulti[] = {'[','~',']',0};
2194 *type=REG_EXPAND_SZ;
2202 if (strstrW(value,szMulti))
2203 *type = REG_MULTI_SZ;
2205 /* remove initial delimiter */
2206 if (!strncmpW(value, szMulti, 3))
2209 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2211 /* add double NULL terminator */
2212 if (*type == REG_MULTI_SZ)
2214 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2215 data = msi_realloc_zero(data, *size);
2221 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2228 if (msi_get_property_int( package, szAllUsers, 0 ))
2230 *root_key = HKEY_LOCAL_MACHINE;
2235 *root_key = HKEY_CURRENT_USER;
2240 *root_key = HKEY_CLASSES_ROOT;
2244 *root_key = HKEY_CURRENT_USER;
2248 *root_key = HKEY_LOCAL_MACHINE;
2252 *root_key = HKEY_USERS;
2256 ERR("Unknown root %i\n", root);
2263 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2265 MSIPACKAGE *package = param;
2266 LPSTR value_data = NULL;
2267 HKEY root_key, hkey;
2270 LPCWSTR szRoot, component, name, key, value;
2275 BOOL check_first = FALSE;
2278 ui_progress(package,2,0,0,0);
2285 component = MSI_RecordGetString(row, 6);
2286 comp = get_loaded_component(package,component);
2288 return ERROR_SUCCESS;
2290 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2292 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2293 comp->Action = comp->Installed;
2294 return ERROR_SUCCESS;
2296 comp->Action = INSTALLSTATE_LOCAL;
2298 name = MSI_RecordGetString(row, 4);
2299 if( MSI_RecordIsNull(row,5) && name )
2301 /* null values can have special meanings */
2302 if (name[0]=='-' && name[1] == 0)
2303 return ERROR_SUCCESS;
2304 else if ((name[0]=='+' && name[1] == 0) ||
2305 (name[0] == '*' && name[1] == 0))
2310 root = MSI_RecordGetInteger(row,2);
2311 key = MSI_RecordGetString(row, 3);
2313 szRoot = get_root_key( package, root, &root_key );
2315 return ERROR_SUCCESS;
2317 deformat_string(package, key , &deformated);
2318 size = strlenW(deformated) + strlenW(szRoot) + 1;
2319 uikey = msi_alloc(size*sizeof(WCHAR));
2320 strcpyW(uikey,szRoot);
2321 strcatW(uikey,deformated);
2323 if (RegCreateKeyW( root_key, deformated, &hkey))
2325 ERR("Could not create key %s\n",debugstr_w(deformated));
2326 msi_free(deformated);
2328 return ERROR_SUCCESS;
2330 msi_free(deformated);
2332 value = MSI_RecordGetString(row,5);
2334 value_data = parse_value(package, value, &type, &size);
2337 value_data = (LPSTR)strdupW(szEmpty);
2338 size = sizeof(szEmpty);
2342 deformat_string(package, name, &deformated);
2346 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2348 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2353 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2354 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2356 TRACE("value %s of %s checked already exists\n",
2357 debugstr_w(deformated), debugstr_w(uikey));
2361 TRACE("Checked and setting value %s of %s\n",
2362 debugstr_w(deformated), debugstr_w(uikey));
2363 if (deformated || size)
2364 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2369 uirow = MSI_CreateRecord(3);
2370 MSI_RecordSetStringW(uirow,2,deformated);
2371 MSI_RecordSetStringW(uirow,1,uikey);
2374 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2376 MSI_RecordSetStringW(uirow,3,value);
2378 ui_actiondata(package,szWriteRegistryValues,uirow);
2379 msiobj_release( &uirow->hdr );
2381 msi_free(value_data);
2382 msi_free(deformated);
2385 return ERROR_SUCCESS;
2388 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2392 static const WCHAR ExecSeqQuery[] =
2393 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2394 '`','R','e','g','i','s','t','r','y','`',0 };
2396 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2397 if (rc != ERROR_SUCCESS)
2398 return ERROR_SUCCESS;
2400 /* increment progress bar each time action data is sent */
2401 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2403 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2405 msiobj_release(&view->hdr);
2409 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2413 DWORD num_subkeys, num_values;
2417 if ((res = RegDeleteTreeW( hkey_root, key )))
2419 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2424 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2426 if ((res = RegDeleteValueW( hkey, value )))
2428 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2430 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2431 NULL, NULL, NULL, NULL );
2432 RegCloseKey( hkey );
2434 if (!res && !num_subkeys && !num_values)
2436 TRACE("Removing empty key %s\n", debugstr_w(key));
2437 RegDeleteKeyW( hkey_root, key );
2441 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2445 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2447 MSIPACKAGE *package = param;
2448 LPCWSTR component, name, key_str, root_key_str;
2449 LPWSTR deformated_key, deformated_name, ui_key_str;
2452 BOOL delete_key = FALSE;
2457 ui_progress( package, 2, 0, 0, 0 );
2459 component = MSI_RecordGetString( row, 6 );
2460 comp = get_loaded_component( package, component );
2462 return ERROR_SUCCESS;
2464 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2466 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2467 comp->Action = comp->Installed;
2468 return ERROR_SUCCESS;
2470 comp->Action = INSTALLSTATE_ABSENT;
2472 name = MSI_RecordGetString( row, 4 );
2473 if (MSI_RecordIsNull( row, 5 ) && name )
2475 if (name[0] == '+' && !name[1])
2476 return ERROR_SUCCESS;
2477 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2484 root = MSI_RecordGetInteger( row, 2 );
2485 key_str = MSI_RecordGetString( row, 3 );
2487 root_key_str = get_root_key( package, root, &hkey_root );
2489 return ERROR_SUCCESS;
2491 deformat_string( package, key_str, &deformated_key );
2492 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2493 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2494 strcpyW( ui_key_str, root_key_str );
2495 strcatW( ui_key_str, deformated_key );
2497 deformat_string( package, name, &deformated_name );
2499 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2500 msi_free( deformated_key );
2502 uirow = MSI_CreateRecord( 2 );
2503 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2504 MSI_RecordSetStringW( uirow, 2, deformated_name );
2506 ui_actiondata( package, szRemoveRegistryValues, uirow );
2507 msiobj_release( &uirow->hdr );
2509 msi_free( ui_key_str );
2510 msi_free( deformated_name );
2511 return ERROR_SUCCESS;
2514 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2516 MSIPACKAGE *package = param;
2517 LPCWSTR component, name, key_str, root_key_str;
2518 LPWSTR deformated_key, deformated_name, ui_key_str;
2521 BOOL delete_key = FALSE;
2526 ui_progress( package, 2, 0, 0, 0 );
2528 component = MSI_RecordGetString( row, 5 );
2529 comp = get_loaded_component( package, component );
2531 return ERROR_SUCCESS;
2533 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2535 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2536 comp->Action = comp->Installed;
2537 return ERROR_SUCCESS;
2539 comp->Action = INSTALLSTATE_LOCAL;
2541 if ((name = MSI_RecordGetString( row, 4 )))
2543 if (name[0] == '-' && !name[1])
2550 root = MSI_RecordGetInteger( row, 2 );
2551 key_str = MSI_RecordGetString( row, 3 );
2553 root_key_str = get_root_key( package, root, &hkey_root );
2555 return ERROR_SUCCESS;
2557 deformat_string( package, key_str, &deformated_key );
2558 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2559 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2560 strcpyW( ui_key_str, root_key_str );
2561 strcatW( ui_key_str, deformated_key );
2563 deformat_string( package, name, &deformated_name );
2565 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2566 msi_free( deformated_key );
2568 uirow = MSI_CreateRecord( 2 );
2569 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2570 MSI_RecordSetStringW( uirow, 2, deformated_name );
2572 ui_actiondata( package, szRemoveRegistryValues, uirow );
2573 msiobj_release( &uirow->hdr );
2575 msi_free( ui_key_str );
2576 msi_free( deformated_name );
2577 return ERROR_SUCCESS;
2580 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2584 static const WCHAR registry_query[] =
2585 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2586 '`','R','e','g','i','s','t','r','y','`',0 };
2587 static const WCHAR remove_registry_query[] =
2588 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2589 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2591 /* increment progress bar each time action data is sent */
2592 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2594 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2595 if (rc == ERROR_SUCCESS)
2597 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2598 msiobj_release( &view->hdr );
2599 if (rc != ERROR_SUCCESS)
2603 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2604 if (rc == ERROR_SUCCESS)
2606 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2607 msiobj_release( &view->hdr );
2608 if (rc != ERROR_SUCCESS)
2612 return ERROR_SUCCESS;
2615 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2617 package->script->CurrentlyScripting = TRUE;
2619 return ERROR_SUCCESS;
2623 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2628 static const WCHAR q1[]=
2629 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2630 '`','R','e','g','i','s','t','r','y','`',0};
2633 MSIFEATURE *feature;
2636 TRACE("InstallValidate\n");
2638 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2639 if (rc == ERROR_SUCCESS)
2641 MSI_IterateRecords( view, &progress, NULL, package );
2642 msiobj_release( &view->hdr );
2643 total += progress * REG_PROGRESS_VALUE;
2646 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2647 total += COMPONENT_PROGRESS_VALUE;
2649 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2650 total += file->FileSize;
2652 ui_progress(package,0,total,0,0);
2654 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2656 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2657 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2658 feature->ActionRequest);
2661 return ERROR_SUCCESS;
2664 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2666 MSIPACKAGE* package = param;
2667 LPCWSTR cond = NULL;
2668 LPCWSTR message = NULL;
2671 static const WCHAR title[]=
2672 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2674 cond = MSI_RecordGetString(row,1);
2676 r = MSI_EvaluateConditionW(package,cond);
2677 if (r == MSICONDITION_FALSE)
2679 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2682 message = MSI_RecordGetString(row,2);
2683 deformat_string(package,message,&deformated);
2684 MessageBoxW(NULL,deformated,title,MB_OK);
2685 msi_free(deformated);
2688 return ERROR_INSTALL_FAILURE;
2691 return ERROR_SUCCESS;
2694 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2697 MSIQUERY * view = NULL;
2698 static const WCHAR ExecSeqQuery[] =
2699 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2700 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2702 TRACE("Checking launch conditions\n");
2704 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2705 if (rc != ERROR_SUCCESS)
2706 return ERROR_SUCCESS;
2708 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2709 msiobj_release(&view->hdr);
2714 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2718 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2720 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2722 MSIRECORD * row = 0;
2724 LPWSTR deformated,buffer,deformated_name;
2726 static const WCHAR ExecSeqQuery[] =
2727 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2728 '`','R','e','g','i','s','t','r','y','`',' ',
2729 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2730 ' ','=',' ' ,'\'','%','s','\'',0 };
2731 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2732 static const WCHAR fmt2[]=
2733 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2735 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2739 root = MSI_RecordGetInteger(row,2);
2740 key = MSI_RecordGetString(row, 3);
2741 name = MSI_RecordGetString(row, 4);
2742 deformat_string(package, key , &deformated);
2743 deformat_string(package, name, &deformated_name);
2745 len = strlenW(deformated) + 6;
2746 if (deformated_name)
2747 len+=strlenW(deformated_name);
2749 buffer = msi_alloc( len *sizeof(WCHAR));
2751 if (deformated_name)
2752 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2754 sprintfW(buffer,fmt,root,deformated);
2756 msi_free(deformated);
2757 msi_free(deformated_name);
2758 msiobj_release(&row->hdr);
2762 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2764 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2769 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2772 return strdupW( file->TargetPath );
2777 static HKEY openSharedDLLsKey(void)
2780 static const WCHAR path[] =
2781 {'S','o','f','t','w','a','r','e','\\',
2782 'M','i','c','r','o','s','o','f','t','\\',
2783 'W','i','n','d','o','w','s','\\',
2784 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2785 'S','h','a','r','e','d','D','L','L','s',0};
2787 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2791 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2796 DWORD sz = sizeof(count);
2799 hkey = openSharedDLLsKey();
2800 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2801 if (rc != ERROR_SUCCESS)
2807 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2811 hkey = openSharedDLLsKey();
2813 msi_reg_set_val_dword( hkey, path, count );
2815 RegDeleteValueW(hkey,path);
2821 * Return TRUE if the count should be written out and FALSE if not
2823 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2825 MSIFEATURE *feature;
2829 /* only refcount DLLs */
2830 if (comp->KeyPath == NULL ||
2831 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2832 comp->Attributes & msidbComponentAttributesODBCDataSource)
2836 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2837 write = (count > 0);
2839 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2843 /* increment counts */
2844 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2848 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2851 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2853 if ( cl->component == comp )
2858 /* decrement counts */
2859 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2863 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2866 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2868 if ( cl->component == comp )
2873 /* ref count all the files in the component */
2878 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2880 if (file->Component == comp)
2881 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2885 /* add a count for permanent */
2886 if (comp->Attributes & msidbComponentAttributesPermanent)
2889 comp->RefCount = count;
2892 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2895 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2897 WCHAR squished_pc[GUID_SIZE];
2898 WCHAR squished_cc[GUID_SIZE];
2905 squash_guid(package->ProductCode,squished_pc);
2906 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2908 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2912 ui_progress(package,2,0,0,0);
2913 if (!comp->ComponentId)
2916 squash_guid(comp->ComponentId,squished_cc);
2918 msi_free(comp->FullKeypath);
2919 comp->FullKeypath = resolve_keypath( package, comp );
2921 ACTION_RefCountComponent( package, comp );
2923 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2924 debugstr_w(comp->Component),
2925 debugstr_w(squished_cc),
2926 debugstr_w(comp->FullKeypath),
2929 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2930 comp->ActionRequest == INSTALLSTATE_SOURCE)
2932 if (!comp->FullKeypath)
2935 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2936 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2939 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2942 if (rc != ERROR_SUCCESS)
2945 if (comp->Attributes & msidbComponentAttributesPermanent)
2947 static const WCHAR szPermKey[] =
2948 { '0','0','0','0','0','0','0','0','0','0','0','0',
2949 '0','0','0','0','0','0','0','0','0','0','0','0',
2950 '0','0','0','0','0','0','0','0',0 };
2952 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2955 if (comp->Action == INSTALLSTATE_LOCAL)
2956 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2962 WCHAR source[MAX_PATH];
2963 WCHAR base[MAX_PATH];
2966 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2967 static const WCHAR query[] = {
2968 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2969 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2970 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2971 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2972 '`','D','i','s','k','I','d','`',0};
2974 file = get_loaded_file(package, comp->KeyPath);
2978 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2979 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2980 ptr2 = strrchrW(source, '\\') + 1;
2981 msiobj_release(&row->hdr);
2983 lstrcpyW(base, package->PackagePath);
2984 ptr = strrchrW(base, '\\');
2987 sourcepath = resolve_file_source(package, file);
2988 ptr = sourcepath + lstrlenW(base);
2989 lstrcpyW(ptr2, ptr);
2990 msi_free(sourcepath);
2992 msi_reg_set_val_str(hkey, squished_pc, source);
2996 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2998 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2999 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3001 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3005 uirow = MSI_CreateRecord(3);
3006 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3007 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3008 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3009 ui_actiondata(package,szProcessComponents,uirow);
3010 msiobj_release( &uirow->hdr );
3013 return ERROR_SUCCESS;
3024 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3025 LPWSTR lpszName, LONG_PTR lParam)
3028 typelib_struct *tl_struct = (typelib_struct*) lParam;
3029 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3033 if (!IS_INTRESOURCE(lpszName))
3035 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3039 sz = strlenW(tl_struct->source)+4;
3040 sz *= sizeof(WCHAR);
3042 if ((INT_PTR)lpszName == 1)
3043 tl_struct->path = strdupW(tl_struct->source);
3046 tl_struct->path = msi_alloc(sz);
3047 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3050 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3051 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3054 msi_free(tl_struct->path);
3055 tl_struct->path = NULL;
3060 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3061 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3063 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3067 msi_free(tl_struct->path);
3068 tl_struct->path = NULL;
3070 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3071 ITypeLib_Release(tl_struct->ptLib);
3076 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3078 MSIPACKAGE* package = param;
3082 typelib_struct tl_struct;
3087 component = MSI_RecordGetString(row,3);
3088 comp = get_loaded_component(package,component);
3090 return ERROR_SUCCESS;
3092 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3094 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3095 comp->Action = comp->Installed;
3096 return ERROR_SUCCESS;
3098 comp->Action = INSTALLSTATE_LOCAL;
3100 file = get_loaded_file( package, comp->KeyPath );
3102 return ERROR_SUCCESS;
3104 ui_actiondata( package, szRegisterTypeLibraries, row );
3106 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3110 guid = MSI_RecordGetString(row,1);
3111 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3112 tl_struct.source = strdupW( file->TargetPath );
3113 tl_struct.path = NULL;
3115 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3116 (LONG_PTR)&tl_struct);
3124 helpid = MSI_RecordGetString(row,6);
3127 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3128 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3132 ERR("Failed to register type library %s\n",
3133 debugstr_w(tl_struct.path));
3135 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3137 ITypeLib_Release(tl_struct.ptLib);
3138 msi_free(tl_struct.path);
3141 ERR("Failed to load type library %s\n",
3142 debugstr_w(tl_struct.source));
3144 FreeLibrary(module);
3145 msi_free(tl_struct.source);
3149 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3152 ERR("Failed to load type library: %08x\n", hr);
3153 return ERROR_INSTALL_FAILURE;
3156 ITypeLib_Release(tlib);
3159 return ERROR_SUCCESS;
3162 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3165 * OK this is a bit confusing.. I am given a _Component key and I believe
3166 * that the file that is being registered as a type library is the "key file
3167 * of that component" which I interpret to mean "The file in the KeyPath of
3172 static const WCHAR Query[] =
3173 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3174 '`','T','y','p','e','L','i','b','`',0};
3176 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3177 if (rc != ERROR_SUCCESS)
3178 return ERROR_SUCCESS;
3180 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3181 msiobj_release(&view->hdr);
3185 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3187 MSIPACKAGE *package = param;
3188 LPCWSTR component, guid;
3196 component = MSI_RecordGetString( row, 3 );
3197 comp = get_loaded_component( package, component );
3199 return ERROR_SUCCESS;
3201 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3203 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3204 comp->Action = comp->Installed;
3205 return ERROR_SUCCESS;
3207 comp->Action = INSTALLSTATE_ABSENT;
3209 ui_actiondata( package, szUnregisterTypeLibraries, row );
3211 guid = MSI_RecordGetString( row, 1 );
3212 CLSIDFromString( (LPWSTR)guid, &libid );
3213 version = MSI_RecordGetInteger( row, 4 );
3214 language = MSI_RecordGetInteger( row, 2 );
3217 syskind = SYS_WIN64;
3219 syskind = SYS_WIN32;
3222 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3225 WARN("Failed to unregister typelib: %08x\n", hr);
3228 return ERROR_SUCCESS;
3231 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3235 static const WCHAR query[] =
3236 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3237 '`','T','y','p','e','L','i','b','`',0};
3239 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3240 if (rc != ERROR_SUCCESS)
3241 return ERROR_SUCCESS;
3243 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3244 msiobj_release( &view->hdr );
3248 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3250 static const WCHAR szlnk[] = {'.','l','n','k',0};
3251 LPCWSTR directory, extension;
3252 LPWSTR link_folder, link_file, filename;
3254 directory = MSI_RecordGetString( row, 2 );
3255 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3257 /* may be needed because of a bug somewhere else */
3258 create_full_pathW( link_folder );
3260 filename = msi_dup_record_field( row, 3 );
3261 reduce_to_longfilename( filename );
3263 extension = strchrW( filename, '.' );
3264 if (!extension || strcmpiW( extension, szlnk ))
3266 int len = strlenW( filename );
3267 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3268 memcpy( filename + len, szlnk, sizeof(szlnk) );
3270 link_file = build_directory_name( 2, link_folder, filename );
3271 msi_free( link_folder );
3272 msi_free( filename );
3277 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3279 MSIPACKAGE *package = param;
3280 LPWSTR link_file, deformated, path;
3281 LPCWSTR component, target;
3283 IShellLinkW *sl = NULL;
3284 IPersistFile *pf = NULL;
3287 component = MSI_RecordGetString(row, 4);
3288 comp = get_loaded_component(package, component);
3290 return ERROR_SUCCESS;
3292 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3294 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3295 comp->Action = comp->Installed;
3296 return ERROR_SUCCESS;
3298 comp->Action = INSTALLSTATE_LOCAL;
3300 ui_actiondata(package,szCreateShortcuts,row);
3302 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3303 &IID_IShellLinkW, (LPVOID *) &sl );
3307 ERR("CLSID_ShellLink not available\n");
3311 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3314 ERR("QueryInterface(IID_IPersistFile) failed\n");
3318 target = MSI_RecordGetString(row, 5);
3319 if (strchrW(target, '['))
3321 deformat_string(package, target, &deformated);
3322 IShellLinkW_SetPath(sl,deformated);
3323 msi_free(deformated);
3327 FIXME("poorly handled shortcut format, advertised shortcut\n");
3328 IShellLinkW_SetPath(sl,comp->FullKeypath);
3331 if (!MSI_RecordIsNull(row,6))
3333 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3334 deformat_string(package, arguments, &deformated);
3335 IShellLinkW_SetArguments(sl,deformated);
3336 msi_free(deformated);
3339 if (!MSI_RecordIsNull(row,7))
3341 LPCWSTR description = MSI_RecordGetString(row, 7);
3342 IShellLinkW_SetDescription(sl, description);
3345 if (!MSI_RecordIsNull(row,8))
3346 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3348 if (!MSI_RecordIsNull(row,9))
3351 LPCWSTR icon = MSI_RecordGetString(row, 9);
3353 path = build_icon_path(package, icon);
3354 index = MSI_RecordGetInteger(row,10);
3356 /* no value means 0 */
3357 if (index == MSI_NULL_INTEGER)
3360 IShellLinkW_SetIconLocation(sl, path, index);
3364 if (!MSI_RecordIsNull(row,11))
3365 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3367 if (!MSI_RecordIsNull(row,12))
3369 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3370 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3372 IShellLinkW_SetWorkingDirectory(sl, path);
3376 link_file = get_link_file(package, row);
3378 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3379 IPersistFile_Save(pf, link_file, FALSE);
3381 msi_free(link_file);
3385 IPersistFile_Release( pf );
3387 IShellLinkW_Release( sl );
3389 return ERROR_SUCCESS;
3392 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3397 static const WCHAR Query[] =
3398 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3399 '`','S','h','o','r','t','c','u','t','`',0};
3401 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3402 if (rc != ERROR_SUCCESS)
3403 return ERROR_SUCCESS;
3405 res = CoInitialize( NULL );
3407 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3408 msiobj_release(&view->hdr);
3416 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3418 MSIPACKAGE *package = param;
3423 component = MSI_RecordGetString( row, 4 );
3424 comp = get_loaded_component( package, component );
3426 return ERROR_SUCCESS;
3428 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3430 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3431 comp->Action = comp->Installed;
3432 return ERROR_SUCCESS;
3434 comp->Action = INSTALLSTATE_ABSENT;
3436 ui_actiondata( package, szRemoveShortcuts, row );
3438 link_file = get_link_file( package, row );
3440 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3441 if (!DeleteFileW( link_file ))
3443 WARN("Failed to remove shortcut file %u\n", GetLastError());
3445 msi_free( link_file );
3447 return ERROR_SUCCESS;
3450 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3454 static const WCHAR query[] =
3455 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3456 '`','S','h','o','r','t','c','u','t','`',0};
3458 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3459 if (rc != ERROR_SUCCESS)
3460 return ERROR_SUCCESS;
3462 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3463 msiobj_release( &view->hdr );
3468 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3470 MSIPACKAGE* package = param;
3479 FileName = MSI_RecordGetString(row,1);
3482 ERR("Unable to get FileName\n");
3483 return ERROR_SUCCESS;
3486 FilePath = build_icon_path(package,FileName);
3488 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3490 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3491 FILE_ATTRIBUTE_NORMAL, NULL);
3493 if (the_file == INVALID_HANDLE_VALUE)
3495 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3497 return ERROR_SUCCESS;
3504 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3505 if (rc != ERROR_SUCCESS)
3507 ERR("Failed to get stream\n");
3508 CloseHandle(the_file);
3509 DeleteFileW(FilePath);
3512 WriteFile(the_file,buffer,sz,&write,NULL);
3513 } while (sz == 1024);
3517 CloseHandle(the_file);
3519 uirow = MSI_CreateRecord(1);
3520 MSI_RecordSetStringW(uirow,1,FileName);
3521 ui_actiondata(package,szPublishProduct,uirow);
3522 msiobj_release( &uirow->hdr );
3524 return ERROR_SUCCESS;
3527 static UINT msi_publish_icons(MSIPACKAGE *package)
3532 static const WCHAR query[]= {
3533 'S','E','L','E','C','T',' ','*',' ',
3534 'F','R','O','M',' ','`','I','c','o','n','`',0};
3536 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3537 if (r == ERROR_SUCCESS)
3539 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3540 msiobj_release(&view->hdr);
3543 return ERROR_SUCCESS;
3546 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3552 MSISOURCELISTINFO *info;
3554 r = RegCreateKeyW(hkey, szSourceList, &source);
3555 if (r != ERROR_SUCCESS)
3558 RegCloseKey(source);
3560 buffer = strrchrW(package->PackagePath, '\\') + 1;
3561 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3562 package->Context, MSICODE_PRODUCT,
3563 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3564 if (r != ERROR_SUCCESS)
3567 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3568 package->Context, MSICODE_PRODUCT,
3569 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3570 if (r != ERROR_SUCCESS)
3573 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3574 package->Context, MSICODE_PRODUCT,
3575 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3576 if (r != ERROR_SUCCESS)
3579 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3581 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3582 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3583 info->options, info->value);
3585 MsiSourceListSetInfoW(package->ProductCode, NULL,
3586 info->context, info->options,
3587 info->property, info->value);
3590 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3592 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3593 disk->context, disk->options,
3594 disk->disk_id, disk->volume_label, disk->disk_prompt);
3597 return ERROR_SUCCESS;
3600 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3602 MSIHANDLE hdb, suminfo;
3603 WCHAR guids[MAX_PATH];
3604 WCHAR packcode[SQUISH_GUID_SIZE];
3611 static const WCHAR szProductLanguage[] =
3612 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3613 static const WCHAR szARPProductIcon[] =
3614 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3615 static const WCHAR szProductVersion[] =
3616 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3617 static const WCHAR szAssignment[] =
3618 {'A','s','s','i','g','n','m','e','n','t',0};
3619 static const WCHAR szAdvertiseFlags[] =
3620 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3621 static const WCHAR szClients[] =
3622 {'C','l','i','e','n','t','s',0};
3623 static const WCHAR szColon[] = {':',0};
3625 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3626 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3629 langid = msi_get_property_int(package, szProductLanguage, 0);
3630 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3633 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3635 buffer = msi_dup_property(package, szARPProductIcon);
3638 LPWSTR path = build_icon_path(package,buffer);
3639 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3644 buffer = msi_dup_property(package, szProductVersion);
3647 DWORD verdword = msi_version_str_to_dword(buffer);
3648 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3652 msi_reg_set_val_dword(hkey, szAssignment, 0);
3653 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3654 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3655 msi_reg_set_val_str(hkey, szClients, szColon);
3657 hdb = alloc_msihandle(&package->db->hdr);
3659 return ERROR_NOT_ENOUGH_MEMORY;
3661 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3662 MsiCloseHandle(hdb);
3663 if (r != ERROR_SUCCESS)
3667 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3668 NULL, guids, &size);
3669 if (r != ERROR_SUCCESS)
3672 ptr = strchrW(guids, ';');
3674 squash_guid(guids, packcode);
3675 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3678 MsiCloseHandle(suminfo);
3679 return ERROR_SUCCESS;
3682 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3687 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3689 static const WCHAR szUpgradeCode[] =
3690 {'U','p','g','r','a','d','e','C','o','d','e',0};
3692 upgrade = msi_dup_property(package, szUpgradeCode);
3694 return ERROR_SUCCESS;
3696 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3698 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3699 if (r != ERROR_SUCCESS)
3704 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3705 if (r != ERROR_SUCCESS)
3709 squash_guid(package->ProductCode, squashed_pc);
3710 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3719 static BOOL msi_check_publish(MSIPACKAGE *package)
3721 MSIFEATURE *feature;
3723 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3725 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3732 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3734 MSIFEATURE *feature;
3736 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3738 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3745 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3747 WCHAR patch_squashed[GUID_SIZE];
3750 UINT r = ERROR_FUNCTION_FAILED;
3752 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3754 if (res != ERROR_SUCCESS)
3755 return ERROR_FUNCTION_FAILED;
3757 squash_guid(package->patch->patchcode, patch_squashed);
3759 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3760 (const BYTE *)patch_squashed,
3761 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3762 if (res != ERROR_SUCCESS)
3765 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3766 (const BYTE *)package->patch->transforms,
3767 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3768 if (res == ERROR_SUCCESS)
3772 RegCloseKey(patches);
3777 * 99% of the work done here is only done for
3778 * advertised installs. However this is where the
3779 * Icon table is processed and written out
3780 * so that is what I am going to do here.
3782 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3788 /* FIXME: also need to publish if the product is in advertise mode */
3789 if (!msi_check_publish(package))
3790 return ERROR_SUCCESS;
3792 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3794 if (rc != ERROR_SUCCESS)
3797 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3798 NULL, &hudkey, TRUE);
3799 if (rc != ERROR_SUCCESS)
3802 rc = msi_publish_upgrade_code(package);
3803 if (rc != ERROR_SUCCESS)
3808 rc = msi_publish_patch(package, hukey, hudkey);
3809 if (rc != ERROR_SUCCESS)
3813 rc = msi_publish_product_properties(package, hukey);
3814 if (rc != ERROR_SUCCESS)
3817 rc = msi_publish_sourcelist(package, hukey);
3818 if (rc != ERROR_SUCCESS)
3821 rc = msi_publish_icons(package);
3825 RegCloseKey(hudkey);
3830 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3832 WCHAR *filename, *ptr, *folder, *ret;
3833 const WCHAR *dirprop;
3835 filename = msi_dup_record_field( row, 2 );
3836 if (filename && (ptr = strchrW( filename, '|' )))
3841 dirprop = MSI_RecordGetString( row, 3 );
3844 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3846 folder = msi_dup_property( package, dirprop );
3849 folder = msi_dup_property( package, szWindowsFolder );
3853 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3854 msi_free( filename );
3858 ret = build_directory_name( 2, folder, ptr );
3860 msi_free( filename );
3865 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3867 MSIPACKAGE *package = param;
3868 LPCWSTR component, section, key, value, identifier;
3869 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3874 component = MSI_RecordGetString(row, 8);
3875 comp = get_loaded_component(package,component);
3877 return ERROR_SUCCESS;
3879 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3881 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3882 comp->Action = comp->Installed;
3883 return ERROR_SUCCESS;
3885 comp->Action = INSTALLSTATE_LOCAL;
3887 identifier = MSI_RecordGetString(row,1);
3888 section = MSI_RecordGetString(row,4);
3889 key = MSI_RecordGetString(row,5);
3890 value = MSI_RecordGetString(row,6);
3891 action = MSI_RecordGetInteger(row,7);
3893 deformat_string(package,section,&deformated_section);
3894 deformat_string(package,key,&deformated_key);
3895 deformat_string(package,value,&deformated_value);
3897 fullname = get_ini_file_name(package, row);
3901 TRACE("Adding value %s to section %s in %s\n",
3902 debugstr_w(deformated_key), debugstr_w(deformated_section),
3903 debugstr_w(fullname));
3904 WritePrivateProfileStringW(deformated_section, deformated_key,
3905 deformated_value, fullname);
3907 else if (action == 1)
3910 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3911 returned, 10, fullname);
3912 if (returned[0] == 0)
3914 TRACE("Adding value %s to section %s in %s\n",
3915 debugstr_w(deformated_key), debugstr_w(deformated_section),
3916 debugstr_w(fullname));
3918 WritePrivateProfileStringW(deformated_section, deformated_key,
3919 deformated_value, fullname);
3922 else if (action == 3)
3923 FIXME("Append to existing section not yet implemented\n");
3925 uirow = MSI_CreateRecord(4);
3926 MSI_RecordSetStringW(uirow,1,identifier);
3927 MSI_RecordSetStringW(uirow,2,deformated_section);
3928 MSI_RecordSetStringW(uirow,3,deformated_key);
3929 MSI_RecordSetStringW(uirow,4,deformated_value);
3930 ui_actiondata(package,szWriteIniValues,uirow);
3931 msiobj_release( &uirow->hdr );
3934 msi_free(deformated_key);
3935 msi_free(deformated_value);
3936 msi_free(deformated_section);
3937 return ERROR_SUCCESS;
3940 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3944 static const WCHAR ExecSeqQuery[] =
3945 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3946 '`','I','n','i','F','i','l','e','`',0};
3948 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3949 if (rc != ERROR_SUCCESS)
3951 TRACE("no IniFile table\n");
3952 return ERROR_SUCCESS;
3955 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3956 msiobj_release(&view->hdr);
3960 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3962 MSIPACKAGE *package = param;
3963 LPCWSTR component, section, key, value, identifier;
3964 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3969 component = MSI_RecordGetString( row, 8 );
3970 comp = get_loaded_component( package, component );
3972 return ERROR_SUCCESS;
3974 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3976 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3977 comp->Action = comp->Installed;
3978 return ERROR_SUCCESS;
3980 comp->Action = INSTALLSTATE_ABSENT;
3982 identifier = MSI_RecordGetString( row, 1 );
3983 section = MSI_RecordGetString( row, 4 );
3984 key = MSI_RecordGetString( row, 5 );
3985 value = MSI_RecordGetString( row, 6 );
3986 action = MSI_RecordGetInteger( row, 7 );
3988 deformat_string( package, section, &deformated_section );
3989 deformat_string( package, key, &deformated_key );
3990 deformat_string( package, value, &deformated_value );
3992 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3994 filename = get_ini_file_name( package, row );
3996 TRACE("Removing key %s from section %s in %s\n",
3997 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3999 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4001 WARN("Unable to remove key %u\n", GetLastError());
4003 msi_free( filename );
4006 FIXME("Unsupported action %d\n", action);
4009 uirow = MSI_CreateRecord( 4 );
4010 MSI_RecordSetStringW( uirow, 1, identifier );
4011 MSI_RecordSetStringW( uirow, 2, deformated_section );
4012 MSI_RecordSetStringW( uirow, 3, deformated_key );
4013 MSI_RecordSetStringW( uirow, 4, deformated_value );
4014 ui_actiondata( package, szRemoveIniValues, uirow );
4015 msiobj_release( &uirow->hdr );
4017 msi_free( deformated_key );
4018 msi_free( deformated_value );
4019 msi_free( deformated_section );
4020 return ERROR_SUCCESS;
4023 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4025 MSIPACKAGE *package = param;
4026 LPCWSTR component, section, key, value, identifier;
4027 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4032 component = MSI_RecordGetString( row, 8 );
4033 comp = get_loaded_component( package, component );
4035 return ERROR_SUCCESS;
4037 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4039 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4040 comp->Action = comp->Installed;
4041 return ERROR_SUCCESS;
4043 comp->Action = INSTALLSTATE_LOCAL;
4045 identifier = MSI_RecordGetString( row, 1 );
4046 section = MSI_RecordGetString( row, 4 );
4047 key = MSI_RecordGetString( row, 5 );
4048 value = MSI_RecordGetString( row, 6 );
4049 action = MSI_RecordGetInteger( row, 7 );
4051 deformat_string( package, section, &deformated_section );
4052 deformat_string( package, key, &deformated_key );
4053 deformat_string( package, value, &deformated_value );
4055 if (action == msidbIniFileActionRemoveLine)
4057 filename = get_ini_file_name( package, row );
4059 TRACE("Removing key %s from section %s in %s\n",
4060 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4062 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4064 WARN("Unable to remove key %u\n", GetLastError());
4066 msi_free( filename );
4069 FIXME("Unsupported action %d\n", action);
4071 uirow = MSI_CreateRecord( 4 );
4072 MSI_RecordSetStringW( uirow, 1, identifier );
4073 MSI_RecordSetStringW( uirow, 2, deformated_section );
4074 MSI_RecordSetStringW( uirow, 3, deformated_key );
4075 MSI_RecordSetStringW( uirow, 4, deformated_value );
4076 ui_actiondata( package, szRemoveIniValues, uirow );
4077 msiobj_release( &uirow->hdr );
4079 msi_free( deformated_key );
4080 msi_free( deformated_value );
4081 msi_free( deformated_section );
4082 return ERROR_SUCCESS;
4085 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4089 static const WCHAR query[] =
4090 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4091 '`','I','n','i','F','i','l','e','`',0};
4092 static const WCHAR remove_query[] =
4093 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4094 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4096 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4097 if (rc == ERROR_SUCCESS)
4099 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4100 msiobj_release( &view->hdr );
4101 if (rc != ERROR_SUCCESS)
4105 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4106 if (rc == ERROR_SUCCESS)
4108 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4109 msiobj_release( &view->hdr );
4110 if (rc != ERROR_SUCCESS)
4114 return ERROR_SUCCESS;
4117 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4119 MSIPACKAGE *package = param;
4124 static const WCHAR ExeStr[] =
4125 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4126 static const WCHAR close[] = {'\"',0};
4128 PROCESS_INFORMATION info;
4133 memset(&si,0,sizeof(STARTUPINFOW));
4135 filename = MSI_RecordGetString(row,1);
4136 file = get_loaded_file( package, filename );
4140 ERR("Unable to find file id %s\n",debugstr_w(filename));
4141 return ERROR_SUCCESS;
4144 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4146 FullName = msi_alloc(len*sizeof(WCHAR));
4147 strcpyW(FullName,ExeStr);
4148 strcatW( FullName, file->TargetPath );
4149 strcatW(FullName,close);
4151 TRACE("Registering %s\n",debugstr_w(FullName));
4152 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4157 CloseHandle(info.hThread);
4158 msi_dialog_check_messages(info.hProcess);
4159 CloseHandle(info.hProcess);
4165 uirow = MSI_CreateRecord( 2 );
4166 uipath = strdupW( file->TargetPath );
4167 p = strrchrW(uipath,'\\');
4170 MSI_RecordSetStringW( uirow, 1, &p[1] );
4171 MSI_RecordSetStringW( uirow, 2, uipath);
4172 ui_actiondata( package, szSelfRegModules, uirow);
4173 msiobj_release( &uirow->hdr );
4175 /* FIXME: call ui_progress? */
4177 return ERROR_SUCCESS;
4180 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4184 static const WCHAR ExecSeqQuery[] =
4185 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4186 '`','S','e','l','f','R','e','g','`',0};
4188 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4189 if (rc != ERROR_SUCCESS)
4191 TRACE("no SelfReg table\n");
4192 return ERROR_SUCCESS;
4195 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4196 msiobj_release(&view->hdr);
4198 return ERROR_SUCCESS;
4201 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4203 static const WCHAR regsvr32[] =
4204 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4205 static const WCHAR close[] = {'\"',0};
4206 MSIPACKAGE *package = param;
4212 PROCESS_INFORMATION pi;
4217 memset( &si, 0, sizeof(STARTUPINFOW) );
4219 filename = MSI_RecordGetString( row, 1 );
4220 file = get_loaded_file( package, filename );
4224 ERR("Unable to find file id %s\n", debugstr_w(filename));
4225 return ERROR_SUCCESS;
4228 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4230 cmdline = msi_alloc( len * sizeof(WCHAR) );
4231 strcpyW( cmdline, regsvr32 );
4232 strcatW( cmdline, file->TargetPath );
4233 strcatW( cmdline, close );
4235 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4237 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4240 CloseHandle( pi.hThread );
4241 msi_dialog_check_messages( pi.hProcess );
4242 CloseHandle( pi.hProcess );
4245 msi_free( cmdline );
4247 uirow = MSI_CreateRecord( 2 );
4248 uipath = strdupW( file->TargetPath );
4249 if ((p = strrchrW( uipath, '\\' )))
4252 MSI_RecordSetStringW( uirow, 1, ++p );
4254 MSI_RecordSetStringW( uirow, 2, uipath );
4255 ui_actiondata( package, szSelfUnregModules, uirow );
4256 msiobj_release( &uirow->hdr );
4258 /* FIXME call ui_progress? */
4260 return ERROR_SUCCESS;
4263 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4267 static const WCHAR query[] =
4268 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4269 '`','S','e','l','f','R','e','g','`',0};
4271 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4272 if (rc != ERROR_SUCCESS)
4274 TRACE("no SelfReg table\n");
4275 return ERROR_SUCCESS;
4278 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4279 msiobj_release( &view->hdr );
4281 return ERROR_SUCCESS;
4284 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4286 MSIFEATURE *feature;
4288 HKEY hkey = NULL, userdata = NULL;
4290 if (!msi_check_publish(package))
4291 return ERROR_SUCCESS;
4293 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4295 if (rc != ERROR_SUCCESS)
4298 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4300 if (rc != ERROR_SUCCESS)
4303 /* here the guids are base 85 encoded */
4304 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4310 BOOL absent = FALSE;
4313 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4314 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4315 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4318 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4322 if (feature->Feature_Parent)
4323 size += strlenW( feature->Feature_Parent )+2;
4325 data = msi_alloc(size * sizeof(WCHAR));
4328 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4330 MSICOMPONENT* component = cl->component;
4334 if (component->ComponentId)
4336 TRACE("From %s\n",debugstr_w(component->ComponentId));
4337 CLSIDFromString(component->ComponentId, &clsid);
4338 encode_base85_guid(&clsid,buf);
4339 TRACE("to %s\n",debugstr_w(buf));
4344 if (feature->Feature_Parent)
4346 static const WCHAR sep[] = {'\2',0};
4348 strcatW(data,feature->Feature_Parent);
4351 msi_reg_set_val_str( userdata, feature->Feature, data );
4355 if (feature->Feature_Parent)
4356 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4359 size += sizeof(WCHAR);
4360 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4361 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4365 size += 2*sizeof(WCHAR);
4366 data = msi_alloc(size);
4369 if (feature->Feature_Parent)
4370 strcpyW( &data[1], feature->Feature_Parent );
4371 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4377 uirow = MSI_CreateRecord( 1 );
4378 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4379 ui_actiondata( package, szPublishFeatures, uirow);
4380 msiobj_release( &uirow->hdr );
4381 /* FIXME: call ui_progress? */
4386 RegCloseKey(userdata);
4390 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4395 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4397 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4399 if (r == ERROR_SUCCESS)
4401 RegDeleteValueW(hkey, feature->Feature);
4405 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4407 if (r == ERROR_SUCCESS)
4409 RegDeleteValueW(hkey, feature->Feature);
4413 return ERROR_SUCCESS;
4416 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4418 MSIFEATURE *feature;
4420 if (!msi_check_unpublish(package))
4421 return ERROR_SUCCESS;
4423 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4425 msi_unpublish_feature(package, feature);
4428 return ERROR_SUCCESS;
4431 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4433 LPWSTR prop, val, key;
4439 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4440 static const WCHAR szWindowsInstaller[] =
4441 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4442 static const WCHAR modpath_fmt[] =
4443 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4444 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4445 static const WCHAR szModifyPath[] =
4446 {'M','o','d','i','f','y','P','a','t','h',0};
4447 static const WCHAR szUninstallString[] =
4448 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4449 static const WCHAR szEstimatedSize[] =
4450 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4451 static const WCHAR szProductLanguage[] =
4452 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4453 static const WCHAR szProductVersion[] =
4454 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4455 static const WCHAR szProductName[] =
4456 {'P','r','o','d','u','c','t','N','a','m','e',0};
4457 static const WCHAR szDisplayName[] =
4458 {'D','i','s','p','l','a','y','N','a','m','e',0};
4459 static const WCHAR szDisplayVersion[] =
4460 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4461 static const WCHAR szManufacturer[] =
4462 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4464 static const LPCSTR propval[] = {
4465 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4466 "ARPCONTACT", "Contact",
4467 "ARPCOMMENTS", "Comments",
4468 "ProductName", "DisplayName",
4469 "ProductVersion", "DisplayVersion",
4470 "ARPHELPLINK", "HelpLink",
4471 "ARPHELPTELEPHONE", "HelpTelephone",
4472 "ARPINSTALLLOCATION", "InstallLocation",
4473 "SourceDir", "InstallSource",
4474 "Manufacturer", "Publisher",
4475 "ARPREADME", "Readme",
4477 "ARPURLINFOABOUT", "URLInfoAbout",
4478 "ARPURLUPDATEINFO", "URLUpdateInfo",
4481 const LPCSTR *p = propval;
4485 prop = strdupAtoW(*p++);
4486 key = strdupAtoW(*p++);
4487 val = msi_dup_property(package, prop);
4488 msi_reg_set_val_str(hkey, key, val);
4494 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4496 size = deformat_string(package, modpath_fmt, &buffer);
4497 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4498 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4501 /* FIXME: Write real Estimated Size when we have it */
4502 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4504 buffer = msi_dup_property(package, szProductName);
4505 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4508 buffer = msi_dup_property(package, cszSourceDir);
4509 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4512 buffer = msi_dup_property(package, szManufacturer);
4513 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4516 GetLocalTime(&systime);
4517 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4518 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4520 langid = msi_get_property_int(package, szProductLanguage, 0);
4521 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4523 buffer = msi_dup_property(package, szProductVersion);
4524 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4527 DWORD verdword = msi_version_str_to_dword(buffer);
4529 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4530 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4531 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4535 return ERROR_SUCCESS;
4538 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4540 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4541 LPWSTR upgrade_code;
4546 static const WCHAR szUpgradeCode[] = {
4547 'U','p','g','r','a','d','e','C','o','d','e',0};
4549 /* FIXME: also need to publish if the product is in advertise mode */
4550 if (!msi_check_publish(package))
4551 return ERROR_SUCCESS;
4553 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4554 if (rc != ERROR_SUCCESS)
4557 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4558 NULL, &props, TRUE);
4559 if (rc != ERROR_SUCCESS)
4562 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4563 msi_free( package->db->localfile );
4564 package->db->localfile = NULL;
4566 rc = msi_publish_install_properties(package, hkey);
4567 if (rc != ERROR_SUCCESS)
4570 rc = msi_publish_install_properties(package, props);
4571 if (rc != ERROR_SUCCESS)
4574 upgrade_code = msi_dup_property(package, szUpgradeCode);
4577 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4578 squash_guid(package->ProductCode, squashed_pc);
4579 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4580 RegCloseKey(upgrade);
4581 msi_free(upgrade_code);
4587 return ERROR_SUCCESS;
4590 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4592 return execute_script(package,INSTALL_SCRIPT);
4595 static UINT msi_unpublish_product(MSIPACKAGE *package)
4598 LPWSTR remove = NULL;
4599 LPWSTR *features = NULL;
4600 BOOL full_uninstall = TRUE;
4601 MSIFEATURE *feature;
4603 static const WCHAR szUpgradeCode[] =
4604 {'U','p','g','r','a','d','e','C','o','d','e',0};
4606 remove = msi_dup_property(package, szRemove);
4608 return ERROR_SUCCESS;
4610 features = msi_split_string(remove, ',');
4614 ERR("REMOVE feature list is empty!\n");
4615 return ERROR_FUNCTION_FAILED;
4618 if (!lstrcmpW(features[0], szAll))
4619 full_uninstall = TRUE;
4622 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4624 if (feature->Action != INSTALLSTATE_ABSENT)
4625 full_uninstall = FALSE;
4629 if (!full_uninstall)
4632 MSIREG_DeleteProductKey(package->ProductCode);
4633 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4634 MSIREG_DeleteUninstallKey(package->ProductCode);
4636 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4638 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4639 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4643 MSIREG_DeleteUserProductKey(package->ProductCode);
4644 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4647 upgrade = msi_dup_property(package, szUpgradeCode);
4650 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4657 return ERROR_SUCCESS;
4660 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4664 rc = msi_unpublish_product(package);
4665 if (rc != ERROR_SUCCESS)
4668 /* turn off scheduling */
4669 package->script->CurrentlyScripting= FALSE;
4671 /* first do the same as an InstallExecute */
4672 rc = ACTION_InstallExecute(package);
4673 if (rc != ERROR_SUCCESS)
4676 /* then handle Commit Actions */
4677 rc = execute_script(package,COMMIT_SCRIPT);
4682 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4684 static const WCHAR RunOnce[] = {
4685 'S','o','f','t','w','a','r','e','\\',
4686 'M','i','c','r','o','s','o','f','t','\\',
4687 'W','i','n','d','o','w','s','\\',
4688 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4689 'R','u','n','O','n','c','e',0};
4690 static const WCHAR InstallRunOnce[] = {
4691 'S','o','f','t','w','a','r','e','\\',
4692 'M','i','c','r','o','s','o','f','t','\\',
4693 'W','i','n','d','o','w','s','\\',
4694 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4695 'I','n','s','t','a','l','l','e','r','\\',
4696 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4698 static const WCHAR msiexec_fmt[] = {
4700 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4701 '\"','%','s','\"',0};
4702 static const WCHAR install_fmt[] = {
4703 '/','I',' ','\"','%','s','\"',' ',
4704 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4705 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4706 WCHAR buffer[256], sysdir[MAX_PATH];
4708 WCHAR squished_pc[100];
4710 squash_guid(package->ProductCode,squished_pc);
4712 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4713 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4714 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4717 msi_reg_set_val_str( hkey, squished_pc, buffer );
4720 TRACE("Reboot command %s\n",debugstr_w(buffer));
4722 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4723 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4725 msi_reg_set_val_str( hkey, squished_pc, buffer );
4728 return ERROR_INSTALL_SUSPEND;
4731 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4737 * We are currently doing what should be done here in the top level Install
4738 * however for Administrative and uninstalls this step will be needed
4740 if (!package->PackagePath)
4741 return ERROR_SUCCESS;
4743 msi_set_sourcedir_props(package, TRUE);
4745 attrib = GetFileAttributesW(package->db->path);
4746 if (attrib == INVALID_FILE_ATTRIBUTES)
4752 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4753 package->Context, MSICODE_PRODUCT,
4754 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4755 if (rc == ERROR_MORE_DATA)
4757 prompt = msi_alloc(size * sizeof(WCHAR));
4758 MsiSourceListGetInfoW(package->ProductCode, NULL,
4759 package->Context, MSICODE_PRODUCT,
4760 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4763 prompt = strdupW(package->db->path);
4765 msg = generate_error_string(package,1302,1,prompt);
4766 while(attrib == INVALID_FILE_ATTRIBUTES)
4768 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4771 rc = ERROR_INSTALL_USEREXIT;
4774 attrib = GetFileAttributesW(package->db->path);
4780 return ERROR_SUCCESS;
4785 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4792 static const WCHAR szPropKeys[][80] =
4794 {'P','r','o','d','u','c','t','I','D',0},
4795 {'U','S','E','R','N','A','M','E',0},
4796 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4800 static const WCHAR szRegKeys[][80] =
4802 {'P','r','o','d','u','c','t','I','D',0},
4803 {'R','e','g','O','w','n','e','r',0},
4804 {'R','e','g','C','o','m','p','a','n','y',0},
4808 if (msi_check_unpublish(package))
4810 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4811 return ERROR_SUCCESS;
4814 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4816 return ERROR_SUCCESS;
4818 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4820 if (rc != ERROR_SUCCESS)
4823 for( i = 0; szPropKeys[i][0]; i++ )
4825 buffer = msi_dup_property( package, szPropKeys[i] );
4826 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4831 msi_free(productid);
4834 /* FIXME: call ui_actiondata */
4840 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4844 package->script->InWhatSequence |= SEQUENCE_EXEC;
4845 rc = ACTION_ProcessExecSequence(package,FALSE);
4850 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4852 MSIPACKAGE *package = param;
4853 LPCWSTR compgroupid, component, feature, qualifier, text;
4854 LPWSTR advertise = NULL, output = NULL;
4862 feature = MSI_RecordGetString(rec, 5);
4863 feat = get_loaded_feature(package, feature);
4865 return ERROR_SUCCESS;
4867 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4868 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4869 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4871 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4872 feat->Action = feat->Installed;
4873 return ERROR_SUCCESS;
4876 component = MSI_RecordGetString(rec, 3);
4877 comp = get_loaded_component(package, component);
4879 return ERROR_SUCCESS;
4881 compgroupid = MSI_RecordGetString(rec,1);
4882 qualifier = MSI_RecordGetString(rec,2);
4884 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4885 if (rc != ERROR_SUCCESS)
4888 text = MSI_RecordGetString(rec,4);
4889 advertise = create_component_advertise_string(package, comp, feature);
4891 sz = strlenW(advertise);
4894 sz += lstrlenW(text);
4897 sz *= sizeof(WCHAR);
4899 output = msi_alloc_zero(sz);
4900 strcpyW(output,advertise);
4901 msi_free(advertise);
4904 strcatW(output,text);
4906 msi_reg_set_val_multi_str( hkey, qualifier, output );
4913 uirow = MSI_CreateRecord( 2 );
4914 MSI_RecordSetStringW( uirow, 1, compgroupid );
4915 MSI_RecordSetStringW( uirow, 2, qualifier);
4916 ui_actiondata( package, szPublishComponents, uirow);
4917 msiobj_release( &uirow->hdr );
4918 /* FIXME: call ui_progress? */
4924 * At present I am ignorning the advertised components part of this and only
4925 * focusing on the qualified component sets
4927 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4931 static const WCHAR ExecSeqQuery[] =
4932 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4933 '`','P','u','b','l','i','s','h',
4934 'C','o','m','p','o','n','e','n','t','`',0};
4936 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4937 if (rc != ERROR_SUCCESS)
4938 return ERROR_SUCCESS;
4940 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4941 msiobj_release(&view->hdr);
4946 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4948 static const WCHAR szInstallerComponents[] = {
4949 'S','o','f','t','w','a','r','e','\\',
4950 'M','i','c','r','o','s','o','f','t','\\',
4951 'I','n','s','t','a','l','l','e','r','\\',
4952 'C','o','m','p','o','n','e','n','t','s','\\',0};
4954 MSIPACKAGE *package = param;
4955 LPCWSTR compgroupid, component, feature, qualifier;
4959 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4962 feature = MSI_RecordGetString( rec, 5 );
4963 feat = get_loaded_feature( package, feature );
4965 return ERROR_SUCCESS;
4967 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4969 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4970 feat->Action = feat->Installed;
4971 return ERROR_SUCCESS;
4974 component = MSI_RecordGetString( rec, 3 );
4975 comp = get_loaded_component( package, component );
4977 return ERROR_SUCCESS;
4979 compgroupid = MSI_RecordGetString( rec, 1 );
4980 qualifier = MSI_RecordGetString( rec, 2 );
4982 squash_guid( compgroupid, squashed );
4983 strcpyW( keypath, szInstallerComponents );
4984 strcatW( keypath, squashed );
4986 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4987 if (res != ERROR_SUCCESS)
4989 WARN("Unable to delete component key %d\n", res);
4992 uirow = MSI_CreateRecord( 2 );
4993 MSI_RecordSetStringW( uirow, 1, compgroupid );
4994 MSI_RecordSetStringW( uirow, 2, qualifier );
4995 ui_actiondata( package, szUnpublishComponents, uirow );
4996 msiobj_release( &uirow->hdr );
4998 return ERROR_SUCCESS;
5001 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5005 static const WCHAR query[] =
5006 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5007 '`','P','u','b','l','i','s','h',
5008 'C','o','m','p','o','n','e','n','t','`',0};
5010 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5011 if (rc != ERROR_SUCCESS)
5012 return ERROR_SUCCESS;
5014 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5015 msiobj_release( &view->hdr );
5020 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5022 MSIPACKAGE *package = param;
5025 SC_HANDLE hscm, service = NULL;
5026 LPCWSTR comp, depends, pass;
5027 LPWSTR name = NULL, disp = NULL;
5028 LPCWSTR load_order, serv_name, key;
5029 DWORD serv_type, start_type;
5032 static const WCHAR query[] =
5033 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5034 '`','C','o','m','p','o','n','e','n','t','`',' ',
5035 'W','H','E','R','E',' ',
5036 '`','C','o','m','p','o','n','e','n','t','`',' ',
5037 '=','\'','%','s','\'',0};
5039 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5042 ERR("Failed to open the SC Manager!\n");
5046 start_type = MSI_RecordGetInteger(rec, 5);
5047 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5050 depends = MSI_RecordGetString(rec, 8);
5051 if (depends && *depends)
5052 FIXME("Dependency list unhandled!\n");
5054 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5055 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5056 serv_type = MSI_RecordGetInteger(rec, 4);
5057 err_control = MSI_RecordGetInteger(rec, 6);
5058 load_order = MSI_RecordGetString(rec, 7);
5059 serv_name = MSI_RecordGetString(rec, 9);
5060 pass = MSI_RecordGetString(rec, 10);
5061 comp = MSI_RecordGetString(rec, 12);
5063 /* fetch the service path */
5064 row = MSI_QueryGetRecord(package->db, query, comp);
5067 ERR("Control query failed!\n");
5071 key = MSI_RecordGetString(row, 6);
5073 file = get_loaded_file(package, key);
5074 msiobj_release(&row->hdr);
5077 ERR("Failed to load the service file\n");
5081 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5082 start_type, err_control, file->TargetPath,
5083 load_order, NULL, NULL, serv_name, pass);
5086 if (GetLastError() != ERROR_SERVICE_EXISTS)
5087 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5091 CloseServiceHandle(service);
5092 CloseServiceHandle(hscm);
5096 return ERROR_SUCCESS;
5099 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5103 static const WCHAR ExecSeqQuery[] =
5104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5105 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5107 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5108 if (rc != ERROR_SUCCESS)
5109 return ERROR_SUCCESS;
5111 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5112 msiobj_release(&view->hdr);
5117 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5118 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5120 LPCWSTR *vector, *temp_vector;
5124 static const WCHAR separator[] = {'[','~',']',0};
5127 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5132 vector = msi_alloc(sizeof(LPWSTR));
5140 vector[*numargs - 1] = p;
5142 if ((q = strstrW(p, separator)))
5146 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5152 vector = temp_vector;
5161 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5163 MSIPACKAGE *package = param;
5165 SC_HANDLE scm = NULL, service = NULL;
5166 LPCWSTR component, *vector = NULL;
5168 DWORD event, numargs;
5169 UINT r = ERROR_FUNCTION_FAILED;
5171 component = MSI_RecordGetString(rec, 6);
5172 comp = get_loaded_component(package, component);
5174 return ERROR_SUCCESS;
5176 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5178 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5179 comp->Action = comp->Installed;
5180 return ERROR_SUCCESS;
5182 comp->Action = INSTALLSTATE_LOCAL;
5184 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5185 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5186 event = MSI_RecordGetInteger(rec, 3);
5188 if (!(event & msidbServiceControlEventStart))
5194 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5197 ERR("Failed to open the service control manager\n");
5201 service = OpenServiceW(scm, name, SERVICE_START);
5204 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5208 vector = msi_service_args_to_vector(args, &numargs);
5210 if (!StartServiceW(service, numargs, vector) &&
5211 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5213 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5220 CloseServiceHandle(service);
5221 CloseServiceHandle(scm);
5229 static UINT ACTION_StartServices( MSIPACKAGE *package )
5234 static const WCHAR query[] = {
5235 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5236 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5238 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5239 if (rc != ERROR_SUCCESS)
5240 return ERROR_SUCCESS;
5242 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5243 msiobj_release(&view->hdr);
5248 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5250 DWORD i, needed, count;
5251 ENUM_SERVICE_STATUSW *dependencies;
5255 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5256 0, &needed, &count))
5259 if (GetLastError() != ERROR_MORE_DATA)
5262 dependencies = msi_alloc(needed);
5266 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5267 needed, &needed, &count))
5270 for (i = 0; i < count; i++)
5272 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5273 SERVICE_STOP | SERVICE_QUERY_STATUS);
5277 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5284 msi_free(dependencies);
5288 static UINT stop_service( LPCWSTR name )
5290 SC_HANDLE scm = NULL, service = NULL;
5291 SERVICE_STATUS status;
5292 SERVICE_STATUS_PROCESS ssp;
5295 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5298 WARN("Failed to open the SCM: %d\n", GetLastError());
5302 service = OpenServiceW(scm, name,
5304 SERVICE_QUERY_STATUS |
5305 SERVICE_ENUMERATE_DEPENDENTS);
5308 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5312 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5313 sizeof(SERVICE_STATUS_PROCESS), &needed))
5315 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5319 if (ssp.dwCurrentState == SERVICE_STOPPED)
5322 stop_service_dependents(scm, service);
5324 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5325 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5328 CloseServiceHandle(service);
5329 CloseServiceHandle(scm);
5331 return ERROR_SUCCESS;
5334 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5336 MSIPACKAGE *package = param;
5342 event = MSI_RecordGetInteger( rec, 3 );
5343 if (!(event & msidbServiceControlEventStop))
5344 return ERROR_SUCCESS;
5346 component = MSI_RecordGetString( rec, 6 );
5347 comp = get_loaded_component( package, component );
5349 return ERROR_SUCCESS;
5351 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5353 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5354 comp->Action = comp->Installed;
5355 return ERROR_SUCCESS;
5357 comp->Action = INSTALLSTATE_ABSENT;
5359 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5360 stop_service( name );
5363 return ERROR_SUCCESS;
5366 static UINT ACTION_StopServices( MSIPACKAGE *package )
5371 static const WCHAR query[] = {
5372 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5373 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5375 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5376 if (rc != ERROR_SUCCESS)
5377 return ERROR_SUCCESS;
5379 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5380 msiobj_release(&view->hdr);
5385 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5387 MSIPACKAGE *package = param;
5392 SC_HANDLE scm = NULL, service = NULL;
5394 event = MSI_RecordGetInteger( rec, 3 );
5395 if (!(event & msidbServiceControlEventDelete))
5396 return ERROR_SUCCESS;
5398 component = MSI_RecordGetString(rec, 6);
5399 comp = get_loaded_component(package, component);
5401 return ERROR_SUCCESS;
5403 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5405 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5406 comp->Action = comp->Installed;
5407 return ERROR_SUCCESS;
5409 comp->Action = INSTALLSTATE_ABSENT;
5411 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5412 stop_service( name );
5414 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5417 WARN("Failed to open the SCM: %d\n", GetLastError());
5421 service = OpenServiceW( scm, name, DELETE );
5424 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5428 if (!DeleteService( service ))
5429 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5432 CloseServiceHandle( service );
5433 CloseServiceHandle( scm );
5436 return ERROR_SUCCESS;
5439 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5444 static const WCHAR query[] = {
5445 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5446 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5448 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5449 if (rc != ERROR_SUCCESS)
5450 return ERROR_SUCCESS;
5452 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5453 msiobj_release( &view->hdr );
5458 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5462 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5464 if (!lstrcmpW(file->File, filename))
5471 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5473 MSIPACKAGE *package = param;
5474 LPWSTR driver, driver_path, ptr;
5475 WCHAR outpath[MAX_PATH];
5476 MSIFILE *driver_file, *setup_file;
5479 UINT r = ERROR_SUCCESS;
5481 static const WCHAR driver_fmt[] = {
5482 'D','r','i','v','e','r','=','%','s',0};
5483 static const WCHAR setup_fmt[] = {
5484 'S','e','t','u','p','=','%','s',0};
5485 static const WCHAR usage_fmt[] = {
5486 'F','i','l','e','U','s','a','g','e','=','1',0};
5488 desc = MSI_RecordGetString(rec, 3);
5490 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5491 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5495 ERR("ODBC Driver entry not found!\n");
5496 return ERROR_FUNCTION_FAILED;
5499 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5501 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5502 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5504 driver = msi_alloc(len * sizeof(WCHAR));
5506 return ERROR_OUTOFMEMORY;
5509 lstrcpyW(ptr, desc);
5510 ptr += lstrlenW(ptr) + 1;
5512 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5517 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5521 lstrcpyW(ptr, usage_fmt);
5522 ptr += lstrlenW(ptr) + 1;
5525 driver_path = strdupW(driver_file->TargetPath);
5526 ptr = strrchrW(driver_path, '\\');
5527 if (ptr) *ptr = '\0';
5529 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5530 NULL, ODBC_INSTALL_COMPLETE, &usage))
5532 ERR("Failed to install SQL driver!\n");
5533 r = ERROR_FUNCTION_FAILED;
5537 msi_free(driver_path);
5542 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5544 MSIPACKAGE *package = param;
5545 LPWSTR translator, translator_path, ptr;
5546 WCHAR outpath[MAX_PATH];
5547 MSIFILE *translator_file, *setup_file;
5550 UINT r = ERROR_SUCCESS;
5552 static const WCHAR translator_fmt[] = {
5553 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5554 static const WCHAR setup_fmt[] = {
5555 'S','e','t','u','p','=','%','s',0};
5557 desc = MSI_RecordGetString(rec, 3);
5559 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5560 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5562 if (!translator_file)
5564 ERR("ODBC Translator entry not found!\n");
5565 return ERROR_FUNCTION_FAILED;
5568 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5570 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5572 translator = msi_alloc(len * sizeof(WCHAR));
5574 return ERROR_OUTOFMEMORY;
5577 lstrcpyW(ptr, desc);
5578 ptr += lstrlenW(ptr) + 1;
5580 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5585 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5590 translator_path = strdupW(translator_file->TargetPath);
5591 ptr = strrchrW(translator_path, '\\');
5592 if (ptr) *ptr = '\0';
5594 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5595 NULL, ODBC_INSTALL_COMPLETE, &usage))
5597 ERR("Failed to install SQL translator!\n");
5598 r = ERROR_FUNCTION_FAILED;
5601 msi_free(translator);
5602 msi_free(translator_path);
5607 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5610 LPCWSTR desc, driver;
5611 WORD request = ODBC_ADD_SYS_DSN;
5614 UINT r = ERROR_SUCCESS;
5616 static const WCHAR attrs_fmt[] = {
5617 'D','S','N','=','%','s',0 };
5619 desc = MSI_RecordGetString(rec, 3);
5620 driver = MSI_RecordGetString(rec, 4);
5621 registration = MSI_RecordGetInteger(rec, 5);
5623 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5624 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5626 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5627 attrs = msi_alloc(len * sizeof(WCHAR));
5629 return ERROR_OUTOFMEMORY;
5631 len = sprintfW(attrs, attrs_fmt, desc);
5634 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5636 ERR("Failed to install SQL data source!\n");
5637 r = ERROR_FUNCTION_FAILED;
5645 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5650 static const WCHAR driver_query[] = {
5651 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5652 'O','D','B','C','D','r','i','v','e','r',0 };
5654 static const WCHAR translator_query[] = {
5655 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5656 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5658 static const WCHAR source_query[] = {
5659 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5660 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5662 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5663 if (rc != ERROR_SUCCESS)
5664 return ERROR_SUCCESS;
5666 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5667 msiobj_release(&view->hdr);
5669 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5670 if (rc != ERROR_SUCCESS)
5671 return ERROR_SUCCESS;
5673 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5674 msiobj_release(&view->hdr);
5676 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5677 if (rc != ERROR_SUCCESS)
5678 return ERROR_SUCCESS;
5680 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5681 msiobj_release(&view->hdr);
5686 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5691 desc = MSI_RecordGetString( rec, 3 );
5692 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5694 WARN("Failed to remove ODBC driver\n");
5698 FIXME("Usage count reached 0\n");
5701 return ERROR_SUCCESS;
5704 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5709 desc = MSI_RecordGetString( rec, 3 );
5710 if (!SQLRemoveTranslatorW( desc, &usage ))
5712 WARN("Failed to remove ODBC translator\n");
5716 FIXME("Usage count reached 0\n");
5719 return ERROR_SUCCESS;
5722 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5725 LPCWSTR desc, driver;
5726 WORD request = ODBC_REMOVE_SYS_DSN;
5730 static const WCHAR attrs_fmt[] = {
5731 'D','S','N','=','%','s',0 };
5733 desc = MSI_RecordGetString( rec, 3 );
5734 driver = MSI_RecordGetString( rec, 4 );
5735 registration = MSI_RecordGetInteger( rec, 5 );
5737 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5738 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5740 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5741 attrs = msi_alloc( len * sizeof(WCHAR) );
5743 return ERROR_OUTOFMEMORY;
5745 FIXME("Use ODBCSourceAttribute table\n");
5747 len = sprintfW( attrs, attrs_fmt, desc );
5750 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5752 WARN("Failed to remove ODBC data source\n");
5756 return ERROR_SUCCESS;
5759 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5764 static const WCHAR driver_query[] = {
5765 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5766 'O','D','B','C','D','r','i','v','e','r',0 };
5768 static const WCHAR translator_query[] = {
5769 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5770 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5772 static const WCHAR source_query[] = {
5773 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5774 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5776 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5777 if (rc != ERROR_SUCCESS)
5778 return ERROR_SUCCESS;
5780 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5781 msiobj_release( &view->hdr );
5783 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5784 if (rc != ERROR_SUCCESS)
5785 return ERROR_SUCCESS;
5787 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5788 msiobj_release( &view->hdr );
5790 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5791 if (rc != ERROR_SUCCESS)
5792 return ERROR_SUCCESS;
5794 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5795 msiobj_release( &view->hdr );
5800 #define ENV_ACT_SETALWAYS 0x1
5801 #define ENV_ACT_SETABSENT 0x2
5802 #define ENV_ACT_REMOVE 0x4
5803 #define ENV_ACT_REMOVEMATCH 0x8
5805 #define ENV_MOD_MACHINE 0x20000000
5806 #define ENV_MOD_APPEND 0x40000000
5807 #define ENV_MOD_PREFIX 0x80000000
5808 #define ENV_MOD_MASK 0xC0000000
5810 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5812 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5814 LPCWSTR cptr = *name;
5816 static const WCHAR prefix[] = {'[','~',']',0};
5817 static const int prefix_len = 3;
5823 *flags |= ENV_ACT_SETALWAYS;
5824 else if (*cptr == '+')
5825 *flags |= ENV_ACT_SETABSENT;
5826 else if (*cptr == '-')
5827 *flags |= ENV_ACT_REMOVE;
5828 else if (*cptr == '!')
5829 *flags |= ENV_ACT_REMOVEMATCH;
5830 else if (*cptr == '*')
5831 *flags |= ENV_MOD_MACHINE;
5841 ERR("Missing environment variable\n");
5842 return ERROR_FUNCTION_FAILED;
5847 LPCWSTR ptr = *value;
5848 if (!strncmpW(ptr, prefix, prefix_len))
5850 if (ptr[prefix_len] == szSemiColon[0])
5852 *flags |= ENV_MOD_APPEND;
5853 *value += lstrlenW(prefix);
5860 else if (lstrlenW(*value) >= prefix_len)
5862 ptr += lstrlenW(ptr) - prefix_len;
5863 if (!lstrcmpW(ptr, prefix))
5865 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5867 *flags |= ENV_MOD_PREFIX;
5868 /* the "[~]" will be removed by deformat_string */;
5878 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5879 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5880 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5881 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5883 ERR("Invalid flags: %08x\n", *flags);
5884 return ERROR_FUNCTION_FAILED;
5888 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5890 return ERROR_SUCCESS;
5893 static UINT open_env_key( DWORD flags, HKEY *key )
5895 static const WCHAR user_env[] =
5896 {'E','n','v','i','r','o','n','m','e','n','t',0};
5897 static const WCHAR machine_env[] =
5898 {'S','y','s','t','e','m','\\',
5899 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5900 'C','o','n','t','r','o','l','\\',
5901 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5902 'E','n','v','i','r','o','n','m','e','n','t',0};
5907 if (flags & ENV_MOD_MACHINE)
5910 root = HKEY_LOCAL_MACHINE;
5915 root = HKEY_CURRENT_USER;
5918 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
5919 if (res != ERROR_SUCCESS)
5921 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
5922 return ERROR_FUNCTION_FAILED;
5925 return ERROR_SUCCESS;
5928 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5930 MSIPACKAGE *package = param;
5931 LPCWSTR name, value, component;
5932 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
5933 DWORD flags, type, size;
5940 component = MSI_RecordGetString(rec, 4);
5941 comp = get_loaded_component(package, component);
5943 return ERROR_SUCCESS;
5945 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5947 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5948 comp->Action = comp->Installed;
5949 return ERROR_SUCCESS;
5951 comp->Action = INSTALLSTATE_LOCAL;
5953 name = MSI_RecordGetString(rec, 2);
5954 value = MSI_RecordGetString(rec, 3);
5956 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
5958 res = env_parse_flags(&name, &value, &flags);
5959 if (res != ERROR_SUCCESS || !value)
5962 if (value && !deformat_string(package, value, &deformatted))
5964 res = ERROR_OUTOFMEMORY;
5968 value = deformatted;
5970 res = open_env_key( flags, &env );
5971 if (res != ERROR_SUCCESS)
5974 if (flags & ENV_MOD_MACHINE)
5975 action |= 0x20000000;
5979 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5980 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5981 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5984 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
5988 /* Nothing to do. */
5991 res = ERROR_SUCCESS;
5995 /* If we are appending but the string was empty, strip ; */
5996 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
5998 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5999 newval = strdupW(value);
6002 res = ERROR_OUTOFMEMORY;
6010 /* Contrary to MSDN, +-variable to [~];path works */
6011 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6013 res = ERROR_SUCCESS;
6017 data = msi_alloc(size);
6021 return ERROR_OUTOFMEMORY;
6024 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6025 if (res != ERROR_SUCCESS)
6028 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6031 res = RegDeleteValueW(env, name);
6032 if (res != ERROR_SUCCESS)
6033 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6037 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6038 if (flags & ENV_MOD_MASK)
6042 if (flags & ENV_MOD_APPEND) multiplier++;
6043 if (flags & ENV_MOD_PREFIX) multiplier++;
6044 mod_size = lstrlenW(value) * multiplier;
6045 size += mod_size * sizeof(WCHAR);
6048 newval = msi_alloc(size);
6052 res = ERROR_OUTOFMEMORY;
6056 if (flags & ENV_MOD_PREFIX)
6058 lstrcpyW(newval, value);
6059 ptr = newval + lstrlenW(value);
6060 action |= 0x80000000;
6063 lstrcpyW(ptr, data);
6065 if (flags & ENV_MOD_APPEND)
6067 lstrcatW(newval, value);
6068 action |= 0x40000000;
6071 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6072 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6075 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6079 uirow = MSI_CreateRecord( 3 );
6080 MSI_RecordSetStringW( uirow, 1, name );
6081 MSI_RecordSetStringW( uirow, 2, newval );
6082 MSI_RecordSetInteger( uirow, 3, action );
6083 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6084 msiobj_release( &uirow->hdr );
6086 if (env) RegCloseKey(env);
6087 msi_free(deformatted);
6093 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6097 static const WCHAR ExecSeqQuery[] =
6098 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6099 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6100 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6101 if (rc != ERROR_SUCCESS)
6102 return ERROR_SUCCESS;
6104 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6105 msiobj_release(&view->hdr);
6110 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6112 MSIPACKAGE *package = param;
6113 LPCWSTR name, value, component;
6114 LPWSTR deformatted = NULL;
6123 component = MSI_RecordGetString( rec, 4 );
6124 comp = get_loaded_component( package, component );
6126 return ERROR_SUCCESS;
6128 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6130 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6131 comp->Action = comp->Installed;
6132 return ERROR_SUCCESS;
6134 comp->Action = INSTALLSTATE_ABSENT;
6136 name = MSI_RecordGetString( rec, 2 );
6137 value = MSI_RecordGetString( rec, 3 );
6139 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6141 r = env_parse_flags( &name, &value, &flags );
6142 if (r != ERROR_SUCCESS)
6145 if (!(flags & ENV_ACT_REMOVE))
6147 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6148 return ERROR_SUCCESS;
6151 if (value && !deformat_string( package, value, &deformatted ))
6152 return ERROR_OUTOFMEMORY;
6154 value = deformatted;
6156 r = open_env_key( flags, &env );
6157 if (r != ERROR_SUCCESS)
6163 if (flags & ENV_MOD_MACHINE)
6164 action |= 0x20000000;
6166 TRACE("Removing %s\n", debugstr_w(name));
6168 res = RegDeleteValueW( env, name );
6169 if (res != ERROR_SUCCESS)
6171 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6176 uirow = MSI_CreateRecord( 3 );
6177 MSI_RecordSetStringW( uirow, 1, name );
6178 MSI_RecordSetStringW( uirow, 2, value );
6179 MSI_RecordSetInteger( uirow, 3, action );
6180 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6181 msiobj_release( &uirow->hdr );
6183 if (env) RegCloseKey( env );
6184 msi_free( deformatted );
6188 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6192 static const WCHAR query[] =
6193 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6194 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6196 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6197 if (rc != ERROR_SUCCESS)
6198 return ERROR_SUCCESS;
6200 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6201 msiobj_release( &view->hdr );
6206 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
6217 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
6221 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
6222 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
6224 WARN("Source or dest is directory, not moving\n");
6228 if (options == msidbMoveFileOptionsMove)
6230 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
6231 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
6234 WARN("MoveFile failed: %d\n", GetLastError());
6240 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
6241 ret = CopyFileW(source, dest, FALSE);
6244 WARN("CopyFile failed: %d\n", GetLastError());
6252 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
6255 DWORD dirlen, pathlen;
6257 ptr = strrchrW(wildcard, '\\');
6258 dirlen = ptr - wildcard + 1;
6260 pathlen = dirlen + lstrlenW(filename) + 1;
6261 path = msi_alloc(pathlen * sizeof(WCHAR));
6263 lstrcpynW(path, wildcard, dirlen + 1);
6264 lstrcatW(path, filename);
6269 static void free_file_entry(FILE_LIST *file)
6271 msi_free(file->source);
6272 msi_free(file->dest);
6276 static void free_list(FILE_LIST *list)
6278 while (!list_empty(&list->entry))
6280 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
6282 list_remove(&file->entry);
6283 free_file_entry(file);
6287 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
6289 FILE_LIST *new, *file;
6290 LPWSTR ptr, filename;
6293 new = msi_alloc_zero(sizeof(FILE_LIST));
6297 new->source = strdupW(source);
6298 ptr = strrchrW(dest, '\\') + 1;
6299 filename = strrchrW(new->source, '\\') + 1;
6301 new->sourcename = filename;
6304 new->destname = ptr;
6306 new->destname = new->sourcename;
6308 size = (ptr - dest) + lstrlenW(filename) + 1;
6309 new->dest = msi_alloc(size * sizeof(WCHAR));
6312 free_file_entry(new);
6316 lstrcpynW(new->dest, dest, ptr - dest + 1);
6317 lstrcatW(new->dest, filename);
6319 if (list_empty(&files->entry))
6321 list_add_head(&files->entry, &new->entry);
6325 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
6327 if (lstrcmpW(source, file->source) < 0)
6329 list_add_before(&file->entry, &new->entry);
6334 list_add_after(&file->entry, &new->entry);
6338 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
6340 WIN32_FIND_DATAW wfd;
6344 FILE_LIST files, *file;
6347 hfile = FindFirstFileW(source, &wfd);
6348 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
6350 list_init(&files.entry);
6352 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
6354 if (is_dot_dir(wfd.cFileName)) continue;
6356 path = wildcard_to_file(source, wfd.cFileName);
6363 add_wildcard(&files, path, dest);
6367 /* no files match the wildcard */
6368 if (list_empty(&files.entry))
6371 /* only the first wildcard match gets renamed to dest */
6372 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
6373 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
6374 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
6381 /* file->dest may be shorter after the reallocation, so add a NULL
6382 * terminator. This is needed for the call to strrchrW, as there will no
6383 * longer be a NULL terminator within the bounds of the allocation in this case.
6385 file->dest[size - 1] = '\0';
6386 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
6388 while (!list_empty(&files.entry))
6390 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
6392 msi_move_file(file->source, file->dest, options);
6394 list_remove(&file->entry);
6395 free_file_entry(file);
6406 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
6408 MSIPACKAGE *package = param;
6410 LPCWSTR sourcename, component;
6411 LPWSTR destname = NULL;
6412 LPWSTR sourcedir = NULL, destdir = NULL;
6413 LPWSTR source = NULL, dest = NULL;
6416 BOOL ret, wildcards;
6418 component = MSI_RecordGetString(rec, 2);
6419 comp = get_loaded_component(package, component);
6421 return ERROR_SUCCESS;
6423 if (comp->ActionRequest != INSTALLSTATE_LOCAL && comp->ActionRequest != INSTALLSTATE_SOURCE)
6425 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6426 comp->Action = comp->Installed;
6427 return ERROR_SUCCESS;
6429 comp->Action = comp->ActionRequest;
6431 sourcename = MSI_RecordGetString(rec, 3);
6432 options = MSI_RecordGetInteger(rec, 7);
6434 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
6438 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
6444 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
6447 source = strdupW(sourcedir);
6453 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
6454 source = msi_alloc(size * sizeof(WCHAR));
6458 lstrcpyW(source, sourcedir);
6459 if (source[lstrlenW(source) - 1] != '\\')
6460 lstrcatW(source, szBackSlash);
6461 lstrcatW(source, sourcename);
6464 wildcards = strchrW(source, '*') || strchrW(source, '?');
6466 if (MSI_RecordIsNull(rec, 4))
6470 destname = strdupW(sourcename);
6477 destname = strdupW(MSI_RecordGetString(rec, 4));
6479 reduce_to_longfilename(destname);
6484 size = lstrlenW(destname);
6486 size += lstrlenW(destdir) + 2;
6487 dest = msi_alloc(size * sizeof(WCHAR));
6491 lstrcpyW(dest, destdir);
6492 if (dest[lstrlenW(dest) - 1] != '\\')
6493 lstrcatW(dest, szBackSlash);
6496 lstrcatW(dest, destname);
6498 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
6500 ret = CreateDirectoryW(destdir, NULL);
6503 WARN("CreateDirectory failed: %d\n", GetLastError());
6504 return ERROR_SUCCESS;
6509 msi_move_file(source, dest, options);
6511 move_files_wildcard(source, dest, options);
6514 msi_free(sourcedir);
6520 return ERROR_SUCCESS;
6523 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
6528 static const WCHAR ExecSeqQuery[] =
6529 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6530 '`','M','o','v','e','F','i','l','e','`',0};
6532 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6533 if (rc != ERROR_SUCCESS)
6534 return ERROR_SUCCESS;
6536 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
6537 msiobj_release(&view->hdr);
6542 typedef struct tagMSIASSEMBLY
6545 MSICOMPONENT *component;
6546 MSIFEATURE *feature;
6554 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6556 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6557 LPVOID pvReserved, HMODULE *phModDll);
6559 static BOOL init_functionpointers(void)
6565 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6567 hmscoree = LoadLibraryA("mscoree.dll");
6570 WARN("mscoree.dll not available\n");
6574 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6575 if (!pLoadLibraryShim)
6577 WARN("LoadLibraryShim not available\n");
6578 FreeLibrary(hmscoree);
6582 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6585 WARN("fusion.dll not available\n");
6586 FreeLibrary(hmscoree);
6590 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6592 FreeLibrary(hmscoree);
6596 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6599 IAssemblyCache *cache;
6601 UINT r = ERROR_FUNCTION_FAILED;
6603 TRACE("installing assembly: %s\n", debugstr_w(path));
6605 if (assembly->feature)
6606 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6608 if (assembly->manifest)
6609 FIXME("Manifest unhandled\n");
6611 if (assembly->application)
6613 FIXME("Assembly should be privately installed\n");
6614 return ERROR_SUCCESS;
6617 if (assembly->attributes == msidbAssemblyAttributesWin32)
6619 FIXME("Win32 assemblies not handled\n");
6620 return ERROR_SUCCESS;
6623 hr = pCreateAssemblyCache(&cache, 0);
6627 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6629 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6634 IAssemblyCache_Release(cache);
6638 typedef struct tagASSEMBLY_LIST
6640 MSIPACKAGE *package;
6641 IAssemblyCache *cache;
6642 struct list *assemblies;
6645 typedef struct tagASSEMBLY_NAME
6653 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6655 ASSEMBLY_NAME *asmname = param;
6656 LPCWSTR name = MSI_RecordGetString(rec, 2);
6657 LPWSTR val = msi_dup_record_field(rec, 3);
6659 static const WCHAR Name[] = {'N','a','m','e',0};
6660 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6661 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6662 static const WCHAR PublicKeyToken[] = {
6663 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6665 if (!strcmpiW(name, Name))
6666 asmname->name = val;
6667 else if (!strcmpiW(name, Version))
6668 asmname->version = val;
6669 else if (!strcmpiW(name, Culture))
6670 asmname->culture = val;
6671 else if (!strcmpiW(name, PublicKeyToken))
6672 asmname->pubkeytoken = val;
6676 return ERROR_SUCCESS;
6679 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6683 *size = lstrlenW(append) + 1;
6684 *str = msi_alloc((*size) * sizeof(WCHAR));
6685 lstrcpyW(*str, append);
6689 (*size) += lstrlenW(append);
6690 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6691 lstrcatW(*str, append);
6694 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
6697 ASSEMBLY_INFO asminfo;
6705 static const WCHAR separator[] = {',',' ',0};
6706 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6707 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6708 static const WCHAR PublicKeyToken[] = {
6709 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6710 static const WCHAR query[] = {
6711 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6712 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6713 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6714 '=','\'','%','s','\'',0};
6718 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
6719 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
6721 r = MSI_OpenQuery(db, &view, query, comp->Component);
6722 if (r != ERROR_SUCCESS)
6723 return ERROR_SUCCESS;
6725 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
6726 msiobj_release(&view->hdr);
6730 ERR("No assembly name specified!\n");
6734 append_str(&disp, &size, name.name);
6738 append_str(&disp, &size, separator);
6739 append_str(&disp, &size, Version);
6740 append_str(&disp, &size, name.version);
6745 append_str(&disp, &size, separator);
6746 append_str(&disp, &size, Culture);
6747 append_str(&disp, &size, name.culture);
6750 if (name.pubkeytoken)
6752 append_str(&disp, &size, separator);
6753 append_str(&disp, &size, PublicKeyToken);
6754 append_str(&disp, &size, name.pubkeytoken);
6757 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6758 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
6760 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6764 msi_free(name.name);
6765 msi_free(name.version);
6766 msi_free(name.culture);
6767 msi_free(name.pubkeytoken);
6772 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6774 ASSEMBLY_LIST *list = param;
6775 MSIASSEMBLY *assembly;
6778 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6780 return ERROR_OUTOFMEMORY;
6782 component = MSI_RecordGetString(rec, 1);
6783 assembly->component = get_loaded_component(list->package, component);
6784 if (!assembly->component)
6785 return ERROR_SUCCESS;
6787 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6788 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6790 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6791 assembly->component->Action = assembly->component->Installed;
6792 return ERROR_SUCCESS;
6794 assembly->component->Action = assembly->component->ActionRequest;
6796 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6797 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6799 if (!assembly->file)
6801 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6802 return ERROR_FUNCTION_FAILED;
6805 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6806 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6807 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6809 if (assembly->application)
6812 DWORD size = sizeof(version)/sizeof(WCHAR);
6814 /* FIXME: we should probably check the manifest file here */
6816 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6817 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6819 assembly->installed = TRUE;
6823 assembly->installed = check_assembly_installed(list->package->db,
6825 assembly->component);
6827 list_add_head(list->assemblies, &assembly->entry);
6828 return ERROR_SUCCESS;
6831 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6833 IAssemblyCache *cache = NULL;
6839 static const WCHAR query[] =
6840 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6841 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6843 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6844 if (r != ERROR_SUCCESS)
6845 return ERROR_SUCCESS;
6847 hr = pCreateAssemblyCache(&cache, 0);
6849 return ERROR_FUNCTION_FAILED;
6851 list.package = package;
6853 list.assemblies = assemblies;
6855 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6856 msiobj_release(&view->hdr);
6858 IAssemblyCache_Release(cache);
6863 static void free_assemblies(struct list *assemblies)
6865 struct list *item, *cursor;
6867 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6869 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6871 list_remove(&assembly->entry);
6872 msi_free(assembly->application);
6873 msi_free(assembly->manifest);
6878 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6880 MSIASSEMBLY *assembly;
6882 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6884 if (!lstrcmpW(assembly->file->File, file))
6894 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6895 LPWSTR *path, DWORD *attrs, PVOID user)
6897 MSIASSEMBLY *assembly;
6898 WCHAR temppath[MAX_PATH];
6899 struct list *assemblies = user;
6902 if (!find_assembly(assemblies, file, &assembly))
6905 GetTempPathW(MAX_PATH, temppath);
6906 PathAddBackslashW(temppath);
6907 lstrcatW(temppath, assembly->file->FileName);
6909 if (action == MSICABEXTRACT_BEGINEXTRACT)
6911 if (assembly->installed)
6914 *path = strdupW(temppath);
6915 *attrs = assembly->file->Attributes;
6917 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6919 assembly->installed = TRUE;
6921 r = install_assembly(package, assembly, temppath);
6922 if (r != ERROR_SUCCESS)
6923 ERR("Failed to install assembly\n");
6929 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6932 struct list assemblies = LIST_INIT(assemblies);
6933 MSIASSEMBLY *assembly;
6936 if (!init_functionpointers() || !pCreateAssemblyCache)
6937 return ERROR_FUNCTION_FAILED;
6939 r = load_assemblies(package, &assemblies);
6940 if (r != ERROR_SUCCESS)
6943 if (list_empty(&assemblies))
6946 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6949 r = ERROR_OUTOFMEMORY;
6953 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6955 if (assembly->installed && !mi->is_continuous)
6958 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6959 (assembly->file->IsCompressed && !mi->is_extracted))
6963 r = ready_media(package, assembly->file, mi);
6964 if (r != ERROR_SUCCESS)
6966 ERR("Failed to ready media\n");
6971 data.package = package;
6972 data.cb = installassembly_cb;
6973 data.user = &assemblies;
6975 if (assembly->file->IsCompressed &&
6976 !msi_cabextract(package, mi, &data))
6978 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6979 r = ERROR_FUNCTION_FAILED;
6984 if (!assembly->file->IsCompressed)
6986 LPWSTR source = resolve_file_source(package, assembly->file);
6988 r = install_assembly(package, assembly, source);
6989 if (r != ERROR_SUCCESS)
6990 ERR("Failed to install assembly\n");
6995 /* FIXME: write Installer assembly reg values */
6999 free_assemblies(&assemblies);
7003 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7005 LPWSTR key, template, id;
7006 UINT r = ERROR_SUCCESS;
7008 id = msi_dup_property( package, szProductID );
7012 return ERROR_SUCCESS;
7014 template = msi_dup_property( package, szPIDTemplate );
7015 key = msi_dup_property( package, szPIDKEY );
7017 if (key && template)
7019 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7020 r = MSI_SetPropertyW( package, szProductID, key );
7022 msi_free( template );
7027 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7030 package->need_reboot = 1;
7031 return ERROR_SUCCESS;
7034 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7036 static const WCHAR szAvailableFreeReg[] =
7037 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7039 TRACE("%p %d kilobytes\n", package, msi_get_property_int( package, szAvailableFreeReg, 0 ));
7040 return ERROR_SUCCESS;
7043 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7045 FIXME("%p\n", package);
7046 return ERROR_SUCCESS;
7049 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7051 FIXME("%p\n", package);
7052 return ERROR_SUCCESS;
7055 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7056 LPCSTR action, LPCWSTR table )
7058 static const WCHAR query[] = {
7059 'S','E','L','E','C','T',' ','*',' ',
7060 'F','R','O','M',' ','`','%','s','`',0 };
7061 MSIQUERY *view = NULL;
7065 r = MSI_OpenQuery( package->db, &view, query, table );
7066 if (r == ERROR_SUCCESS)
7068 r = MSI_IterateRecords(view, &count, NULL, package);
7069 msiobj_release(&view->hdr);
7073 FIXME("%s -> %u ignored %s table values\n",
7074 action, count, debugstr_w(table));
7076 return ERROR_SUCCESS;
7079 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7081 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7082 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7085 static UINT ACTION_BindImage( MSIPACKAGE *package )
7087 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7088 return msi_unimplemented_action_stub( package, "BindImage", table );
7091 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7093 static const WCHAR table[] = {
7094 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7095 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7098 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7100 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7101 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7104 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7106 static const WCHAR table[] = {
7107 'M','s','i','A','s','s','e','m','b','l','y',0 };
7108 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7111 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7113 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7114 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7117 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7119 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7120 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7123 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7125 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7126 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7129 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7131 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7132 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7135 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7137 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7138 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7141 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7143 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
7144 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
7147 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
7149 static const WCHAR table[] = { 'A','p','p','I','d',0 };
7150 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
7153 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
7155 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
7156 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
7159 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
7161 static const WCHAR table[] = { 'M','I','M','E',0 };
7162 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
7165 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
7167 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
7168 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
7171 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7175 const WCHAR *action;
7176 UINT (*handler)(MSIPACKAGE *);
7180 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7181 { szAppSearch, ACTION_AppSearch },
7182 { szBindImage, ACTION_BindImage },
7183 { szCCPSearch, ACTION_CCPSearch },
7184 { szCostFinalize, ACTION_CostFinalize },
7185 { szCostInitialize, ACTION_CostInitialize },
7186 { szCreateFolders, ACTION_CreateFolders },
7187 { szCreateShortcuts, ACTION_CreateShortcuts },
7188 { szDeleteServices, ACTION_DeleteServices },
7189 { szDisableRollback, ACTION_DisableRollback },
7190 { szDuplicateFiles, ACTION_DuplicateFiles },
7191 { szExecuteAction, ACTION_ExecuteAction },
7192 { szFileCost, ACTION_FileCost },
7193 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7194 { szForceReboot, ACTION_ForceReboot },
7195 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7196 { szInstallExecute, ACTION_InstallExecute },
7197 { szInstallExecuteAgain, ACTION_InstallExecute },
7198 { szInstallFiles, ACTION_InstallFiles},
7199 { szInstallFinalize, ACTION_InstallFinalize },
7200 { szInstallInitialize, ACTION_InstallInitialize },
7201 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7202 { szInstallValidate, ACTION_InstallValidate },
7203 { szIsolateComponents, ACTION_IsolateComponents },
7204 { szLaunchConditions, ACTION_LaunchConditions },
7205 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7206 { szMoveFiles, ACTION_MoveFiles },
7207 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7208 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7209 { szInstallODBC, ACTION_InstallODBC },
7210 { szInstallServices, ACTION_InstallServices },
7211 { szPatchFiles, ACTION_PatchFiles },
7212 { szProcessComponents, ACTION_ProcessComponents },
7213 { szPublishComponents, ACTION_PublishComponents },
7214 { szPublishFeatures, ACTION_PublishFeatures },
7215 { szPublishProduct, ACTION_PublishProduct },
7216 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7217 { szRegisterComPlus, ACTION_RegisterComPlus},
7218 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7219 { szRegisterFonts, ACTION_RegisterFonts },
7220 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7221 { szRegisterProduct, ACTION_RegisterProduct },
7222 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7223 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7224 { szRegisterUser, ACTION_RegisterUser },
7225 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7226 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7227 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7228 { szRemoveFiles, ACTION_RemoveFiles },
7229 { szRemoveFolders, ACTION_RemoveFolders },
7230 { szRemoveIniValues, ACTION_RemoveIniValues },
7231 { szRemoveODBC, ACTION_RemoveODBC },
7232 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7233 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7234 { szResolveSource, ACTION_ResolveSource },
7235 { szRMCCPSearch, ACTION_RMCCPSearch },
7236 { szScheduleReboot, ACTION_ScheduleReboot },
7237 { szSelfRegModules, ACTION_SelfRegModules },
7238 { szSelfUnregModules, ACTION_SelfUnregModules },
7239 { szSetODBCFolders, ACTION_SetODBCFolders },
7240 { szStartServices, ACTION_StartServices },
7241 { szStopServices, ACTION_StopServices },
7242 { szUnpublishComponents, ACTION_UnpublishComponents },
7243 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7244 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7245 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7246 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7247 { szUnregisterFonts, ACTION_UnregisterFonts },
7248 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7249 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7250 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7251 { szValidateProductID, ACTION_ValidateProductID },
7252 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7253 { szWriteIniValues, ACTION_WriteIniValues },
7254 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7258 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7259 UINT* rc, BOOL force )
7265 if (!run && !package->script->CurrentlyScripting)
7270 if (strcmpW(action,szInstallFinalize) == 0 ||
7271 strcmpW(action,szInstallExecute) == 0 ||
7272 strcmpW(action,szInstallExecuteAgain) == 0)
7277 while (StandardActions[i].action != NULL)
7279 if (strcmpW(StandardActions[i].action, action)==0)
7283 ui_actioninfo(package, action, TRUE, 0);
7284 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7285 ui_actioninfo(package, action, FALSE, *rc);
7289 ui_actionstart(package, action);
7290 if (StandardActions[i].handler)
7292 *rc = StandardActions[i].handler(package);
7296 FIXME("unhandled standard action %s\n",debugstr_w(action));
7297 *rc = ERROR_SUCCESS;
7308 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7310 UINT rc = ERROR_SUCCESS;
7313 TRACE("Performing action (%s)\n", debugstr_w(action));
7315 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7318 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7322 WARN("unhandled msi action %s\n", debugstr_w(action));
7323 rc = ERROR_FUNCTION_NOT_CALLED;
7329 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7331 UINT rc = ERROR_SUCCESS;
7332 BOOL handled = FALSE;
7334 TRACE("Performing action (%s)\n", debugstr_w(action));
7336 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7339 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7341 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7346 WARN("unhandled msi action %s\n", debugstr_w(action));
7347 rc = ERROR_FUNCTION_NOT_CALLED;
7353 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7355 UINT rc = ERROR_SUCCESS;
7358 static const WCHAR ExecSeqQuery[] =
7359 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7360 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7361 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7362 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7363 static const WCHAR UISeqQuery[] =
7364 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7365 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7366 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7367 ' ', '=',' ','%','i',0};
7369 if (needs_ui_sequence(package))
7370 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7372 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7376 LPCWSTR action, cond;
7378 TRACE("Running the actions\n");
7380 /* check conditions */
7381 cond = MSI_RecordGetString(row, 2);
7383 /* this is a hack to skip errors in the condition code */
7384 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7386 msiobj_release(&row->hdr);
7387 return ERROR_SUCCESS;
7390 action = MSI_RecordGetString(row, 1);
7393 ERR("failed to fetch action\n");
7394 msiobj_release(&row->hdr);
7395 return ERROR_FUNCTION_FAILED;
7398 if (needs_ui_sequence(package))
7399 rc = ACTION_PerformUIAction(package, action, -1);
7401 rc = ACTION_PerformAction(package, action, -1, FALSE);
7403 msiobj_release(&row->hdr);
7409 /****************************************************
7410 * TOP level entry points
7411 *****************************************************/
7413 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7414 LPCWSTR szCommandLine )
7419 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7420 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7422 MSI_SetPropertyW(package, szAction, szInstall);
7424 package->script->InWhatSequence = SEQUENCE_INSTALL;
7431 dir = strdupW(szPackagePath);
7432 p = strrchrW(dir, '\\');
7436 file = szPackagePath + (p - dir);
7441 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7442 GetCurrentDirectoryW(MAX_PATH, dir);
7443 lstrcatW(dir, szBackSlash);
7444 file = szPackagePath;
7447 msi_free( package->PackagePath );
7448 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7449 if (!package->PackagePath)
7452 return ERROR_OUTOFMEMORY;
7455 lstrcpyW(package->PackagePath, dir);
7456 lstrcatW(package->PackagePath, file);
7459 msi_set_sourcedir_props(package, FALSE);
7462 msi_parse_command_line( package, szCommandLine, FALSE );
7464 msi_apply_transforms( package );
7465 msi_apply_patches( package );
7467 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7469 TRACE("setting reinstall property\n");
7470 MSI_SetPropertyW( package, szReinstall, szAll );
7473 /* properties may have been added by a transform */
7474 msi_clone_properties( package );
7475 msi_set_context( package );
7477 if (needs_ui_sequence( package))
7479 package->script->InWhatSequence |= SEQUENCE_UI;
7480 rc = ACTION_ProcessUISequence(package);
7481 ui_exists = ui_sequence_exists(package);
7482 if (rc == ERROR_SUCCESS || !ui_exists)
7484 package->script->InWhatSequence |= SEQUENCE_EXEC;
7485 rc = ACTION_ProcessExecSequence(package, ui_exists);
7489 rc = ACTION_ProcessExecSequence(package, FALSE);
7491 package->script->CurrentlyScripting = FALSE;
7493 /* process the ending type action */
7494 if (rc == ERROR_SUCCESS)
7495 ACTION_PerformActionSequence(package, -1);
7496 else if (rc == ERROR_INSTALL_USEREXIT)
7497 ACTION_PerformActionSequence(package, -2);
7498 else if (rc == ERROR_INSTALL_SUSPEND)
7499 ACTION_PerformActionSequence(package, -4);
7501 ACTION_PerformActionSequence(package, -3);
7503 /* finish up running custom actions */
7504 ACTION_FinishCustomActions(package);
7506 if (rc == ERROR_SUCCESS && package->need_reboot)
7507 return ERROR_SUCCESS_REBOOT_REQUIRED;