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 szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings[] =
130 {'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};
131 static const WCHAR szRemoveExistingProducts[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterTypeLibraries[] =
162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
163 static const WCHAR szValidateProductID[] =
164 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
165 static const WCHAR szWriteEnvironmentStrings[] =
166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
168 /********************************************************
170 ********************************************************/
172 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
174 static const WCHAR Query_t[] =
175 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
176 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
177 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
178 ' ','\'','%','s','\'',0};
181 row = MSI_QueryGetRecord( package->db, Query_t, action );
184 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
185 msiobj_release(&row->hdr);
188 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
192 static const WCHAR template_s[]=
193 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
195 static const WCHAR template_e[]=
196 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
197 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
199 static const WCHAR format[] =
200 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
204 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
206 sprintfW(message,template_s,timet,action);
208 sprintfW(message,template_e,timet,action,rc);
210 row = MSI_CreateRecord(1);
211 MSI_RecordSetStringW(row,1,message);
213 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
214 msiobj_release(&row->hdr);
217 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
223 LPWSTR prop = NULL, val = NULL;
226 return ERROR_SUCCESS;
238 TRACE("Looking at %s\n",debugstr_w(ptr));
240 ptr2 = strchrW(ptr,'=');
243 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
250 prop = msi_alloc((len+1)*sizeof(WCHAR));
251 memcpy(prop,ptr,len*sizeof(WCHAR));
261 while (*ptr && (quote || (!quote && *ptr!=' ')))
274 val = msi_alloc((len+1)*sizeof(WCHAR));
275 memcpy(val,ptr2,len*sizeof(WCHAR));
278 if (lstrlenW(prop) > 0)
280 UINT r = msi_set_property( package->db, prop, val );
282 TRACE("Found commandline property (%s) = (%s)\n",
283 debugstr_w(prop), debugstr_w(val));
285 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
286 msi_reset_folders( package, TRUE );
292 return ERROR_SUCCESS;
296 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
299 LPWSTR p, *ret = NULL;
305 /* count the number of substrings */
306 for ( pc = str, count = 0; pc; count++ )
308 pc = strchrW( pc, sep );
313 /* allocate space for an array of substring pointers and the substrings */
314 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
315 (lstrlenW(str)+1) * sizeof(WCHAR) );
319 /* copy the string and set the pointers */
320 p = (LPWSTR) &ret[count+1];
322 for( count = 0; (ret[count] = p); count++ )
324 p = strchrW( p, sep );
332 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
334 static const WCHAR szSystemLanguageID[] =
335 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
337 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
338 UINT ret = ERROR_FUNCTION_FAILED;
340 prod_code = msi_dup_property( package->db, szProductCode );
341 patch_product = msi_get_suminfo_product( patch );
343 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
345 if ( strstrW( patch_product, prod_code ) )
350 si = MSI_GetSummaryInformationW( patch, 0 );
353 ERR("no summary information!\n");
357 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
360 ERR("no template property!\n");
361 msiobj_release( &si->hdr );
368 msiobj_release( &si->hdr );
372 langid = msi_dup_property( package->db, szSystemLanguageID );
375 msiobj_release( &si->hdr );
379 p = strchrW( template, ';' );
380 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
382 TRACE("applicable transform\n");
386 /* FIXME: check platform */
388 msiobj_release( &si->hdr );
392 msi_free( patch_product );
393 msi_free( prod_code );
394 msi_free( template );
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
407 TRACE("%p %s\n", package, debugstr_w(name) );
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
418 ret = msi_check_transform_applicable( package, stg );
419 if (ret == ERROR_SUCCESS)
420 msi_table_apply_transform( package->db, stg );
422 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
423 IStorage_Release( stg );
426 ERR("failed to open substorage %s\n", debugstr_w(name));
428 return ERROR_SUCCESS;
431 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
433 LPWSTR guid_list, *guids, product_code;
434 UINT i, ret = ERROR_FUNCTION_FAILED;
436 product_code = msi_dup_property( package->db, szProductCode );
439 /* FIXME: the property ProductCode should be written into the DB somewhere */
440 ERR("no product code to check\n");
441 return ERROR_SUCCESS;
444 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
445 guids = msi_split_string( guid_list, ';' );
446 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
448 if (!lstrcmpW( guids[i], product_code ))
452 msi_free( guid_list );
453 msi_free( product_code );
458 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
461 MSIRECORD *rec = NULL;
466 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
467 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
468 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
469 '`','S','o','u','r','c','e','`',' ','I','S',' ',
470 'N','O','T',' ','N','U','L','L',0};
472 r = MSI_DatabaseOpenViewW(package->db, query, &view);
473 if (r != ERROR_SUCCESS)
476 r = MSI_ViewExecute(view, 0);
477 if (r != ERROR_SUCCESS)
480 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
482 prop = MSI_RecordGetString(rec, 1);
483 patch = msi_dup_property(package->db, szPatch);
484 msi_set_property(package->db, prop, patch);
489 if (rec) msiobj_release(&rec->hdr);
490 msiobj_release(&view->hdr);
495 static UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
498 UINT r = ERROR_SUCCESS;
500 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
502 return ERROR_OUTOFMEMORY;
504 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
508 return ERROR_OUTOFMEMORY;
511 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
514 msi_free( pi->patchcode );
516 return ERROR_OUTOFMEMORY;
523 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
525 static const WCHAR dotmsp[] = {'.','m','s','p',0};
526 MSIDATABASE *patch_db = NULL;
527 WCHAR localfile[MAX_PATH];
530 MSIPATCHINFO *patch = NULL;
531 UINT i, r = ERROR_SUCCESS;
533 TRACE("%p %s\n", package, debugstr_w( file ) );
535 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
536 if ( r != ERROR_SUCCESS )
538 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
542 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
545 msiobj_release( &patch_db->hdr );
546 return ERROR_FUNCTION_FAILED;
549 r = msi_check_patch_applicable( package, si );
550 if (r != ERROR_SUCCESS)
552 TRACE("patch not applicable\n");
557 r = msi_parse_patch_summary( si, &patch );
558 if ( r != ERROR_SUCCESS )
561 r = msi_get_local_package_name( localfile, dotmsp );
562 if ( r != ERROR_SUCCESS )
565 TRACE("copying to local package %s\n", debugstr_w(localfile));
567 if (!CopyFileW( file, localfile, FALSE ))
569 ERR("Unable to copy package (%s -> %s) (error %u)\n",
570 debugstr_w(file), debugstr_w(localfile), GetLastError());
574 patch->localfile = strdupW( localfile );
576 /* apply substorage transforms */
577 substorage = msi_split_string( patch->transforms, ';' );
578 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
579 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
581 msi_free( substorage );
582 if (r != ERROR_SUCCESS)
584 msi_set_media_source_prop( package );
587 * There might be a CAB file in the patch package,
588 * so append it to the list of storages to search for streams.
590 append_storage_to_db( package->db, patch_db->storage );
592 list_add_tail( &package->patches, &patch->entry );
595 msiobj_release( &si->hdr );
596 msiobj_release( &patch_db->hdr );
597 if (patch && r != ERROR_SUCCESS)
599 if (patch->localfile)
600 DeleteFileW( patch->localfile );
602 msi_free( patch->patchcode );
603 msi_free( patch->transforms );
604 msi_free( patch->localfile );
610 /* get the PATCH property, and apply all the patches it specifies */
611 static UINT msi_apply_patches( MSIPACKAGE *package )
613 LPWSTR patch_list, *patches;
614 UINT i, r = ERROR_SUCCESS;
616 patch_list = msi_dup_property( package->db, szPatch );
618 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
620 patches = msi_split_string( patch_list, ';' );
621 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
622 r = msi_apply_patch_package( package, patches[i] );
625 msi_free( patch_list );
630 static UINT msi_apply_transforms( MSIPACKAGE *package )
632 static const WCHAR szTransforms[] = {
633 'T','R','A','N','S','F','O','R','M','S',0 };
634 LPWSTR xform_list, *xforms;
635 UINT i, r = ERROR_SUCCESS;
637 xform_list = msi_dup_property( package->db, szTransforms );
638 xforms = msi_split_string( xform_list, ';' );
640 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
642 if (xforms[i][0] == ':')
643 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
645 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
649 msi_free( xform_list );
654 static BOOL ui_sequence_exists( MSIPACKAGE *package )
659 static const WCHAR ExecSeqQuery [] =
660 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
661 '`','I','n','s','t','a','l','l',
662 'U','I','S','e','q','u','e','n','c','e','`',
663 ' ','W','H','E','R','E',' ',
664 '`','S','e','q','u','e','n','c','e','`',' ',
665 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
666 '`','S','e','q','u','e','n','c','e','`',0};
668 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
669 if (rc == ERROR_SUCCESS)
671 msiobj_release(&view->hdr);
678 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
681 LPWSTR source, check;
684 static const WCHAR szOriginalDatabase[] =
685 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
687 db = msi_dup_property( package->db, szOriginalDatabase );
689 return ERROR_OUTOFMEMORY;
691 p = strrchrW( db, '\\' );
694 p = strrchrW( db, '/' );
698 return ERROR_SUCCESS;
703 source = msi_alloc( len * sizeof(WCHAR) );
704 lstrcpynW( source, db, len );
706 check = msi_dup_property( package->db, cszSourceDir );
707 if (!check || replace)
709 UINT r = msi_set_property( package->db, cszSourceDir, source );
710 if (r == ERROR_SUCCESS)
711 msi_reset_folders( package, TRUE );
715 check = msi_dup_property( package->db, cszSOURCEDIR );
716 if (!check || replace)
717 msi_set_property( package->db, cszSOURCEDIR, source );
723 return ERROR_SUCCESS;
726 static BOOL needs_ui_sequence(MSIPACKAGE *package)
728 INT level = msi_get_property_int(package->db, szUILevel, 0);
729 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
732 static UINT msi_set_context(MSIPACKAGE *package)
736 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
738 num = msi_get_property_int(package->db, szAllUsers, 0);
739 if (num == 1 || num == 2)
740 package->Context = MSIINSTALLCONTEXT_MACHINE;
742 return ERROR_SUCCESS;
745 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
748 LPCWSTR cond, action;
749 MSIPACKAGE *package = param;
751 action = MSI_RecordGetString(row,1);
754 ERR("Error is retrieving action name\n");
755 return ERROR_FUNCTION_FAILED;
758 /* check conditions */
759 cond = MSI_RecordGetString(row,2);
761 /* this is a hack to skip errors in the condition code */
762 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
764 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
765 return ERROR_SUCCESS;
768 if (needs_ui_sequence(package))
769 rc = ACTION_PerformUIAction(package, action, -1);
771 rc = ACTION_PerformAction(package, action, -1, FALSE);
773 msi_dialog_check_messages( NULL );
775 if (package->CurrentInstallState != ERROR_SUCCESS)
776 rc = package->CurrentInstallState;
778 if (rc == ERROR_FUNCTION_NOT_CALLED)
781 if (rc != ERROR_SUCCESS)
782 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
787 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
791 static const WCHAR query[] =
792 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
794 ' ','W','H','E','R','E',' ',
795 '`','S','e','q','u','e','n','c','e','`',' ',
796 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
797 '`','S','e','q','u','e','n','c','e','`',0};
799 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
801 r = MSI_OpenQuery( package->db, &view, query, szTable );
802 if (r == ERROR_SUCCESS)
804 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
805 msiobj_release(&view->hdr);
811 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
815 static const WCHAR ExecSeqQuery[] =
816 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
817 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
818 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
819 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
820 'O','R','D','E','R',' ', 'B','Y',' ',
821 '`','S','e','q','u','e','n','c','e','`',0 };
822 static const WCHAR IVQuery[] =
823 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
824 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
825 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
826 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
827 ' ','\'', 'I','n','s','t','a','l','l',
828 'V','a','l','i','d','a','t','e','\'', 0};
831 if (package->script->ExecuteSequenceRun)
833 TRACE("Execute Sequence already Run\n");
834 return ERROR_SUCCESS;
837 package->script->ExecuteSequenceRun = TRUE;
839 /* get the sequence number */
842 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
844 return ERROR_FUNCTION_FAILED;
845 seq = MSI_RecordGetInteger(row,1);
846 msiobj_release(&row->hdr);
849 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
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 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
865 static const WCHAR ExecSeqQuery [] =
866 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
867 '`','I','n','s','t','a','l','l',
868 'U','I','S','e','q','u','e','n','c','e','`',
869 ' ','W','H','E','R','E',' ',
870 '`','S','e','q','u','e','n','c','e','`',' ',
871 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
872 '`','S','e','q','u','e','n','c','e','`',0};
874 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
875 if (rc == ERROR_SUCCESS)
877 TRACE("Running the actions\n");
879 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
880 msiobj_release(&view->hdr);
886 /********************************************************
887 * ACTION helper functions and functions that perform the actions
888 *******************************************************/
889 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
890 UINT* rc, UINT script, BOOL force )
895 arc = ACTION_CustomAction(package, action, script, force);
897 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
906 * Actual Action Handlers
909 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
911 MSIPACKAGE *package = param;
912 LPCWSTR dir, component;
918 component = MSI_RecordGetString(row, 2);
919 comp = get_loaded_component(package, component);
921 return ERROR_SUCCESS;
923 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
925 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
926 comp->Action = comp->Installed;
927 return ERROR_SUCCESS;
929 comp->Action = INSTALLSTATE_LOCAL;
931 dir = MSI_RecordGetString(row,1);
934 ERR("Unable to get folder id\n");
935 return ERROR_SUCCESS;
938 uirow = MSI_CreateRecord(1);
939 MSI_RecordSetStringW(uirow, 1, dir);
940 ui_actiondata(package, szCreateFolders, uirow);
941 msiobj_release(&uirow->hdr);
943 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
946 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
947 return ERROR_SUCCESS;
950 TRACE("Folder is %s\n",debugstr_w(full_path));
952 if (folder->State == 0)
953 create_full_pathW(full_path);
958 return ERROR_SUCCESS;
961 /* FIXME: probably should merge this with the above function */
962 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
964 UINT rc = ERROR_SUCCESS;
968 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
970 return ERROR_FUNCTION_FAILED;
972 /* create the path */
973 if (folder->State == 0)
975 create_full_pathW(install_path);
978 msi_free(install_path);
983 UINT msi_create_component_directories( MSIPACKAGE *package )
987 /* create all the folders required by the components are going to install */
988 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
990 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
992 msi_create_directory( package, comp->Directory );
995 return ERROR_SUCCESS;
998 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1000 static const WCHAR ExecSeqQuery[] =
1001 {'S','E','L','E','C','T',' ',
1002 '`','D','i','r','e','c','t','o','r','y','_','`',
1003 ' ','F','R','O','M',' ',
1004 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1008 /* create all the empty folders specified in the CreateFolder table */
1009 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1010 if (rc != ERROR_SUCCESS)
1011 return ERROR_SUCCESS;
1013 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1014 msiobj_release(&view->hdr);
1019 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1021 MSIPACKAGE *package = param;
1022 LPCWSTR dir, component;
1028 component = MSI_RecordGetString(row, 2);
1029 comp = get_loaded_component(package, component);
1031 return ERROR_SUCCESS;
1033 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1035 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1036 comp->Action = comp->Installed;
1037 return ERROR_SUCCESS;
1039 comp->Action = INSTALLSTATE_ABSENT;
1041 dir = MSI_RecordGetString( row, 1 );
1044 ERR("Unable to get folder id\n");
1045 return ERROR_SUCCESS;
1048 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1051 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1052 return ERROR_SUCCESS;
1055 TRACE("folder is %s\n", debugstr_w(full_path));
1057 uirow = MSI_CreateRecord( 1 );
1058 MSI_RecordSetStringW( uirow, 1, full_path );
1059 ui_actiondata( package, szRemoveFolders, uirow );
1060 msiobj_release( &uirow->hdr );
1062 RemoveDirectoryW( full_path );
1065 msi_free( full_path );
1066 return ERROR_SUCCESS;
1069 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1071 static const WCHAR query[] =
1072 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1073 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1078 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1079 if (rc != ERROR_SUCCESS)
1080 return ERROR_SUCCESS;
1082 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1083 msiobj_release( &view->hdr );
1088 static UINT load_component( MSIRECORD *row, LPVOID param )
1090 MSIPACKAGE *package = param;
1093 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1095 return ERROR_FUNCTION_FAILED;
1097 list_add_tail( &package->components, &comp->entry );
1099 /* fill in the data */
1100 comp->Component = msi_dup_record_field( row, 1 );
1102 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1104 comp->ComponentId = msi_dup_record_field( row, 2 );
1105 comp->Directory = msi_dup_record_field( row, 3 );
1106 comp->Attributes = MSI_RecordGetInteger(row,4);
1107 comp->Condition = msi_dup_record_field( row, 5 );
1108 comp->KeyPath = msi_dup_record_field( row, 6 );
1110 comp->Installed = INSTALLSTATE_UNKNOWN;
1111 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1113 return ERROR_SUCCESS;
1116 static UINT load_all_components( MSIPACKAGE *package )
1118 static const WCHAR query[] = {
1119 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1120 '`','C','o','m','p','o','n','e','n','t','`',0 };
1124 if (!list_empty(&package->components))
1125 return ERROR_SUCCESS;
1127 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1128 if (r != ERROR_SUCCESS)
1131 r = MSI_IterateRecords(view, NULL, load_component, package);
1132 msiobj_release(&view->hdr);
1137 MSIPACKAGE *package;
1138 MSIFEATURE *feature;
1141 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1145 cl = msi_alloc( sizeof (*cl) );
1147 return ERROR_NOT_ENOUGH_MEMORY;
1148 cl->component = comp;
1149 list_add_tail( &feature->Components, &cl->entry );
1151 return ERROR_SUCCESS;
1154 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1158 fl = msi_alloc( sizeof(*fl) );
1160 return ERROR_NOT_ENOUGH_MEMORY;
1161 fl->feature = child;
1162 list_add_tail( &parent->Children, &fl->entry );
1164 return ERROR_SUCCESS;
1167 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1169 _ilfs* ilfs = param;
1173 component = MSI_RecordGetString(row,1);
1175 /* check to see if the component is already loaded */
1176 comp = get_loaded_component( ilfs->package, component );
1179 ERR("unknown component %s\n", debugstr_w(component));
1180 return ERROR_FUNCTION_FAILED;
1183 add_feature_component( ilfs->feature, comp );
1184 comp->Enabled = TRUE;
1186 return ERROR_SUCCESS;
1189 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1191 MSIFEATURE *feature;
1196 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1198 if ( !lstrcmpW( feature->Feature, name ) )
1205 static UINT load_feature(MSIRECORD * row, LPVOID param)
1207 MSIPACKAGE* package = param;
1208 MSIFEATURE* feature;
1209 static const WCHAR Query1[] =
1210 {'S','E','L','E','C','T',' ',
1211 '`','C','o','m','p','o','n','e','n','t','_','`',
1212 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1213 'C','o','m','p','o','n','e','n','t','s','`',' ',
1214 'W','H','E','R','E',' ',
1215 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1220 /* fill in the data */
1222 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1224 return ERROR_NOT_ENOUGH_MEMORY;
1226 list_init( &feature->Children );
1227 list_init( &feature->Components );
1229 feature->Feature = msi_dup_record_field( row, 1 );
1231 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1233 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1234 feature->Title = msi_dup_record_field( row, 3 );
1235 feature->Description = msi_dup_record_field( row, 4 );
1237 if (!MSI_RecordIsNull(row,5))
1238 feature->Display = MSI_RecordGetInteger(row,5);
1240 feature->Level= MSI_RecordGetInteger(row,6);
1241 feature->Directory = msi_dup_record_field( row, 7 );
1242 feature->Attributes = MSI_RecordGetInteger(row,8);
1244 feature->Installed = INSTALLSTATE_UNKNOWN;
1245 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1247 list_add_tail( &package->features, &feature->entry );
1249 /* load feature components */
1251 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1252 if (rc != ERROR_SUCCESS)
1253 return ERROR_SUCCESS;
1255 ilfs.package = package;
1256 ilfs.feature = feature;
1258 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1259 msiobj_release(&view->hdr);
1261 return ERROR_SUCCESS;
1264 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1266 MSIPACKAGE* package = param;
1267 MSIFEATURE *parent, *child;
1269 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1271 return ERROR_FUNCTION_FAILED;
1273 if (!child->Feature_Parent)
1274 return ERROR_SUCCESS;
1276 parent = find_feature_by_name( package, child->Feature_Parent );
1278 return ERROR_FUNCTION_FAILED;
1280 add_feature_child( parent, child );
1281 return ERROR_SUCCESS;
1284 static UINT load_all_features( MSIPACKAGE *package )
1286 static const WCHAR query[] = {
1287 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1288 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1289 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1293 if (!list_empty(&package->features))
1294 return ERROR_SUCCESS;
1296 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1297 if (r != ERROR_SUCCESS)
1300 r = MSI_IterateRecords( view, NULL, load_feature, package );
1301 if (r != ERROR_SUCCESS)
1304 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1305 msiobj_release( &view->hdr );
1310 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1321 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1323 static const WCHAR query[] = {
1324 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1325 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1326 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1327 MSIQUERY *view = NULL;
1328 MSIRECORD *row = NULL;
1331 TRACE("%s\n", debugstr_w(file->File));
1333 r = MSI_OpenQuery(package->db, &view, query, file->File);
1334 if (r != ERROR_SUCCESS)
1337 r = MSI_ViewExecute(view, NULL);
1338 if (r != ERROR_SUCCESS)
1341 r = MSI_ViewFetch(view, &row);
1342 if (r != ERROR_SUCCESS)
1345 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1346 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1347 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1348 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1349 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1352 if (view) msiobj_release(&view->hdr);
1353 if (row) msiobj_release(&row->hdr);
1357 static UINT load_file(MSIRECORD *row, LPVOID param)
1359 MSIPACKAGE* package = param;
1363 /* fill in the data */
1365 file = msi_alloc_zero( sizeof (MSIFILE) );
1367 return ERROR_NOT_ENOUGH_MEMORY;
1369 file->File = msi_dup_record_field( row, 1 );
1371 component = MSI_RecordGetString( row, 2 );
1372 file->Component = get_loaded_component( package, component );
1374 if (!file->Component)
1376 WARN("Component not found: %s\n", debugstr_w(component));
1377 msi_free(file->File);
1379 return ERROR_SUCCESS;
1382 file->FileName = msi_dup_record_field( row, 3 );
1383 reduce_to_longfilename( file->FileName );
1385 file->ShortName = msi_dup_record_field( row, 3 );
1386 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1388 file->FileSize = MSI_RecordGetInteger( row, 4 );
1389 file->Version = msi_dup_record_field( row, 5 );
1390 file->Language = msi_dup_record_field( row, 6 );
1391 file->Attributes = MSI_RecordGetInteger( row, 7 );
1392 file->Sequence = MSI_RecordGetInteger( row, 8 );
1394 file->state = msifs_invalid;
1396 /* if the compressed bits are not set in the file attributes,
1397 * then read the information from the package word count property
1399 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1401 file->IsCompressed = FALSE;
1403 else if (file->Attributes &
1404 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1406 file->IsCompressed = TRUE;
1408 else if (file->Attributes & msidbFileAttributesNoncompressed)
1410 file->IsCompressed = FALSE;
1414 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1417 load_file_hash(package, file);
1419 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1421 list_add_tail( &package->files, &file->entry );
1423 return ERROR_SUCCESS;
1426 static UINT load_all_files(MSIPACKAGE *package)
1430 static const WCHAR Query[] =
1431 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1432 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1433 '`','S','e','q','u','e','n','c','e','`', 0};
1435 if (!list_empty(&package->files))
1436 return ERROR_SUCCESS;
1438 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1439 if (rc != ERROR_SUCCESS)
1440 return ERROR_SUCCESS;
1442 rc = MSI_IterateRecords(view, NULL, load_file, package);
1443 msiobj_release(&view->hdr);
1445 return ERROR_SUCCESS;
1448 static UINT load_folder( MSIRECORD *row, LPVOID param )
1450 MSIPACKAGE *package = param;
1451 static WCHAR szEmpty[] = { 0 };
1452 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1455 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1457 return ERROR_NOT_ENOUGH_MEMORY;
1459 folder->Directory = msi_dup_record_field( row, 1 );
1461 TRACE("%s\n", debugstr_w(folder->Directory));
1463 p = msi_dup_record_field(row, 3);
1465 /* split src and target dir */
1467 src_short = folder_split_path( p, ':' );
1469 /* split the long and short paths */
1470 tgt_long = folder_split_path( tgt_short, '|' );
1471 src_long = folder_split_path( src_short, '|' );
1473 /* check for no-op dirs */
1474 if (!lstrcmpW(szDot, tgt_short))
1475 tgt_short = szEmpty;
1476 if (!lstrcmpW(szDot, src_short))
1477 src_short = szEmpty;
1480 tgt_long = tgt_short;
1483 src_short = tgt_short;
1484 src_long = tgt_long;
1488 src_long = src_short;
1490 /* FIXME: use the target short path too */
1491 folder->TargetDefault = strdupW(tgt_long);
1492 folder->SourceShortPath = strdupW(src_short);
1493 folder->SourceLongPath = strdupW(src_long);
1496 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1497 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1498 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1500 folder->Parent = msi_dup_record_field( row, 2 );
1502 folder->Property = msi_dup_property( package->db, folder->Directory );
1504 list_add_tail( &package->folders, &folder->entry );
1506 TRACE("returning %p\n", folder);
1508 return ERROR_SUCCESS;
1511 static UINT load_all_folders( MSIPACKAGE *package )
1513 static const WCHAR query[] = {
1514 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1515 '`','D','i','r','e','c','t','o','r','y','`',0 };
1519 if (!list_empty(&package->folders))
1520 return ERROR_SUCCESS;
1522 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1523 if (r != ERROR_SUCCESS)
1526 r = MSI_IterateRecords(view, NULL, load_folder, package);
1527 msiobj_release(&view->hdr);
1532 * I am not doing any of the costing functionality yet.
1533 * Mostly looking at doing the Component and Feature loading
1535 * The native MSI does A LOT of modification to tables here. Mostly adding
1536 * a lot of temporary columns to the Feature and Component tables.
1538 * note: Native msi also tracks the short filename. But I am only going to
1539 * track the long ones. Also looking at this directory table
1540 * it appears that the directory table does not get the parents
1541 * resolved base on property only based on their entries in the
1544 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1546 static const WCHAR szCosting[] =
1547 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1549 msi_set_property( package->db, szCosting, szZero );
1550 msi_set_property( package->db, cszRootDrive, c_colon );
1552 load_all_folders( package );
1553 load_all_components( package );
1554 load_all_features( package );
1555 load_all_files( package );
1557 return ERROR_SUCCESS;
1560 static UINT execute_script(MSIPACKAGE *package, UINT script )
1563 UINT rc = ERROR_SUCCESS;
1565 TRACE("Executing Script %i\n",script);
1567 if (!package->script)
1569 ERR("no script!\n");
1570 return ERROR_FUNCTION_FAILED;
1573 for (i = 0; i < package->script->ActionCount[script]; i++)
1576 action = package->script->Actions[script][i];
1577 ui_actionstart(package, action);
1578 TRACE("Executing Action (%s)\n",debugstr_w(action));
1579 rc = ACTION_PerformAction(package, action, script, TRUE);
1580 if (rc != ERROR_SUCCESS)
1583 msi_free_action_script(package, script);
1587 static UINT ACTION_FileCost(MSIPACKAGE *package)
1589 return ERROR_SUCCESS;
1592 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1598 state = MsiQueryProductStateW(package->ProductCode);
1600 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1602 if (!comp->ComponentId)
1605 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1606 comp->Installed = INSTALLSTATE_ABSENT;
1609 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1610 package->Context, comp->ComponentId,
1612 if (r != ERROR_SUCCESS)
1613 comp->Installed = INSTALLSTATE_ABSENT;
1618 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1620 MSIFEATURE *feature;
1623 state = MsiQueryProductStateW(package->ProductCode);
1625 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1627 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1628 feature->Installed = INSTALLSTATE_ABSENT;
1631 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1637 static BOOL process_state_property(MSIPACKAGE* package, int level,
1638 LPCWSTR property, INSTALLSTATE state)
1641 MSIFEATURE *feature;
1643 override = msi_dup_property( package->db, property );
1647 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1649 if (lstrcmpW(property, szRemove) &&
1650 (feature->Level <= 0 || feature->Level > level))
1653 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1655 if (strcmpiW(override, szAll)==0)
1656 msi_feature_set_state(package, feature, state);
1659 LPWSTR ptr = override;
1660 LPWSTR ptr2 = strchrW(override,',');
1664 int len = ptr2 - ptr;
1666 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1667 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1669 msi_feature_set_state(package, feature, state);
1675 ptr2 = strchrW(ptr,',');
1687 static BOOL process_overrides( MSIPACKAGE *package, int level )
1689 static const WCHAR szAddLocal[] =
1690 {'A','D','D','L','O','C','A','L',0};
1691 static const WCHAR szAddSource[] =
1692 {'A','D','D','S','O','U','R','C','E',0};
1693 static const WCHAR szAdvertise[] =
1694 {'A','D','V','E','R','T','I','S','E',0};
1697 /* all these activation/deactivation things happen in order and things
1698 * later on the list override things earlier on the list.
1700 * 0 INSTALLLEVEL processing
1713 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1714 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1715 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1716 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1717 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1720 msi_set_property( package->db, szPreselected, szOne );
1725 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1728 static const WCHAR szlevel[] =
1729 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1730 MSICOMPONENT* component;
1731 MSIFEATURE *feature;
1733 TRACE("Checking Install Level\n");
1735 level = msi_get_property_int(package->db, szlevel, 1);
1737 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1739 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1741 BOOL feature_state = ((feature->Level > 0) &&
1742 (feature->Level <= level));
1744 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1746 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1747 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1748 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1749 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1751 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1755 /* disable child features of unselected parent features */
1756 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1760 if (feature->Level > 0 && feature->Level <= level)
1763 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1764 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1769 * now we want to enable or disable components base on feature
1772 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1776 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1777 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1779 if (!feature->Level)
1782 /* features with components that have compressed files are made local */
1783 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1785 if (cl->component->Enabled &&
1786 cl->component->ForceLocalState &&
1787 feature->Action == INSTALLSTATE_SOURCE)
1789 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1794 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1796 component = cl->component;
1798 if (!component->Enabled)
1801 switch (feature->Action)
1803 case INSTALLSTATE_ABSENT:
1804 component->anyAbsent = 1;
1806 case INSTALLSTATE_ADVERTISED:
1807 component->hasAdvertiseFeature = 1;
1809 case INSTALLSTATE_SOURCE:
1810 component->hasSourceFeature = 1;
1812 case INSTALLSTATE_LOCAL:
1813 component->hasLocalFeature = 1;
1815 case INSTALLSTATE_DEFAULT:
1816 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1817 component->hasAdvertiseFeature = 1;
1818 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1819 component->hasSourceFeature = 1;
1821 component->hasLocalFeature = 1;
1829 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1831 /* if the component isn't enabled, leave it alone */
1832 if (!component->Enabled)
1835 /* check if it's local or source */
1836 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1837 (component->hasLocalFeature || component->hasSourceFeature))
1839 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1840 !component->ForceLocalState)
1841 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1843 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1847 /* if any feature is local, the component must be local too */
1848 if (component->hasLocalFeature)
1850 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1854 if (component->hasSourceFeature)
1856 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1860 if (component->hasAdvertiseFeature)
1862 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1866 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1867 if (component->anyAbsent)
1868 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1871 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1873 if (component->Action == INSTALLSTATE_DEFAULT)
1875 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1876 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1879 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1880 debugstr_w(component->Component), component->Installed, component->Action);
1884 return ERROR_SUCCESS;
1887 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1889 MSIPACKAGE *package = param;
1894 name = MSI_RecordGetString(row,1);
1896 f = get_loaded_folder(package, name);
1897 if (!f) return ERROR_SUCCESS;
1899 /* reset the ResolvedTarget */
1900 msi_free(f->ResolvedTarget);
1901 f->ResolvedTarget = NULL;
1903 /* This helper function now does ALL the work */
1904 TRACE("Dir %s ...\n",debugstr_w(name));
1905 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1906 TRACE("resolves to %s\n",debugstr_w(path));
1909 return ERROR_SUCCESS;
1912 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1914 MSIPACKAGE *package = param;
1916 MSIFEATURE *feature;
1918 name = MSI_RecordGetString( row, 1 );
1920 feature = get_loaded_feature( package, name );
1922 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1926 Condition = MSI_RecordGetString(row,3);
1928 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1930 int level = MSI_RecordGetInteger(row,2);
1931 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1932 feature->Level = level;
1935 return ERROR_SUCCESS;
1938 static LPWSTR get_disk_file_version( LPCWSTR filename )
1940 static const WCHAR name_fmt[] =
1941 {'%','u','.','%','u','.','%','u','.','%','u',0};
1942 static const WCHAR name[] = {'\\',0};
1943 VS_FIXEDFILEINFO *lpVer;
1944 WCHAR filever[0x100];
1950 TRACE("%s\n", debugstr_w(filename));
1952 versize = GetFileVersionInfoSizeW( filename, &handle );
1956 version = msi_alloc( versize );
1957 GetFileVersionInfoW( filename, 0, versize, version );
1959 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1961 msi_free( version );
1965 sprintfW( filever, name_fmt,
1966 HIWORD(lpVer->dwFileVersionMS),
1967 LOWORD(lpVer->dwFileVersionMS),
1968 HIWORD(lpVer->dwFileVersionLS),
1969 LOWORD(lpVer->dwFileVersionLS));
1971 msi_free( version );
1973 return strdupW( filever );
1976 static DWORD get_disk_file_size( LPCWSTR filename )
1981 TRACE("%s\n", debugstr_w(filename));
1983 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
1984 if (file == INVALID_HANDLE_VALUE)
1985 return INVALID_FILE_SIZE;
1987 size = GetFileSize( file, NULL );
1988 CloseHandle( file );
1992 static BOOL hash_matches( MSIFILE *file )
1995 MSIFILEHASHINFO hash;
1997 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1998 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
1999 if (r != ERROR_SUCCESS)
2002 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2005 static UINT set_file_install_states( MSIPACKAGE *package )
2007 LPWSTR file_version;
2010 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2012 MSICOMPONENT* comp = file->Component;
2019 if (file->IsCompressed)
2020 comp->ForceLocalState = TRUE;
2022 /* calculate target */
2023 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2025 msi_free(file->TargetPath);
2027 TRACE("file %s is named %s\n",
2028 debugstr_w(file->File), debugstr_w(file->FileName));
2030 file->TargetPath = build_directory_name(2, p, file->FileName);
2034 TRACE("file %s resolves to %s\n",
2035 debugstr_w(file->File), debugstr_w(file->TargetPath));
2037 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2039 file->state = msifs_missing;
2040 comp->Cost += file->FileSize;
2043 if (file->Version && (file_version = get_disk_file_version( file->TargetPath )))
2045 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(file_version));
2047 if (strcmpiW(file_version, file->Version) < 0)
2049 file->state = msifs_overwrite;
2050 comp->Cost += file->FileSize;
2054 TRACE("Destination file version equal or greater, not overwriting\n");
2055 file->state = msifs_present;
2057 msi_free( file_version );
2060 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2062 file->state = msifs_overwrite;
2063 comp->Cost += file->FileSize - file_size;
2066 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2068 TRACE("File hashes match, not overwriting\n");
2069 file->state = msifs_present;
2072 file->state = msifs_overwrite;
2073 comp->Cost += file->FileSize - file_size;
2076 return ERROR_SUCCESS;
2080 * A lot is done in this function aside from just the costing.
2081 * The costing needs to be implemented at some point but for now I am going
2082 * to focus on the directory building
2085 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2087 static const WCHAR ExecSeqQuery[] =
2088 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2089 '`','D','i','r','e','c','t','o','r','y','`',0};
2090 static const WCHAR ConditionQuery[] =
2091 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2092 '`','C','o','n','d','i','t','i','o','n','`',0};
2093 static const WCHAR szCosting[] =
2094 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2095 static const WCHAR szlevel[] =
2096 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2097 static const WCHAR szOutOfDiskSpace[] =
2098 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2100 UINT rc = ERROR_SUCCESS;
2104 TRACE("Building Directory properties\n");
2106 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2107 if (rc == ERROR_SUCCESS)
2109 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2111 msiobj_release(&view->hdr);
2114 /* read components states from the registry */
2115 ACTION_GetComponentInstallStates(package);
2116 ACTION_GetFeatureInstallStates(package);
2118 TRACE("Calculating file install states\n");
2119 set_file_install_states( package );
2121 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2123 TRACE("Evaluating feature conditions\n");
2125 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2126 if (rc == ERROR_SUCCESS)
2128 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2129 msiobj_release( &view->hdr );
2132 TRACE("Evaluating component conditions\n");
2134 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2136 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2138 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2139 comp->Enabled = FALSE;
2142 comp->Enabled = TRUE;
2145 msi_set_property( package->db, szCosting, szOne );
2146 /* set default run level if not set */
2147 level = msi_dup_property( package->db, szlevel );
2149 msi_set_property( package->db, szlevel, szOne );
2152 /* FIXME: check volume disk space */
2153 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2155 return MSI_SetFeatureStates(package);
2158 /* OK this value is "interpreted" and then formatted based on the
2159 first few characters */
2160 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2165 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2171 LPWSTR deformated = NULL;
2174 deformat_string(package, &value[2], &deformated);
2176 /* binary value type */
2180 *size = (strlenW(ptr)/2)+1;
2182 *size = strlenW(ptr)/2;
2184 data = msi_alloc(*size);
2190 /* if uneven pad with a zero in front */
2196 data[count] = (BYTE)strtol(byte,NULL,0);
2198 TRACE("Uneven byte count\n");
2206 data[count] = (BYTE)strtol(byte,NULL,0);
2209 msi_free(deformated);
2211 TRACE("Data %i bytes(%i)\n",*size,count);
2218 deformat_string(package, &value[1], &deformated);
2221 *size = sizeof(DWORD);
2222 data = msi_alloc(*size);
2228 if ( (*p < '0') || (*p > '9') )
2234 if (deformated[0] == '-')
2237 TRACE("DWORD %i\n",*(LPDWORD)data);
2239 msi_free(deformated);
2244 static const WCHAR szMulti[] = {'[','~',']',0};
2253 *type=REG_EXPAND_SZ;
2261 if (strstrW(value,szMulti))
2262 *type = REG_MULTI_SZ;
2264 /* remove initial delimiter */
2265 if (!strncmpW(value, szMulti, 3))
2268 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2270 /* add double NULL terminator */
2271 if (*type == REG_MULTI_SZ)
2273 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2274 data = msi_realloc_zero(data, *size);
2280 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2287 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2289 *root_key = HKEY_LOCAL_MACHINE;
2294 *root_key = HKEY_CURRENT_USER;
2299 *root_key = HKEY_CLASSES_ROOT;
2303 *root_key = HKEY_CURRENT_USER;
2307 *root_key = HKEY_LOCAL_MACHINE;
2311 *root_key = HKEY_USERS;
2315 ERR("Unknown root %i\n", root);
2322 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2324 MSIPACKAGE *package = param;
2325 LPSTR value_data = NULL;
2326 HKEY root_key, hkey;
2329 LPCWSTR szRoot, component, name, key, value;
2334 BOOL check_first = FALSE;
2337 ui_progress(package,2,0,0,0);
2344 component = MSI_RecordGetString(row, 6);
2345 comp = get_loaded_component(package,component);
2347 return ERROR_SUCCESS;
2349 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2351 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2352 comp->Action = comp->Installed;
2353 return ERROR_SUCCESS;
2355 comp->Action = INSTALLSTATE_LOCAL;
2357 name = MSI_RecordGetString(row, 4);
2358 if( MSI_RecordIsNull(row,5) && name )
2360 /* null values can have special meanings */
2361 if (name[0]=='-' && name[1] == 0)
2362 return ERROR_SUCCESS;
2363 else if ((name[0]=='+' && name[1] == 0) ||
2364 (name[0] == '*' && name[1] == 0))
2369 root = MSI_RecordGetInteger(row,2);
2370 key = MSI_RecordGetString(row, 3);
2372 szRoot = get_root_key( package, root, &root_key );
2374 return ERROR_SUCCESS;
2376 deformat_string(package, key , &deformated);
2377 size = strlenW(deformated) + strlenW(szRoot) + 1;
2378 uikey = msi_alloc(size*sizeof(WCHAR));
2379 strcpyW(uikey,szRoot);
2380 strcatW(uikey,deformated);
2382 if (RegCreateKeyW( root_key, deformated, &hkey))
2384 ERR("Could not create key %s\n",debugstr_w(deformated));
2385 msi_free(deformated);
2387 return ERROR_SUCCESS;
2389 msi_free(deformated);
2391 value = MSI_RecordGetString(row,5);
2393 value_data = parse_value(package, value, &type, &size);
2396 value_data = (LPSTR)strdupW(szEmpty);
2397 size = sizeof(szEmpty);
2401 deformat_string(package, name, &deformated);
2405 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2407 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2412 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2413 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2415 TRACE("value %s of %s checked already exists\n",
2416 debugstr_w(deformated), debugstr_w(uikey));
2420 TRACE("Checked and setting value %s of %s\n",
2421 debugstr_w(deformated), debugstr_w(uikey));
2422 if (deformated || size)
2423 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2428 uirow = MSI_CreateRecord(3);
2429 MSI_RecordSetStringW(uirow,2,deformated);
2430 MSI_RecordSetStringW(uirow,1,uikey);
2431 if (type == REG_SZ || type == REG_EXPAND_SZ)
2432 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2433 ui_actiondata(package,szWriteRegistryValues,uirow);
2434 msiobj_release( &uirow->hdr );
2436 msi_free(value_data);
2437 msi_free(deformated);
2440 return ERROR_SUCCESS;
2443 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2447 static const WCHAR ExecSeqQuery[] =
2448 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2449 '`','R','e','g','i','s','t','r','y','`',0 };
2451 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2452 if (rc != ERROR_SUCCESS)
2453 return ERROR_SUCCESS;
2455 /* increment progress bar each time action data is sent */
2456 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2458 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2460 msiobj_release(&view->hdr);
2464 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2468 DWORD num_subkeys, num_values;
2472 if ((res = RegDeleteTreeW( hkey_root, key )))
2474 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2479 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2481 if ((res = RegDeleteValueW( hkey, value )))
2483 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2485 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2486 NULL, NULL, NULL, NULL );
2487 RegCloseKey( hkey );
2489 if (!res && !num_subkeys && !num_values)
2491 TRACE("Removing empty key %s\n", debugstr_w(key));
2492 RegDeleteKeyW( hkey_root, key );
2496 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2500 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2502 MSIPACKAGE *package = param;
2503 LPCWSTR component, name, key_str, root_key_str;
2504 LPWSTR deformated_key, deformated_name, ui_key_str;
2507 BOOL delete_key = FALSE;
2512 ui_progress( package, 2, 0, 0, 0 );
2514 component = MSI_RecordGetString( row, 6 );
2515 comp = get_loaded_component( package, component );
2517 return ERROR_SUCCESS;
2519 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2521 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2522 comp->Action = comp->Installed;
2523 return ERROR_SUCCESS;
2525 comp->Action = INSTALLSTATE_ABSENT;
2527 name = MSI_RecordGetString( row, 4 );
2528 if (MSI_RecordIsNull( row, 5 ) && name )
2530 if (name[0] == '+' && !name[1])
2531 return ERROR_SUCCESS;
2532 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2539 root = MSI_RecordGetInteger( row, 2 );
2540 key_str = MSI_RecordGetString( row, 3 );
2542 root_key_str = get_root_key( package, root, &hkey_root );
2544 return ERROR_SUCCESS;
2546 deformat_string( package, key_str, &deformated_key );
2547 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2548 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2549 strcpyW( ui_key_str, root_key_str );
2550 strcatW( ui_key_str, deformated_key );
2552 deformat_string( package, name, &deformated_name );
2554 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2555 msi_free( deformated_key );
2557 uirow = MSI_CreateRecord( 2 );
2558 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2559 MSI_RecordSetStringW( uirow, 2, deformated_name );
2561 ui_actiondata( package, szRemoveRegistryValues, uirow );
2562 msiobj_release( &uirow->hdr );
2564 msi_free( ui_key_str );
2565 msi_free( deformated_name );
2566 return ERROR_SUCCESS;
2569 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2571 MSIPACKAGE *package = param;
2572 LPCWSTR component, name, key_str, root_key_str;
2573 LPWSTR deformated_key, deformated_name, ui_key_str;
2576 BOOL delete_key = FALSE;
2581 ui_progress( package, 2, 0, 0, 0 );
2583 component = MSI_RecordGetString( row, 5 );
2584 comp = get_loaded_component( package, component );
2586 return ERROR_SUCCESS;
2588 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2590 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2591 comp->Action = comp->Installed;
2592 return ERROR_SUCCESS;
2594 comp->Action = INSTALLSTATE_LOCAL;
2596 if ((name = MSI_RecordGetString( row, 4 )))
2598 if (name[0] == '-' && !name[1])
2605 root = MSI_RecordGetInteger( row, 2 );
2606 key_str = MSI_RecordGetString( row, 3 );
2608 root_key_str = get_root_key( package, root, &hkey_root );
2610 return ERROR_SUCCESS;
2612 deformat_string( package, key_str, &deformated_key );
2613 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2614 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2615 strcpyW( ui_key_str, root_key_str );
2616 strcatW( ui_key_str, deformated_key );
2618 deformat_string( package, name, &deformated_name );
2620 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2621 msi_free( deformated_key );
2623 uirow = MSI_CreateRecord( 2 );
2624 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2625 MSI_RecordSetStringW( uirow, 2, deformated_name );
2627 ui_actiondata( package, szRemoveRegistryValues, uirow );
2628 msiobj_release( &uirow->hdr );
2630 msi_free( ui_key_str );
2631 msi_free( deformated_name );
2632 return ERROR_SUCCESS;
2635 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2639 static const WCHAR registry_query[] =
2640 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2641 '`','R','e','g','i','s','t','r','y','`',0 };
2642 static const WCHAR remove_registry_query[] =
2643 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2644 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2646 /* increment progress bar each time action data is sent */
2647 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2649 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2650 if (rc == ERROR_SUCCESS)
2652 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2653 msiobj_release( &view->hdr );
2654 if (rc != ERROR_SUCCESS)
2658 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2659 if (rc == ERROR_SUCCESS)
2661 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2662 msiobj_release( &view->hdr );
2663 if (rc != ERROR_SUCCESS)
2667 return ERROR_SUCCESS;
2670 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2672 package->script->CurrentlyScripting = TRUE;
2674 return ERROR_SUCCESS;
2678 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2683 static const WCHAR q1[]=
2684 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2685 '`','R','e','g','i','s','t','r','y','`',0};
2688 MSIFEATURE *feature;
2691 TRACE("InstallValidate\n");
2693 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2694 if (rc == ERROR_SUCCESS)
2696 MSI_IterateRecords( view, &progress, NULL, package );
2697 msiobj_release( &view->hdr );
2698 total += progress * REG_PROGRESS_VALUE;
2701 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2702 total += COMPONENT_PROGRESS_VALUE;
2704 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2705 total += file->FileSize;
2707 ui_progress(package,0,total,0,0);
2709 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2711 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2712 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2713 feature->ActionRequest);
2716 return ERROR_SUCCESS;
2719 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2721 MSIPACKAGE* package = param;
2722 LPCWSTR cond = NULL;
2723 LPCWSTR message = NULL;
2726 static const WCHAR title[]=
2727 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2729 cond = MSI_RecordGetString(row,1);
2731 r = MSI_EvaluateConditionW(package,cond);
2732 if (r == MSICONDITION_FALSE)
2734 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2737 message = MSI_RecordGetString(row,2);
2738 deformat_string(package,message,&deformated);
2739 MessageBoxW(NULL,deformated,title,MB_OK);
2740 msi_free(deformated);
2743 return ERROR_INSTALL_FAILURE;
2746 return ERROR_SUCCESS;
2749 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2752 MSIQUERY * view = NULL;
2753 static const WCHAR ExecSeqQuery[] =
2754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2755 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2757 TRACE("Checking launch conditions\n");
2759 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2760 if (rc != ERROR_SUCCESS)
2761 return ERROR_SUCCESS;
2763 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2764 msiobj_release(&view->hdr);
2769 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2773 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2775 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2777 MSIRECORD * row = 0;
2779 LPWSTR deformated,buffer,deformated_name;
2781 static const WCHAR ExecSeqQuery[] =
2782 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2783 '`','R','e','g','i','s','t','r','y','`',' ',
2784 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2785 ' ','=',' ' ,'\'','%','s','\'',0 };
2786 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2787 static const WCHAR fmt2[]=
2788 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2790 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2794 root = MSI_RecordGetInteger(row,2);
2795 key = MSI_RecordGetString(row, 3);
2796 name = MSI_RecordGetString(row, 4);
2797 deformat_string(package, key , &deformated);
2798 deformat_string(package, name, &deformated_name);
2800 len = strlenW(deformated) + 6;
2801 if (deformated_name)
2802 len+=strlenW(deformated_name);
2804 buffer = msi_alloc( len *sizeof(WCHAR));
2806 if (deformated_name)
2807 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2809 sprintfW(buffer,fmt,root,deformated);
2811 msi_free(deformated);
2812 msi_free(deformated_name);
2813 msiobj_release(&row->hdr);
2817 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2819 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2824 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2827 return strdupW( file->TargetPath );
2832 static HKEY openSharedDLLsKey(void)
2835 static const WCHAR path[] =
2836 {'S','o','f','t','w','a','r','e','\\',
2837 'M','i','c','r','o','s','o','f','t','\\',
2838 'W','i','n','d','o','w','s','\\',
2839 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2840 'S','h','a','r','e','d','D','L','L','s',0};
2842 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2846 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2851 DWORD sz = sizeof(count);
2854 hkey = openSharedDLLsKey();
2855 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2856 if (rc != ERROR_SUCCESS)
2862 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2866 hkey = openSharedDLLsKey();
2868 msi_reg_set_val_dword( hkey, path, count );
2870 RegDeleteValueW(hkey,path);
2876 * Return TRUE if the count should be written out and FALSE if not
2878 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2880 MSIFEATURE *feature;
2884 /* only refcount DLLs */
2885 if (comp->KeyPath == NULL ||
2886 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2887 comp->Attributes & msidbComponentAttributesODBCDataSource)
2891 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2892 write = (count > 0);
2894 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2898 /* increment counts */
2899 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2903 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2906 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2908 if ( cl->component == comp )
2913 /* decrement counts */
2914 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2918 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2921 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2923 if ( cl->component == comp )
2928 /* ref count all the files in the component */
2933 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2935 if (file->Component == comp)
2936 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2940 /* add a count for permanent */
2941 if (comp->Attributes & msidbComponentAttributesPermanent)
2944 comp->RefCount = count;
2947 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2950 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2952 WCHAR squished_pc[GUID_SIZE];
2953 WCHAR squished_cc[GUID_SIZE];
2960 squash_guid(package->ProductCode,squished_pc);
2961 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2963 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2967 ui_progress(package,2,0,0,0);
2968 if (!comp->ComponentId)
2971 squash_guid(comp->ComponentId,squished_cc);
2973 msi_free(comp->FullKeypath);
2974 comp->FullKeypath = resolve_keypath( package, comp );
2976 ACTION_RefCountComponent( package, comp );
2978 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2979 debugstr_w(comp->Component),
2980 debugstr_w(squished_cc),
2981 debugstr_w(comp->FullKeypath),
2984 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2985 comp->ActionRequest == INSTALLSTATE_SOURCE)
2987 if (!comp->FullKeypath)
2990 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2991 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2994 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2997 if (rc != ERROR_SUCCESS)
3000 if (comp->Attributes & msidbComponentAttributesPermanent)
3002 static const WCHAR szPermKey[] =
3003 { '0','0','0','0','0','0','0','0','0','0','0','0',
3004 '0','0','0','0','0','0','0','0','0','0','0','0',
3005 '0','0','0','0','0','0','0','0',0 };
3007 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3010 if (comp->Action == INSTALLSTATE_LOCAL)
3011 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3017 WCHAR source[MAX_PATH];
3018 WCHAR base[MAX_PATH];
3021 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3022 static const WCHAR query[] = {
3023 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3024 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3025 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3026 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3027 '`','D','i','s','k','I','d','`',0};
3029 file = get_loaded_file(package, comp->KeyPath);
3033 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3034 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3035 ptr2 = strrchrW(source, '\\') + 1;
3036 msiobj_release(&row->hdr);
3038 lstrcpyW(base, package->PackagePath);
3039 ptr = strrchrW(base, '\\');
3042 sourcepath = resolve_file_source(package, file);
3043 ptr = sourcepath + lstrlenW(base);
3044 lstrcpyW(ptr2, ptr);
3045 msi_free(sourcepath);
3047 msi_reg_set_val_str(hkey, squished_pc, source);
3051 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3053 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3054 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3056 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3058 comp->Action = comp->ActionRequest;
3061 uirow = MSI_CreateRecord(3);
3062 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3063 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3064 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3065 ui_actiondata(package,szProcessComponents,uirow);
3066 msiobj_release( &uirow->hdr );
3069 return ERROR_SUCCESS;
3080 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3081 LPWSTR lpszName, LONG_PTR lParam)
3084 typelib_struct *tl_struct = (typelib_struct*) lParam;
3085 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3089 if (!IS_INTRESOURCE(lpszName))
3091 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3095 sz = strlenW(tl_struct->source)+4;
3096 sz *= sizeof(WCHAR);
3098 if ((INT_PTR)lpszName == 1)
3099 tl_struct->path = strdupW(tl_struct->source);
3102 tl_struct->path = msi_alloc(sz);
3103 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3106 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3107 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3110 msi_free(tl_struct->path);
3111 tl_struct->path = NULL;
3116 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3117 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3119 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3123 msi_free(tl_struct->path);
3124 tl_struct->path = NULL;
3126 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3127 ITypeLib_Release(tl_struct->ptLib);
3132 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3134 MSIPACKAGE* package = param;
3138 typelib_struct tl_struct;
3143 component = MSI_RecordGetString(row,3);
3144 comp = get_loaded_component(package,component);
3146 return ERROR_SUCCESS;
3148 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3150 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3151 comp->Action = comp->Installed;
3152 return ERROR_SUCCESS;
3154 comp->Action = INSTALLSTATE_LOCAL;
3156 file = get_loaded_file( package, comp->KeyPath );
3158 return ERROR_SUCCESS;
3160 ui_actiondata( package, szRegisterTypeLibraries, row );
3162 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3166 guid = MSI_RecordGetString(row,1);
3167 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3168 tl_struct.source = strdupW( file->TargetPath );
3169 tl_struct.path = NULL;
3171 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3172 (LONG_PTR)&tl_struct);
3180 helpid = MSI_RecordGetString(row,6);
3183 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3184 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3188 ERR("Failed to register type library %s\n",
3189 debugstr_w(tl_struct.path));
3191 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3193 ITypeLib_Release(tl_struct.ptLib);
3194 msi_free(tl_struct.path);
3197 ERR("Failed to load type library %s\n",
3198 debugstr_w(tl_struct.source));
3200 FreeLibrary(module);
3201 msi_free(tl_struct.source);
3205 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3208 ERR("Failed to load type library: %08x\n", hr);
3209 return ERROR_INSTALL_FAILURE;
3212 ITypeLib_Release(tlib);
3215 return ERROR_SUCCESS;
3218 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3221 * OK this is a bit confusing.. I am given a _Component key and I believe
3222 * that the file that is being registered as a type library is the "key file
3223 * of that component" which I interpret to mean "The file in the KeyPath of
3228 static const WCHAR Query[] =
3229 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3230 '`','T','y','p','e','L','i','b','`',0};
3232 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3233 if (rc != ERROR_SUCCESS)
3234 return ERROR_SUCCESS;
3236 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3237 msiobj_release(&view->hdr);
3241 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3243 MSIPACKAGE *package = param;
3244 LPCWSTR component, guid;
3252 component = MSI_RecordGetString( row, 3 );
3253 comp = get_loaded_component( package, component );
3255 return ERROR_SUCCESS;
3257 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3259 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3260 comp->Action = comp->Installed;
3261 return ERROR_SUCCESS;
3263 comp->Action = INSTALLSTATE_ABSENT;
3265 ui_actiondata( package, szUnregisterTypeLibraries, row );
3267 guid = MSI_RecordGetString( row, 1 );
3268 CLSIDFromString( (LPCWSTR)guid, &libid );
3269 version = MSI_RecordGetInteger( row, 4 );
3270 language = MSI_RecordGetInteger( row, 2 );
3273 syskind = SYS_WIN64;
3275 syskind = SYS_WIN32;
3278 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3281 WARN("Failed to unregister typelib: %08x\n", hr);
3284 return ERROR_SUCCESS;
3287 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3291 static const WCHAR query[] =
3292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3293 '`','T','y','p','e','L','i','b','`',0};
3295 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3296 if (rc != ERROR_SUCCESS)
3297 return ERROR_SUCCESS;
3299 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3300 msiobj_release( &view->hdr );
3304 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3306 static const WCHAR szlnk[] = {'.','l','n','k',0};
3307 LPCWSTR directory, extension;
3308 LPWSTR link_folder, link_file, filename;
3310 directory = MSI_RecordGetString( row, 2 );
3311 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3313 /* may be needed because of a bug somewhere else */
3314 create_full_pathW( link_folder );
3316 filename = msi_dup_record_field( row, 3 );
3317 reduce_to_longfilename( filename );
3319 extension = strchrW( filename, '.' );
3320 if (!extension || strcmpiW( extension, szlnk ))
3322 int len = strlenW( filename );
3323 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3324 memcpy( filename + len, szlnk, sizeof(szlnk) );
3326 link_file = build_directory_name( 2, link_folder, filename );
3327 msi_free( link_folder );
3328 msi_free( filename );
3333 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3335 MSIPACKAGE *package = param;
3336 LPWSTR link_file, deformated, path;
3337 LPCWSTR component, target;
3339 IShellLinkW *sl = NULL;
3340 IPersistFile *pf = NULL;
3343 component = MSI_RecordGetString(row, 4);
3344 comp = get_loaded_component(package, component);
3346 return ERROR_SUCCESS;
3348 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3350 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3351 comp->Action = comp->Installed;
3352 return ERROR_SUCCESS;
3354 comp->Action = INSTALLSTATE_LOCAL;
3356 ui_actiondata(package,szCreateShortcuts,row);
3358 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3359 &IID_IShellLinkW, (LPVOID *) &sl );
3363 ERR("CLSID_ShellLink not available\n");
3367 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3370 ERR("QueryInterface(IID_IPersistFile) failed\n");
3374 target = MSI_RecordGetString(row, 5);
3375 if (strchrW(target, '['))
3377 deformat_string(package, target, &deformated);
3378 IShellLinkW_SetPath(sl,deformated);
3379 msi_free(deformated);
3383 FIXME("poorly handled shortcut format, advertised shortcut\n");
3384 IShellLinkW_SetPath(sl,comp->FullKeypath);
3387 if (!MSI_RecordIsNull(row,6))
3389 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3390 deformat_string(package, arguments, &deformated);
3391 IShellLinkW_SetArguments(sl,deformated);
3392 msi_free(deformated);
3395 if (!MSI_RecordIsNull(row,7))
3397 LPCWSTR description = MSI_RecordGetString(row, 7);
3398 IShellLinkW_SetDescription(sl, description);
3401 if (!MSI_RecordIsNull(row,8))
3402 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3404 if (!MSI_RecordIsNull(row,9))
3407 LPCWSTR icon = MSI_RecordGetString(row, 9);
3409 path = build_icon_path(package, icon);
3410 index = MSI_RecordGetInteger(row,10);
3412 /* no value means 0 */
3413 if (index == MSI_NULL_INTEGER)
3416 IShellLinkW_SetIconLocation(sl, path, index);
3420 if (!MSI_RecordIsNull(row,11))
3421 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3423 if (!MSI_RecordIsNull(row,12))
3425 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3426 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3428 IShellLinkW_SetWorkingDirectory(sl, path);
3432 link_file = get_link_file(package, row);
3434 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3435 IPersistFile_Save(pf, link_file, FALSE);
3437 msi_free(link_file);
3441 IPersistFile_Release( pf );
3443 IShellLinkW_Release( sl );
3445 return ERROR_SUCCESS;
3448 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3453 static const WCHAR Query[] =
3454 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3455 '`','S','h','o','r','t','c','u','t','`',0};
3457 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3458 if (rc != ERROR_SUCCESS)
3459 return ERROR_SUCCESS;
3461 res = CoInitialize( NULL );
3463 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3464 msiobj_release(&view->hdr);
3472 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3474 MSIPACKAGE *package = param;
3479 component = MSI_RecordGetString( row, 4 );
3480 comp = get_loaded_component( package, component );
3482 return ERROR_SUCCESS;
3484 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3486 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3487 comp->Action = comp->Installed;
3488 return ERROR_SUCCESS;
3490 comp->Action = INSTALLSTATE_ABSENT;
3492 ui_actiondata( package, szRemoveShortcuts, row );
3494 link_file = get_link_file( package, row );
3496 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3497 if (!DeleteFileW( link_file ))
3499 WARN("Failed to remove shortcut file %u\n", GetLastError());
3501 msi_free( link_file );
3503 return ERROR_SUCCESS;
3506 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3510 static const WCHAR query[] =
3511 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3512 '`','S','h','o','r','t','c','u','t','`',0};
3514 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3515 if (rc != ERROR_SUCCESS)
3516 return ERROR_SUCCESS;
3518 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3519 msiobj_release( &view->hdr );
3524 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3526 MSIPACKAGE* package = param;
3534 FileName = MSI_RecordGetString(row,1);
3537 ERR("Unable to get FileName\n");
3538 return ERROR_SUCCESS;
3541 FilePath = build_icon_path(package,FileName);
3543 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3545 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3546 FILE_ATTRIBUTE_NORMAL, NULL);
3548 if (the_file == INVALID_HANDLE_VALUE)
3550 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3552 return ERROR_SUCCESS;
3559 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3560 if (rc != ERROR_SUCCESS)
3562 ERR("Failed to get stream\n");
3563 CloseHandle(the_file);
3564 DeleteFileW(FilePath);
3567 WriteFile(the_file,buffer,sz,&write,NULL);
3568 } while (sz == 1024);
3571 CloseHandle(the_file);
3573 return ERROR_SUCCESS;
3576 static UINT msi_publish_icons(MSIPACKAGE *package)
3581 static const WCHAR query[]= {
3582 'S','E','L','E','C','T',' ','*',' ',
3583 'F','R','O','M',' ','`','I','c','o','n','`',0};
3585 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3586 if (r == ERROR_SUCCESS)
3588 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3589 msiobj_release(&view->hdr);
3592 return ERROR_SUCCESS;
3595 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3601 MSISOURCELISTINFO *info;
3603 r = RegCreateKeyW(hkey, szSourceList, &source);
3604 if (r != ERROR_SUCCESS)
3607 RegCloseKey(source);
3609 buffer = strrchrW(package->PackagePath, '\\') + 1;
3610 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3611 package->Context, MSICODE_PRODUCT,
3612 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3613 if (r != ERROR_SUCCESS)
3616 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3617 package->Context, MSICODE_PRODUCT,
3618 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3619 if (r != ERROR_SUCCESS)
3622 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3623 package->Context, MSICODE_PRODUCT,
3624 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3625 if (r != ERROR_SUCCESS)
3628 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3630 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3631 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3632 info->options, info->value);
3634 MsiSourceListSetInfoW(package->ProductCode, NULL,
3635 info->context, info->options,
3636 info->property, info->value);
3639 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3641 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3642 disk->context, disk->options,
3643 disk->disk_id, disk->volume_label, disk->disk_prompt);
3646 return ERROR_SUCCESS;
3649 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3651 MSIHANDLE hdb, suminfo;
3652 WCHAR guids[MAX_PATH];
3653 WCHAR packcode[SQUISH_GUID_SIZE];
3660 static const WCHAR szProductLanguage[] =
3661 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3662 static const WCHAR szARPProductIcon[] =
3663 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3664 static const WCHAR szProductVersion[] =
3665 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3666 static const WCHAR szAssignment[] =
3667 {'A','s','s','i','g','n','m','e','n','t',0};
3668 static const WCHAR szAdvertiseFlags[] =
3669 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3670 static const WCHAR szClients[] =
3671 {'C','l','i','e','n','t','s',0};
3672 static const WCHAR szColon[] = {':',0};
3674 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3675 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3678 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3679 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3682 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3684 buffer = msi_dup_property(package->db, szARPProductIcon);
3687 LPWSTR path = build_icon_path(package,buffer);
3688 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3693 buffer = msi_dup_property(package->db, szProductVersion);
3696 DWORD verdword = msi_version_str_to_dword(buffer);
3697 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3701 msi_reg_set_val_dword(hkey, szAssignment, 0);
3702 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3703 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3704 msi_reg_set_val_str(hkey, szClients, szColon);
3706 hdb = alloc_msihandle(&package->db->hdr);
3708 return ERROR_NOT_ENOUGH_MEMORY;
3710 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3711 MsiCloseHandle(hdb);
3712 if (r != ERROR_SUCCESS)
3716 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3717 NULL, guids, &size);
3718 if (r != ERROR_SUCCESS)
3721 ptr = strchrW(guids, ';');
3723 squash_guid(guids, packcode);
3724 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3727 MsiCloseHandle(suminfo);
3728 return ERROR_SUCCESS;
3731 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3736 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3738 static const WCHAR szUpgradeCode[] =
3739 {'U','p','g','r','a','d','e','C','o','d','e',0};
3741 upgrade = msi_dup_property(package->db, szUpgradeCode);
3743 return ERROR_SUCCESS;
3745 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3747 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3748 if (r != ERROR_SUCCESS)
3753 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3754 if (r != ERROR_SUCCESS)
3758 squash_guid(package->ProductCode, squashed_pc);
3759 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3768 static BOOL msi_check_publish(MSIPACKAGE *package)
3770 MSIFEATURE *feature;
3772 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3774 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3781 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3783 MSIFEATURE *feature;
3785 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3787 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3794 static UINT msi_publish_patches( MSIPACKAGE *package, HKEY prodkey, HKEY hudkey )
3796 WCHAR patch_squashed[GUID_SIZE];
3799 MSIPATCHINFO *patch;
3800 UINT r = ERROR_FUNCTION_FAILED;
3801 WCHAR *p, *all_patches = NULL;
3804 res = RegCreateKeyExW( prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches, NULL );
3805 if (res != ERROR_SUCCESS)
3806 return ERROR_FUNCTION_FAILED;
3808 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3810 squash_guid( patch->patchcode, patch_squashed );
3811 len += strlenW( patch_squashed ) + 1;
3814 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3818 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3820 squash_guid( patch->patchcode, p );
3821 p += strlenW( p ) + 1;
3823 res = RegSetValueExW( patches, patch_squashed, 0, REG_SZ,
3824 (const BYTE *)patch->transforms,
3825 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3826 if (res != ERROR_SUCCESS)
3830 all_patches[len] = 0;
3831 res = RegSetValueExW( patches, szPatches, 0, REG_MULTI_SZ,
3832 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3833 if (res == ERROR_SUCCESS)
3837 RegCloseKey(patches);
3838 msi_free( all_patches );
3843 * 99% of the work done here is only done for
3844 * advertised installs. However this is where the
3845 * Icon table is processed and written out
3846 * so that is what I am going to do here.
3848 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3851 HKEY hukey = NULL, hudkey = NULL;
3854 /* FIXME: also need to publish if the product is in advertise mode */
3855 if (!msi_check_publish(package))
3856 return ERROR_SUCCESS;
3858 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3860 if (rc != ERROR_SUCCESS)
3863 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3864 NULL, &hudkey, TRUE);
3865 if (rc != ERROR_SUCCESS)
3868 rc = msi_publish_upgrade_code(package);
3869 if (rc != ERROR_SUCCESS)
3872 if (!list_empty(&package->patches))
3874 rc = msi_publish_patches(package, hukey, hudkey);
3875 if (rc != ERROR_SUCCESS)
3879 rc = msi_publish_product_properties(package, hukey);
3880 if (rc != ERROR_SUCCESS)
3883 rc = msi_publish_sourcelist(package, hukey);
3884 if (rc != ERROR_SUCCESS)
3887 rc = msi_publish_icons(package);
3890 uirow = MSI_CreateRecord( 1 );
3891 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3892 ui_actiondata( package, szPublishProduct, uirow );
3893 msiobj_release( &uirow->hdr );
3896 RegCloseKey(hudkey);
3901 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3903 WCHAR *filename, *ptr, *folder, *ret;
3904 const WCHAR *dirprop;
3906 filename = msi_dup_record_field( row, 2 );
3907 if (filename && (ptr = strchrW( filename, '|' )))
3912 dirprop = MSI_RecordGetString( row, 3 );
3915 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3917 folder = msi_dup_property( package->db, dirprop );
3920 folder = msi_dup_property( package->db, szWindowsFolder );
3924 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3925 msi_free( filename );
3929 ret = build_directory_name( 2, folder, ptr );
3931 msi_free( filename );
3936 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3938 MSIPACKAGE *package = param;
3939 LPCWSTR component, section, key, value, identifier;
3940 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3945 component = MSI_RecordGetString(row, 8);
3946 comp = get_loaded_component(package,component);
3948 return ERROR_SUCCESS;
3950 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3952 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3953 comp->Action = comp->Installed;
3954 return ERROR_SUCCESS;
3956 comp->Action = INSTALLSTATE_LOCAL;
3958 identifier = MSI_RecordGetString(row,1);
3959 section = MSI_RecordGetString(row,4);
3960 key = MSI_RecordGetString(row,5);
3961 value = MSI_RecordGetString(row,6);
3962 action = MSI_RecordGetInteger(row,7);
3964 deformat_string(package,section,&deformated_section);
3965 deformat_string(package,key,&deformated_key);
3966 deformat_string(package,value,&deformated_value);
3968 fullname = get_ini_file_name(package, row);
3972 TRACE("Adding value %s to section %s in %s\n",
3973 debugstr_w(deformated_key), debugstr_w(deformated_section),
3974 debugstr_w(fullname));
3975 WritePrivateProfileStringW(deformated_section, deformated_key,
3976 deformated_value, fullname);
3978 else if (action == 1)
3981 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3982 returned, 10, fullname);
3983 if (returned[0] == 0)
3985 TRACE("Adding value %s to section %s in %s\n",
3986 debugstr_w(deformated_key), debugstr_w(deformated_section),
3987 debugstr_w(fullname));
3989 WritePrivateProfileStringW(deformated_section, deformated_key,
3990 deformated_value, fullname);
3993 else if (action == 3)
3994 FIXME("Append to existing section not yet implemented\n");
3996 uirow = MSI_CreateRecord(4);
3997 MSI_RecordSetStringW(uirow,1,identifier);
3998 MSI_RecordSetStringW(uirow,2,deformated_section);
3999 MSI_RecordSetStringW(uirow,3,deformated_key);
4000 MSI_RecordSetStringW(uirow,4,deformated_value);
4001 ui_actiondata(package,szWriteIniValues,uirow);
4002 msiobj_release( &uirow->hdr );
4005 msi_free(deformated_key);
4006 msi_free(deformated_value);
4007 msi_free(deformated_section);
4008 return ERROR_SUCCESS;
4011 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4015 static const WCHAR ExecSeqQuery[] =
4016 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4017 '`','I','n','i','F','i','l','e','`',0};
4019 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4020 if (rc != ERROR_SUCCESS)
4022 TRACE("no IniFile table\n");
4023 return ERROR_SUCCESS;
4026 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4027 msiobj_release(&view->hdr);
4031 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4033 MSIPACKAGE *package = param;
4034 LPCWSTR component, section, key, value, identifier;
4035 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4040 component = MSI_RecordGetString( row, 8 );
4041 comp = get_loaded_component( package, component );
4043 return ERROR_SUCCESS;
4045 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4047 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4048 comp->Action = comp->Installed;
4049 return ERROR_SUCCESS;
4051 comp->Action = INSTALLSTATE_ABSENT;
4053 identifier = MSI_RecordGetString( row, 1 );
4054 section = MSI_RecordGetString( row, 4 );
4055 key = MSI_RecordGetString( row, 5 );
4056 value = MSI_RecordGetString( row, 6 );
4057 action = MSI_RecordGetInteger( row, 7 );
4059 deformat_string( package, section, &deformated_section );
4060 deformat_string( package, key, &deformated_key );
4061 deformat_string( package, value, &deformated_value );
4063 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4065 filename = get_ini_file_name( package, row );
4067 TRACE("Removing key %s from section %s in %s\n",
4068 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4070 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4072 WARN("Unable to remove key %u\n", GetLastError());
4074 msi_free( filename );
4077 FIXME("Unsupported action %d\n", action);
4080 uirow = MSI_CreateRecord( 4 );
4081 MSI_RecordSetStringW( uirow, 1, identifier );
4082 MSI_RecordSetStringW( uirow, 2, deformated_section );
4083 MSI_RecordSetStringW( uirow, 3, deformated_key );
4084 MSI_RecordSetStringW( uirow, 4, deformated_value );
4085 ui_actiondata( package, szRemoveIniValues, uirow );
4086 msiobj_release( &uirow->hdr );
4088 msi_free( deformated_key );
4089 msi_free( deformated_value );
4090 msi_free( deformated_section );
4091 return ERROR_SUCCESS;
4094 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4096 MSIPACKAGE *package = param;
4097 LPCWSTR component, section, key, value, identifier;
4098 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4103 component = MSI_RecordGetString( row, 8 );
4104 comp = get_loaded_component( package, component );
4106 return ERROR_SUCCESS;
4108 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4110 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4111 comp->Action = comp->Installed;
4112 return ERROR_SUCCESS;
4114 comp->Action = INSTALLSTATE_LOCAL;
4116 identifier = MSI_RecordGetString( row, 1 );
4117 section = MSI_RecordGetString( row, 4 );
4118 key = MSI_RecordGetString( row, 5 );
4119 value = MSI_RecordGetString( row, 6 );
4120 action = MSI_RecordGetInteger( row, 7 );
4122 deformat_string( package, section, &deformated_section );
4123 deformat_string( package, key, &deformated_key );
4124 deformat_string( package, value, &deformated_value );
4126 if (action == msidbIniFileActionRemoveLine)
4128 filename = get_ini_file_name( package, row );
4130 TRACE("Removing key %s from section %s in %s\n",
4131 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4133 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4135 WARN("Unable to remove key %u\n", GetLastError());
4137 msi_free( filename );
4140 FIXME("Unsupported action %d\n", action);
4142 uirow = MSI_CreateRecord( 4 );
4143 MSI_RecordSetStringW( uirow, 1, identifier );
4144 MSI_RecordSetStringW( uirow, 2, deformated_section );
4145 MSI_RecordSetStringW( uirow, 3, deformated_key );
4146 MSI_RecordSetStringW( uirow, 4, deformated_value );
4147 ui_actiondata( package, szRemoveIniValues, uirow );
4148 msiobj_release( &uirow->hdr );
4150 msi_free( deformated_key );
4151 msi_free( deformated_value );
4152 msi_free( deformated_section );
4153 return ERROR_SUCCESS;
4156 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4160 static const WCHAR query[] =
4161 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4162 '`','I','n','i','F','i','l','e','`',0};
4163 static const WCHAR remove_query[] =
4164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4165 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4167 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4168 if (rc == ERROR_SUCCESS)
4170 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4171 msiobj_release( &view->hdr );
4172 if (rc != ERROR_SUCCESS)
4176 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4177 if (rc == ERROR_SUCCESS)
4179 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4180 msiobj_release( &view->hdr );
4181 if (rc != ERROR_SUCCESS)
4185 return ERROR_SUCCESS;
4188 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4190 MSIPACKAGE *package = param;
4195 static const WCHAR ExeStr[] =
4196 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4197 static const WCHAR close[] = {'\"',0};
4199 PROCESS_INFORMATION info;
4204 memset(&si,0,sizeof(STARTUPINFOW));
4206 filename = MSI_RecordGetString(row,1);
4207 file = get_loaded_file( package, filename );
4211 ERR("Unable to find file id %s\n",debugstr_w(filename));
4212 return ERROR_SUCCESS;
4215 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4217 FullName = msi_alloc(len*sizeof(WCHAR));
4218 strcpyW(FullName,ExeStr);
4219 strcatW( FullName, file->TargetPath );
4220 strcatW(FullName,close);
4222 TRACE("Registering %s\n",debugstr_w(FullName));
4223 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4228 CloseHandle(info.hThread);
4229 msi_dialog_check_messages(info.hProcess);
4230 CloseHandle(info.hProcess);
4233 uirow = MSI_CreateRecord( 2 );
4234 MSI_RecordSetStringW( uirow, 1, filename );
4235 uipath = strdupW( file->TargetPath );
4236 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4237 MSI_RecordSetStringW( uirow, 2, uipath );
4238 ui_actiondata( package, szSelfRegModules, uirow );
4239 msiobj_release( &uirow->hdr );
4241 msi_free( FullName );
4243 return ERROR_SUCCESS;
4246 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4250 static const WCHAR ExecSeqQuery[] =
4251 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4252 '`','S','e','l','f','R','e','g','`',0};
4254 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4255 if (rc != ERROR_SUCCESS)
4257 TRACE("no SelfReg table\n");
4258 return ERROR_SUCCESS;
4261 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4262 msiobj_release(&view->hdr);
4264 return ERROR_SUCCESS;
4267 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4269 static const WCHAR regsvr32[] =
4270 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4271 static const WCHAR close[] = {'\"',0};
4272 MSIPACKAGE *package = param;
4278 PROCESS_INFORMATION pi;
4283 memset( &si, 0, sizeof(STARTUPINFOW) );
4285 filename = MSI_RecordGetString( row, 1 );
4286 file = get_loaded_file( package, filename );
4290 ERR("Unable to find file id %s\n", debugstr_w(filename));
4291 return ERROR_SUCCESS;
4294 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4296 cmdline = msi_alloc( len * sizeof(WCHAR) );
4297 strcpyW( cmdline, regsvr32 );
4298 strcatW( cmdline, file->TargetPath );
4299 strcatW( cmdline, close );
4301 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4303 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4306 CloseHandle( pi.hThread );
4307 msi_dialog_check_messages( pi.hProcess );
4308 CloseHandle( pi.hProcess );
4311 uirow = MSI_CreateRecord( 2 );
4312 MSI_RecordSetStringW( uirow, 1, filename );
4313 uipath = strdupW( file->TargetPath );
4314 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4315 MSI_RecordSetStringW( uirow, 2, uipath );
4316 ui_actiondata( package, szSelfUnregModules, uirow );
4317 msiobj_release( &uirow->hdr );
4319 msi_free( cmdline );
4321 return ERROR_SUCCESS;
4324 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4328 static const WCHAR query[] =
4329 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4330 '`','S','e','l','f','R','e','g','`',0};
4332 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4333 if (rc != ERROR_SUCCESS)
4335 TRACE("no SelfReg table\n");
4336 return ERROR_SUCCESS;
4339 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4340 msiobj_release( &view->hdr );
4342 return ERROR_SUCCESS;
4345 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4347 MSIFEATURE *feature;
4349 HKEY hkey = NULL, userdata = NULL;
4351 if (!msi_check_publish(package))
4352 return ERROR_SUCCESS;
4354 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4356 if (rc != ERROR_SUCCESS)
4359 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4361 if (rc != ERROR_SUCCESS)
4364 /* here the guids are base 85 encoded */
4365 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4371 BOOL absent = FALSE;
4374 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4375 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4376 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4379 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4383 if (feature->Feature_Parent)
4384 size += strlenW( feature->Feature_Parent )+2;
4386 data = msi_alloc(size * sizeof(WCHAR));
4389 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4391 MSICOMPONENT* component = cl->component;
4395 if (component->ComponentId)
4397 TRACE("From %s\n",debugstr_w(component->ComponentId));
4398 CLSIDFromString(component->ComponentId, &clsid);
4399 encode_base85_guid(&clsid,buf);
4400 TRACE("to %s\n",debugstr_w(buf));
4405 if (feature->Feature_Parent)
4407 static const WCHAR sep[] = {'\2',0};
4409 strcatW(data,feature->Feature_Parent);
4412 msi_reg_set_val_str( userdata, feature->Feature, data );
4416 if (feature->Feature_Parent)
4417 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4420 size += sizeof(WCHAR);
4421 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4422 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4426 size += 2*sizeof(WCHAR);
4427 data = msi_alloc(size);
4430 if (feature->Feature_Parent)
4431 strcpyW( &data[1], feature->Feature_Parent );
4432 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4438 uirow = MSI_CreateRecord( 1 );
4439 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4440 ui_actiondata( package, szPublishFeatures, uirow);
4441 msiobj_release( &uirow->hdr );
4442 /* FIXME: call ui_progress? */
4447 RegCloseKey(userdata);
4451 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4457 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4459 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4461 if (r == ERROR_SUCCESS)
4463 RegDeleteValueW(hkey, feature->Feature);
4467 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4469 if (r == ERROR_SUCCESS)
4471 RegDeleteValueW(hkey, feature->Feature);
4475 uirow = MSI_CreateRecord( 1 );
4476 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4477 ui_actiondata( package, szUnpublishFeatures, uirow );
4478 msiobj_release( &uirow->hdr );
4480 return ERROR_SUCCESS;
4483 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4485 MSIFEATURE *feature;
4487 if (!msi_check_unpublish(package))
4488 return ERROR_SUCCESS;
4490 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4492 msi_unpublish_feature(package, feature);
4495 return ERROR_SUCCESS;
4498 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4500 LPWSTR prop, val, key;
4506 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4507 static const WCHAR szWindowsInstaller[] =
4508 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4509 static const WCHAR modpath_fmt[] =
4510 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4511 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4512 static const WCHAR szModifyPath[] =
4513 {'M','o','d','i','f','y','P','a','t','h',0};
4514 static const WCHAR szUninstallString[] =
4515 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4516 static const WCHAR szEstimatedSize[] =
4517 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4518 static const WCHAR szProductLanguage[] =
4519 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4520 static const WCHAR szProductVersion[] =
4521 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4522 static const WCHAR szProductName[] =
4523 {'P','r','o','d','u','c','t','N','a','m','e',0};
4524 static const WCHAR szDisplayName[] =
4525 {'D','i','s','p','l','a','y','N','a','m','e',0};
4526 static const WCHAR szDisplayVersion[] =
4527 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4528 static const WCHAR szManufacturer[] =
4529 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4531 static const LPCSTR propval[] = {
4532 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4533 "ARPCONTACT", "Contact",
4534 "ARPCOMMENTS", "Comments",
4535 "ProductName", "DisplayName",
4536 "ProductVersion", "DisplayVersion",
4537 "ARPHELPLINK", "HelpLink",
4538 "ARPHELPTELEPHONE", "HelpTelephone",
4539 "ARPINSTALLLOCATION", "InstallLocation",
4540 "SourceDir", "InstallSource",
4541 "Manufacturer", "Publisher",
4542 "ARPREADME", "Readme",
4544 "ARPURLINFOABOUT", "URLInfoAbout",
4545 "ARPURLUPDATEINFO", "URLUpdateInfo",
4548 const LPCSTR *p = propval;
4552 prop = strdupAtoW(*p++);
4553 key = strdupAtoW(*p++);
4554 val = msi_dup_property(package->db, prop);
4555 msi_reg_set_val_str(hkey, key, val);
4561 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4563 size = deformat_string(package, modpath_fmt, &buffer);
4564 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4565 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4568 /* FIXME: Write real Estimated Size when we have it */
4569 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4571 buffer = msi_dup_property(package->db, szProductName);
4572 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4575 buffer = msi_dup_property(package->db, cszSourceDir);
4576 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4579 buffer = msi_dup_property(package->db, szManufacturer);
4580 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4583 GetLocalTime(&systime);
4584 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4585 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4587 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4588 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4590 buffer = msi_dup_property(package->db, szProductVersion);
4591 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4594 DWORD verdword = msi_version_str_to_dword(buffer);
4596 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4597 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4598 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4602 return ERROR_SUCCESS;
4605 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4607 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4609 LPWSTR upgrade_code;
4614 static const WCHAR szUpgradeCode[] = {
4615 'U','p','g','r','a','d','e','C','o','d','e',0};
4617 /* FIXME: also need to publish if the product is in advertise mode */
4618 if (!msi_check_publish(package))
4619 return ERROR_SUCCESS;
4621 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4622 if (rc != ERROR_SUCCESS)
4625 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4626 NULL, &props, TRUE);
4627 if (rc != ERROR_SUCCESS)
4630 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4631 msi_free( package->db->localfile );
4632 package->db->localfile = NULL;
4634 rc = msi_publish_install_properties(package, hkey);
4635 if (rc != ERROR_SUCCESS)
4638 rc = msi_publish_install_properties(package, props);
4639 if (rc != ERROR_SUCCESS)
4642 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4645 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4646 squash_guid(package->ProductCode, squashed_pc);
4647 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4648 RegCloseKey(upgrade);
4649 msi_free(upgrade_code);
4653 uirow = MSI_CreateRecord( 1 );
4654 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4655 ui_actiondata( package, szRegisterProduct, uirow );
4656 msiobj_release( &uirow->hdr );
4659 return ERROR_SUCCESS;
4662 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4664 return execute_script(package,INSTALL_SCRIPT);
4667 static UINT msi_unpublish_product(MSIPACKAGE *package)
4670 LPWSTR remove = NULL;
4671 LPWSTR *features = NULL;
4672 BOOL full_uninstall = TRUE;
4673 MSIFEATURE *feature;
4675 static const WCHAR szUpgradeCode[] =
4676 {'U','p','g','r','a','d','e','C','o','d','e',0};
4678 remove = msi_dup_property(package->db, szRemove);
4680 return ERROR_SUCCESS;
4682 features = msi_split_string(remove, ',');
4686 ERR("REMOVE feature list is empty!\n");
4687 return ERROR_FUNCTION_FAILED;
4690 if (!lstrcmpW(features[0], szAll))
4691 full_uninstall = TRUE;
4694 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4696 if (feature->Action != INSTALLSTATE_ABSENT)
4697 full_uninstall = FALSE;
4701 if (!full_uninstall)
4704 MSIREG_DeleteProductKey(package->ProductCode);
4705 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4706 MSIREG_DeleteUninstallKey(package->ProductCode);
4708 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4710 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4711 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4715 MSIREG_DeleteUserProductKey(package->ProductCode);
4716 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4719 upgrade = msi_dup_property(package->db, szUpgradeCode);
4722 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4729 return ERROR_SUCCESS;
4732 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4736 rc = msi_unpublish_product(package);
4737 if (rc != ERROR_SUCCESS)
4740 /* turn off scheduling */
4741 package->script->CurrentlyScripting= FALSE;
4743 /* first do the same as an InstallExecute */
4744 rc = ACTION_InstallExecute(package);
4745 if (rc != ERROR_SUCCESS)
4748 /* then handle Commit Actions */
4749 rc = execute_script(package,COMMIT_SCRIPT);
4754 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4756 static const WCHAR RunOnce[] = {
4757 'S','o','f','t','w','a','r','e','\\',
4758 'M','i','c','r','o','s','o','f','t','\\',
4759 'W','i','n','d','o','w','s','\\',
4760 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4761 'R','u','n','O','n','c','e',0};
4762 static const WCHAR InstallRunOnce[] = {
4763 'S','o','f','t','w','a','r','e','\\',
4764 'M','i','c','r','o','s','o','f','t','\\',
4765 'W','i','n','d','o','w','s','\\',
4766 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4767 'I','n','s','t','a','l','l','e','r','\\',
4768 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4770 static const WCHAR msiexec_fmt[] = {
4772 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4773 '\"','%','s','\"',0};
4774 static const WCHAR install_fmt[] = {
4775 '/','I',' ','\"','%','s','\"',' ',
4776 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4777 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4778 WCHAR buffer[256], sysdir[MAX_PATH];
4780 WCHAR squished_pc[100];
4782 squash_guid(package->ProductCode,squished_pc);
4784 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4785 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4786 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4789 msi_reg_set_val_str( hkey, squished_pc, buffer );
4792 TRACE("Reboot command %s\n",debugstr_w(buffer));
4794 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4795 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4797 msi_reg_set_val_str( hkey, squished_pc, buffer );
4800 return ERROR_INSTALL_SUSPEND;
4803 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4809 * We are currently doing what should be done here in the top level Install
4810 * however for Administrative and uninstalls this step will be needed
4812 if (!package->PackagePath)
4813 return ERROR_SUCCESS;
4815 msi_set_sourcedir_props(package, TRUE);
4817 attrib = GetFileAttributesW(package->db->path);
4818 if (attrib == INVALID_FILE_ATTRIBUTES)
4824 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4825 package->Context, MSICODE_PRODUCT,
4826 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4827 if (rc == ERROR_MORE_DATA)
4829 prompt = msi_alloc(size * sizeof(WCHAR));
4830 MsiSourceListGetInfoW(package->ProductCode, NULL,
4831 package->Context, MSICODE_PRODUCT,
4832 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4835 prompt = strdupW(package->db->path);
4837 msg = generate_error_string(package,1302,1,prompt);
4838 while(attrib == INVALID_FILE_ATTRIBUTES)
4840 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4843 rc = ERROR_INSTALL_USEREXIT;
4846 attrib = GetFileAttributesW(package->db->path);
4852 return ERROR_SUCCESS;
4857 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4860 LPWSTR buffer, productid = NULL;
4861 UINT i, rc = ERROR_SUCCESS;
4864 static const WCHAR szPropKeys[][80] =
4866 {'P','r','o','d','u','c','t','I','D',0},
4867 {'U','S','E','R','N','A','M','E',0},
4868 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4872 static const WCHAR szRegKeys[][80] =
4874 {'P','r','o','d','u','c','t','I','D',0},
4875 {'R','e','g','O','w','n','e','r',0},
4876 {'R','e','g','C','o','m','p','a','n','y',0},
4880 if (msi_check_unpublish(package))
4882 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4886 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
4890 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4892 if (rc != ERROR_SUCCESS)
4895 for( i = 0; szPropKeys[i][0]; i++ )
4897 buffer = msi_dup_property( package->db, szPropKeys[i] );
4898 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4903 uirow = MSI_CreateRecord( 1 );
4904 MSI_RecordSetStringW( uirow, 1, productid );
4905 ui_actiondata( package, szRegisterUser, uirow );
4906 msiobj_release( &uirow->hdr );
4908 msi_free(productid);
4914 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4918 package->script->InWhatSequence |= SEQUENCE_EXEC;
4919 rc = ACTION_ProcessExecSequence(package,FALSE);
4924 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4926 MSIPACKAGE *package = param;
4927 LPCWSTR compgroupid, component, feature, qualifier, text;
4928 LPWSTR advertise = NULL, output = NULL;
4936 feature = MSI_RecordGetString(rec, 5);
4937 feat = get_loaded_feature(package, feature);
4939 return ERROR_SUCCESS;
4941 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4942 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4943 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4945 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4946 feat->Action = feat->Installed;
4947 return ERROR_SUCCESS;
4950 component = MSI_RecordGetString(rec, 3);
4951 comp = get_loaded_component(package, component);
4953 return ERROR_SUCCESS;
4955 compgroupid = MSI_RecordGetString(rec,1);
4956 qualifier = MSI_RecordGetString(rec,2);
4958 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4959 if (rc != ERROR_SUCCESS)
4962 text = MSI_RecordGetString(rec,4);
4963 advertise = create_component_advertise_string(package, comp, feature);
4965 sz = strlenW(advertise);
4968 sz += lstrlenW(text);
4971 sz *= sizeof(WCHAR);
4973 output = msi_alloc_zero(sz);
4974 strcpyW(output,advertise);
4975 msi_free(advertise);
4978 strcatW(output,text);
4980 msi_reg_set_val_multi_str( hkey, qualifier, output );
4987 uirow = MSI_CreateRecord( 2 );
4988 MSI_RecordSetStringW( uirow, 1, compgroupid );
4989 MSI_RecordSetStringW( uirow, 2, qualifier);
4990 ui_actiondata( package, szPublishComponents, uirow);
4991 msiobj_release( &uirow->hdr );
4992 /* FIXME: call ui_progress? */
4998 * At present I am ignorning the advertised components part of this and only
4999 * focusing on the qualified component sets
5001 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5005 static const WCHAR ExecSeqQuery[] =
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, ExecSeqQuery, &view);
5011 if (rc != ERROR_SUCCESS)
5012 return ERROR_SUCCESS;
5014 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5015 msiobj_release(&view->hdr);
5020 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5022 static const WCHAR szInstallerComponents[] = {
5023 'S','o','f','t','w','a','r','e','\\',
5024 'M','i','c','r','o','s','o','f','t','\\',
5025 'I','n','s','t','a','l','l','e','r','\\',
5026 'C','o','m','p','o','n','e','n','t','s','\\',0};
5028 MSIPACKAGE *package = param;
5029 LPCWSTR compgroupid, component, feature, qualifier;
5033 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5036 feature = MSI_RecordGetString( rec, 5 );
5037 feat = get_loaded_feature( package, feature );
5039 return ERROR_SUCCESS;
5041 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5043 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5044 feat->Action = feat->Installed;
5045 return ERROR_SUCCESS;
5048 component = MSI_RecordGetString( rec, 3 );
5049 comp = get_loaded_component( package, component );
5051 return ERROR_SUCCESS;
5053 compgroupid = MSI_RecordGetString( rec, 1 );
5054 qualifier = MSI_RecordGetString( rec, 2 );
5056 squash_guid( compgroupid, squashed );
5057 strcpyW( keypath, szInstallerComponents );
5058 strcatW( keypath, squashed );
5060 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5061 if (res != ERROR_SUCCESS)
5063 WARN("Unable to delete component key %d\n", res);
5066 uirow = MSI_CreateRecord( 2 );
5067 MSI_RecordSetStringW( uirow, 1, compgroupid );
5068 MSI_RecordSetStringW( uirow, 2, qualifier );
5069 ui_actiondata( package, szUnpublishComponents, uirow );
5070 msiobj_release( &uirow->hdr );
5072 return ERROR_SUCCESS;
5075 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5079 static const WCHAR query[] =
5080 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5081 '`','P','u','b','l','i','s','h',
5082 'C','o','m','p','o','n','e','n','t','`',0};
5084 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5085 if (rc != ERROR_SUCCESS)
5086 return ERROR_SUCCESS;
5088 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5089 msiobj_release( &view->hdr );
5094 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5096 MSIPACKAGE *package = param;
5099 SC_HANDLE hscm, service = NULL;
5100 LPCWSTR comp, depends, pass;
5101 LPWSTR name = NULL, disp = NULL;
5102 LPCWSTR load_order, serv_name, key;
5103 DWORD serv_type, start_type;
5106 static const WCHAR query[] =
5107 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5108 '`','C','o','m','p','o','n','e','n','t','`',' ',
5109 'W','H','E','R','E',' ',
5110 '`','C','o','m','p','o','n','e','n','t','`',' ',
5111 '=','\'','%','s','\'',0};
5113 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5116 ERR("Failed to open the SC Manager!\n");
5120 start_type = MSI_RecordGetInteger(rec, 5);
5121 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5124 depends = MSI_RecordGetString(rec, 8);
5125 if (depends && *depends)
5126 FIXME("Dependency list unhandled!\n");
5128 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5129 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5130 serv_type = MSI_RecordGetInteger(rec, 4);
5131 err_control = MSI_RecordGetInteger(rec, 6);
5132 load_order = MSI_RecordGetString(rec, 7);
5133 serv_name = MSI_RecordGetString(rec, 9);
5134 pass = MSI_RecordGetString(rec, 10);
5135 comp = MSI_RecordGetString(rec, 12);
5137 /* fetch the service path */
5138 row = MSI_QueryGetRecord(package->db, query, comp);
5141 ERR("Control query failed!\n");
5145 key = MSI_RecordGetString(row, 6);
5147 file = get_loaded_file(package, key);
5148 msiobj_release(&row->hdr);
5151 ERR("Failed to load the service file\n");
5155 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5156 start_type, err_control, file->TargetPath,
5157 load_order, NULL, NULL, serv_name, pass);
5160 if (GetLastError() != ERROR_SERVICE_EXISTS)
5161 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5165 CloseServiceHandle(service);
5166 CloseServiceHandle(hscm);
5170 return ERROR_SUCCESS;
5173 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5177 static const WCHAR ExecSeqQuery[] =
5178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5179 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5181 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5182 if (rc != ERROR_SUCCESS)
5183 return ERROR_SUCCESS;
5185 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5186 msiobj_release(&view->hdr);
5191 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5192 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5194 LPCWSTR *vector, *temp_vector;
5198 static const WCHAR separator[] = {'[','~',']',0};
5201 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5206 vector = msi_alloc(sizeof(LPWSTR));
5214 vector[*numargs - 1] = p;
5216 if ((q = strstrW(p, separator)))
5220 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5226 vector = temp_vector;
5235 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5237 MSIPACKAGE *package = param;
5240 SC_HANDLE scm = NULL, service = NULL;
5241 LPCWSTR component, *vector = NULL;
5242 LPWSTR name, args, display_name = NULL;
5243 DWORD event, numargs, len;
5244 UINT r = ERROR_FUNCTION_FAILED;
5246 component = MSI_RecordGetString(rec, 6);
5247 comp = get_loaded_component(package, component);
5249 return ERROR_SUCCESS;
5251 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5253 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5254 comp->Action = comp->Installed;
5255 return ERROR_SUCCESS;
5257 comp->Action = INSTALLSTATE_LOCAL;
5259 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5260 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5261 event = MSI_RecordGetInteger(rec, 3);
5263 if (!(event & msidbServiceControlEventStart))
5269 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5272 ERR("Failed to open the service control manager\n");
5277 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5278 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5280 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5281 GetServiceDisplayNameW( scm, name, display_name, &len );
5284 service = OpenServiceW(scm, name, SERVICE_START);
5287 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5291 vector = msi_service_args_to_vector(args, &numargs);
5293 if (!StartServiceW(service, numargs, vector) &&
5294 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5296 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5303 uirow = MSI_CreateRecord( 2 );
5304 MSI_RecordSetStringW( uirow, 1, display_name );
5305 MSI_RecordSetStringW( uirow, 2, name );
5306 ui_actiondata( package, szStartServices, uirow );
5307 msiobj_release( &uirow->hdr );
5309 CloseServiceHandle(service);
5310 CloseServiceHandle(scm);
5315 msi_free(display_name);
5319 static UINT ACTION_StartServices( MSIPACKAGE *package )
5324 static const WCHAR query[] = {
5325 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5326 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5328 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5329 if (rc != ERROR_SUCCESS)
5330 return ERROR_SUCCESS;
5332 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5333 msiobj_release(&view->hdr);
5338 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5340 DWORD i, needed, count;
5341 ENUM_SERVICE_STATUSW *dependencies;
5345 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5346 0, &needed, &count))
5349 if (GetLastError() != ERROR_MORE_DATA)
5352 dependencies = msi_alloc(needed);
5356 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5357 needed, &needed, &count))
5360 for (i = 0; i < count; i++)
5362 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5363 SERVICE_STOP | SERVICE_QUERY_STATUS);
5367 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5374 msi_free(dependencies);
5378 static UINT stop_service( LPCWSTR name )
5380 SC_HANDLE scm = NULL, service = NULL;
5381 SERVICE_STATUS status;
5382 SERVICE_STATUS_PROCESS ssp;
5385 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5388 WARN("Failed to open the SCM: %d\n", GetLastError());
5392 service = OpenServiceW(scm, name,
5394 SERVICE_QUERY_STATUS |
5395 SERVICE_ENUMERATE_DEPENDENTS);
5398 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5402 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5403 sizeof(SERVICE_STATUS_PROCESS), &needed))
5405 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5409 if (ssp.dwCurrentState == SERVICE_STOPPED)
5412 stop_service_dependents(scm, service);
5414 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5415 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5418 CloseServiceHandle(service);
5419 CloseServiceHandle(scm);
5421 return ERROR_SUCCESS;
5424 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5426 MSIPACKAGE *package = param;
5430 LPWSTR name = NULL, display_name = NULL;
5434 event = MSI_RecordGetInteger( rec, 3 );
5435 if (!(event & msidbServiceControlEventStop))
5436 return ERROR_SUCCESS;
5438 component = MSI_RecordGetString( rec, 6 );
5439 comp = get_loaded_component( package, component );
5441 return ERROR_SUCCESS;
5443 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5445 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5446 comp->Action = comp->Installed;
5447 return ERROR_SUCCESS;
5449 comp->Action = INSTALLSTATE_ABSENT;
5451 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5454 ERR("Failed to open the service control manager\n");
5459 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5460 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5462 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5463 GetServiceDisplayNameW( scm, name, display_name, &len );
5465 CloseServiceHandle( scm );
5467 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5468 stop_service( name );
5471 uirow = MSI_CreateRecord( 2 );
5472 MSI_RecordSetStringW( uirow, 1, display_name );
5473 MSI_RecordSetStringW( uirow, 2, name );
5474 ui_actiondata( package, szStopServices, uirow );
5475 msiobj_release( &uirow->hdr );
5478 msi_free( display_name );
5479 return ERROR_SUCCESS;
5482 static UINT ACTION_StopServices( MSIPACKAGE *package )
5487 static const WCHAR query[] = {
5488 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5489 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5491 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5492 if (rc != ERROR_SUCCESS)
5493 return ERROR_SUCCESS;
5495 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5496 msiobj_release(&view->hdr);
5501 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5503 MSIPACKAGE *package = param;
5507 LPWSTR name = NULL, display_name = NULL;
5509 SC_HANDLE scm = NULL, service = NULL;
5511 event = MSI_RecordGetInteger( rec, 3 );
5512 if (!(event & msidbServiceControlEventDelete))
5513 return ERROR_SUCCESS;
5515 component = MSI_RecordGetString(rec, 6);
5516 comp = get_loaded_component(package, component);
5518 return ERROR_SUCCESS;
5520 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5522 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5523 comp->Action = comp->Installed;
5524 return ERROR_SUCCESS;
5526 comp->Action = INSTALLSTATE_ABSENT;
5528 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5529 stop_service( name );
5531 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5534 WARN("Failed to open the SCM: %d\n", GetLastError());
5539 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5540 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5542 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5543 GetServiceDisplayNameW( scm, name, display_name, &len );
5546 service = OpenServiceW( scm, name, DELETE );
5549 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5553 if (!DeleteService( service ))
5554 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5557 uirow = MSI_CreateRecord( 2 );
5558 MSI_RecordSetStringW( uirow, 1, display_name );
5559 MSI_RecordSetStringW( uirow, 2, name );
5560 ui_actiondata( package, szDeleteServices, uirow );
5561 msiobj_release( &uirow->hdr );
5563 CloseServiceHandle( service );
5564 CloseServiceHandle( scm );
5566 msi_free( display_name );
5568 return ERROR_SUCCESS;
5571 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5576 static const WCHAR query[] = {
5577 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5578 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5580 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5581 if (rc != ERROR_SUCCESS)
5582 return ERROR_SUCCESS;
5584 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5585 msiobj_release( &view->hdr );
5590 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5594 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5596 if (!lstrcmpW(file->File, filename))
5603 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5605 MSIPACKAGE *package = param;
5606 LPWSTR driver, driver_path, ptr;
5607 WCHAR outpath[MAX_PATH];
5608 MSIFILE *driver_file, *setup_file;
5612 UINT r = ERROR_SUCCESS;
5614 static const WCHAR driver_fmt[] = {
5615 'D','r','i','v','e','r','=','%','s',0};
5616 static const WCHAR setup_fmt[] = {
5617 'S','e','t','u','p','=','%','s',0};
5618 static const WCHAR usage_fmt[] = {
5619 'F','i','l','e','U','s','a','g','e','=','1',0};
5621 desc = MSI_RecordGetString(rec, 3);
5623 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5624 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5628 ERR("ODBC Driver entry not found!\n");
5629 return ERROR_FUNCTION_FAILED;
5632 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5634 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5635 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5637 driver = msi_alloc(len * sizeof(WCHAR));
5639 return ERROR_OUTOFMEMORY;
5642 lstrcpyW(ptr, desc);
5643 ptr += lstrlenW(ptr) + 1;
5645 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5650 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5654 lstrcpyW(ptr, usage_fmt);
5655 ptr += lstrlenW(ptr) + 1;
5658 driver_path = strdupW(driver_file->TargetPath);
5659 ptr = strrchrW(driver_path, '\\');
5660 if (ptr) *ptr = '\0';
5662 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5663 NULL, ODBC_INSTALL_COMPLETE, &usage))
5665 ERR("Failed to install SQL driver!\n");
5666 r = ERROR_FUNCTION_FAILED;
5669 uirow = MSI_CreateRecord( 5 );
5670 MSI_RecordSetStringW( uirow, 1, desc );
5671 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5672 MSI_RecordSetStringW( uirow, 3, driver_path );
5673 ui_actiondata( package, szInstallODBC, uirow );
5674 msiobj_release( &uirow->hdr );
5677 msi_free(driver_path);
5682 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5684 MSIPACKAGE *package = param;
5685 LPWSTR translator, translator_path, ptr;
5686 WCHAR outpath[MAX_PATH];
5687 MSIFILE *translator_file, *setup_file;
5691 UINT r = ERROR_SUCCESS;
5693 static const WCHAR translator_fmt[] = {
5694 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5695 static const WCHAR setup_fmt[] = {
5696 'S','e','t','u','p','=','%','s',0};
5698 desc = MSI_RecordGetString(rec, 3);
5700 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5701 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5703 if (!translator_file)
5705 ERR("ODBC Translator entry not found!\n");
5706 return ERROR_FUNCTION_FAILED;
5709 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5711 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5713 translator = msi_alloc(len * sizeof(WCHAR));
5715 return ERROR_OUTOFMEMORY;
5718 lstrcpyW(ptr, desc);
5719 ptr += lstrlenW(ptr) + 1;
5721 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5726 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5731 translator_path = strdupW(translator_file->TargetPath);
5732 ptr = strrchrW(translator_path, '\\');
5733 if (ptr) *ptr = '\0';
5735 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5736 NULL, ODBC_INSTALL_COMPLETE, &usage))
5738 ERR("Failed to install SQL translator!\n");
5739 r = ERROR_FUNCTION_FAILED;
5742 uirow = MSI_CreateRecord( 5 );
5743 MSI_RecordSetStringW( uirow, 1, desc );
5744 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5745 MSI_RecordSetStringW( uirow, 3, translator_path );
5746 ui_actiondata( package, szInstallODBC, uirow );
5747 msiobj_release( &uirow->hdr );
5749 msi_free(translator);
5750 msi_free(translator_path);
5755 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5757 MSIPACKAGE *package = param;
5759 LPCWSTR desc, driver;
5760 WORD request = ODBC_ADD_SYS_DSN;
5763 UINT r = ERROR_SUCCESS;
5766 static const WCHAR attrs_fmt[] = {
5767 'D','S','N','=','%','s',0 };
5769 desc = MSI_RecordGetString(rec, 3);
5770 driver = MSI_RecordGetString(rec, 4);
5771 registration = MSI_RecordGetInteger(rec, 5);
5773 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5774 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5776 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5777 attrs = msi_alloc(len * sizeof(WCHAR));
5779 return ERROR_OUTOFMEMORY;
5781 len = sprintfW(attrs, attrs_fmt, desc);
5784 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5786 ERR("Failed to install SQL data source!\n");
5787 r = ERROR_FUNCTION_FAILED;
5790 uirow = MSI_CreateRecord( 5 );
5791 MSI_RecordSetStringW( uirow, 1, desc );
5792 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5793 MSI_RecordSetInteger( uirow, 3, request );
5794 ui_actiondata( package, szInstallODBC, uirow );
5795 msiobj_release( &uirow->hdr );
5802 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5807 static const WCHAR driver_query[] = {
5808 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5809 'O','D','B','C','D','r','i','v','e','r',0 };
5811 static const WCHAR translator_query[] = {
5812 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5813 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5815 static const WCHAR source_query[] = {
5816 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5817 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5819 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5820 if (rc != ERROR_SUCCESS)
5821 return ERROR_SUCCESS;
5823 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5824 msiobj_release(&view->hdr);
5826 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5827 if (rc != ERROR_SUCCESS)
5828 return ERROR_SUCCESS;
5830 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5831 msiobj_release(&view->hdr);
5833 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5834 if (rc != ERROR_SUCCESS)
5835 return ERROR_SUCCESS;
5837 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5838 msiobj_release(&view->hdr);
5843 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5845 MSIPACKAGE *package = param;
5850 desc = MSI_RecordGetString( rec, 3 );
5851 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5853 WARN("Failed to remove ODBC driver\n");
5857 FIXME("Usage count reached 0\n");
5860 uirow = MSI_CreateRecord( 2 );
5861 MSI_RecordSetStringW( uirow, 1, desc );
5862 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5863 ui_actiondata( package, szRemoveODBC, uirow );
5864 msiobj_release( &uirow->hdr );
5866 return ERROR_SUCCESS;
5869 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5871 MSIPACKAGE *package = param;
5876 desc = MSI_RecordGetString( rec, 3 );
5877 if (!SQLRemoveTranslatorW( desc, &usage ))
5879 WARN("Failed to remove ODBC translator\n");
5883 FIXME("Usage count reached 0\n");
5886 uirow = MSI_CreateRecord( 2 );
5887 MSI_RecordSetStringW( uirow, 1, desc );
5888 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5889 ui_actiondata( package, szRemoveODBC, uirow );
5890 msiobj_release( &uirow->hdr );
5892 return ERROR_SUCCESS;
5895 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5897 MSIPACKAGE *package = param;
5900 LPCWSTR desc, driver;
5901 WORD request = ODBC_REMOVE_SYS_DSN;
5905 static const WCHAR attrs_fmt[] = {
5906 'D','S','N','=','%','s',0 };
5908 desc = MSI_RecordGetString( rec, 3 );
5909 driver = MSI_RecordGetString( rec, 4 );
5910 registration = MSI_RecordGetInteger( rec, 5 );
5912 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5913 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5915 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5916 attrs = msi_alloc( len * sizeof(WCHAR) );
5918 return ERROR_OUTOFMEMORY;
5920 FIXME("Use ODBCSourceAttribute table\n");
5922 len = sprintfW( attrs, attrs_fmt, desc );
5925 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5927 WARN("Failed to remove ODBC data source\n");
5931 uirow = MSI_CreateRecord( 3 );
5932 MSI_RecordSetStringW( uirow, 1, desc );
5933 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5934 MSI_RecordSetInteger( uirow, 3, request );
5935 ui_actiondata( package, szRemoveODBC, uirow );
5936 msiobj_release( &uirow->hdr );
5938 return ERROR_SUCCESS;
5941 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5946 static const WCHAR driver_query[] = {
5947 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5948 'O','D','B','C','D','r','i','v','e','r',0 };
5950 static const WCHAR translator_query[] = {
5951 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5952 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5954 static const WCHAR source_query[] = {
5955 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5956 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5958 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5959 if (rc != ERROR_SUCCESS)
5960 return ERROR_SUCCESS;
5962 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5963 msiobj_release( &view->hdr );
5965 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5966 if (rc != ERROR_SUCCESS)
5967 return ERROR_SUCCESS;
5969 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5970 msiobj_release( &view->hdr );
5972 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5973 if (rc != ERROR_SUCCESS)
5974 return ERROR_SUCCESS;
5976 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5977 msiobj_release( &view->hdr );
5982 #define ENV_ACT_SETALWAYS 0x1
5983 #define ENV_ACT_SETABSENT 0x2
5984 #define ENV_ACT_REMOVE 0x4
5985 #define ENV_ACT_REMOVEMATCH 0x8
5987 #define ENV_MOD_MACHINE 0x20000000
5988 #define ENV_MOD_APPEND 0x40000000
5989 #define ENV_MOD_PREFIX 0x80000000
5990 #define ENV_MOD_MASK 0xC0000000
5992 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5994 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5996 LPCWSTR cptr = *name;
5998 static const WCHAR prefix[] = {'[','~',']',0};
5999 static const int prefix_len = 3;
6005 *flags |= ENV_ACT_SETALWAYS;
6006 else if (*cptr == '+')
6007 *flags |= ENV_ACT_SETABSENT;
6008 else if (*cptr == '-')
6009 *flags |= ENV_ACT_REMOVE;
6010 else if (*cptr == '!')
6011 *flags |= ENV_ACT_REMOVEMATCH;
6012 else if (*cptr == '*')
6013 *flags |= ENV_MOD_MACHINE;
6023 ERR("Missing environment variable\n");
6024 return ERROR_FUNCTION_FAILED;
6029 LPCWSTR ptr = *value;
6030 if (!strncmpW(ptr, prefix, prefix_len))
6032 if (ptr[prefix_len] == szSemiColon[0])
6034 *flags |= ENV_MOD_APPEND;
6035 *value += lstrlenW(prefix);
6042 else if (lstrlenW(*value) >= prefix_len)
6044 ptr += lstrlenW(ptr) - prefix_len;
6045 if (!lstrcmpW(ptr, prefix))
6047 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6049 *flags |= ENV_MOD_PREFIX;
6050 /* the "[~]" will be removed by deformat_string */;
6060 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6061 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6062 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6063 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6065 ERR("Invalid flags: %08x\n", *flags);
6066 return ERROR_FUNCTION_FAILED;
6070 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6072 return ERROR_SUCCESS;
6075 static UINT open_env_key( DWORD flags, HKEY *key )
6077 static const WCHAR user_env[] =
6078 {'E','n','v','i','r','o','n','m','e','n','t',0};
6079 static const WCHAR machine_env[] =
6080 {'S','y','s','t','e','m','\\',
6081 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6082 'C','o','n','t','r','o','l','\\',
6083 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6084 'E','n','v','i','r','o','n','m','e','n','t',0};
6089 if (flags & ENV_MOD_MACHINE)
6092 root = HKEY_LOCAL_MACHINE;
6097 root = HKEY_CURRENT_USER;
6100 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6101 if (res != ERROR_SUCCESS)
6103 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6104 return ERROR_FUNCTION_FAILED;
6107 return ERROR_SUCCESS;
6110 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6112 MSIPACKAGE *package = param;
6113 LPCWSTR name, value, component;
6114 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6115 DWORD flags, type, size;
6122 component = MSI_RecordGetString(rec, 4);
6123 comp = get_loaded_component(package, component);
6125 return ERROR_SUCCESS;
6127 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6129 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6130 comp->Action = comp->Installed;
6131 return ERROR_SUCCESS;
6133 comp->Action = INSTALLSTATE_LOCAL;
6135 name = MSI_RecordGetString(rec, 2);
6136 value = MSI_RecordGetString(rec, 3);
6138 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6140 res = env_parse_flags(&name, &value, &flags);
6141 if (res != ERROR_SUCCESS || !value)
6144 if (value && !deformat_string(package, value, &deformatted))
6146 res = ERROR_OUTOFMEMORY;
6150 value = deformatted;
6152 res = open_env_key( flags, &env );
6153 if (res != ERROR_SUCCESS)
6156 if (flags & ENV_MOD_MACHINE)
6157 action |= 0x20000000;
6161 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6162 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6163 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6166 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6170 /* Nothing to do. */
6173 res = ERROR_SUCCESS;
6177 /* If we are appending but the string was empty, strip ; */
6178 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6180 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6181 newval = strdupW(value);
6184 res = ERROR_OUTOFMEMORY;
6192 /* Contrary to MSDN, +-variable to [~];path works */
6193 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6195 res = ERROR_SUCCESS;
6199 data = msi_alloc(size);
6203 return ERROR_OUTOFMEMORY;
6206 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6207 if (res != ERROR_SUCCESS)
6210 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6213 res = RegDeleteValueW(env, name);
6214 if (res != ERROR_SUCCESS)
6215 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6219 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6220 if (flags & ENV_MOD_MASK)
6224 if (flags & ENV_MOD_APPEND) multiplier++;
6225 if (flags & ENV_MOD_PREFIX) multiplier++;
6226 mod_size = lstrlenW(value) * multiplier;
6227 size += mod_size * sizeof(WCHAR);
6230 newval = msi_alloc(size);
6234 res = ERROR_OUTOFMEMORY;
6238 if (flags & ENV_MOD_PREFIX)
6240 lstrcpyW(newval, value);
6241 ptr = newval + lstrlenW(value);
6242 action |= 0x80000000;
6245 lstrcpyW(ptr, data);
6247 if (flags & ENV_MOD_APPEND)
6249 lstrcatW(newval, value);
6250 action |= 0x40000000;
6253 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6254 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6257 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6261 uirow = MSI_CreateRecord( 3 );
6262 MSI_RecordSetStringW( uirow, 1, name );
6263 MSI_RecordSetStringW( uirow, 2, newval );
6264 MSI_RecordSetInteger( uirow, 3, action );
6265 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6266 msiobj_release( &uirow->hdr );
6268 if (env) RegCloseKey(env);
6269 msi_free(deformatted);
6275 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6279 static const WCHAR ExecSeqQuery[] =
6280 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6281 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6282 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6283 if (rc != ERROR_SUCCESS)
6284 return ERROR_SUCCESS;
6286 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6287 msiobj_release(&view->hdr);
6292 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6294 MSIPACKAGE *package = param;
6295 LPCWSTR name, value, component;
6296 LPWSTR deformatted = NULL;
6305 component = MSI_RecordGetString( rec, 4 );
6306 comp = get_loaded_component( package, component );
6308 return ERROR_SUCCESS;
6310 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6312 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6313 comp->Action = comp->Installed;
6314 return ERROR_SUCCESS;
6316 comp->Action = INSTALLSTATE_ABSENT;
6318 name = MSI_RecordGetString( rec, 2 );
6319 value = MSI_RecordGetString( rec, 3 );
6321 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6323 r = env_parse_flags( &name, &value, &flags );
6324 if (r != ERROR_SUCCESS)
6327 if (!(flags & ENV_ACT_REMOVE))
6329 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6330 return ERROR_SUCCESS;
6333 if (value && !deformat_string( package, value, &deformatted ))
6334 return ERROR_OUTOFMEMORY;
6336 value = deformatted;
6338 r = open_env_key( flags, &env );
6339 if (r != ERROR_SUCCESS)
6345 if (flags & ENV_MOD_MACHINE)
6346 action |= 0x20000000;
6348 TRACE("Removing %s\n", debugstr_w(name));
6350 res = RegDeleteValueW( env, name );
6351 if (res != ERROR_SUCCESS)
6353 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6358 uirow = MSI_CreateRecord( 3 );
6359 MSI_RecordSetStringW( uirow, 1, name );
6360 MSI_RecordSetStringW( uirow, 2, value );
6361 MSI_RecordSetInteger( uirow, 3, action );
6362 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6363 msiobj_release( &uirow->hdr );
6365 if (env) RegCloseKey( env );
6366 msi_free( deformatted );
6370 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6374 static const WCHAR query[] =
6375 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6376 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6378 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6379 if (rc != ERROR_SUCCESS)
6380 return ERROR_SUCCESS;
6382 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6383 msiobj_release( &view->hdr );
6388 typedef struct tagMSIASSEMBLY
6391 MSICOMPONENT *component;
6392 MSIFEATURE *feature;
6396 LPWSTR display_name;
6401 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6403 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6404 LPVOID pvReserved, HMODULE *phModDll);
6406 static BOOL init_functionpointers(void)
6412 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6414 hmscoree = LoadLibraryA("mscoree.dll");
6417 WARN("mscoree.dll not available\n");
6421 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6422 if (!pLoadLibraryShim)
6424 WARN("LoadLibraryShim not available\n");
6425 FreeLibrary(hmscoree);
6429 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6432 WARN("fusion.dll not available\n");
6433 FreeLibrary(hmscoree);
6437 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6439 FreeLibrary(hmscoree);
6443 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6446 IAssemblyCache *cache;
6449 UINT r = ERROR_FUNCTION_FAILED;
6451 TRACE("installing assembly: %s\n", debugstr_w(path));
6453 uirow = MSI_CreateRecord( 2 );
6454 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6455 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6456 msiobj_release( &uirow->hdr );
6458 if (assembly->feature)
6459 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6461 if (assembly->manifest)
6462 FIXME("Manifest unhandled\n");
6464 if (assembly->application)
6466 FIXME("Assembly should be privately installed\n");
6467 return ERROR_SUCCESS;
6470 if (assembly->attributes == msidbAssemblyAttributesWin32)
6472 FIXME("Win32 assemblies not handled\n");
6473 return ERROR_SUCCESS;
6476 hr = pCreateAssemblyCache(&cache, 0);
6480 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6482 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6487 IAssemblyCache_Release(cache);
6491 typedef struct tagASSEMBLY_LIST
6493 MSIPACKAGE *package;
6494 IAssemblyCache *cache;
6495 struct list *assemblies;
6498 typedef struct tagASSEMBLY_NAME
6506 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6508 ASSEMBLY_NAME *asmname = param;
6509 LPCWSTR name = MSI_RecordGetString(rec, 2);
6510 LPWSTR val = msi_dup_record_field(rec, 3);
6512 static const WCHAR Name[] = {'N','a','m','e',0};
6513 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6514 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6515 static const WCHAR PublicKeyToken[] = {
6516 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6518 if (!strcmpiW(name, Name))
6519 asmname->name = val;
6520 else if (!strcmpiW(name, Version))
6521 asmname->version = val;
6522 else if (!strcmpiW(name, Culture))
6523 asmname->culture = val;
6524 else if (!strcmpiW(name, PublicKeyToken))
6525 asmname->pubkeytoken = val;
6529 return ERROR_SUCCESS;
6532 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6536 *size = lstrlenW(append) + 1;
6537 *str = msi_alloc((*size) * sizeof(WCHAR));
6538 lstrcpyW(*str, append);
6542 (*size) += lstrlenW(append);
6543 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6544 lstrcatW(*str, append);
6547 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6549 static const WCHAR separator[] = {',',' ',0};
6550 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6551 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6552 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6553 static const WCHAR query[] = {
6554 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6555 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6556 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6557 '=','\'','%','s','\'',0};
6560 LPWSTR display_name;
6564 display_name = NULL;
6565 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6567 r = MSI_OpenQuery( db, &view, query, comp->Component );
6568 if (r != ERROR_SUCCESS)
6571 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6572 msiobj_release( &view->hdr );
6576 ERR("No assembly name specified!\n");
6580 append_str( &display_name, &size, name.name );
6584 append_str( &display_name, &size, separator );
6585 append_str( &display_name, &size, Version );
6586 append_str( &display_name, &size, name.version );
6590 append_str( &display_name, &size, separator );
6591 append_str( &display_name, &size, Culture );
6592 append_str( &display_name, &size, name.culture );
6594 if (name.pubkeytoken)
6596 append_str( &display_name, &size, separator );
6597 append_str( &display_name, &size, PublicKeyToken );
6598 append_str( &display_name, &size, name.pubkeytoken );
6601 msi_free( name.name );
6602 msi_free( name.version );
6603 msi_free( name.culture );
6604 msi_free( name.pubkeytoken );
6606 return display_name;
6609 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6611 ASSEMBLY_INFO asminfo;
6616 disp = get_assembly_display_name( db, comp );
6620 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6621 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6623 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6625 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6631 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6633 ASSEMBLY_LIST *list = param;
6634 MSIASSEMBLY *assembly;
6637 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6639 return ERROR_OUTOFMEMORY;
6641 component = MSI_RecordGetString(rec, 1);
6642 assembly->component = get_loaded_component(list->package, component);
6643 if (!assembly->component)
6644 return ERROR_SUCCESS;
6646 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6647 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6649 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6650 assembly->component->Action = assembly->component->Installed;
6651 return ERROR_SUCCESS;
6653 assembly->component->Action = assembly->component->ActionRequest;
6655 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6656 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6658 if (!assembly->file)
6660 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6661 return ERROR_FUNCTION_FAILED;
6664 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6665 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6666 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6668 if (assembly->application)
6671 DWORD size = sizeof(version)/sizeof(WCHAR);
6673 /* FIXME: we should probably check the manifest file here */
6675 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6676 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6678 assembly->installed = TRUE;
6682 assembly->installed = check_assembly_installed(list->package->db,
6684 assembly->component);
6686 list_add_head(list->assemblies, &assembly->entry);
6687 return ERROR_SUCCESS;
6690 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6692 IAssemblyCache *cache = NULL;
6698 static const WCHAR query[] =
6699 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6700 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6702 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6703 if (r != ERROR_SUCCESS)
6704 return ERROR_SUCCESS;
6706 hr = pCreateAssemblyCache(&cache, 0);
6708 return ERROR_FUNCTION_FAILED;
6710 list.package = package;
6712 list.assemblies = assemblies;
6714 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6715 msiobj_release(&view->hdr);
6717 IAssemblyCache_Release(cache);
6722 static void free_assemblies(struct list *assemblies)
6724 struct list *item, *cursor;
6726 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6728 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6730 list_remove(&assembly->entry);
6731 msi_free(assembly->application);
6732 msi_free(assembly->manifest);
6733 msi_free(assembly->display_name);
6738 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6740 MSIASSEMBLY *assembly;
6742 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6744 if (!lstrcmpW(assembly->file->File, file))
6754 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6755 LPWSTR *path, DWORD *attrs, PVOID user)
6757 MSIASSEMBLY *assembly;
6758 WCHAR temppath[MAX_PATH];
6759 struct list *assemblies = user;
6762 if (!find_assembly(assemblies, file, &assembly))
6765 GetTempPathW(MAX_PATH, temppath);
6766 PathAddBackslashW(temppath);
6767 lstrcatW(temppath, assembly->file->FileName);
6769 if (action == MSICABEXTRACT_BEGINEXTRACT)
6771 if (assembly->installed)
6774 *path = strdupW(temppath);
6775 *attrs = assembly->file->Attributes;
6777 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6779 assembly->installed = TRUE;
6781 r = install_assembly(package, assembly, temppath);
6782 if (r != ERROR_SUCCESS)
6783 ERR("Failed to install assembly\n");
6789 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6792 struct list assemblies = LIST_INIT(assemblies);
6793 MSIASSEMBLY *assembly;
6796 if (!init_functionpointers() || !pCreateAssemblyCache)
6797 return ERROR_FUNCTION_FAILED;
6799 r = load_assemblies(package, &assemblies);
6800 if (r != ERROR_SUCCESS)
6803 if (list_empty(&assemblies))
6806 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6809 r = ERROR_OUTOFMEMORY;
6813 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6815 if (assembly->installed && !mi->is_continuous)
6818 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6819 (assembly->file->IsCompressed && !mi->is_extracted))
6823 r = ready_media(package, assembly->file, mi);
6824 if (r != ERROR_SUCCESS)
6826 ERR("Failed to ready media\n");
6831 data.package = package;
6832 data.cb = installassembly_cb;
6833 data.user = &assemblies;
6835 if (assembly->file->IsCompressed &&
6836 !msi_cabextract(package, mi, &data))
6838 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6839 r = ERROR_FUNCTION_FAILED;
6844 if (!assembly->file->IsCompressed)
6846 LPWSTR source = resolve_file_source(package, assembly->file);
6848 r = install_assembly(package, assembly, source);
6849 if (r != ERROR_SUCCESS)
6850 ERR("Failed to install assembly\n");
6855 /* FIXME: write Installer assembly reg values */
6859 free_assemblies(&assemblies);
6863 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6865 LPWSTR key, template, id;
6866 UINT r = ERROR_SUCCESS;
6868 id = msi_dup_property( package->db, szProductID );
6872 return ERROR_SUCCESS;
6874 template = msi_dup_property( package->db, szPIDTemplate );
6875 key = msi_dup_property( package->db, szPIDKEY );
6877 if (key && template)
6879 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6880 r = msi_set_property( package->db, szProductID, key );
6882 msi_free( template );
6887 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6890 package->need_reboot = 1;
6891 return ERROR_SUCCESS;
6894 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6896 static const WCHAR szAvailableFreeReg[] =
6897 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6899 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6901 TRACE("%p %d kilobytes\n", package, space);
6903 uirow = MSI_CreateRecord( 1 );
6904 MSI_RecordSetInteger( uirow, 1, space );
6905 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6906 msiobj_release( &uirow->hdr );
6908 return ERROR_SUCCESS;
6911 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6913 FIXME("%p\n", package);
6914 return ERROR_SUCCESS;
6917 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6919 FIXME("%p\n", package);
6920 return ERROR_SUCCESS;
6923 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6928 static const WCHAR driver_query[] = {
6929 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6930 'O','D','B','C','D','r','i','v','e','r',0 };
6932 static const WCHAR translator_query[] = {
6933 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6934 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6936 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6937 if (r == ERROR_SUCCESS)
6940 r = MSI_IterateRecords( view, &count, NULL, package );
6941 msiobj_release( &view->hdr );
6942 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6945 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6946 if (r == ERROR_SUCCESS)
6949 r = MSI_IterateRecords( view, &count, NULL, package );
6950 msiobj_release( &view->hdr );
6951 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6954 return ERROR_SUCCESS;
6957 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6958 LPCSTR action, LPCWSTR table )
6960 static const WCHAR query[] = {
6961 'S','E','L','E','C','T',' ','*',' ',
6962 'F','R','O','M',' ','`','%','s','`',0 };
6963 MSIQUERY *view = NULL;
6967 r = MSI_OpenQuery( package->db, &view, query, table );
6968 if (r == ERROR_SUCCESS)
6970 r = MSI_IterateRecords(view, &count, NULL, package);
6971 msiobj_release(&view->hdr);
6975 FIXME("%s -> %u ignored %s table values\n",
6976 action, count, debugstr_w(table));
6978 return ERROR_SUCCESS;
6981 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6983 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6984 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6987 static UINT ACTION_BindImage( MSIPACKAGE *package )
6989 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6990 return msi_unimplemented_action_stub( package, "BindImage", table );
6993 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6995 static const WCHAR table[] = {
6996 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6997 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7000 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7002 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7003 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7006 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7008 static const WCHAR table[] = {
7009 'M','s','i','A','s','s','e','m','b','l','y',0 };
7010 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7013 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7015 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7016 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7019 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7021 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7022 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7025 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7027 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7028 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7031 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7033 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7034 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7037 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7039 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7040 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7043 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7047 const WCHAR *action;
7048 UINT (*handler)(MSIPACKAGE *);
7052 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7053 { szAppSearch, ACTION_AppSearch },
7054 { szBindImage, ACTION_BindImage },
7055 { szCCPSearch, ACTION_CCPSearch },
7056 { szCostFinalize, ACTION_CostFinalize },
7057 { szCostInitialize, ACTION_CostInitialize },
7058 { szCreateFolders, ACTION_CreateFolders },
7059 { szCreateShortcuts, ACTION_CreateShortcuts },
7060 { szDeleteServices, ACTION_DeleteServices },
7061 { szDisableRollback, ACTION_DisableRollback },
7062 { szDuplicateFiles, ACTION_DuplicateFiles },
7063 { szExecuteAction, ACTION_ExecuteAction },
7064 { szFileCost, ACTION_FileCost },
7065 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7066 { szForceReboot, ACTION_ForceReboot },
7067 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7068 { szInstallExecute, ACTION_InstallExecute },
7069 { szInstallExecuteAgain, ACTION_InstallExecute },
7070 { szInstallFiles, ACTION_InstallFiles},
7071 { szInstallFinalize, ACTION_InstallFinalize },
7072 { szInstallInitialize, ACTION_InstallInitialize },
7073 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7074 { szInstallValidate, ACTION_InstallValidate },
7075 { szIsolateComponents, ACTION_IsolateComponents },
7076 { szLaunchConditions, ACTION_LaunchConditions },
7077 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7078 { szMoveFiles, ACTION_MoveFiles },
7079 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7080 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7081 { szInstallODBC, ACTION_InstallODBC },
7082 { szInstallServices, ACTION_InstallServices },
7083 { szPatchFiles, ACTION_PatchFiles },
7084 { szProcessComponents, ACTION_ProcessComponents },
7085 { szPublishComponents, ACTION_PublishComponents },
7086 { szPublishFeatures, ACTION_PublishFeatures },
7087 { szPublishProduct, ACTION_PublishProduct },
7088 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7089 { szRegisterComPlus, ACTION_RegisterComPlus},
7090 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7091 { szRegisterFonts, ACTION_RegisterFonts },
7092 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7093 { szRegisterProduct, ACTION_RegisterProduct },
7094 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7095 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7096 { szRegisterUser, ACTION_RegisterUser },
7097 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7098 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7099 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7100 { szRemoveFiles, ACTION_RemoveFiles },
7101 { szRemoveFolders, ACTION_RemoveFolders },
7102 { szRemoveIniValues, ACTION_RemoveIniValues },
7103 { szRemoveODBC, ACTION_RemoveODBC },
7104 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7105 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7106 { szResolveSource, ACTION_ResolveSource },
7107 { szRMCCPSearch, ACTION_RMCCPSearch },
7108 { szScheduleReboot, ACTION_ScheduleReboot },
7109 { szSelfRegModules, ACTION_SelfRegModules },
7110 { szSelfUnregModules, ACTION_SelfUnregModules },
7111 { szSetODBCFolders, ACTION_SetODBCFolders },
7112 { szStartServices, ACTION_StartServices },
7113 { szStopServices, ACTION_StopServices },
7114 { szUnpublishComponents, ACTION_UnpublishComponents },
7115 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7116 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7117 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7118 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7119 { szUnregisterFonts, ACTION_UnregisterFonts },
7120 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7121 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7122 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7123 { szValidateProductID, ACTION_ValidateProductID },
7124 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7125 { szWriteIniValues, ACTION_WriteIniValues },
7126 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7130 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7131 UINT* rc, BOOL force )
7137 if (!run && !package->script->CurrentlyScripting)
7142 if (strcmpW(action,szInstallFinalize) == 0 ||
7143 strcmpW(action,szInstallExecute) == 0 ||
7144 strcmpW(action,szInstallExecuteAgain) == 0)
7149 while (StandardActions[i].action != NULL)
7151 if (strcmpW(StandardActions[i].action, action)==0)
7155 ui_actioninfo(package, action, TRUE, 0);
7156 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7157 ui_actioninfo(package, action, FALSE, *rc);
7161 ui_actionstart(package, action);
7162 if (StandardActions[i].handler)
7164 *rc = StandardActions[i].handler(package);
7168 FIXME("unhandled standard action %s\n",debugstr_w(action));
7169 *rc = ERROR_SUCCESS;
7180 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7182 UINT rc = ERROR_SUCCESS;
7185 TRACE("Performing action (%s)\n", debugstr_w(action));
7187 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7190 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7194 WARN("unhandled msi action %s\n", debugstr_w(action));
7195 rc = ERROR_FUNCTION_NOT_CALLED;
7201 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7203 UINT rc = ERROR_SUCCESS;
7204 BOOL handled = FALSE;
7206 TRACE("Performing action (%s)\n", debugstr_w(action));
7208 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7211 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7213 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7218 WARN("unhandled msi action %s\n", debugstr_w(action));
7219 rc = ERROR_FUNCTION_NOT_CALLED;
7225 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7227 UINT rc = ERROR_SUCCESS;
7230 static const WCHAR ExecSeqQuery[] =
7231 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7232 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7233 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7234 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7235 static const WCHAR UISeqQuery[] =
7236 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7237 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7238 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7239 ' ', '=',' ','%','i',0};
7241 if (needs_ui_sequence(package))
7242 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7244 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7248 LPCWSTR action, cond;
7250 TRACE("Running the actions\n");
7252 /* check conditions */
7253 cond = MSI_RecordGetString(row, 2);
7255 /* this is a hack to skip errors in the condition code */
7256 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7258 msiobj_release(&row->hdr);
7259 return ERROR_SUCCESS;
7262 action = MSI_RecordGetString(row, 1);
7265 ERR("failed to fetch action\n");
7266 msiobj_release(&row->hdr);
7267 return ERROR_FUNCTION_FAILED;
7270 if (needs_ui_sequence(package))
7271 rc = ACTION_PerformUIAction(package, action, -1);
7273 rc = ACTION_PerformAction(package, action, -1, FALSE);
7275 msiobj_release(&row->hdr);
7281 /****************************************************
7282 * TOP level entry points
7283 *****************************************************/
7285 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7286 LPCWSTR szCommandLine )
7291 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7292 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7294 msi_set_property( package->db, szAction, szInstall );
7296 package->script->InWhatSequence = SEQUENCE_INSTALL;
7303 dir = strdupW(szPackagePath);
7304 p = strrchrW(dir, '\\');
7308 file = szPackagePath + (p - dir);
7313 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7314 GetCurrentDirectoryW(MAX_PATH, dir);
7315 lstrcatW(dir, szBackSlash);
7316 file = szPackagePath;
7319 msi_free( package->PackagePath );
7320 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7321 if (!package->PackagePath)
7324 return ERROR_OUTOFMEMORY;
7327 lstrcpyW(package->PackagePath, dir);
7328 lstrcatW(package->PackagePath, file);
7331 msi_set_sourcedir_props(package, FALSE);
7334 msi_parse_command_line( package, szCommandLine, FALSE );
7336 msi_apply_transforms( package );
7337 msi_apply_patches( package );
7339 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7341 TRACE("setting reinstall property\n");
7342 msi_set_property( package->db, szReinstall, szAll );
7345 /* properties may have been added by a transform */
7346 msi_clone_properties( package );
7347 msi_set_context( package );
7349 if (needs_ui_sequence( package))
7351 package->script->InWhatSequence |= SEQUENCE_UI;
7352 rc = ACTION_ProcessUISequence(package);
7353 ui_exists = ui_sequence_exists(package);
7354 if (rc == ERROR_SUCCESS || !ui_exists)
7356 package->script->InWhatSequence |= SEQUENCE_EXEC;
7357 rc = ACTION_ProcessExecSequence(package, ui_exists);
7361 rc = ACTION_ProcessExecSequence(package, FALSE);
7363 package->script->CurrentlyScripting = FALSE;
7365 /* process the ending type action */
7366 if (rc == ERROR_SUCCESS)
7367 ACTION_PerformActionSequence(package, -1);
7368 else if (rc == ERROR_INSTALL_USEREXIT)
7369 ACTION_PerformActionSequence(package, -2);
7370 else if (rc == ERROR_INSTALL_SUSPEND)
7371 ACTION_PerformActionSequence(package, -4);
7373 ACTION_PerformActionSequence(package, -3);
7375 /* finish up running custom actions */
7376 ACTION_FinishCustomActions(package);
7378 if (rc == ERROR_SUCCESS && package->need_reboot)
7379 return ERROR_SUCCESS_REBOOT_REQUIRED;