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 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
498 UINT r = ERROR_SUCCESS;
501 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
503 return ERROR_OUTOFMEMORY;
505 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
509 return ERROR_OUTOFMEMORY;
515 msi_free( pi->patchcode );
517 return ERROR_PATCH_PACKAGE_INVALID;
520 p = strchrW( p + 1, '}' );
523 msi_free( pi->patchcode );
525 return ERROR_PATCH_PACKAGE_INVALID;
530 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
534 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
536 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
539 msi_free( pi->patchcode );
541 return ERROR_OUTOFMEMORY;
548 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
550 UINT i, r = ERROR_SUCCESS;
553 /* apply substorage transforms */
554 substorage = msi_split_string( patch->transforms, ';' );
555 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
556 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
558 msi_free( substorage );
559 if (r != ERROR_SUCCESS)
562 msi_set_media_source_prop( package );
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storages to search for streams.
568 append_storage_to_db( package->db, patch_db->storage );
570 list_add_tail( &package->patches, &patch->entry );
571 return ERROR_SUCCESS;
574 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
576 static const WCHAR dotmsp[] = {'.','m','s','p',0};
577 MSIDATABASE *patch_db = NULL;
578 WCHAR localfile[MAX_PATH];
580 MSIPATCHINFO *patch = NULL;
581 UINT r = ERROR_SUCCESS;
583 TRACE("%p %s\n", package, debugstr_w( file ) );
585 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
586 if ( r != ERROR_SUCCESS )
588 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
592 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
595 msiobj_release( &patch_db->hdr );
596 return ERROR_FUNCTION_FAILED;
599 r = msi_check_patch_applicable( package, si );
600 if (r != ERROR_SUCCESS)
602 TRACE("patch not applicable\n");
607 r = msi_parse_patch_summary( si, &patch );
608 if ( r != ERROR_SUCCESS )
611 r = msi_get_local_package_name( localfile, dotmsp );
612 if ( r != ERROR_SUCCESS )
615 TRACE("copying to local package %s\n", debugstr_w(localfile));
617 if (!CopyFileW( file, localfile, FALSE ))
619 ERR("Unable to copy package (%s -> %s) (error %u)\n",
620 debugstr_w(file), debugstr_w(localfile), GetLastError());
624 patch->localfile = strdupW( localfile );
626 r = msi_apply_patch_db( package, patch_db, patch );
627 if ( r != ERROR_SUCCESS )
628 WARN("patch failed to apply %u\n", r);
631 msiobj_release( &si->hdr );
632 msiobj_release( &patch_db->hdr );
633 if (patch && r != ERROR_SUCCESS)
635 if (patch->localfile)
636 DeleteFileW( patch->localfile );
638 msi_free( patch->patchcode );
639 msi_free( patch->transforms );
640 msi_free( patch->localfile );
646 /* get the PATCH property, and apply all the patches it specifies */
647 static UINT msi_apply_patches( MSIPACKAGE *package )
649 LPWSTR patch_list, *patches;
650 UINT i, r = ERROR_SUCCESS;
652 patch_list = msi_dup_property( package->db, szPatch );
654 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
656 patches = msi_split_string( patch_list, ';' );
657 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
658 r = msi_apply_patch_package( package, patches[i] );
661 msi_free( patch_list );
666 static UINT msi_apply_transforms( MSIPACKAGE *package )
668 static const WCHAR szTransforms[] = {
669 'T','R','A','N','S','F','O','R','M','S',0 };
670 LPWSTR xform_list, *xforms;
671 UINT i, r = ERROR_SUCCESS;
673 xform_list = msi_dup_property( package->db, szTransforms );
674 xforms = msi_split_string( xform_list, ';' );
676 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
678 if (xforms[i][0] == ':')
679 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
681 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
685 msi_free( xform_list );
690 static BOOL ui_sequence_exists( MSIPACKAGE *package )
695 static const WCHAR ExecSeqQuery [] =
696 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
697 '`','I','n','s','t','a','l','l',
698 'U','I','S','e','q','u','e','n','c','e','`',
699 ' ','W','H','E','R','E',' ',
700 '`','S','e','q','u','e','n','c','e','`',' ',
701 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
702 '`','S','e','q','u','e','n','c','e','`',0};
704 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
705 if (rc == ERROR_SUCCESS)
707 msiobj_release(&view->hdr);
714 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
716 LPWSTR source, check;
718 if (msi_get_property_int( package->db, szInstalled, 0 ))
722 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
723 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
731 db = msi_dup_property( package->db, szOriginalDatabase );
733 return ERROR_OUTOFMEMORY;
735 p = strrchrW( db, '\\' );
738 p = strrchrW( db, '/' );
742 return ERROR_SUCCESS;
747 source = msi_alloc( len * sizeof(WCHAR) );
748 lstrcpynW( source, db, len );
752 check = msi_dup_property( package->db, cszSourceDir );
753 if (!check || replace)
755 UINT r = msi_set_property( package->db, cszSourceDir, source );
756 if (r == ERROR_SUCCESS)
757 msi_reset_folders( package, TRUE );
761 check = msi_dup_property( package->db, cszSOURCEDIR );
762 if (!check || replace)
763 msi_set_property( package->db, cszSOURCEDIR, source );
768 return ERROR_SUCCESS;
771 static BOOL needs_ui_sequence(MSIPACKAGE *package)
773 INT level = msi_get_property_int(package->db, szUILevel, 0);
774 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
777 UINT msi_set_context(MSIPACKAGE *package)
781 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
783 num = msi_get_property_int(package->db, szAllUsers, 0);
784 if (num == 1 || num == 2)
785 package->Context = MSIINSTALLCONTEXT_MACHINE;
787 return ERROR_SUCCESS;
790 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
793 LPCWSTR cond, action;
794 MSIPACKAGE *package = param;
796 action = MSI_RecordGetString(row,1);
799 ERR("Error is retrieving action name\n");
800 return ERROR_FUNCTION_FAILED;
803 /* check conditions */
804 cond = MSI_RecordGetString(row,2);
806 /* this is a hack to skip errors in the condition code */
807 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
809 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
810 return ERROR_SUCCESS;
813 if (needs_ui_sequence(package))
814 rc = ACTION_PerformUIAction(package, action, -1);
816 rc = ACTION_PerformAction(package, action, -1, FALSE);
818 msi_dialog_check_messages( NULL );
820 if (package->CurrentInstallState != ERROR_SUCCESS)
821 rc = package->CurrentInstallState;
823 if (rc == ERROR_FUNCTION_NOT_CALLED)
826 if (rc != ERROR_SUCCESS)
827 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
832 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
836 static const WCHAR query[] =
837 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
839 ' ','W','H','E','R','E',' ',
840 '`','S','e','q','u','e','n','c','e','`',' ',
841 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
842 '`','S','e','q','u','e','n','c','e','`',0};
844 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
846 r = MSI_OpenQuery( package->db, &view, query, szTable );
847 if (r == ERROR_SUCCESS)
849 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
850 msiobj_release(&view->hdr);
856 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
860 static const WCHAR ExecSeqQuery[] =
861 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
862 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
863 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
864 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
865 'O','R','D','E','R',' ', 'B','Y',' ',
866 '`','S','e','q','u','e','n','c','e','`',0 };
867 static const WCHAR IVQuery[] =
868 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
869 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
870 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
871 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
872 ' ','\'', 'I','n','s','t','a','l','l',
873 'V','a','l','i','d','a','t','e','\'', 0};
876 if (package->script->ExecuteSequenceRun)
878 TRACE("Execute Sequence already Run\n");
879 return ERROR_SUCCESS;
882 package->script->ExecuteSequenceRun = TRUE;
884 /* get the sequence number */
887 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
889 return ERROR_FUNCTION_FAILED;
890 seq = MSI_RecordGetInteger(row,1);
891 msiobj_release(&row->hdr);
894 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
895 if (rc == ERROR_SUCCESS)
897 TRACE("Running the actions\n");
899 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
900 msiobj_release(&view->hdr);
906 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
910 static const WCHAR ExecSeqQuery [] =
911 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
912 '`','I','n','s','t','a','l','l',
913 'U','I','S','e','q','u','e','n','c','e','`',
914 ' ','W','H','E','R','E',' ',
915 '`','S','e','q','u','e','n','c','e','`',' ',
916 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
917 '`','S','e','q','u','e','n','c','e','`',0};
919 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
920 if (rc == ERROR_SUCCESS)
922 TRACE("Running the actions\n");
924 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
925 msiobj_release(&view->hdr);
931 /********************************************************
932 * ACTION helper functions and functions that perform the actions
933 *******************************************************/
934 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
935 UINT* rc, UINT script, BOOL force )
940 arc = ACTION_CustomAction(package, action, script, force);
942 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
951 * Actual Action Handlers
954 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
956 MSIPACKAGE *package = param;
957 LPCWSTR dir, component;
963 component = MSI_RecordGetString(row, 2);
964 comp = get_loaded_component(package, component);
966 return ERROR_SUCCESS;
968 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
970 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
971 comp->Action = comp->Installed;
972 return ERROR_SUCCESS;
974 comp->Action = INSTALLSTATE_LOCAL;
976 dir = MSI_RecordGetString(row,1);
979 ERR("Unable to get folder id\n");
980 return ERROR_SUCCESS;
983 uirow = MSI_CreateRecord(1);
984 MSI_RecordSetStringW(uirow, 1, dir);
985 ui_actiondata(package, szCreateFolders, uirow);
986 msiobj_release(&uirow->hdr);
988 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
991 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
992 return ERROR_SUCCESS;
995 TRACE("Folder is %s\n",debugstr_w(full_path));
997 if (folder->State == 0)
998 create_full_pathW(full_path);
1002 msi_free(full_path);
1003 return ERROR_SUCCESS;
1006 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1008 static const WCHAR ExecSeqQuery[] =
1009 {'S','E','L','E','C','T',' ',
1010 '`','D','i','r','e','c','t','o','r','y','_','`',
1011 ' ','F','R','O','M',' ',
1012 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1016 /* create all the empty folders specified in the CreateFolder table */
1017 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1018 if (rc != ERROR_SUCCESS)
1019 return ERROR_SUCCESS;
1021 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1022 msiobj_release(&view->hdr);
1027 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1029 MSIPACKAGE *package = param;
1030 LPCWSTR dir, component;
1036 component = MSI_RecordGetString(row, 2);
1037 comp = get_loaded_component(package, component);
1039 return ERROR_SUCCESS;
1041 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1043 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1044 comp->Action = comp->Installed;
1045 return ERROR_SUCCESS;
1047 comp->Action = INSTALLSTATE_ABSENT;
1049 dir = MSI_RecordGetString( row, 1 );
1052 ERR("Unable to get folder id\n");
1053 return ERROR_SUCCESS;
1056 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1059 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1060 return ERROR_SUCCESS;
1063 TRACE("folder is %s\n", debugstr_w(full_path));
1065 uirow = MSI_CreateRecord( 1 );
1066 MSI_RecordSetStringW( uirow, 1, dir );
1067 ui_actiondata( package, szRemoveFolders, uirow );
1068 msiobj_release( &uirow->hdr );
1070 RemoveDirectoryW( full_path );
1073 msi_free( full_path );
1074 return ERROR_SUCCESS;
1077 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1079 static const WCHAR query[] =
1080 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1081 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1086 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1087 if (rc != ERROR_SUCCESS)
1088 return ERROR_SUCCESS;
1090 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1091 msiobj_release( &view->hdr );
1096 static UINT load_component( MSIRECORD *row, LPVOID param )
1098 MSIPACKAGE *package = param;
1101 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1103 return ERROR_FUNCTION_FAILED;
1105 list_add_tail( &package->components, &comp->entry );
1107 /* fill in the data */
1108 comp->Component = msi_dup_record_field( row, 1 );
1110 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1112 comp->ComponentId = msi_dup_record_field( row, 2 );
1113 comp->Directory = msi_dup_record_field( row, 3 );
1114 comp->Attributes = MSI_RecordGetInteger(row,4);
1115 comp->Condition = msi_dup_record_field( row, 5 );
1116 comp->KeyPath = msi_dup_record_field( row, 6 );
1118 comp->Installed = INSTALLSTATE_UNKNOWN;
1119 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1121 return ERROR_SUCCESS;
1124 static UINT load_all_components( MSIPACKAGE *package )
1126 static const WCHAR query[] = {
1127 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1128 '`','C','o','m','p','o','n','e','n','t','`',0 };
1132 if (!list_empty(&package->components))
1133 return ERROR_SUCCESS;
1135 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1136 if (r != ERROR_SUCCESS)
1139 r = MSI_IterateRecords(view, NULL, load_component, package);
1140 msiobj_release(&view->hdr);
1145 MSIPACKAGE *package;
1146 MSIFEATURE *feature;
1149 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1153 cl = msi_alloc( sizeof (*cl) );
1155 return ERROR_NOT_ENOUGH_MEMORY;
1156 cl->component = comp;
1157 list_add_tail( &feature->Components, &cl->entry );
1159 return ERROR_SUCCESS;
1162 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1166 fl = msi_alloc( sizeof(*fl) );
1168 return ERROR_NOT_ENOUGH_MEMORY;
1169 fl->feature = child;
1170 list_add_tail( &parent->Children, &fl->entry );
1172 return ERROR_SUCCESS;
1175 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1177 _ilfs* ilfs = param;
1181 component = MSI_RecordGetString(row,1);
1183 /* check to see if the component is already loaded */
1184 comp = get_loaded_component( ilfs->package, component );
1187 ERR("unknown component %s\n", debugstr_w(component));
1188 return ERROR_FUNCTION_FAILED;
1191 add_feature_component( ilfs->feature, comp );
1192 comp->Enabled = TRUE;
1194 return ERROR_SUCCESS;
1197 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1199 MSIFEATURE *feature;
1204 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1206 if ( !lstrcmpW( feature->Feature, name ) )
1213 static UINT load_feature(MSIRECORD * row, LPVOID param)
1215 MSIPACKAGE* package = param;
1216 MSIFEATURE* feature;
1217 static const WCHAR Query1[] =
1218 {'S','E','L','E','C','T',' ',
1219 '`','C','o','m','p','o','n','e','n','t','_','`',
1220 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1221 'C','o','m','p','o','n','e','n','t','s','`',' ',
1222 'W','H','E','R','E',' ',
1223 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1228 /* fill in the data */
1230 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1232 return ERROR_NOT_ENOUGH_MEMORY;
1234 list_init( &feature->Children );
1235 list_init( &feature->Components );
1237 feature->Feature = msi_dup_record_field( row, 1 );
1239 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1241 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1242 feature->Title = msi_dup_record_field( row, 3 );
1243 feature->Description = msi_dup_record_field( row, 4 );
1245 if (!MSI_RecordIsNull(row,5))
1246 feature->Display = MSI_RecordGetInteger(row,5);
1248 feature->Level= MSI_RecordGetInteger(row,6);
1249 feature->Directory = msi_dup_record_field( row, 7 );
1250 feature->Attributes = MSI_RecordGetInteger(row,8);
1252 feature->Installed = INSTALLSTATE_UNKNOWN;
1253 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1255 list_add_tail( &package->features, &feature->entry );
1257 /* load feature components */
1259 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1260 if (rc != ERROR_SUCCESS)
1261 return ERROR_SUCCESS;
1263 ilfs.package = package;
1264 ilfs.feature = feature;
1266 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1267 msiobj_release(&view->hdr);
1269 return ERROR_SUCCESS;
1272 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1274 MSIPACKAGE* package = param;
1275 MSIFEATURE *parent, *child;
1277 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1279 return ERROR_FUNCTION_FAILED;
1281 if (!child->Feature_Parent)
1282 return ERROR_SUCCESS;
1284 parent = find_feature_by_name( package, child->Feature_Parent );
1286 return ERROR_FUNCTION_FAILED;
1288 add_feature_child( parent, child );
1289 return ERROR_SUCCESS;
1292 static UINT load_all_features( MSIPACKAGE *package )
1294 static const WCHAR query[] = {
1295 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1296 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1297 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1301 if (!list_empty(&package->features))
1302 return ERROR_SUCCESS;
1304 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1305 if (r != ERROR_SUCCESS)
1308 r = MSI_IterateRecords( view, NULL, load_feature, package );
1309 if (r != ERROR_SUCCESS)
1312 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1313 msiobj_release( &view->hdr );
1318 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1329 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1331 static const WCHAR query[] = {
1332 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1334 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1335 MSIQUERY *view = NULL;
1336 MSIRECORD *row = NULL;
1339 TRACE("%s\n", debugstr_w(file->File));
1341 r = MSI_OpenQuery(package->db, &view, query, file->File);
1342 if (r != ERROR_SUCCESS)
1345 r = MSI_ViewExecute(view, NULL);
1346 if (r != ERROR_SUCCESS)
1349 r = MSI_ViewFetch(view, &row);
1350 if (r != ERROR_SUCCESS)
1353 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1354 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1355 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1356 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1357 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1360 if (view) msiobj_release(&view->hdr);
1361 if (row) msiobj_release(&row->hdr);
1365 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1368 static const WCHAR query[] = {
1369 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1370 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1371 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1373 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1376 WARN("query failed\n");
1377 return ERROR_FUNCTION_FAILED;
1380 file->disk_id = MSI_RecordGetInteger( row, 1 );
1381 msiobj_release( &row->hdr );
1382 return ERROR_SUCCESS;
1385 static UINT load_file(MSIRECORD *row, LPVOID param)
1387 MSIPACKAGE* package = param;
1391 /* fill in the data */
1393 file = msi_alloc_zero( sizeof (MSIFILE) );
1395 return ERROR_NOT_ENOUGH_MEMORY;
1397 file->File = msi_dup_record_field( row, 1 );
1399 component = MSI_RecordGetString( row, 2 );
1400 file->Component = get_loaded_component( package, component );
1402 if (!file->Component)
1404 WARN("Component not found: %s\n", debugstr_w(component));
1405 msi_free(file->File);
1407 return ERROR_SUCCESS;
1410 file->FileName = msi_dup_record_field( row, 3 );
1411 reduce_to_longfilename( file->FileName );
1413 file->ShortName = msi_dup_record_field( row, 3 );
1414 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1416 file->FileSize = MSI_RecordGetInteger( row, 4 );
1417 file->Version = msi_dup_record_field( row, 5 );
1418 file->Language = msi_dup_record_field( row, 6 );
1419 file->Attributes = MSI_RecordGetInteger( row, 7 );
1420 file->Sequence = MSI_RecordGetInteger( row, 8 );
1422 file->state = msifs_invalid;
1424 /* if the compressed bits are not set in the file attributes,
1425 * then read the information from the package word count property
1427 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1429 file->IsCompressed = FALSE;
1431 else if (file->Attributes &
1432 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1434 file->IsCompressed = TRUE;
1436 else if (file->Attributes & msidbFileAttributesNoncompressed)
1438 file->IsCompressed = FALSE;
1442 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1445 load_file_hash(package, file);
1446 load_file_disk_id(package, file);
1448 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1450 list_add_tail( &package->files, &file->entry );
1452 return ERROR_SUCCESS;
1455 static UINT load_all_files(MSIPACKAGE *package)
1459 static const WCHAR Query[] =
1460 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1461 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1462 '`','S','e','q','u','e','n','c','e','`', 0};
1464 if (!list_empty(&package->files))
1465 return ERROR_SUCCESS;
1467 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1468 if (rc != ERROR_SUCCESS)
1469 return ERROR_SUCCESS;
1471 rc = MSI_IterateRecords(view, NULL, load_file, package);
1472 msiobj_release(&view->hdr);
1474 return ERROR_SUCCESS;
1477 static UINT load_folder( MSIRECORD *row, LPVOID param )
1479 MSIPACKAGE *package = param;
1480 static WCHAR szEmpty[] = { 0 };
1481 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1484 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1486 return ERROR_NOT_ENOUGH_MEMORY;
1488 folder->Directory = msi_dup_record_field( row, 1 );
1490 TRACE("%s\n", debugstr_w(folder->Directory));
1492 p = msi_dup_record_field(row, 3);
1494 /* split src and target dir */
1496 src_short = folder_split_path( p, ':' );
1498 /* split the long and short paths */
1499 tgt_long = folder_split_path( tgt_short, '|' );
1500 src_long = folder_split_path( src_short, '|' );
1502 /* check for no-op dirs */
1503 if (!lstrcmpW(szDot, tgt_short))
1504 tgt_short = szEmpty;
1505 if (!lstrcmpW(szDot, src_short))
1506 src_short = szEmpty;
1509 tgt_long = tgt_short;
1512 src_short = tgt_short;
1513 src_long = tgt_long;
1517 src_long = src_short;
1519 /* FIXME: use the target short path too */
1520 folder->TargetDefault = strdupW(tgt_long);
1521 folder->SourceShortPath = strdupW(src_short);
1522 folder->SourceLongPath = strdupW(src_long);
1525 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1526 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1527 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1529 folder->Parent = msi_dup_record_field( row, 2 );
1531 folder->Property = msi_dup_property( package->db, folder->Directory );
1533 list_add_tail( &package->folders, &folder->entry );
1535 TRACE("returning %p\n", folder);
1537 return ERROR_SUCCESS;
1540 static UINT load_all_folders( MSIPACKAGE *package )
1542 static const WCHAR query[] = {
1543 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1544 '`','D','i','r','e','c','t','o','r','y','`',0 };
1548 if (!list_empty(&package->folders))
1549 return ERROR_SUCCESS;
1551 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1552 if (r != ERROR_SUCCESS)
1555 r = MSI_IterateRecords(view, NULL, load_folder, package);
1556 msiobj_release(&view->hdr);
1561 * I am not doing any of the costing functionality yet.
1562 * Mostly looking at doing the Component and Feature loading
1564 * The native MSI does A LOT of modification to tables here. Mostly adding
1565 * a lot of temporary columns to the Feature and Component tables.
1567 * note: Native msi also tracks the short filename. But I am only going to
1568 * track the long ones. Also looking at this directory table
1569 * it appears that the directory table does not get the parents
1570 * resolved base on property only based on their entries in the
1573 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1575 static const WCHAR szCosting[] =
1576 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1578 msi_set_property( package->db, szCosting, szZero );
1579 msi_set_property( package->db, cszRootDrive, c_colon );
1581 load_all_folders( package );
1582 load_all_components( package );
1583 load_all_features( package );
1584 load_all_files( package );
1586 return ERROR_SUCCESS;
1589 static UINT execute_script(MSIPACKAGE *package, UINT script )
1592 UINT rc = ERROR_SUCCESS;
1594 TRACE("Executing Script %i\n",script);
1596 if (!package->script)
1598 ERR("no script!\n");
1599 return ERROR_FUNCTION_FAILED;
1602 for (i = 0; i < package->script->ActionCount[script]; i++)
1605 action = package->script->Actions[script][i];
1606 ui_actionstart(package, action);
1607 TRACE("Executing Action (%s)\n",debugstr_w(action));
1608 rc = ACTION_PerformAction(package, action, script, TRUE);
1609 if (rc != ERROR_SUCCESS)
1612 msi_free_action_script(package, script);
1616 static UINT ACTION_FileCost(MSIPACKAGE *package)
1618 return ERROR_SUCCESS;
1621 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1627 state = MsiQueryProductStateW(package->ProductCode);
1629 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1631 if (!comp->ComponentId)
1634 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1635 comp->Installed = INSTALLSTATE_ABSENT;
1638 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1639 package->Context, comp->ComponentId,
1641 if (r != ERROR_SUCCESS)
1642 comp->Installed = INSTALLSTATE_ABSENT;
1647 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1649 MSIFEATURE *feature;
1652 state = MsiQueryProductStateW(package->ProductCode);
1654 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1656 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1657 feature->Installed = INSTALLSTATE_ABSENT;
1660 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1666 static BOOL process_state_property(MSIPACKAGE* package, int level,
1667 LPCWSTR property, INSTALLSTATE state)
1670 MSIFEATURE *feature;
1672 override = msi_dup_property( package->db, property );
1676 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1678 if (lstrcmpW(property, szRemove) &&
1679 (feature->Level <= 0 || feature->Level > level))
1682 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1684 if (strcmpiW(override, szAll)==0)
1685 msi_feature_set_state(package, feature, state);
1688 LPWSTR ptr = override;
1689 LPWSTR ptr2 = strchrW(override,',');
1693 int len = ptr2 - ptr;
1695 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1696 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1698 msi_feature_set_state(package, feature, state);
1704 ptr2 = strchrW(ptr,',');
1716 static BOOL process_overrides( MSIPACKAGE *package, int level )
1718 static const WCHAR szAddLocal[] =
1719 {'A','D','D','L','O','C','A','L',0};
1720 static const WCHAR szAddSource[] =
1721 {'A','D','D','S','O','U','R','C','E',0};
1722 static const WCHAR szAdvertise[] =
1723 {'A','D','V','E','R','T','I','S','E',0};
1726 /* all these activation/deactivation things happen in order and things
1727 * later on the list override things earlier on the list.
1729 * 0 INSTALLLEVEL processing
1742 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1743 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1744 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1745 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1746 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1749 msi_set_property( package->db, szPreselected, szOne );
1754 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1757 static const WCHAR szlevel[] =
1758 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1759 MSICOMPONENT* component;
1760 MSIFEATURE *feature;
1762 TRACE("Checking Install Level\n");
1764 level = msi_get_property_int(package->db, szlevel, 1);
1766 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1768 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1770 BOOL feature_state = ((feature->Level > 0) &&
1771 (feature->Level <= level));
1773 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1775 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1776 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1777 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1778 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1780 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1784 /* disable child features of unselected parent features */
1785 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1789 if (feature->Level > 0 && feature->Level <= level)
1792 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1793 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1798 * now we want to enable or disable components base on feature
1801 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1805 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1806 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1808 if (!feature->Level)
1811 /* features with components that have compressed files are made local */
1812 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1814 if (cl->component->Enabled &&
1815 cl->component->ForceLocalState &&
1816 feature->Action == INSTALLSTATE_SOURCE)
1818 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1823 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1825 component = cl->component;
1827 if (!component->Enabled)
1830 switch (feature->Action)
1832 case INSTALLSTATE_ABSENT:
1833 component->anyAbsent = 1;
1835 case INSTALLSTATE_ADVERTISED:
1836 component->hasAdvertiseFeature = 1;
1838 case INSTALLSTATE_SOURCE:
1839 component->hasSourceFeature = 1;
1841 case INSTALLSTATE_LOCAL:
1842 component->hasLocalFeature = 1;
1844 case INSTALLSTATE_DEFAULT:
1845 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1846 component->hasAdvertiseFeature = 1;
1847 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1848 component->hasSourceFeature = 1;
1850 component->hasLocalFeature = 1;
1858 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1860 /* if the component isn't enabled, leave it alone */
1861 if (!component->Enabled)
1864 /* check if it's local or source */
1865 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1866 (component->hasLocalFeature || component->hasSourceFeature))
1868 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1869 !component->ForceLocalState)
1870 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1872 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1876 /* if any feature is local, the component must be local too */
1877 if (component->hasLocalFeature)
1879 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1883 if (component->hasSourceFeature)
1885 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1889 if (component->hasAdvertiseFeature)
1891 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1895 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1896 if (component->anyAbsent)
1897 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1900 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1902 if (component->Action == INSTALLSTATE_DEFAULT)
1904 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1905 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1908 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1909 debugstr_w(component->Component), component->Installed, component->Action);
1913 return ERROR_SUCCESS;
1916 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1918 MSIPACKAGE *package = param;
1923 name = MSI_RecordGetString(row,1);
1925 f = get_loaded_folder(package, name);
1926 if (!f) return ERROR_SUCCESS;
1928 /* reset the ResolvedTarget */
1929 msi_free(f->ResolvedTarget);
1930 f->ResolvedTarget = NULL;
1932 /* This helper function now does ALL the work */
1933 TRACE("Dir %s ...\n",debugstr_w(name));
1934 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1935 TRACE("resolves to %s\n",debugstr_w(path));
1938 return ERROR_SUCCESS;
1941 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1943 MSIPACKAGE *package = param;
1945 MSIFEATURE *feature;
1947 name = MSI_RecordGetString( row, 1 );
1949 feature = get_loaded_feature( package, name );
1951 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1955 Condition = MSI_RecordGetString(row,3);
1957 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1959 int level = MSI_RecordGetInteger(row,2);
1960 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1961 feature->Level = level;
1964 return ERROR_SUCCESS;
1967 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1969 static const WCHAR name[] = {'\\',0};
1970 VS_FIXEDFILEINFO *ret;
1972 DWORD versize, handle;
1975 TRACE("%s\n", debugstr_w(filename));
1977 versize = GetFileVersionInfoSizeW( filename, &handle );
1981 version = msi_alloc( versize );
1985 GetFileVersionInfoW( filename, 0, versize, version );
1987 if (!VerQueryValueW( version, name, (LPVOID *)&ret, &sz ))
1989 msi_free( version );
1993 msi_free( version );
1997 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2001 msi_parse_version_string( version, &ms, &ls );
2003 if (fi->dwFileVersionMS > ms) return 1;
2004 else if (fi->dwFileVersionMS < ms) return -1;
2005 else if (fi->dwFileVersionLS > ls) return 1;
2006 else if (fi->dwFileVersionLS < ls) return -1;
2010 static DWORD get_disk_file_size( LPCWSTR filename )
2015 TRACE("%s\n", debugstr_w(filename));
2017 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2018 if (file == INVALID_HANDLE_VALUE)
2019 return INVALID_FILE_SIZE;
2021 size = GetFileSize( file, NULL );
2022 CloseHandle( file );
2026 static BOOL hash_matches( MSIFILE *file )
2029 MSIFILEHASHINFO hash;
2031 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2032 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2033 if (r != ERROR_SUCCESS)
2036 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2039 static UINT set_file_install_states( MSIPACKAGE *package )
2041 VS_FIXEDFILEINFO *file_version;
2044 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2046 MSICOMPONENT* comp = file->Component;
2053 if (file->IsCompressed)
2054 comp->ForceLocalState = TRUE;
2056 /* calculate target */
2057 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2058 msi_free(file->TargetPath);
2060 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2062 file->TargetPath = build_directory_name(2, p, file->FileName);
2065 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2067 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2069 file->state = msifs_missing;
2070 comp->Cost += file->FileSize;
2073 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2075 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2076 HIWORD(file_version->dwFileVersionMS),
2077 LOWORD(file_version->dwFileVersionMS),
2078 HIWORD(file_version->dwFileVersionLS),
2079 LOWORD(file_version->dwFileVersionLS));
2081 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2083 file->state = msifs_overwrite;
2084 comp->Cost += file->FileSize;
2088 TRACE("Destination file version equal or greater, not overwriting\n");
2089 file->state = msifs_present;
2091 msi_free( file_version );
2094 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2096 file->state = msifs_overwrite;
2097 comp->Cost += file->FileSize - file_size;
2100 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2102 TRACE("File hashes match, not overwriting\n");
2103 file->state = msifs_present;
2106 file->state = msifs_overwrite;
2107 comp->Cost += file->FileSize - file_size;
2110 return ERROR_SUCCESS;
2114 * A lot is done in this function aside from just the costing.
2115 * The costing needs to be implemented at some point but for now I am going
2116 * to focus on the directory building
2119 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2121 static const WCHAR ExecSeqQuery[] =
2122 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2123 '`','D','i','r','e','c','t','o','r','y','`',0};
2124 static const WCHAR ConditionQuery[] =
2125 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2126 '`','C','o','n','d','i','t','i','o','n','`',0};
2127 static const WCHAR szCosting[] =
2128 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2129 static const WCHAR szlevel[] =
2130 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2131 static const WCHAR szOutOfDiskSpace[] =
2132 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2134 UINT rc = ERROR_SUCCESS;
2138 TRACE("Building Directory properties\n");
2140 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2141 if (rc == ERROR_SUCCESS)
2143 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2145 msiobj_release(&view->hdr);
2148 /* read components states from the registry */
2149 ACTION_GetComponentInstallStates(package);
2150 ACTION_GetFeatureInstallStates(package);
2152 TRACE("Calculating file install states\n");
2153 set_file_install_states( package );
2155 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2157 TRACE("Evaluating feature conditions\n");
2159 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2160 if (rc == ERROR_SUCCESS)
2162 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2163 msiobj_release( &view->hdr );
2166 TRACE("Evaluating component conditions\n");
2168 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2170 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2172 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2173 comp->Enabled = FALSE;
2176 comp->Enabled = TRUE;
2179 msi_set_property( package->db, szCosting, szOne );
2180 /* set default run level if not set */
2181 level = msi_dup_property( package->db, szlevel );
2183 msi_set_property( package->db, szlevel, szOne );
2186 /* FIXME: check volume disk space */
2187 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2189 return MSI_SetFeatureStates(package);
2192 /* OK this value is "interpreted" and then formatted based on the
2193 first few characters */
2194 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2199 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2205 LPWSTR deformated = NULL;
2208 deformat_string(package, &value[2], &deformated);
2210 /* binary value type */
2214 *size = (strlenW(ptr)/2)+1;
2216 *size = strlenW(ptr)/2;
2218 data = msi_alloc(*size);
2224 /* if uneven pad with a zero in front */
2230 data[count] = (BYTE)strtol(byte,NULL,0);
2232 TRACE("Uneven byte count\n");
2240 data[count] = (BYTE)strtol(byte,NULL,0);
2243 msi_free(deformated);
2245 TRACE("Data %i bytes(%i)\n",*size,count);
2252 deformat_string(package, &value[1], &deformated);
2255 *size = sizeof(DWORD);
2256 data = msi_alloc(*size);
2262 if ( (*p < '0') || (*p > '9') )
2268 if (deformated[0] == '-')
2271 TRACE("DWORD %i\n",*(LPDWORD)data);
2273 msi_free(deformated);
2278 static const WCHAR szMulti[] = {'[','~',']',0};
2287 *type=REG_EXPAND_SZ;
2295 if (strstrW(value,szMulti))
2296 *type = REG_MULTI_SZ;
2298 /* remove initial delimiter */
2299 if (!strncmpW(value, szMulti, 3))
2302 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2304 /* add double NULL terminator */
2305 if (*type == REG_MULTI_SZ)
2307 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2308 data = msi_realloc_zero(data, *size);
2314 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2321 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2323 *root_key = HKEY_LOCAL_MACHINE;
2328 *root_key = HKEY_CURRENT_USER;
2333 *root_key = HKEY_CLASSES_ROOT;
2337 *root_key = HKEY_CURRENT_USER;
2341 *root_key = HKEY_LOCAL_MACHINE;
2345 *root_key = HKEY_USERS;
2349 ERR("Unknown root %i\n", root);
2356 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2358 MSIPACKAGE *package = param;
2359 LPSTR value_data = NULL;
2360 HKEY root_key, hkey;
2363 LPCWSTR szRoot, component, name, key, value;
2368 BOOL check_first = FALSE;
2371 ui_progress(package,2,0,0,0);
2378 component = MSI_RecordGetString(row, 6);
2379 comp = get_loaded_component(package,component);
2381 return ERROR_SUCCESS;
2383 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2385 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2386 comp->Action = comp->Installed;
2387 return ERROR_SUCCESS;
2389 comp->Action = INSTALLSTATE_LOCAL;
2391 name = MSI_RecordGetString(row, 4);
2392 if( MSI_RecordIsNull(row,5) && name )
2394 /* null values can have special meanings */
2395 if (name[0]=='-' && name[1] == 0)
2396 return ERROR_SUCCESS;
2397 else if ((name[0]=='+' && name[1] == 0) ||
2398 (name[0] == '*' && name[1] == 0))
2403 root = MSI_RecordGetInteger(row,2);
2404 key = MSI_RecordGetString(row, 3);
2406 szRoot = get_root_key( package, root, &root_key );
2408 return ERROR_SUCCESS;
2410 deformat_string(package, key , &deformated);
2411 size = strlenW(deformated) + strlenW(szRoot) + 1;
2412 uikey = msi_alloc(size*sizeof(WCHAR));
2413 strcpyW(uikey,szRoot);
2414 strcatW(uikey,deformated);
2416 if (RegCreateKeyW( root_key, deformated, &hkey))
2418 ERR("Could not create key %s\n",debugstr_w(deformated));
2419 msi_free(deformated);
2421 return ERROR_SUCCESS;
2423 msi_free(deformated);
2425 value = MSI_RecordGetString(row,5);
2427 value_data = parse_value(package, value, &type, &size);
2430 value_data = (LPSTR)strdupW(szEmpty);
2431 size = sizeof(szEmpty);
2435 deformat_string(package, name, &deformated);
2439 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2441 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2446 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2447 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2449 TRACE("value %s of %s checked already exists\n",
2450 debugstr_w(deformated), debugstr_w(uikey));
2454 TRACE("Checked and setting value %s of %s\n",
2455 debugstr_w(deformated), debugstr_w(uikey));
2456 if (deformated || size)
2457 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2462 uirow = MSI_CreateRecord(3);
2463 MSI_RecordSetStringW(uirow,2,deformated);
2464 MSI_RecordSetStringW(uirow,1,uikey);
2465 if (type == REG_SZ || type == REG_EXPAND_SZ)
2466 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2467 ui_actiondata(package,szWriteRegistryValues,uirow);
2468 msiobj_release( &uirow->hdr );
2470 msi_free(value_data);
2471 msi_free(deformated);
2474 return ERROR_SUCCESS;
2477 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2481 static const WCHAR ExecSeqQuery[] =
2482 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2483 '`','R','e','g','i','s','t','r','y','`',0 };
2485 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2486 if (rc != ERROR_SUCCESS)
2487 return ERROR_SUCCESS;
2489 /* increment progress bar each time action data is sent */
2490 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2492 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2494 msiobj_release(&view->hdr);
2498 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2502 DWORD num_subkeys, num_values;
2506 if ((res = RegDeleteTreeW( hkey_root, key )))
2508 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2513 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2515 if ((res = RegDeleteValueW( hkey, value )))
2517 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2519 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2520 NULL, NULL, NULL, NULL );
2521 RegCloseKey( hkey );
2523 if (!res && !num_subkeys && !num_values)
2525 TRACE("Removing empty key %s\n", debugstr_w(key));
2526 RegDeleteKeyW( hkey_root, key );
2530 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2534 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2536 MSIPACKAGE *package = param;
2537 LPCWSTR component, name, key_str, root_key_str;
2538 LPWSTR deformated_key, deformated_name, ui_key_str;
2541 BOOL delete_key = FALSE;
2546 ui_progress( package, 2, 0, 0, 0 );
2548 component = MSI_RecordGetString( row, 6 );
2549 comp = get_loaded_component( package, component );
2551 return ERROR_SUCCESS;
2553 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2555 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2556 comp->Action = comp->Installed;
2557 return ERROR_SUCCESS;
2559 comp->Action = INSTALLSTATE_ABSENT;
2561 name = MSI_RecordGetString( row, 4 );
2562 if (MSI_RecordIsNull( row, 5 ) && name )
2564 if (name[0] == '+' && !name[1])
2565 return ERROR_SUCCESS;
2566 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2573 root = MSI_RecordGetInteger( row, 2 );
2574 key_str = MSI_RecordGetString( row, 3 );
2576 root_key_str = get_root_key( package, root, &hkey_root );
2578 return ERROR_SUCCESS;
2580 deformat_string( package, key_str, &deformated_key );
2581 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2582 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2583 strcpyW( ui_key_str, root_key_str );
2584 strcatW( ui_key_str, deformated_key );
2586 deformat_string( package, name, &deformated_name );
2588 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2589 msi_free( deformated_key );
2591 uirow = MSI_CreateRecord( 2 );
2592 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2593 MSI_RecordSetStringW( uirow, 2, deformated_name );
2595 ui_actiondata( package, szRemoveRegistryValues, uirow );
2596 msiobj_release( &uirow->hdr );
2598 msi_free( ui_key_str );
2599 msi_free( deformated_name );
2600 return ERROR_SUCCESS;
2603 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2605 MSIPACKAGE *package = param;
2606 LPCWSTR component, name, key_str, root_key_str;
2607 LPWSTR deformated_key, deformated_name, ui_key_str;
2610 BOOL delete_key = FALSE;
2615 ui_progress( package, 2, 0, 0, 0 );
2617 component = MSI_RecordGetString( row, 5 );
2618 comp = get_loaded_component( package, component );
2620 return ERROR_SUCCESS;
2622 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2624 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2625 comp->Action = comp->Installed;
2626 return ERROR_SUCCESS;
2628 comp->Action = INSTALLSTATE_LOCAL;
2630 if ((name = MSI_RecordGetString( row, 4 )))
2632 if (name[0] == '-' && !name[1])
2639 root = MSI_RecordGetInteger( row, 2 );
2640 key_str = MSI_RecordGetString( row, 3 );
2642 root_key_str = get_root_key( package, root, &hkey_root );
2644 return ERROR_SUCCESS;
2646 deformat_string( package, key_str, &deformated_key );
2647 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2648 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2649 strcpyW( ui_key_str, root_key_str );
2650 strcatW( ui_key_str, deformated_key );
2652 deformat_string( package, name, &deformated_name );
2654 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2655 msi_free( deformated_key );
2657 uirow = MSI_CreateRecord( 2 );
2658 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2659 MSI_RecordSetStringW( uirow, 2, deformated_name );
2661 ui_actiondata( package, szRemoveRegistryValues, uirow );
2662 msiobj_release( &uirow->hdr );
2664 msi_free( ui_key_str );
2665 msi_free( deformated_name );
2666 return ERROR_SUCCESS;
2669 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2673 static const WCHAR registry_query[] =
2674 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2675 '`','R','e','g','i','s','t','r','y','`',0 };
2676 static const WCHAR remove_registry_query[] =
2677 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2678 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2680 /* increment progress bar each time action data is sent */
2681 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2683 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2684 if (rc == ERROR_SUCCESS)
2686 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2687 msiobj_release( &view->hdr );
2688 if (rc != ERROR_SUCCESS)
2692 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2693 if (rc == ERROR_SUCCESS)
2695 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2696 msiobj_release( &view->hdr );
2697 if (rc != ERROR_SUCCESS)
2701 return ERROR_SUCCESS;
2704 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2706 package->script->CurrentlyScripting = TRUE;
2708 return ERROR_SUCCESS;
2712 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2717 static const WCHAR q1[]=
2718 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2719 '`','R','e','g','i','s','t','r','y','`',0};
2722 MSIFEATURE *feature;
2725 TRACE("InstallValidate\n");
2727 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2728 if (rc == ERROR_SUCCESS)
2730 MSI_IterateRecords( view, &progress, NULL, package );
2731 msiobj_release( &view->hdr );
2732 total += progress * REG_PROGRESS_VALUE;
2735 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2736 total += COMPONENT_PROGRESS_VALUE;
2738 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2739 total += file->FileSize;
2741 ui_progress(package,0,total,0,0);
2743 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2745 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2746 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2747 feature->ActionRequest);
2750 return ERROR_SUCCESS;
2753 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2755 MSIPACKAGE* package = param;
2756 LPCWSTR cond = NULL;
2757 LPCWSTR message = NULL;
2760 static const WCHAR title[]=
2761 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2763 cond = MSI_RecordGetString(row,1);
2765 r = MSI_EvaluateConditionW(package,cond);
2766 if (r == MSICONDITION_FALSE)
2768 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2771 message = MSI_RecordGetString(row,2);
2772 deformat_string(package,message,&deformated);
2773 MessageBoxW(NULL,deformated,title,MB_OK);
2774 msi_free(deformated);
2777 return ERROR_INSTALL_FAILURE;
2780 return ERROR_SUCCESS;
2783 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2786 MSIQUERY * view = NULL;
2787 static const WCHAR ExecSeqQuery[] =
2788 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2789 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2791 TRACE("Checking launch conditions\n");
2793 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2794 if (rc != ERROR_SUCCESS)
2795 return ERROR_SUCCESS;
2797 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2798 msiobj_release(&view->hdr);
2803 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2807 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2809 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2811 MSIRECORD * row = 0;
2813 LPWSTR deformated,buffer,deformated_name;
2815 static const WCHAR ExecSeqQuery[] =
2816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2817 '`','R','e','g','i','s','t','r','y','`',' ',
2818 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2819 ' ','=',' ' ,'\'','%','s','\'',0 };
2820 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2821 static const WCHAR fmt2[]=
2822 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2824 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2828 root = MSI_RecordGetInteger(row,2);
2829 key = MSI_RecordGetString(row, 3);
2830 name = MSI_RecordGetString(row, 4);
2831 deformat_string(package, key , &deformated);
2832 deformat_string(package, name, &deformated_name);
2834 len = strlenW(deformated) + 6;
2835 if (deformated_name)
2836 len+=strlenW(deformated_name);
2838 buffer = msi_alloc( len *sizeof(WCHAR));
2840 if (deformated_name)
2841 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2843 sprintfW(buffer,fmt,root,deformated);
2845 msi_free(deformated);
2846 msi_free(deformated_name);
2847 msiobj_release(&row->hdr);
2851 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2853 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2858 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2861 return strdupW( file->TargetPath );
2866 static HKEY openSharedDLLsKey(void)
2869 static const WCHAR path[] =
2870 {'S','o','f','t','w','a','r','e','\\',
2871 'M','i','c','r','o','s','o','f','t','\\',
2872 'W','i','n','d','o','w','s','\\',
2873 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2874 'S','h','a','r','e','d','D','L','L','s',0};
2876 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2880 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2885 DWORD sz = sizeof(count);
2888 hkey = openSharedDLLsKey();
2889 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2890 if (rc != ERROR_SUCCESS)
2896 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2900 hkey = openSharedDLLsKey();
2902 msi_reg_set_val_dword( hkey, path, count );
2904 RegDeleteValueW(hkey,path);
2910 * Return TRUE if the count should be written out and FALSE if not
2912 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2914 MSIFEATURE *feature;
2918 /* only refcount DLLs */
2919 if (comp->KeyPath == NULL ||
2920 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2921 comp->Attributes & msidbComponentAttributesODBCDataSource)
2925 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2926 write = (count > 0);
2928 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2932 /* increment counts */
2933 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2937 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2940 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2942 if ( cl->component == comp )
2947 /* decrement counts */
2948 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2952 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2955 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2957 if ( cl->component == comp )
2962 /* ref count all the files in the component */
2967 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2969 if (file->Component == comp)
2970 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2974 /* add a count for permanent */
2975 if (comp->Attributes & msidbComponentAttributesPermanent)
2978 comp->RefCount = count;
2981 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2984 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2986 WCHAR squished_pc[GUID_SIZE];
2987 WCHAR squished_cc[GUID_SIZE];
2994 squash_guid(package->ProductCode,squished_pc);
2995 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2997 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3001 ui_progress(package,2,0,0,0);
3002 if (!comp->ComponentId)
3005 squash_guid(comp->ComponentId,squished_cc);
3007 msi_free(comp->FullKeypath);
3008 comp->FullKeypath = resolve_keypath( package, comp );
3010 ACTION_RefCountComponent( package, comp );
3012 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
3013 debugstr_w(comp->Component),
3014 debugstr_w(squished_cc),
3015 debugstr_w(comp->FullKeypath),
3018 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3019 comp->ActionRequest == INSTALLSTATE_SOURCE)
3021 if (!comp->FullKeypath)
3024 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3025 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3028 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3031 if (rc != ERROR_SUCCESS)
3034 if (comp->Attributes & msidbComponentAttributesPermanent)
3036 static const WCHAR szPermKey[] =
3037 { '0','0','0','0','0','0','0','0','0','0','0','0',
3038 '0','0','0','0','0','0','0','0','0','0','0','0',
3039 '0','0','0','0','0','0','0','0',0 };
3041 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3044 if (comp->Action == INSTALLSTATE_LOCAL)
3045 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3051 WCHAR source[MAX_PATH];
3052 WCHAR base[MAX_PATH];
3055 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3056 static const WCHAR query[] = {
3057 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3058 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3059 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3060 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3061 '`','D','i','s','k','I','d','`',0};
3063 file = get_loaded_file(package, comp->KeyPath);
3067 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3068 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3069 ptr2 = strrchrW(source, '\\') + 1;
3070 msiobj_release(&row->hdr);
3072 lstrcpyW(base, package->PackagePath);
3073 ptr = strrchrW(base, '\\');
3076 sourcepath = resolve_file_source(package, file);
3077 ptr = sourcepath + lstrlenW(base);
3078 lstrcpyW(ptr2, ptr);
3079 msi_free(sourcepath);
3081 msi_reg_set_val_str(hkey, squished_pc, source);
3085 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3087 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3088 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3090 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3092 comp->Action = comp->ActionRequest;
3095 uirow = MSI_CreateRecord(3);
3096 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3097 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3098 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3099 ui_actiondata(package,szProcessComponents,uirow);
3100 msiobj_release( &uirow->hdr );
3103 return ERROR_SUCCESS;
3114 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3115 LPWSTR lpszName, LONG_PTR lParam)
3118 typelib_struct *tl_struct = (typelib_struct*) lParam;
3119 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3123 if (!IS_INTRESOURCE(lpszName))
3125 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3129 sz = strlenW(tl_struct->source)+4;
3130 sz *= sizeof(WCHAR);
3132 if ((INT_PTR)lpszName == 1)
3133 tl_struct->path = strdupW(tl_struct->source);
3136 tl_struct->path = msi_alloc(sz);
3137 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3140 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3141 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3144 msi_free(tl_struct->path);
3145 tl_struct->path = NULL;
3150 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3151 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3153 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3157 msi_free(tl_struct->path);
3158 tl_struct->path = NULL;
3160 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3161 ITypeLib_Release(tl_struct->ptLib);
3166 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3168 MSIPACKAGE* package = param;
3172 typelib_struct tl_struct;
3177 component = MSI_RecordGetString(row,3);
3178 comp = get_loaded_component(package,component);
3180 return ERROR_SUCCESS;
3182 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3184 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3185 comp->Action = comp->Installed;
3186 return ERROR_SUCCESS;
3188 comp->Action = INSTALLSTATE_LOCAL;
3190 file = get_loaded_file( package, comp->KeyPath );
3192 return ERROR_SUCCESS;
3194 ui_actiondata( package, szRegisterTypeLibraries, row );
3196 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3200 guid = MSI_RecordGetString(row,1);
3201 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3202 tl_struct.source = strdupW( file->TargetPath );
3203 tl_struct.path = NULL;
3205 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3206 (LONG_PTR)&tl_struct);
3214 helpid = MSI_RecordGetString(row,6);
3217 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3218 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3222 ERR("Failed to register type library %s\n",
3223 debugstr_w(tl_struct.path));
3225 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3227 ITypeLib_Release(tl_struct.ptLib);
3228 msi_free(tl_struct.path);
3231 ERR("Failed to load type library %s\n",
3232 debugstr_w(tl_struct.source));
3234 FreeLibrary(module);
3235 msi_free(tl_struct.source);
3239 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3242 ERR("Failed to load type library: %08x\n", hr);
3243 return ERROR_INSTALL_FAILURE;
3246 ITypeLib_Release(tlib);
3249 return ERROR_SUCCESS;
3252 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3255 * OK this is a bit confusing.. I am given a _Component key and I believe
3256 * that the file that is being registered as a type library is the "key file
3257 * of that component" which I interpret to mean "The file in the KeyPath of
3262 static const WCHAR Query[] =
3263 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3264 '`','T','y','p','e','L','i','b','`',0};
3266 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3267 if (rc != ERROR_SUCCESS)
3268 return ERROR_SUCCESS;
3270 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3271 msiobj_release(&view->hdr);
3275 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3277 MSIPACKAGE *package = param;
3278 LPCWSTR component, guid;
3286 component = MSI_RecordGetString( row, 3 );
3287 comp = get_loaded_component( package, component );
3289 return ERROR_SUCCESS;
3291 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3293 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3294 comp->Action = comp->Installed;
3295 return ERROR_SUCCESS;
3297 comp->Action = INSTALLSTATE_ABSENT;
3299 ui_actiondata( package, szUnregisterTypeLibraries, row );
3301 guid = MSI_RecordGetString( row, 1 );
3302 CLSIDFromString( (LPCWSTR)guid, &libid );
3303 version = MSI_RecordGetInteger( row, 4 );
3304 language = MSI_RecordGetInteger( row, 2 );
3307 syskind = SYS_WIN64;
3309 syskind = SYS_WIN32;
3312 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3315 WARN("Failed to unregister typelib: %08x\n", hr);
3318 return ERROR_SUCCESS;
3321 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3325 static const WCHAR query[] =
3326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3327 '`','T','y','p','e','L','i','b','`',0};
3329 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3330 if (rc != ERROR_SUCCESS)
3331 return ERROR_SUCCESS;
3333 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3334 msiobj_release( &view->hdr );
3338 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3340 static const WCHAR szlnk[] = {'.','l','n','k',0};
3341 LPCWSTR directory, extension;
3342 LPWSTR link_folder, link_file, filename;
3344 directory = MSI_RecordGetString( row, 2 );
3345 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3347 /* may be needed because of a bug somewhere else */
3348 create_full_pathW( link_folder );
3350 filename = msi_dup_record_field( row, 3 );
3351 reduce_to_longfilename( filename );
3353 extension = strchrW( filename, '.' );
3354 if (!extension || strcmpiW( extension, szlnk ))
3356 int len = strlenW( filename );
3357 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3358 memcpy( filename + len, szlnk, sizeof(szlnk) );
3360 link_file = build_directory_name( 2, link_folder, filename );
3361 msi_free( link_folder );
3362 msi_free( filename );
3367 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3369 MSIPACKAGE *package = param;
3370 LPWSTR link_file, deformated, path;
3371 LPCWSTR component, target;
3373 IShellLinkW *sl = NULL;
3374 IPersistFile *pf = NULL;
3377 component = MSI_RecordGetString(row, 4);
3378 comp = get_loaded_component(package, component);
3380 return ERROR_SUCCESS;
3382 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3384 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3385 comp->Action = comp->Installed;
3386 return ERROR_SUCCESS;
3388 comp->Action = INSTALLSTATE_LOCAL;
3390 ui_actiondata(package,szCreateShortcuts,row);
3392 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3393 &IID_IShellLinkW, (LPVOID *) &sl );
3397 ERR("CLSID_ShellLink not available\n");
3401 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3404 ERR("QueryInterface(IID_IPersistFile) failed\n");
3408 target = MSI_RecordGetString(row, 5);
3409 if (strchrW(target, '['))
3411 deformat_string(package, target, &deformated);
3412 IShellLinkW_SetPath(sl,deformated);
3413 msi_free(deformated);
3417 FIXME("poorly handled shortcut format, advertised shortcut\n");
3418 IShellLinkW_SetPath(sl,comp->FullKeypath);
3421 if (!MSI_RecordIsNull(row,6))
3423 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3424 deformat_string(package, arguments, &deformated);
3425 IShellLinkW_SetArguments(sl,deformated);
3426 msi_free(deformated);
3429 if (!MSI_RecordIsNull(row,7))
3431 LPCWSTR description = MSI_RecordGetString(row, 7);
3432 IShellLinkW_SetDescription(sl, description);
3435 if (!MSI_RecordIsNull(row,8))
3436 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3438 if (!MSI_RecordIsNull(row,9))
3441 LPCWSTR icon = MSI_RecordGetString(row, 9);
3443 path = build_icon_path(package, icon);
3444 index = MSI_RecordGetInteger(row,10);
3446 /* no value means 0 */
3447 if (index == MSI_NULL_INTEGER)
3450 IShellLinkW_SetIconLocation(sl, path, index);
3454 if (!MSI_RecordIsNull(row,11))
3455 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3457 if (!MSI_RecordIsNull(row,12))
3459 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3460 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3462 IShellLinkW_SetWorkingDirectory(sl, path);
3466 link_file = get_link_file(package, row);
3468 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3469 IPersistFile_Save(pf, link_file, FALSE);
3471 msi_free(link_file);
3475 IPersistFile_Release( pf );
3477 IShellLinkW_Release( sl );
3479 return ERROR_SUCCESS;
3482 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3487 static const WCHAR Query[] =
3488 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3489 '`','S','h','o','r','t','c','u','t','`',0};
3491 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3492 if (rc != ERROR_SUCCESS)
3493 return ERROR_SUCCESS;
3495 res = CoInitialize( NULL );
3497 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3498 msiobj_release(&view->hdr);
3506 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3508 MSIPACKAGE *package = param;
3513 component = MSI_RecordGetString( row, 4 );
3514 comp = get_loaded_component( package, component );
3516 return ERROR_SUCCESS;
3518 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3520 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3521 comp->Action = comp->Installed;
3522 return ERROR_SUCCESS;
3524 comp->Action = INSTALLSTATE_ABSENT;
3526 ui_actiondata( package, szRemoveShortcuts, row );
3528 link_file = get_link_file( package, row );
3530 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3531 if (!DeleteFileW( link_file ))
3533 WARN("Failed to remove shortcut file %u\n", GetLastError());
3535 msi_free( link_file );
3537 return ERROR_SUCCESS;
3540 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3544 static const WCHAR query[] =
3545 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3546 '`','S','h','o','r','t','c','u','t','`',0};
3548 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3549 if (rc != ERROR_SUCCESS)
3550 return ERROR_SUCCESS;
3552 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3553 msiobj_release( &view->hdr );
3558 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3560 MSIPACKAGE* package = param;
3568 FileName = MSI_RecordGetString(row,1);
3571 ERR("Unable to get FileName\n");
3572 return ERROR_SUCCESS;
3575 FilePath = build_icon_path(package,FileName);
3577 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3579 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3580 FILE_ATTRIBUTE_NORMAL, NULL);
3582 if (the_file == INVALID_HANDLE_VALUE)
3584 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3586 return ERROR_SUCCESS;
3593 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3594 if (rc != ERROR_SUCCESS)
3596 ERR("Failed to get stream\n");
3597 CloseHandle(the_file);
3598 DeleteFileW(FilePath);
3601 WriteFile(the_file,buffer,sz,&write,NULL);
3602 } while (sz == 1024);
3605 CloseHandle(the_file);
3607 return ERROR_SUCCESS;
3610 static UINT msi_publish_icons(MSIPACKAGE *package)
3615 static const WCHAR query[]= {
3616 'S','E','L','E','C','T',' ','*',' ',
3617 'F','R','O','M',' ','`','I','c','o','n','`',0};
3619 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3620 if (r == ERROR_SUCCESS)
3622 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3623 msiobj_release(&view->hdr);
3626 return ERROR_SUCCESS;
3629 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3635 MSISOURCELISTINFO *info;
3637 r = RegCreateKeyW(hkey, szSourceList, &source);
3638 if (r != ERROR_SUCCESS)
3641 RegCloseKey(source);
3643 buffer = strrchrW(package->PackagePath, '\\') + 1;
3644 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3645 package->Context, MSICODE_PRODUCT,
3646 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3647 if (r != ERROR_SUCCESS)
3650 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3651 package->Context, MSICODE_PRODUCT,
3652 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3653 if (r != ERROR_SUCCESS)
3656 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3657 package->Context, MSICODE_PRODUCT,
3658 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3659 if (r != ERROR_SUCCESS)
3662 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3664 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3665 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3666 info->options, info->value);
3668 MsiSourceListSetInfoW(package->ProductCode, NULL,
3669 info->context, info->options,
3670 info->property, info->value);
3673 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3675 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3676 disk->context, disk->options,
3677 disk->disk_id, disk->volume_label, disk->disk_prompt);
3680 return ERROR_SUCCESS;
3683 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3685 MSIHANDLE hdb, suminfo;
3686 WCHAR guids[MAX_PATH];
3687 WCHAR packcode[SQUISH_GUID_SIZE];
3694 static const WCHAR szProductLanguage[] =
3695 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3696 static const WCHAR szARPProductIcon[] =
3697 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3698 static const WCHAR szProductVersion[] =
3699 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3700 static const WCHAR szAssignment[] =
3701 {'A','s','s','i','g','n','m','e','n','t',0};
3702 static const WCHAR szAdvertiseFlags[] =
3703 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3704 static const WCHAR szClients[] =
3705 {'C','l','i','e','n','t','s',0};
3706 static const WCHAR szColon[] = {':',0};
3708 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3709 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3712 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3713 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3716 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3718 buffer = msi_dup_property(package->db, szARPProductIcon);
3721 LPWSTR path = build_icon_path(package,buffer);
3722 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3727 buffer = msi_dup_property(package->db, szProductVersion);
3730 DWORD verdword = msi_version_str_to_dword(buffer);
3731 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3735 msi_reg_set_val_dword(hkey, szAssignment, 0);
3736 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3737 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3738 msi_reg_set_val_str(hkey, szClients, szColon);
3740 hdb = alloc_msihandle(&package->db->hdr);
3742 return ERROR_NOT_ENOUGH_MEMORY;
3744 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3745 MsiCloseHandle(hdb);
3746 if (r != ERROR_SUCCESS)
3750 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3751 NULL, guids, &size);
3752 if (r != ERROR_SUCCESS)
3755 ptr = strchrW(guids, ';');
3757 squash_guid(guids, packcode);
3758 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3761 MsiCloseHandle(suminfo);
3762 return ERROR_SUCCESS;
3765 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3770 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3772 static const WCHAR szUpgradeCode[] =
3773 {'U','p','g','r','a','d','e','C','o','d','e',0};
3775 upgrade = msi_dup_property(package->db, szUpgradeCode);
3777 return ERROR_SUCCESS;
3779 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3781 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3782 if (r != ERROR_SUCCESS)
3787 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3788 if (r != ERROR_SUCCESS)
3792 squash_guid(package->ProductCode, squashed_pc);
3793 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3802 static BOOL msi_check_publish(MSIPACKAGE *package)
3804 MSIFEATURE *feature;
3806 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3808 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3815 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3817 MSIFEATURE *feature;
3819 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3821 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3828 static UINT msi_publish_patches( MSIPACKAGE *package, HKEY prodkey )
3830 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3831 WCHAR patch_squashed[GUID_SIZE];
3832 HKEY patches_key = NULL, product_patches_key;
3834 MSIPATCHINFO *patch;
3836 WCHAR *p, *all_patches = NULL;
3839 res = RegCreateKeyExW( prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3840 if (res != ERROR_SUCCESS)
3841 return ERROR_FUNCTION_FAILED;
3843 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3844 if (r != ERROR_SUCCESS)
3847 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3849 squash_guid( patch->patchcode, patch_squashed );
3850 len += strlenW( patch_squashed ) + 1;
3853 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3857 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3861 squash_guid( patch->patchcode, p );
3862 p += strlenW( p ) + 1;
3864 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3865 (const BYTE *)patch->transforms,
3866 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3867 if (res != ERROR_SUCCESS)
3870 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3871 if (r != ERROR_SUCCESS)
3874 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3875 (const BYTE *)patch->localfile,
3876 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3877 RegCloseKey( patch_key );
3878 if (res != ERROR_SUCCESS)
3881 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3882 RegCloseKey( patch_key );
3883 if (res != ERROR_SUCCESS)
3887 all_patches[len] = 0;
3888 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3889 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3890 if (res != ERROR_SUCCESS)
3893 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3894 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3895 if (res != ERROR_SUCCESS)
3896 r = ERROR_FUNCTION_FAILED;
3899 RegCloseKey( product_patches_key );
3900 RegCloseKey( patches_key );
3901 msi_free( all_patches );
3906 * 99% of the work done here is only done for
3907 * advertised installs. However this is where the
3908 * Icon table is processed and written out
3909 * so that is what I am going to do here.
3911 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3914 HKEY hukey = NULL, hudkey = NULL;
3917 /* FIXME: also need to publish if the product is in advertise mode */
3918 if (!msi_check_publish(package))
3919 return ERROR_SUCCESS;
3921 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3923 if (rc != ERROR_SUCCESS)
3926 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3927 NULL, &hudkey, TRUE);
3928 if (rc != ERROR_SUCCESS)
3931 rc = msi_publish_upgrade_code(package);
3932 if (rc != ERROR_SUCCESS)
3935 if (!list_empty(&package->patches))
3937 rc = msi_publish_patches(package, hukey);
3938 if (rc != ERROR_SUCCESS)
3942 rc = msi_publish_product_properties(package, hukey);
3943 if (rc != ERROR_SUCCESS)
3946 rc = msi_publish_sourcelist(package, hukey);
3947 if (rc != ERROR_SUCCESS)
3950 rc = msi_publish_icons(package);
3953 uirow = MSI_CreateRecord( 1 );
3954 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3955 ui_actiondata( package, szPublishProduct, uirow );
3956 msiobj_release( &uirow->hdr );
3959 RegCloseKey(hudkey);
3964 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3966 WCHAR *filename, *ptr, *folder, *ret;
3967 const WCHAR *dirprop;
3969 filename = msi_dup_record_field( row, 2 );
3970 if (filename && (ptr = strchrW( filename, '|' )))
3975 dirprop = MSI_RecordGetString( row, 3 );
3978 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3980 folder = msi_dup_property( package->db, dirprop );
3983 folder = msi_dup_property( package->db, szWindowsFolder );
3987 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3988 msi_free( filename );
3992 ret = build_directory_name( 2, folder, ptr );
3994 msi_free( filename );
3999 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4001 MSIPACKAGE *package = param;
4002 LPCWSTR component, section, key, value, identifier;
4003 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4008 component = MSI_RecordGetString(row, 8);
4009 comp = get_loaded_component(package,component);
4011 return ERROR_SUCCESS;
4013 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4015 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4016 comp->Action = comp->Installed;
4017 return ERROR_SUCCESS;
4019 comp->Action = INSTALLSTATE_LOCAL;
4021 identifier = MSI_RecordGetString(row,1);
4022 section = MSI_RecordGetString(row,4);
4023 key = MSI_RecordGetString(row,5);
4024 value = MSI_RecordGetString(row,6);
4025 action = MSI_RecordGetInteger(row,7);
4027 deformat_string(package,section,&deformated_section);
4028 deformat_string(package,key,&deformated_key);
4029 deformat_string(package,value,&deformated_value);
4031 fullname = get_ini_file_name(package, row);
4035 TRACE("Adding value %s to section %s in %s\n",
4036 debugstr_w(deformated_key), debugstr_w(deformated_section),
4037 debugstr_w(fullname));
4038 WritePrivateProfileStringW(deformated_section, deformated_key,
4039 deformated_value, fullname);
4041 else if (action == 1)
4044 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4045 returned, 10, fullname);
4046 if (returned[0] == 0)
4048 TRACE("Adding value %s to section %s in %s\n",
4049 debugstr_w(deformated_key), debugstr_w(deformated_section),
4050 debugstr_w(fullname));
4052 WritePrivateProfileStringW(deformated_section, deformated_key,
4053 deformated_value, fullname);
4056 else if (action == 3)
4057 FIXME("Append to existing section not yet implemented\n");
4059 uirow = MSI_CreateRecord(4);
4060 MSI_RecordSetStringW(uirow,1,identifier);
4061 MSI_RecordSetStringW(uirow,2,deformated_section);
4062 MSI_RecordSetStringW(uirow,3,deformated_key);
4063 MSI_RecordSetStringW(uirow,4,deformated_value);
4064 ui_actiondata(package,szWriteIniValues,uirow);
4065 msiobj_release( &uirow->hdr );
4068 msi_free(deformated_key);
4069 msi_free(deformated_value);
4070 msi_free(deformated_section);
4071 return ERROR_SUCCESS;
4074 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4078 static const WCHAR ExecSeqQuery[] =
4079 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4080 '`','I','n','i','F','i','l','e','`',0};
4082 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4083 if (rc != ERROR_SUCCESS)
4085 TRACE("no IniFile table\n");
4086 return ERROR_SUCCESS;
4089 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4090 msiobj_release(&view->hdr);
4094 static UINT ITERATE_RemoveIniValuesOnUninstall( 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_ABSENT)
4110 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4111 comp->Action = comp->Installed;
4112 return ERROR_SUCCESS;
4114 comp->Action = INSTALLSTATE_ABSENT;
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 == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
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);
4143 uirow = MSI_CreateRecord( 4 );
4144 MSI_RecordSetStringW( uirow, 1, identifier );
4145 MSI_RecordSetStringW( uirow, 2, deformated_section );
4146 MSI_RecordSetStringW( uirow, 3, deformated_key );
4147 MSI_RecordSetStringW( uirow, 4, deformated_value );
4148 ui_actiondata( package, szRemoveIniValues, uirow );
4149 msiobj_release( &uirow->hdr );
4151 msi_free( deformated_key );
4152 msi_free( deformated_value );
4153 msi_free( deformated_section );
4154 return ERROR_SUCCESS;
4157 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4159 MSIPACKAGE *package = param;
4160 LPCWSTR component, section, key, value, identifier;
4161 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4166 component = MSI_RecordGetString( row, 8 );
4167 comp = get_loaded_component( package, component );
4169 return ERROR_SUCCESS;
4171 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4173 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4174 comp->Action = comp->Installed;
4175 return ERROR_SUCCESS;
4177 comp->Action = INSTALLSTATE_LOCAL;
4179 identifier = MSI_RecordGetString( row, 1 );
4180 section = MSI_RecordGetString( row, 4 );
4181 key = MSI_RecordGetString( row, 5 );
4182 value = MSI_RecordGetString( row, 6 );
4183 action = MSI_RecordGetInteger( row, 7 );
4185 deformat_string( package, section, &deformated_section );
4186 deformat_string( package, key, &deformated_key );
4187 deformat_string( package, value, &deformated_value );
4189 if (action == msidbIniFileActionRemoveLine)
4191 filename = get_ini_file_name( package, row );
4193 TRACE("Removing key %s from section %s in %s\n",
4194 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4196 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4198 WARN("Unable to remove key %u\n", GetLastError());
4200 msi_free( filename );
4203 FIXME("Unsupported action %d\n", action);
4205 uirow = MSI_CreateRecord( 4 );
4206 MSI_RecordSetStringW( uirow, 1, identifier );
4207 MSI_RecordSetStringW( uirow, 2, deformated_section );
4208 MSI_RecordSetStringW( uirow, 3, deformated_key );
4209 MSI_RecordSetStringW( uirow, 4, deformated_value );
4210 ui_actiondata( package, szRemoveIniValues, uirow );
4211 msiobj_release( &uirow->hdr );
4213 msi_free( deformated_key );
4214 msi_free( deformated_value );
4215 msi_free( deformated_section );
4216 return ERROR_SUCCESS;
4219 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4223 static const WCHAR query[] =
4224 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4225 '`','I','n','i','F','i','l','e','`',0};
4226 static const WCHAR remove_query[] =
4227 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4228 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4230 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4231 if (rc == ERROR_SUCCESS)
4233 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4234 msiobj_release( &view->hdr );
4235 if (rc != ERROR_SUCCESS)
4239 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4240 if (rc == ERROR_SUCCESS)
4242 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4243 msiobj_release( &view->hdr );
4244 if (rc != ERROR_SUCCESS)
4248 return ERROR_SUCCESS;
4251 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4253 MSIPACKAGE *package = param;
4258 static const WCHAR ExeStr[] =
4259 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4260 static const WCHAR close[] = {'\"',0};
4262 PROCESS_INFORMATION info;
4266 memset(&si,0,sizeof(STARTUPINFOW));
4268 filename = MSI_RecordGetString(row,1);
4269 file = get_loaded_file( package, filename );
4273 ERR("Unable to find file id %s\n",debugstr_w(filename));
4274 return ERROR_SUCCESS;
4277 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4279 FullName = msi_alloc(len*sizeof(WCHAR));
4280 strcpyW(FullName,ExeStr);
4281 strcatW( FullName, file->TargetPath );
4282 strcatW(FullName,close);
4284 TRACE("Registering %s\n",debugstr_w(FullName));
4285 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4290 CloseHandle(info.hThread);
4291 msi_dialog_check_messages(info.hProcess);
4292 CloseHandle(info.hProcess);
4295 uirow = MSI_CreateRecord( 2 );
4296 MSI_RecordSetStringW( uirow, 1, filename );
4297 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4298 ui_actiondata( package, szSelfRegModules, uirow );
4299 msiobj_release( &uirow->hdr );
4301 msi_free( FullName );
4302 return ERROR_SUCCESS;
4305 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4309 static const WCHAR ExecSeqQuery[] =
4310 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4311 '`','S','e','l','f','R','e','g','`',0};
4313 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4314 if (rc != ERROR_SUCCESS)
4316 TRACE("no SelfReg table\n");
4317 return ERROR_SUCCESS;
4320 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4321 msiobj_release(&view->hdr);
4323 return ERROR_SUCCESS;
4326 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4328 static const WCHAR regsvr32[] =
4329 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4330 static const WCHAR close[] = {'\"',0};
4331 MSIPACKAGE *package = param;
4337 PROCESS_INFORMATION pi;
4341 memset( &si, 0, sizeof(STARTUPINFOW) );
4343 filename = MSI_RecordGetString( row, 1 );
4344 file = get_loaded_file( package, filename );
4348 ERR("Unable to find file id %s\n", debugstr_w(filename));
4349 return ERROR_SUCCESS;
4352 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4354 cmdline = msi_alloc( len * sizeof(WCHAR) );
4355 strcpyW( cmdline, regsvr32 );
4356 strcatW( cmdline, file->TargetPath );
4357 strcatW( cmdline, close );
4359 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4361 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4364 CloseHandle( pi.hThread );
4365 msi_dialog_check_messages( pi.hProcess );
4366 CloseHandle( pi.hProcess );
4369 uirow = MSI_CreateRecord( 2 );
4370 MSI_RecordSetStringW( uirow, 1, filename );
4371 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4372 ui_actiondata( package, szSelfUnregModules, uirow );
4373 msiobj_release( &uirow->hdr );
4375 msi_free( cmdline );
4376 return ERROR_SUCCESS;
4379 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4383 static const WCHAR query[] =
4384 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4385 '`','S','e','l','f','R','e','g','`',0};
4387 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4388 if (rc != ERROR_SUCCESS)
4390 TRACE("no SelfReg table\n");
4391 return ERROR_SUCCESS;
4394 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4395 msiobj_release( &view->hdr );
4397 return ERROR_SUCCESS;
4400 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4402 MSIFEATURE *feature;
4404 HKEY hkey = NULL, userdata = NULL;
4406 if (!msi_check_publish(package))
4407 return ERROR_SUCCESS;
4409 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4411 if (rc != ERROR_SUCCESS)
4414 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4416 if (rc != ERROR_SUCCESS)
4419 /* here the guids are base 85 encoded */
4420 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4426 BOOL absent = FALSE;
4429 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4430 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4431 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4434 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4438 if (feature->Feature_Parent)
4439 size += strlenW( feature->Feature_Parent )+2;
4441 data = msi_alloc(size * sizeof(WCHAR));
4444 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4446 MSICOMPONENT* component = cl->component;
4450 if (component->ComponentId)
4452 TRACE("From %s\n",debugstr_w(component->ComponentId));
4453 CLSIDFromString(component->ComponentId, &clsid);
4454 encode_base85_guid(&clsid,buf);
4455 TRACE("to %s\n",debugstr_w(buf));
4460 if (feature->Feature_Parent)
4462 static const WCHAR sep[] = {'\2',0};
4464 strcatW(data,feature->Feature_Parent);
4467 msi_reg_set_val_str( userdata, feature->Feature, data );
4471 if (feature->Feature_Parent)
4472 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4475 size += sizeof(WCHAR);
4476 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4477 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4481 size += 2*sizeof(WCHAR);
4482 data = msi_alloc(size);
4485 if (feature->Feature_Parent)
4486 strcpyW( &data[1], feature->Feature_Parent );
4487 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4493 uirow = MSI_CreateRecord( 1 );
4494 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4495 ui_actiondata( package, szPublishFeatures, uirow);
4496 msiobj_release( &uirow->hdr );
4497 /* FIXME: call ui_progress? */
4502 RegCloseKey(userdata);
4506 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4512 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4514 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4516 if (r == ERROR_SUCCESS)
4518 RegDeleteValueW(hkey, feature->Feature);
4522 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4524 if (r == ERROR_SUCCESS)
4526 RegDeleteValueW(hkey, feature->Feature);
4530 uirow = MSI_CreateRecord( 1 );
4531 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4532 ui_actiondata( package, szUnpublishFeatures, uirow );
4533 msiobj_release( &uirow->hdr );
4535 return ERROR_SUCCESS;
4538 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4540 MSIFEATURE *feature;
4542 if (!msi_check_unpublish(package))
4543 return ERROR_SUCCESS;
4545 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4547 msi_unpublish_feature(package, feature);
4550 return ERROR_SUCCESS;
4553 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4557 WCHAR date[9], *val, *buffer;
4558 const WCHAR *prop, *key;
4560 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4561 static const WCHAR szWindowsInstaller[] =
4562 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4563 static const WCHAR modpath_fmt[] =
4564 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4565 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4566 static const WCHAR szModifyPath[] =
4567 {'M','o','d','i','f','y','P','a','t','h',0};
4568 static const WCHAR szUninstallString[] =
4569 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4570 static const WCHAR szEstimatedSize[] =
4571 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4572 static const WCHAR szProductLanguage[] =
4573 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4574 static const WCHAR szProductVersion[] =
4575 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4576 static const WCHAR szDisplayVersion[] =
4577 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4578 static const WCHAR szInstallSource[] =
4579 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4580 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4581 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4582 static const WCHAR szAuthorizedCDFPrefix[] =
4583 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4584 static const WCHAR szARPCONTACT[] =
4585 {'A','R','P','C','O','N','T','A','C','T',0};
4586 static const WCHAR szContact[] =
4587 {'C','o','n','t','a','c','t',0};
4588 static const WCHAR szARPCOMMENTS[] =
4589 {'A','R','P','C','O','M','M','E','N','T','S',0};
4590 static const WCHAR szComments[] =
4591 {'C','o','m','m','e','n','t','s',0};
4592 static const WCHAR szProductName[] =
4593 {'P','r','o','d','u','c','t','N','a','m','e',0};
4594 static const WCHAR szDisplayName[] =
4595 {'D','i','s','p','l','a','y','N','a','m','e',0};
4596 static const WCHAR szARPHELPLINK[] =
4597 {'A','R','P','H','E','L','P','L','I','N','K',0};
4598 static const WCHAR szHelpLink[] =
4599 {'H','e','l','p','L','i','n','k',0};
4600 static const WCHAR szARPHELPTELEPHONE[] =
4601 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4602 static const WCHAR szHelpTelephone[] =
4603 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4604 static const WCHAR szARPINSTALLLOCATION[] =
4605 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4606 static const WCHAR szInstallLocation[] =
4607 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4608 static const WCHAR szManufacturer[] =
4609 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4610 static const WCHAR szPublisher[] =
4611 {'P','u','b','l','i','s','h','e','r',0};
4612 static const WCHAR szARPREADME[] =
4613 {'A','R','P','R','E','A','D','M','E',0};
4614 static const WCHAR szReadme[] =
4615 {'R','e','a','d','M','e',0};
4616 static const WCHAR szARPSIZE[] =
4617 {'A','R','P','S','I','Z','E',0};
4618 static const WCHAR szSize[] =
4619 {'S','i','z','e',0};
4620 static const WCHAR szARPURLINFOABOUT[] =
4621 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4622 static const WCHAR szURLInfoAbout[] =
4623 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4624 static const WCHAR szARPURLUPDATEINFO[] =
4625 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4626 static const WCHAR szURLUpdateInfo[] =
4627 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4629 static const WCHAR *propval[] = {
4630 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4631 szARPCONTACT, szContact,
4632 szARPCOMMENTS, szComments,
4633 szProductName, szDisplayName,
4634 szARPHELPLINK, szHelpLink,
4635 szARPHELPTELEPHONE, szHelpTelephone,
4636 szARPINSTALLLOCATION, szInstallLocation,
4637 cszSourceDir, szInstallSource,
4638 szManufacturer, szPublisher,
4639 szARPREADME, szReadme,
4641 szARPURLINFOABOUT, szURLInfoAbout,
4642 szARPURLUPDATEINFO, szURLUpdateInfo,
4645 const WCHAR **p = propval;
4651 val = msi_dup_property(package->db, prop);
4652 msi_reg_set_val_str(hkey, key, val);
4656 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4658 size = deformat_string(package, modpath_fmt, &buffer);
4659 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4660 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4663 /* FIXME: Write real Estimated Size when we have it */
4664 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4666 GetLocalTime(&systime);
4667 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4668 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4670 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4671 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4673 buffer = msi_dup_property(package->db, szProductVersion);
4674 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4677 DWORD verdword = msi_version_str_to_dword(buffer);
4679 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4680 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4681 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4685 return ERROR_SUCCESS;
4688 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4690 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4692 LPWSTR upgrade_code;
4697 static const WCHAR szUpgradeCode[] = {
4698 'U','p','g','r','a','d','e','C','o','d','e',0};
4700 /* FIXME: also need to publish if the product is in advertise mode */
4701 if (!msi_check_publish(package))
4702 return ERROR_SUCCESS;
4704 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4705 if (rc != ERROR_SUCCESS)
4708 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4709 NULL, &props, TRUE);
4710 if (rc != ERROR_SUCCESS)
4713 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4714 msi_free( package->db->localfile );
4715 package->db->localfile = NULL;
4717 rc = msi_publish_install_properties(package, hkey);
4718 if (rc != ERROR_SUCCESS)
4721 rc = msi_publish_install_properties(package, props);
4722 if (rc != ERROR_SUCCESS)
4725 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4728 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4729 squash_guid(package->ProductCode, squashed_pc);
4730 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4731 RegCloseKey(upgrade);
4732 msi_free(upgrade_code);
4736 uirow = MSI_CreateRecord( 1 );
4737 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4738 ui_actiondata( package, szRegisterProduct, uirow );
4739 msiobj_release( &uirow->hdr );
4742 return ERROR_SUCCESS;
4745 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4747 return execute_script(package,INSTALL_SCRIPT);
4750 static UINT msi_unpublish_product(MSIPACKAGE *package)
4753 LPWSTR remove = NULL;
4754 LPWSTR *features = NULL;
4755 BOOL full_uninstall = TRUE;
4756 MSIFEATURE *feature;
4757 MSIPATCHINFO *patch;
4759 static const WCHAR szUpgradeCode[] =
4760 {'U','p','g','r','a','d','e','C','o','d','e',0};
4762 remove = msi_dup_property(package->db, szRemove);
4764 return ERROR_SUCCESS;
4766 features = msi_split_string(remove, ',');
4770 ERR("REMOVE feature list is empty!\n");
4771 return ERROR_FUNCTION_FAILED;
4774 if (!lstrcmpW(features[0], szAll))
4775 full_uninstall = TRUE;
4778 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4780 if (feature->Action != INSTALLSTATE_ABSENT)
4781 full_uninstall = FALSE;
4785 if (!full_uninstall)
4788 MSIREG_DeleteProductKey(package->ProductCode);
4789 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4790 MSIREG_DeleteUninstallKey(package->ProductCode);
4792 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4794 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4795 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4799 MSIREG_DeleteUserProductKey(package->ProductCode);
4800 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4803 upgrade = msi_dup_property(package->db, szUpgradeCode);
4806 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4810 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4812 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4818 return ERROR_SUCCESS;
4821 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4825 rc = msi_unpublish_product(package);
4826 if (rc != ERROR_SUCCESS)
4829 /* turn off scheduling */
4830 package->script->CurrentlyScripting= FALSE;
4832 /* first do the same as an InstallExecute */
4833 rc = ACTION_InstallExecute(package);
4834 if (rc != ERROR_SUCCESS)
4837 /* then handle Commit Actions */
4838 rc = execute_script(package,COMMIT_SCRIPT);
4843 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4845 static const WCHAR RunOnce[] = {
4846 'S','o','f','t','w','a','r','e','\\',
4847 'M','i','c','r','o','s','o','f','t','\\',
4848 'W','i','n','d','o','w','s','\\',
4849 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4850 'R','u','n','O','n','c','e',0};
4851 static const WCHAR InstallRunOnce[] = {
4852 'S','o','f','t','w','a','r','e','\\',
4853 'M','i','c','r','o','s','o','f','t','\\',
4854 'W','i','n','d','o','w','s','\\',
4855 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4856 'I','n','s','t','a','l','l','e','r','\\',
4857 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4859 static const WCHAR msiexec_fmt[] = {
4861 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4862 '\"','%','s','\"',0};
4863 static const WCHAR install_fmt[] = {
4864 '/','I',' ','\"','%','s','\"',' ',
4865 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4866 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4867 WCHAR buffer[256], sysdir[MAX_PATH];
4869 WCHAR squished_pc[100];
4871 squash_guid(package->ProductCode,squished_pc);
4873 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4874 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4875 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4878 msi_reg_set_val_str( hkey, squished_pc, buffer );
4881 TRACE("Reboot command %s\n",debugstr_w(buffer));
4883 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4884 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4886 msi_reg_set_val_str( hkey, squished_pc, buffer );
4889 return ERROR_INSTALL_SUSPEND;
4892 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4898 * We are currently doing what should be done here in the top level Install
4899 * however for Administrative and uninstalls this step will be needed
4901 if (!package->PackagePath)
4902 return ERROR_SUCCESS;
4904 msi_set_sourcedir_props(package, TRUE);
4906 attrib = GetFileAttributesW(package->db->path);
4907 if (attrib == INVALID_FILE_ATTRIBUTES)
4913 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4914 package->Context, MSICODE_PRODUCT,
4915 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4916 if (rc == ERROR_MORE_DATA)
4918 prompt = msi_alloc(size * sizeof(WCHAR));
4919 MsiSourceListGetInfoW(package->ProductCode, NULL,
4920 package->Context, MSICODE_PRODUCT,
4921 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4924 prompt = strdupW(package->db->path);
4926 msg = generate_error_string(package,1302,1,prompt);
4927 while(attrib == INVALID_FILE_ATTRIBUTES)
4929 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4932 rc = ERROR_INSTALL_USEREXIT;
4935 attrib = GetFileAttributesW(package->db->path);
4941 return ERROR_SUCCESS;
4946 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4949 LPWSTR buffer, productid = NULL;
4950 UINT i, rc = ERROR_SUCCESS;
4953 static const WCHAR szPropKeys[][80] =
4955 {'P','r','o','d','u','c','t','I','D',0},
4956 {'U','S','E','R','N','A','M','E',0},
4957 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4961 static const WCHAR szRegKeys[][80] =
4963 {'P','r','o','d','u','c','t','I','D',0},
4964 {'R','e','g','O','w','n','e','r',0},
4965 {'R','e','g','C','o','m','p','a','n','y',0},
4969 if (msi_check_unpublish(package))
4971 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4975 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
4979 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4981 if (rc != ERROR_SUCCESS)
4984 for( i = 0; szPropKeys[i][0]; i++ )
4986 buffer = msi_dup_property( package->db, szPropKeys[i] );
4987 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4992 uirow = MSI_CreateRecord( 1 );
4993 MSI_RecordSetStringW( uirow, 1, productid );
4994 ui_actiondata( package, szRegisterUser, uirow );
4995 msiobj_release( &uirow->hdr );
4997 msi_free(productid);
5003 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5007 package->script->InWhatSequence |= SEQUENCE_EXEC;
5008 rc = ACTION_ProcessExecSequence(package,FALSE);
5013 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5015 MSIPACKAGE *package = param;
5016 LPCWSTR compgroupid, component, feature, qualifier, text;
5017 LPWSTR advertise = NULL, output = NULL;
5025 feature = MSI_RecordGetString(rec, 5);
5026 feat = get_loaded_feature(package, feature);
5028 return ERROR_SUCCESS;
5030 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5031 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5032 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5034 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5035 feat->Action = feat->Installed;
5036 return ERROR_SUCCESS;
5039 component = MSI_RecordGetString(rec, 3);
5040 comp = get_loaded_component(package, component);
5042 return ERROR_SUCCESS;
5044 compgroupid = MSI_RecordGetString(rec,1);
5045 qualifier = MSI_RecordGetString(rec,2);
5047 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5048 if (rc != ERROR_SUCCESS)
5051 text = MSI_RecordGetString(rec,4);
5052 advertise = create_component_advertise_string(package, comp, feature);
5054 sz = strlenW(advertise);
5057 sz += lstrlenW(text);
5060 sz *= sizeof(WCHAR);
5062 output = msi_alloc_zero(sz);
5063 strcpyW(output,advertise);
5064 msi_free(advertise);
5067 strcatW(output,text);
5069 msi_reg_set_val_multi_str( hkey, qualifier, output );
5076 uirow = MSI_CreateRecord( 2 );
5077 MSI_RecordSetStringW( uirow, 1, compgroupid );
5078 MSI_RecordSetStringW( uirow, 2, qualifier);
5079 ui_actiondata( package, szPublishComponents, uirow);
5080 msiobj_release( &uirow->hdr );
5081 /* FIXME: call ui_progress? */
5087 * At present I am ignorning the advertised components part of this and only
5088 * focusing on the qualified component sets
5090 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5094 static const WCHAR ExecSeqQuery[] =
5095 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5096 '`','P','u','b','l','i','s','h',
5097 'C','o','m','p','o','n','e','n','t','`',0};
5099 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5100 if (rc != ERROR_SUCCESS)
5101 return ERROR_SUCCESS;
5103 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5104 msiobj_release(&view->hdr);
5109 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5111 static const WCHAR szInstallerComponents[] = {
5112 'S','o','f','t','w','a','r','e','\\',
5113 'M','i','c','r','o','s','o','f','t','\\',
5114 'I','n','s','t','a','l','l','e','r','\\',
5115 'C','o','m','p','o','n','e','n','t','s','\\',0};
5117 MSIPACKAGE *package = param;
5118 LPCWSTR compgroupid, component, feature, qualifier;
5122 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5125 feature = MSI_RecordGetString( rec, 5 );
5126 feat = get_loaded_feature( package, feature );
5128 return ERROR_SUCCESS;
5130 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5132 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5133 feat->Action = feat->Installed;
5134 return ERROR_SUCCESS;
5137 component = MSI_RecordGetString( rec, 3 );
5138 comp = get_loaded_component( package, component );
5140 return ERROR_SUCCESS;
5142 compgroupid = MSI_RecordGetString( rec, 1 );
5143 qualifier = MSI_RecordGetString( rec, 2 );
5145 squash_guid( compgroupid, squashed );
5146 strcpyW( keypath, szInstallerComponents );
5147 strcatW( keypath, squashed );
5149 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5150 if (res != ERROR_SUCCESS)
5152 WARN("Unable to delete component key %d\n", res);
5155 uirow = MSI_CreateRecord( 2 );
5156 MSI_RecordSetStringW( uirow, 1, compgroupid );
5157 MSI_RecordSetStringW( uirow, 2, qualifier );
5158 ui_actiondata( package, szUnpublishComponents, uirow );
5159 msiobj_release( &uirow->hdr );
5161 return ERROR_SUCCESS;
5164 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5168 static const WCHAR query[] =
5169 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5170 '`','P','u','b','l','i','s','h',
5171 'C','o','m','p','o','n','e','n','t','`',0};
5173 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5174 if (rc != ERROR_SUCCESS)
5175 return ERROR_SUCCESS;
5177 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5178 msiobj_release( &view->hdr );
5183 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5185 MSIPACKAGE *package = param;
5188 SC_HANDLE hscm, service = NULL;
5189 LPCWSTR comp, depends, pass;
5190 LPWSTR name = NULL, disp = NULL;
5191 LPCWSTR load_order, serv_name, key;
5192 DWORD serv_type, start_type;
5195 static const WCHAR query[] =
5196 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5197 '`','C','o','m','p','o','n','e','n','t','`',' ',
5198 'W','H','E','R','E',' ',
5199 '`','C','o','m','p','o','n','e','n','t','`',' ',
5200 '=','\'','%','s','\'',0};
5202 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5205 ERR("Failed to open the SC Manager!\n");
5209 start_type = MSI_RecordGetInteger(rec, 5);
5210 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5213 depends = MSI_RecordGetString(rec, 8);
5214 if (depends && *depends)
5215 FIXME("Dependency list unhandled!\n");
5217 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5218 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5219 serv_type = MSI_RecordGetInteger(rec, 4);
5220 err_control = MSI_RecordGetInteger(rec, 6);
5221 load_order = MSI_RecordGetString(rec, 7);
5222 serv_name = MSI_RecordGetString(rec, 9);
5223 pass = MSI_RecordGetString(rec, 10);
5224 comp = MSI_RecordGetString(rec, 12);
5226 /* fetch the service path */
5227 row = MSI_QueryGetRecord(package->db, query, comp);
5230 ERR("Control query failed!\n");
5234 key = MSI_RecordGetString(row, 6);
5236 file = get_loaded_file(package, key);
5237 msiobj_release(&row->hdr);
5240 ERR("Failed to load the service file\n");
5244 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5245 start_type, err_control, file->TargetPath,
5246 load_order, NULL, NULL, serv_name, pass);
5249 if (GetLastError() != ERROR_SERVICE_EXISTS)
5250 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5254 CloseServiceHandle(service);
5255 CloseServiceHandle(hscm);
5259 return ERROR_SUCCESS;
5262 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5266 static const WCHAR ExecSeqQuery[] =
5267 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5268 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5270 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5271 if (rc != ERROR_SUCCESS)
5272 return ERROR_SUCCESS;
5274 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5275 msiobj_release(&view->hdr);
5280 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5281 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5283 LPCWSTR *vector, *temp_vector;
5287 static const WCHAR separator[] = {'[','~',']',0};
5290 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5295 vector = msi_alloc(sizeof(LPWSTR));
5303 vector[*numargs - 1] = p;
5305 if ((q = strstrW(p, separator)))
5309 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5315 vector = temp_vector;
5324 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5326 MSIPACKAGE *package = param;
5329 SC_HANDLE scm = NULL, service = NULL;
5330 LPCWSTR component, *vector = NULL;
5331 LPWSTR name, args, display_name = NULL;
5332 DWORD event, numargs, len;
5333 UINT r = ERROR_FUNCTION_FAILED;
5335 component = MSI_RecordGetString(rec, 6);
5336 comp = get_loaded_component(package, component);
5338 return ERROR_SUCCESS;
5340 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5342 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5343 comp->Action = comp->Installed;
5344 return ERROR_SUCCESS;
5346 comp->Action = INSTALLSTATE_LOCAL;
5348 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5349 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5350 event = MSI_RecordGetInteger(rec, 3);
5352 if (!(event & msidbServiceControlEventStart))
5358 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5361 ERR("Failed to open the service control manager\n");
5366 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5367 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5369 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5370 GetServiceDisplayNameW( scm, name, display_name, &len );
5373 service = OpenServiceW(scm, name, SERVICE_START);
5376 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5380 vector = msi_service_args_to_vector(args, &numargs);
5382 if (!StartServiceW(service, numargs, vector) &&
5383 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5385 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5392 uirow = MSI_CreateRecord( 2 );
5393 MSI_RecordSetStringW( uirow, 1, display_name );
5394 MSI_RecordSetStringW( uirow, 2, name );
5395 ui_actiondata( package, szStartServices, uirow );
5396 msiobj_release( &uirow->hdr );
5398 CloseServiceHandle(service);
5399 CloseServiceHandle(scm);
5404 msi_free(display_name);
5408 static UINT ACTION_StartServices( MSIPACKAGE *package )
5413 static const WCHAR query[] = {
5414 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5415 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5417 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5418 if (rc != ERROR_SUCCESS)
5419 return ERROR_SUCCESS;
5421 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5422 msiobj_release(&view->hdr);
5427 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5429 DWORD i, needed, count;
5430 ENUM_SERVICE_STATUSW *dependencies;
5434 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5435 0, &needed, &count))
5438 if (GetLastError() != ERROR_MORE_DATA)
5441 dependencies = msi_alloc(needed);
5445 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5446 needed, &needed, &count))
5449 for (i = 0; i < count; i++)
5451 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5452 SERVICE_STOP | SERVICE_QUERY_STATUS);
5456 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5463 msi_free(dependencies);
5467 static UINT stop_service( LPCWSTR name )
5469 SC_HANDLE scm = NULL, service = NULL;
5470 SERVICE_STATUS status;
5471 SERVICE_STATUS_PROCESS ssp;
5474 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5477 WARN("Failed to open the SCM: %d\n", GetLastError());
5481 service = OpenServiceW(scm, name,
5483 SERVICE_QUERY_STATUS |
5484 SERVICE_ENUMERATE_DEPENDENTS);
5487 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5491 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5492 sizeof(SERVICE_STATUS_PROCESS), &needed))
5494 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5498 if (ssp.dwCurrentState == SERVICE_STOPPED)
5501 stop_service_dependents(scm, service);
5503 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5504 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5507 CloseServiceHandle(service);
5508 CloseServiceHandle(scm);
5510 return ERROR_SUCCESS;
5513 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5515 MSIPACKAGE *package = param;
5519 LPWSTR name = NULL, display_name = NULL;
5523 event = MSI_RecordGetInteger( rec, 3 );
5524 if (!(event & msidbServiceControlEventStop))
5525 return ERROR_SUCCESS;
5527 component = MSI_RecordGetString( rec, 6 );
5528 comp = get_loaded_component( package, component );
5530 return ERROR_SUCCESS;
5532 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5534 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5535 comp->Action = comp->Installed;
5536 return ERROR_SUCCESS;
5538 comp->Action = INSTALLSTATE_ABSENT;
5540 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5543 ERR("Failed to open the service control manager\n");
5548 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5549 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5551 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5552 GetServiceDisplayNameW( scm, name, display_name, &len );
5554 CloseServiceHandle( scm );
5556 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5557 stop_service( name );
5560 uirow = MSI_CreateRecord( 2 );
5561 MSI_RecordSetStringW( uirow, 1, display_name );
5562 MSI_RecordSetStringW( uirow, 2, name );
5563 ui_actiondata( package, szStopServices, uirow );
5564 msiobj_release( &uirow->hdr );
5567 msi_free( display_name );
5568 return ERROR_SUCCESS;
5571 static UINT ACTION_StopServices( 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_StopService, package);
5585 msiobj_release(&view->hdr);
5590 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5592 MSIPACKAGE *package = param;
5596 LPWSTR name = NULL, display_name = NULL;
5598 SC_HANDLE scm = NULL, service = NULL;
5600 event = MSI_RecordGetInteger( rec, 3 );
5601 if (!(event & msidbServiceControlEventDelete))
5602 return ERROR_SUCCESS;
5604 component = MSI_RecordGetString(rec, 6);
5605 comp = get_loaded_component(package, component);
5607 return ERROR_SUCCESS;
5609 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5611 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5612 comp->Action = comp->Installed;
5613 return ERROR_SUCCESS;
5615 comp->Action = INSTALLSTATE_ABSENT;
5617 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5618 stop_service( name );
5620 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5623 WARN("Failed to open the SCM: %d\n", GetLastError());
5628 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5629 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5631 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5632 GetServiceDisplayNameW( scm, name, display_name, &len );
5635 service = OpenServiceW( scm, name, DELETE );
5638 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5642 if (!DeleteService( service ))
5643 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5646 uirow = MSI_CreateRecord( 2 );
5647 MSI_RecordSetStringW( uirow, 1, display_name );
5648 MSI_RecordSetStringW( uirow, 2, name );
5649 ui_actiondata( package, szDeleteServices, uirow );
5650 msiobj_release( &uirow->hdr );
5652 CloseServiceHandle( service );
5653 CloseServiceHandle( scm );
5655 msi_free( display_name );
5657 return ERROR_SUCCESS;
5660 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5665 static const WCHAR query[] = {
5666 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5667 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5669 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5670 if (rc != ERROR_SUCCESS)
5671 return ERROR_SUCCESS;
5673 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5674 msiobj_release( &view->hdr );
5679 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5683 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5685 if (!lstrcmpW(file->File, filename))
5692 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5694 MSIPACKAGE *package = param;
5695 LPWSTR driver, driver_path, ptr;
5696 WCHAR outpath[MAX_PATH];
5697 MSIFILE *driver_file, *setup_file;
5701 UINT r = ERROR_SUCCESS;
5703 static const WCHAR driver_fmt[] = {
5704 'D','r','i','v','e','r','=','%','s',0};
5705 static const WCHAR setup_fmt[] = {
5706 'S','e','t','u','p','=','%','s',0};
5707 static const WCHAR usage_fmt[] = {
5708 'F','i','l','e','U','s','a','g','e','=','1',0};
5710 desc = MSI_RecordGetString(rec, 3);
5712 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5713 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5717 ERR("ODBC Driver entry not found!\n");
5718 return ERROR_FUNCTION_FAILED;
5721 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5723 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5724 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5726 driver = msi_alloc(len * sizeof(WCHAR));
5728 return ERROR_OUTOFMEMORY;
5731 lstrcpyW(ptr, desc);
5732 ptr += lstrlenW(ptr) + 1;
5734 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5739 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5743 lstrcpyW(ptr, usage_fmt);
5744 ptr += lstrlenW(ptr) + 1;
5747 driver_path = strdupW(driver_file->TargetPath);
5748 ptr = strrchrW(driver_path, '\\');
5749 if (ptr) *ptr = '\0';
5751 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5752 NULL, ODBC_INSTALL_COMPLETE, &usage))
5754 ERR("Failed to install SQL driver!\n");
5755 r = ERROR_FUNCTION_FAILED;
5758 uirow = MSI_CreateRecord( 5 );
5759 MSI_RecordSetStringW( uirow, 1, desc );
5760 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5761 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5762 ui_actiondata( package, szInstallODBC, uirow );
5763 msiobj_release( &uirow->hdr );
5766 msi_free(driver_path);
5771 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5773 MSIPACKAGE *package = param;
5774 LPWSTR translator, translator_path, ptr;
5775 WCHAR outpath[MAX_PATH];
5776 MSIFILE *translator_file, *setup_file;
5780 UINT r = ERROR_SUCCESS;
5782 static const WCHAR translator_fmt[] = {
5783 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5784 static const WCHAR setup_fmt[] = {
5785 'S','e','t','u','p','=','%','s',0};
5787 desc = MSI_RecordGetString(rec, 3);
5789 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5790 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5792 if (!translator_file)
5794 ERR("ODBC Translator entry not found!\n");
5795 return ERROR_FUNCTION_FAILED;
5798 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5800 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5802 translator = msi_alloc(len * sizeof(WCHAR));
5804 return ERROR_OUTOFMEMORY;
5807 lstrcpyW(ptr, desc);
5808 ptr += lstrlenW(ptr) + 1;
5810 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5815 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5820 translator_path = strdupW(translator_file->TargetPath);
5821 ptr = strrchrW(translator_path, '\\');
5822 if (ptr) *ptr = '\0';
5824 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5825 NULL, ODBC_INSTALL_COMPLETE, &usage))
5827 ERR("Failed to install SQL translator!\n");
5828 r = ERROR_FUNCTION_FAILED;
5831 uirow = MSI_CreateRecord( 5 );
5832 MSI_RecordSetStringW( uirow, 1, desc );
5833 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5834 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5835 ui_actiondata( package, szInstallODBC, uirow );
5836 msiobj_release( &uirow->hdr );
5838 msi_free(translator);
5839 msi_free(translator_path);
5844 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5846 MSIPACKAGE *package = param;
5848 LPCWSTR desc, driver;
5849 WORD request = ODBC_ADD_SYS_DSN;
5852 UINT r = ERROR_SUCCESS;
5855 static const WCHAR attrs_fmt[] = {
5856 'D','S','N','=','%','s',0 };
5858 desc = MSI_RecordGetString(rec, 3);
5859 driver = MSI_RecordGetString(rec, 4);
5860 registration = MSI_RecordGetInteger(rec, 5);
5862 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5863 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5865 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5866 attrs = msi_alloc(len * sizeof(WCHAR));
5868 return ERROR_OUTOFMEMORY;
5870 len = sprintfW(attrs, attrs_fmt, desc);
5873 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5875 ERR("Failed to install SQL data source!\n");
5876 r = ERROR_FUNCTION_FAILED;
5879 uirow = MSI_CreateRecord( 5 );
5880 MSI_RecordSetStringW( uirow, 1, desc );
5881 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5882 MSI_RecordSetInteger( uirow, 3, request );
5883 ui_actiondata( package, szInstallODBC, uirow );
5884 msiobj_release( &uirow->hdr );
5891 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5896 static const WCHAR driver_query[] = {
5897 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5898 'O','D','B','C','D','r','i','v','e','r',0 };
5900 static const WCHAR translator_query[] = {
5901 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5902 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5904 static const WCHAR source_query[] = {
5905 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5906 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5908 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5909 if (rc != ERROR_SUCCESS)
5910 return ERROR_SUCCESS;
5912 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5913 msiobj_release(&view->hdr);
5915 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5916 if (rc != ERROR_SUCCESS)
5917 return ERROR_SUCCESS;
5919 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5920 msiobj_release(&view->hdr);
5922 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5923 if (rc != ERROR_SUCCESS)
5924 return ERROR_SUCCESS;
5926 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5927 msiobj_release(&view->hdr);
5932 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5934 MSIPACKAGE *package = param;
5939 desc = MSI_RecordGetString( rec, 3 );
5940 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5942 WARN("Failed to remove ODBC driver\n");
5946 FIXME("Usage count reached 0\n");
5949 uirow = MSI_CreateRecord( 2 );
5950 MSI_RecordSetStringW( uirow, 1, desc );
5951 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5952 ui_actiondata( package, szRemoveODBC, uirow );
5953 msiobj_release( &uirow->hdr );
5955 return ERROR_SUCCESS;
5958 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5960 MSIPACKAGE *package = param;
5965 desc = MSI_RecordGetString( rec, 3 );
5966 if (!SQLRemoveTranslatorW( desc, &usage ))
5968 WARN("Failed to remove ODBC translator\n");
5972 FIXME("Usage count reached 0\n");
5975 uirow = MSI_CreateRecord( 2 );
5976 MSI_RecordSetStringW( uirow, 1, desc );
5977 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5978 ui_actiondata( package, szRemoveODBC, uirow );
5979 msiobj_release( &uirow->hdr );
5981 return ERROR_SUCCESS;
5984 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5986 MSIPACKAGE *package = param;
5989 LPCWSTR desc, driver;
5990 WORD request = ODBC_REMOVE_SYS_DSN;
5994 static const WCHAR attrs_fmt[] = {
5995 'D','S','N','=','%','s',0 };
5997 desc = MSI_RecordGetString( rec, 3 );
5998 driver = MSI_RecordGetString( rec, 4 );
5999 registration = MSI_RecordGetInteger( rec, 5 );
6001 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6002 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6004 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6005 attrs = msi_alloc( len * sizeof(WCHAR) );
6007 return ERROR_OUTOFMEMORY;
6009 FIXME("Use ODBCSourceAttribute table\n");
6011 len = sprintfW( attrs, attrs_fmt, desc );
6014 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6016 WARN("Failed to remove ODBC data source\n");
6020 uirow = MSI_CreateRecord( 3 );
6021 MSI_RecordSetStringW( uirow, 1, desc );
6022 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6023 MSI_RecordSetInteger( uirow, 3, request );
6024 ui_actiondata( package, szRemoveODBC, uirow );
6025 msiobj_release( &uirow->hdr );
6027 return ERROR_SUCCESS;
6030 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6035 static const WCHAR driver_query[] = {
6036 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6037 'O','D','B','C','D','r','i','v','e','r',0 };
6039 static const WCHAR translator_query[] = {
6040 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6041 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6043 static const WCHAR source_query[] = {
6044 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6045 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6047 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6048 if (rc != ERROR_SUCCESS)
6049 return ERROR_SUCCESS;
6051 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6052 msiobj_release( &view->hdr );
6054 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6055 if (rc != ERROR_SUCCESS)
6056 return ERROR_SUCCESS;
6058 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6059 msiobj_release( &view->hdr );
6061 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6062 if (rc != ERROR_SUCCESS)
6063 return ERROR_SUCCESS;
6065 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6066 msiobj_release( &view->hdr );
6071 #define ENV_ACT_SETALWAYS 0x1
6072 #define ENV_ACT_SETABSENT 0x2
6073 #define ENV_ACT_REMOVE 0x4
6074 #define ENV_ACT_REMOVEMATCH 0x8
6076 #define ENV_MOD_MACHINE 0x20000000
6077 #define ENV_MOD_APPEND 0x40000000
6078 #define ENV_MOD_PREFIX 0x80000000
6079 #define ENV_MOD_MASK 0xC0000000
6081 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6083 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6085 LPCWSTR cptr = *name;
6087 static const WCHAR prefix[] = {'[','~',']',0};
6088 static const int prefix_len = 3;
6094 *flags |= ENV_ACT_SETALWAYS;
6095 else if (*cptr == '+')
6096 *flags |= ENV_ACT_SETABSENT;
6097 else if (*cptr == '-')
6098 *flags |= ENV_ACT_REMOVE;
6099 else if (*cptr == '!')
6100 *flags |= ENV_ACT_REMOVEMATCH;
6101 else if (*cptr == '*')
6102 *flags |= ENV_MOD_MACHINE;
6112 ERR("Missing environment variable\n");
6113 return ERROR_FUNCTION_FAILED;
6118 LPCWSTR ptr = *value;
6119 if (!strncmpW(ptr, prefix, prefix_len))
6121 if (ptr[prefix_len] == szSemiColon[0])
6123 *flags |= ENV_MOD_APPEND;
6124 *value += lstrlenW(prefix);
6131 else if (lstrlenW(*value) >= prefix_len)
6133 ptr += lstrlenW(ptr) - prefix_len;
6134 if (!lstrcmpW(ptr, prefix))
6136 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6138 *flags |= ENV_MOD_PREFIX;
6139 /* the "[~]" will be removed by deformat_string */;
6149 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6150 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6151 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6152 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6154 ERR("Invalid flags: %08x\n", *flags);
6155 return ERROR_FUNCTION_FAILED;
6159 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6161 return ERROR_SUCCESS;
6164 static UINT open_env_key( DWORD flags, HKEY *key )
6166 static const WCHAR user_env[] =
6167 {'E','n','v','i','r','o','n','m','e','n','t',0};
6168 static const WCHAR machine_env[] =
6169 {'S','y','s','t','e','m','\\',
6170 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6171 'C','o','n','t','r','o','l','\\',
6172 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6173 'E','n','v','i','r','o','n','m','e','n','t',0};
6178 if (flags & ENV_MOD_MACHINE)
6181 root = HKEY_LOCAL_MACHINE;
6186 root = HKEY_CURRENT_USER;
6189 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6190 if (res != ERROR_SUCCESS)
6192 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6193 return ERROR_FUNCTION_FAILED;
6196 return ERROR_SUCCESS;
6199 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6201 MSIPACKAGE *package = param;
6202 LPCWSTR name, value, component;
6203 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6204 DWORD flags, type, size;
6211 component = MSI_RecordGetString(rec, 4);
6212 comp = get_loaded_component(package, component);
6214 return ERROR_SUCCESS;
6216 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6218 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6219 comp->Action = comp->Installed;
6220 return ERROR_SUCCESS;
6222 comp->Action = INSTALLSTATE_LOCAL;
6224 name = MSI_RecordGetString(rec, 2);
6225 value = MSI_RecordGetString(rec, 3);
6227 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6229 res = env_parse_flags(&name, &value, &flags);
6230 if (res != ERROR_SUCCESS || !value)
6233 if (value && !deformat_string(package, value, &deformatted))
6235 res = ERROR_OUTOFMEMORY;
6239 value = deformatted;
6241 res = open_env_key( flags, &env );
6242 if (res != ERROR_SUCCESS)
6245 if (flags & ENV_MOD_MACHINE)
6246 action |= 0x20000000;
6250 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6251 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6252 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6255 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6259 /* Nothing to do. */
6262 res = ERROR_SUCCESS;
6266 /* If we are appending but the string was empty, strip ; */
6267 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6269 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6270 newval = strdupW(value);
6273 res = ERROR_OUTOFMEMORY;
6281 /* Contrary to MSDN, +-variable to [~];path works */
6282 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6284 res = ERROR_SUCCESS;
6288 data = msi_alloc(size);
6292 return ERROR_OUTOFMEMORY;
6295 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6296 if (res != ERROR_SUCCESS)
6299 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6302 res = RegDeleteValueW(env, name);
6303 if (res != ERROR_SUCCESS)
6304 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6308 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6309 if (flags & ENV_MOD_MASK)
6313 if (flags & ENV_MOD_APPEND) multiplier++;
6314 if (flags & ENV_MOD_PREFIX) multiplier++;
6315 mod_size = lstrlenW(value) * multiplier;
6316 size += mod_size * sizeof(WCHAR);
6319 newval = msi_alloc(size);
6323 res = ERROR_OUTOFMEMORY;
6327 if (flags & ENV_MOD_PREFIX)
6329 lstrcpyW(newval, value);
6330 ptr = newval + lstrlenW(value);
6331 action |= 0x80000000;
6334 lstrcpyW(ptr, data);
6336 if (flags & ENV_MOD_APPEND)
6338 lstrcatW(newval, value);
6339 action |= 0x40000000;
6342 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6343 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6346 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6350 uirow = MSI_CreateRecord( 3 );
6351 MSI_RecordSetStringW( uirow, 1, name );
6352 MSI_RecordSetStringW( uirow, 2, newval );
6353 MSI_RecordSetInteger( uirow, 3, action );
6354 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6355 msiobj_release( &uirow->hdr );
6357 if (env) RegCloseKey(env);
6358 msi_free(deformatted);
6364 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6368 static const WCHAR ExecSeqQuery[] =
6369 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6370 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6371 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6372 if (rc != ERROR_SUCCESS)
6373 return ERROR_SUCCESS;
6375 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6376 msiobj_release(&view->hdr);
6381 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6383 MSIPACKAGE *package = param;
6384 LPCWSTR name, value, component;
6385 LPWSTR deformatted = NULL;
6394 component = MSI_RecordGetString( rec, 4 );
6395 comp = get_loaded_component( package, component );
6397 return ERROR_SUCCESS;
6399 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6401 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6402 comp->Action = comp->Installed;
6403 return ERROR_SUCCESS;
6405 comp->Action = INSTALLSTATE_ABSENT;
6407 name = MSI_RecordGetString( rec, 2 );
6408 value = MSI_RecordGetString( rec, 3 );
6410 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6412 r = env_parse_flags( &name, &value, &flags );
6413 if (r != ERROR_SUCCESS)
6416 if (!(flags & ENV_ACT_REMOVE))
6418 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6419 return ERROR_SUCCESS;
6422 if (value && !deformat_string( package, value, &deformatted ))
6423 return ERROR_OUTOFMEMORY;
6425 value = deformatted;
6427 r = open_env_key( flags, &env );
6428 if (r != ERROR_SUCCESS)
6434 if (flags & ENV_MOD_MACHINE)
6435 action |= 0x20000000;
6437 TRACE("Removing %s\n", debugstr_w(name));
6439 res = RegDeleteValueW( env, name );
6440 if (res != ERROR_SUCCESS)
6442 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6447 uirow = MSI_CreateRecord( 3 );
6448 MSI_RecordSetStringW( uirow, 1, name );
6449 MSI_RecordSetStringW( uirow, 2, value );
6450 MSI_RecordSetInteger( uirow, 3, action );
6451 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6452 msiobj_release( &uirow->hdr );
6454 if (env) RegCloseKey( env );
6455 msi_free( deformatted );
6459 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6463 static const WCHAR query[] =
6464 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6465 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6467 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6468 if (rc != ERROR_SUCCESS)
6469 return ERROR_SUCCESS;
6471 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6472 msiobj_release( &view->hdr );
6477 typedef struct tagMSIASSEMBLY
6480 MSICOMPONENT *component;
6481 MSIFEATURE *feature;
6485 LPWSTR display_name;
6490 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6492 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6493 LPVOID pvReserved, HMODULE *phModDll);
6495 static BOOL init_functionpointers(void)
6501 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6503 hmscoree = LoadLibraryA("mscoree.dll");
6506 WARN("mscoree.dll not available\n");
6510 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6511 if (!pLoadLibraryShim)
6513 WARN("LoadLibraryShim not available\n");
6514 FreeLibrary(hmscoree);
6518 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6521 WARN("fusion.dll not available\n");
6522 FreeLibrary(hmscoree);
6526 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6528 FreeLibrary(hmscoree);
6532 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6535 IAssemblyCache *cache;
6538 UINT r = ERROR_FUNCTION_FAILED;
6540 TRACE("installing assembly: %s\n", debugstr_w(path));
6542 uirow = MSI_CreateRecord( 2 );
6543 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6544 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6545 msiobj_release( &uirow->hdr );
6547 if (assembly->feature)
6548 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6550 if (assembly->manifest)
6551 FIXME("Manifest unhandled\n");
6553 if (assembly->application)
6555 FIXME("Assembly should be privately installed\n");
6556 return ERROR_SUCCESS;
6559 if (assembly->attributes == msidbAssemblyAttributesWin32)
6561 FIXME("Win32 assemblies not handled\n");
6562 return ERROR_SUCCESS;
6565 hr = pCreateAssemblyCache(&cache, 0);
6569 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6571 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6576 IAssemblyCache_Release(cache);
6580 typedef struct tagASSEMBLY_LIST
6582 MSIPACKAGE *package;
6583 IAssemblyCache *cache;
6584 struct list *assemblies;
6587 typedef struct tagASSEMBLY_NAME
6595 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6597 ASSEMBLY_NAME *asmname = param;
6598 LPCWSTR name = MSI_RecordGetString(rec, 2);
6599 LPWSTR val = msi_dup_record_field(rec, 3);
6601 static const WCHAR Name[] = {'N','a','m','e',0};
6602 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6603 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6604 static const WCHAR PublicKeyToken[] = {
6605 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6607 if (!strcmpiW(name, Name))
6608 asmname->name = val;
6609 else if (!strcmpiW(name, Version))
6610 asmname->version = val;
6611 else if (!strcmpiW(name, Culture))
6612 asmname->culture = val;
6613 else if (!strcmpiW(name, PublicKeyToken))
6614 asmname->pubkeytoken = val;
6618 return ERROR_SUCCESS;
6621 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6625 *size = lstrlenW(append) + 1;
6626 *str = msi_alloc((*size) * sizeof(WCHAR));
6627 lstrcpyW(*str, append);
6631 (*size) += lstrlenW(append);
6632 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6633 lstrcatW(*str, append);
6636 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6638 static const WCHAR separator[] = {',',' ',0};
6639 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6640 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6641 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6642 static const WCHAR query[] = {
6643 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6644 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6645 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6646 '=','\'','%','s','\'',0};
6649 LPWSTR display_name;
6653 display_name = NULL;
6654 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6656 r = MSI_OpenQuery( db, &view, query, comp->Component );
6657 if (r != ERROR_SUCCESS)
6660 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6661 msiobj_release( &view->hdr );
6665 ERR("No assembly name specified!\n");
6669 append_str( &display_name, &size, name.name );
6673 append_str( &display_name, &size, separator );
6674 append_str( &display_name, &size, Version );
6675 append_str( &display_name, &size, name.version );
6679 append_str( &display_name, &size, separator );
6680 append_str( &display_name, &size, Culture );
6681 append_str( &display_name, &size, name.culture );
6683 if (name.pubkeytoken)
6685 append_str( &display_name, &size, separator );
6686 append_str( &display_name, &size, PublicKeyToken );
6687 append_str( &display_name, &size, name.pubkeytoken );
6690 msi_free( name.name );
6691 msi_free( name.version );
6692 msi_free( name.culture );
6693 msi_free( name.pubkeytoken );
6695 return display_name;
6698 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6700 ASSEMBLY_INFO asminfo;
6705 disp = get_assembly_display_name( db, comp );
6709 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6710 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6712 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6714 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6720 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6722 ASSEMBLY_LIST *list = param;
6723 MSIASSEMBLY *assembly;
6726 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6728 return ERROR_OUTOFMEMORY;
6730 component = MSI_RecordGetString(rec, 1);
6731 assembly->component = get_loaded_component(list->package, component);
6732 if (!assembly->component)
6733 return ERROR_SUCCESS;
6735 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6736 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6738 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6739 assembly->component->Action = assembly->component->Installed;
6740 return ERROR_SUCCESS;
6742 assembly->component->Action = assembly->component->ActionRequest;
6744 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6745 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6747 if (!assembly->file)
6749 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6750 return ERROR_FUNCTION_FAILED;
6753 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6754 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6755 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6757 if (assembly->application)
6760 DWORD size = sizeof(version)/sizeof(WCHAR);
6762 /* FIXME: we should probably check the manifest file here */
6764 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6765 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6767 assembly->installed = TRUE;
6771 assembly->installed = check_assembly_installed(list->package->db,
6773 assembly->component);
6775 list_add_head(list->assemblies, &assembly->entry);
6776 return ERROR_SUCCESS;
6779 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6781 IAssemblyCache *cache = NULL;
6787 static const WCHAR query[] =
6788 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6789 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6791 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6792 if (r != ERROR_SUCCESS)
6793 return ERROR_SUCCESS;
6795 hr = pCreateAssemblyCache(&cache, 0);
6797 return ERROR_FUNCTION_FAILED;
6799 list.package = package;
6801 list.assemblies = assemblies;
6803 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6804 msiobj_release(&view->hdr);
6806 IAssemblyCache_Release(cache);
6811 static void free_assemblies(struct list *assemblies)
6813 struct list *item, *cursor;
6815 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6817 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6819 list_remove(&assembly->entry);
6820 msi_free(assembly->application);
6821 msi_free(assembly->manifest);
6822 msi_free(assembly->display_name);
6827 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6829 MSIASSEMBLY *assembly;
6831 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6833 if (!lstrcmpW(assembly->file->File, file))
6843 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6844 LPWSTR *path, DWORD *attrs, PVOID user)
6846 MSIASSEMBLY *assembly;
6847 WCHAR temppath[MAX_PATH];
6848 struct list *assemblies = user;
6851 if (!find_assembly(assemblies, file, &assembly))
6854 GetTempPathW(MAX_PATH, temppath);
6855 PathAddBackslashW(temppath);
6856 lstrcatW(temppath, assembly->file->FileName);
6858 if (action == MSICABEXTRACT_BEGINEXTRACT)
6860 if (assembly->installed)
6863 *path = strdupW(temppath);
6864 *attrs = assembly->file->Attributes;
6866 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6868 assembly->installed = TRUE;
6870 r = install_assembly(package, assembly, temppath);
6871 if (r != ERROR_SUCCESS)
6872 ERR("Failed to install assembly\n");
6878 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6881 struct list assemblies = LIST_INIT(assemblies);
6882 MSIASSEMBLY *assembly;
6885 if (!init_functionpointers() || !pCreateAssemblyCache)
6886 return ERROR_FUNCTION_FAILED;
6888 r = load_assemblies(package, &assemblies);
6889 if (r != ERROR_SUCCESS)
6892 if (list_empty(&assemblies))
6895 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6898 r = ERROR_OUTOFMEMORY;
6902 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6904 if (assembly->installed && !mi->is_continuous)
6907 if (assembly->file->IsCompressed)
6909 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
6913 r = ready_media(package, assembly->file, mi);
6914 if (r != ERROR_SUCCESS)
6916 ERR("Failed to ready media\n");
6921 data.package = package;
6922 data.cb = installassembly_cb;
6923 data.user = &assemblies;
6925 if (!msi_cabextract(package, mi, &data))
6927 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6928 r = ERROR_FUNCTION_FAILED;
6935 LPWSTR source = resolve_file_source(package, assembly->file);
6937 r = install_assembly(package, assembly, source);
6938 if (r != ERROR_SUCCESS)
6939 ERR("Failed to install assembly\n");
6944 /* FIXME: write Installer assembly reg values */
6948 free_assemblies(&assemblies);
6952 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6954 LPWSTR key, template, id;
6955 UINT r = ERROR_SUCCESS;
6957 id = msi_dup_property( package->db, szProductID );
6961 return ERROR_SUCCESS;
6963 template = msi_dup_property( package->db, szPIDTemplate );
6964 key = msi_dup_property( package->db, szPIDKEY );
6966 if (key && template)
6968 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6969 r = msi_set_property( package->db, szProductID, key );
6971 msi_free( template );
6976 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6979 package->need_reboot = 1;
6980 return ERROR_SUCCESS;
6983 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6985 static const WCHAR szAvailableFreeReg[] =
6986 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6988 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6990 TRACE("%p %d kilobytes\n", package, space);
6992 uirow = MSI_CreateRecord( 1 );
6993 MSI_RecordSetInteger( uirow, 1, space );
6994 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6995 msiobj_release( &uirow->hdr );
6997 return ERROR_SUCCESS;
7000 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7002 FIXME("%p\n", package);
7003 return ERROR_SUCCESS;
7006 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7008 FIXME("%p\n", package);
7009 return ERROR_SUCCESS;
7012 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7017 static const WCHAR driver_query[] = {
7018 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7019 'O','D','B','C','D','r','i','v','e','r',0 };
7021 static const WCHAR translator_query[] = {
7022 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7023 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7025 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7026 if (r == ERROR_SUCCESS)
7029 r = MSI_IterateRecords( view, &count, NULL, package );
7030 msiobj_release( &view->hdr );
7031 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7034 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7035 if (r == ERROR_SUCCESS)
7038 r = MSI_IterateRecords( view, &count, NULL, package );
7039 msiobj_release( &view->hdr );
7040 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7043 return ERROR_SUCCESS;
7046 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7047 LPCSTR action, LPCWSTR table )
7049 static const WCHAR query[] = {
7050 'S','E','L','E','C','T',' ','*',' ',
7051 'F','R','O','M',' ','`','%','s','`',0 };
7052 MSIQUERY *view = NULL;
7056 r = MSI_OpenQuery( package->db, &view, query, table );
7057 if (r == ERROR_SUCCESS)
7059 r = MSI_IterateRecords(view, &count, NULL, package);
7060 msiobj_release(&view->hdr);
7064 FIXME("%s -> %u ignored %s table values\n",
7065 action, count, debugstr_w(table));
7067 return ERROR_SUCCESS;
7070 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7072 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7073 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7076 static UINT ACTION_BindImage( MSIPACKAGE *package )
7078 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7079 return msi_unimplemented_action_stub( package, "BindImage", table );
7082 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7084 static const WCHAR table[] = {
7085 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7086 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7089 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7091 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7092 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7095 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7097 static const WCHAR table[] = {
7098 'M','s','i','A','s','s','e','m','b','l','y',0 };
7099 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7102 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7104 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7105 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7108 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7110 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7111 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7114 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7116 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7117 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7120 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7122 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7123 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7126 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7128 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7129 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7132 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7136 const WCHAR *action;
7137 UINT (*handler)(MSIPACKAGE *);
7141 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7142 { szAppSearch, ACTION_AppSearch },
7143 { szBindImage, ACTION_BindImage },
7144 { szCCPSearch, ACTION_CCPSearch },
7145 { szCostFinalize, ACTION_CostFinalize },
7146 { szCostInitialize, ACTION_CostInitialize },
7147 { szCreateFolders, ACTION_CreateFolders },
7148 { szCreateShortcuts, ACTION_CreateShortcuts },
7149 { szDeleteServices, ACTION_DeleteServices },
7150 { szDisableRollback, ACTION_DisableRollback },
7151 { szDuplicateFiles, ACTION_DuplicateFiles },
7152 { szExecuteAction, ACTION_ExecuteAction },
7153 { szFileCost, ACTION_FileCost },
7154 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7155 { szForceReboot, ACTION_ForceReboot },
7156 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7157 { szInstallExecute, ACTION_InstallExecute },
7158 { szInstallExecuteAgain, ACTION_InstallExecute },
7159 { szInstallFiles, ACTION_InstallFiles},
7160 { szInstallFinalize, ACTION_InstallFinalize },
7161 { szInstallInitialize, ACTION_InstallInitialize },
7162 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7163 { szInstallValidate, ACTION_InstallValidate },
7164 { szIsolateComponents, ACTION_IsolateComponents },
7165 { szLaunchConditions, ACTION_LaunchConditions },
7166 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7167 { szMoveFiles, ACTION_MoveFiles },
7168 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7169 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7170 { szInstallODBC, ACTION_InstallODBC },
7171 { szInstallServices, ACTION_InstallServices },
7172 { szPatchFiles, ACTION_PatchFiles },
7173 { szProcessComponents, ACTION_ProcessComponents },
7174 { szPublishComponents, ACTION_PublishComponents },
7175 { szPublishFeatures, ACTION_PublishFeatures },
7176 { szPublishProduct, ACTION_PublishProduct },
7177 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7178 { szRegisterComPlus, ACTION_RegisterComPlus},
7179 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7180 { szRegisterFonts, ACTION_RegisterFonts },
7181 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7182 { szRegisterProduct, ACTION_RegisterProduct },
7183 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7184 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7185 { szRegisterUser, ACTION_RegisterUser },
7186 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7187 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7188 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7189 { szRemoveFiles, ACTION_RemoveFiles },
7190 { szRemoveFolders, ACTION_RemoveFolders },
7191 { szRemoveIniValues, ACTION_RemoveIniValues },
7192 { szRemoveODBC, ACTION_RemoveODBC },
7193 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7194 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7195 { szResolveSource, ACTION_ResolveSource },
7196 { szRMCCPSearch, ACTION_RMCCPSearch },
7197 { szScheduleReboot, ACTION_ScheduleReboot },
7198 { szSelfRegModules, ACTION_SelfRegModules },
7199 { szSelfUnregModules, ACTION_SelfUnregModules },
7200 { szSetODBCFolders, ACTION_SetODBCFolders },
7201 { szStartServices, ACTION_StartServices },
7202 { szStopServices, ACTION_StopServices },
7203 { szUnpublishComponents, ACTION_UnpublishComponents },
7204 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7205 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7206 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7207 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7208 { szUnregisterFonts, ACTION_UnregisterFonts },
7209 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7210 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7211 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7212 { szValidateProductID, ACTION_ValidateProductID },
7213 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7214 { szWriteIniValues, ACTION_WriteIniValues },
7215 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7219 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7220 UINT* rc, BOOL force )
7226 if (!run && !package->script->CurrentlyScripting)
7231 if (strcmpW(action,szInstallFinalize) == 0 ||
7232 strcmpW(action,szInstallExecute) == 0 ||
7233 strcmpW(action,szInstallExecuteAgain) == 0)
7238 while (StandardActions[i].action != NULL)
7240 if (strcmpW(StandardActions[i].action, action)==0)
7244 ui_actioninfo(package, action, TRUE, 0);
7245 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7246 ui_actioninfo(package, action, FALSE, *rc);
7250 ui_actionstart(package, action);
7251 if (StandardActions[i].handler)
7253 *rc = StandardActions[i].handler(package);
7257 FIXME("unhandled standard action %s\n",debugstr_w(action));
7258 *rc = ERROR_SUCCESS;
7269 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7271 UINT rc = ERROR_SUCCESS;
7274 TRACE("Performing action (%s)\n", debugstr_w(action));
7276 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7279 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7283 WARN("unhandled msi action %s\n", debugstr_w(action));
7284 rc = ERROR_FUNCTION_NOT_CALLED;
7290 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7292 UINT rc = ERROR_SUCCESS;
7293 BOOL handled = FALSE;
7295 TRACE("Performing action (%s)\n", debugstr_w(action));
7297 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7300 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7302 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7307 WARN("unhandled msi action %s\n", debugstr_w(action));
7308 rc = ERROR_FUNCTION_NOT_CALLED;
7314 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7316 UINT rc = ERROR_SUCCESS;
7319 static const WCHAR ExecSeqQuery[] =
7320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7321 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7322 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7323 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7324 static const WCHAR UISeqQuery[] =
7325 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7326 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7327 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7328 ' ', '=',' ','%','i',0};
7330 if (needs_ui_sequence(package))
7331 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7333 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7337 LPCWSTR action, cond;
7339 TRACE("Running the actions\n");
7341 /* check conditions */
7342 cond = MSI_RecordGetString(row, 2);
7344 /* this is a hack to skip errors in the condition code */
7345 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7347 msiobj_release(&row->hdr);
7348 return ERROR_SUCCESS;
7351 action = MSI_RecordGetString(row, 1);
7354 ERR("failed to fetch action\n");
7355 msiobj_release(&row->hdr);
7356 return ERROR_FUNCTION_FAILED;
7359 if (needs_ui_sequence(package))
7360 rc = ACTION_PerformUIAction(package, action, -1);
7362 rc = ACTION_PerformAction(package, action, -1, FALSE);
7364 msiobj_release(&row->hdr);
7370 /****************************************************
7371 * TOP level entry points
7372 *****************************************************/
7374 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7375 LPCWSTR szCommandLine )
7380 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7381 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7383 msi_set_property( package->db, szAction, szInstall );
7385 package->script->InWhatSequence = SEQUENCE_INSTALL;
7392 dir = strdupW(szPackagePath);
7393 p = strrchrW(dir, '\\');
7397 file = szPackagePath + (p - dir);
7402 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7403 GetCurrentDirectoryW(MAX_PATH, dir);
7404 lstrcatW(dir, szBackSlash);
7405 file = szPackagePath;
7408 msi_free( package->PackagePath );
7409 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7410 if (!package->PackagePath)
7413 return ERROR_OUTOFMEMORY;
7416 lstrcpyW(package->PackagePath, dir);
7417 lstrcatW(package->PackagePath, file);
7420 msi_set_sourcedir_props(package, FALSE);
7423 msi_parse_command_line( package, szCommandLine, FALSE );
7425 msi_apply_transforms( package );
7426 msi_apply_patches( package );
7428 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7430 TRACE("setting reinstall property\n");
7431 msi_set_property( package->db, szReinstall, szAll );
7434 /* properties may have been added by a transform */
7435 msi_clone_properties( package );
7436 msi_set_context( package );
7438 if (needs_ui_sequence( package))
7440 package->script->InWhatSequence |= SEQUENCE_UI;
7441 rc = ACTION_ProcessUISequence(package);
7442 ui_exists = ui_sequence_exists(package);
7443 if (rc == ERROR_SUCCESS || !ui_exists)
7445 package->script->InWhatSequence |= SEQUENCE_EXEC;
7446 rc = ACTION_ProcessExecSequence(package, ui_exists);
7450 rc = ACTION_ProcessExecSequence(package, FALSE);
7452 package->script->CurrentlyScripting = FALSE;
7454 /* process the ending type action */
7455 if (rc == ERROR_SUCCESS)
7456 ACTION_PerformActionSequence(package, -1);
7457 else if (rc == ERROR_INSTALL_USEREXIT)
7458 ACTION_PerformActionSequence(package, -2);
7459 else if (rc == ERROR_INSTALL_SUSPEND)
7460 ACTION_PerformActionSequence(package, -4);
7462 ACTION_PerformActionSequence(package, -3);
7464 /* finish up running custom actions */
7465 ACTION_FinishCustomActions(package);
7467 if (rc == ERROR_SUCCESS && package->need_reboot)
7468 return ERROR_SUCCESS_REBOOT_REQUIRED;