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 static LPWSTR get_disk_file_version( LPCWSTR filename )
1969 static const WCHAR name_fmt[] =
1970 {'%','u','.','%','u','.','%','u','.','%','u',0};
1971 static const WCHAR name[] = {'\\',0};
1972 VS_FIXEDFILEINFO *lpVer;
1973 WCHAR filever[0x100];
1979 TRACE("%s\n", debugstr_w(filename));
1981 versize = GetFileVersionInfoSizeW( filename, &handle );
1985 version = msi_alloc( versize );
1986 GetFileVersionInfoW( filename, 0, versize, version );
1988 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1990 msi_free( version );
1994 sprintfW( filever, name_fmt,
1995 HIWORD(lpVer->dwFileVersionMS),
1996 LOWORD(lpVer->dwFileVersionMS),
1997 HIWORD(lpVer->dwFileVersionLS),
1998 LOWORD(lpVer->dwFileVersionLS));
2000 msi_free( version );
2002 return strdupW( filever );
2005 static DWORD get_disk_file_size( LPCWSTR filename )
2010 TRACE("%s\n", debugstr_w(filename));
2012 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2013 if (file == INVALID_HANDLE_VALUE)
2014 return INVALID_FILE_SIZE;
2016 size = GetFileSize( file, NULL );
2017 CloseHandle( file );
2021 static BOOL hash_matches( MSIFILE *file )
2024 MSIFILEHASHINFO hash;
2026 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2027 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2028 if (r != ERROR_SUCCESS)
2031 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2034 static UINT set_file_install_states( MSIPACKAGE *package )
2036 LPWSTR file_version;
2039 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2041 MSICOMPONENT* comp = file->Component;
2048 if (file->IsCompressed)
2049 comp->ForceLocalState = TRUE;
2051 /* calculate target */
2052 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2054 msi_free(file->TargetPath);
2056 TRACE("file %s is named %s\n",
2057 debugstr_w(file->File), debugstr_w(file->FileName));
2059 file->TargetPath = build_directory_name(2, p, file->FileName);
2063 TRACE("file %s resolves to %s\n",
2064 debugstr_w(file->File), debugstr_w(file->TargetPath));
2066 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2068 file->state = msifs_missing;
2069 comp->Cost += file->FileSize;
2072 if (file->Version && (file_version = get_disk_file_version( file->TargetPath )))
2074 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(file_version));
2076 if (strcmpiW(file_version, file->Version) < 0)
2078 file->state = msifs_overwrite;
2079 comp->Cost += file->FileSize;
2083 TRACE("Destination file version equal or greater, not overwriting\n");
2084 file->state = msifs_present;
2086 msi_free( file_version );
2089 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2091 file->state = msifs_overwrite;
2092 comp->Cost += file->FileSize - file_size;
2095 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2097 TRACE("File hashes match, not overwriting\n");
2098 file->state = msifs_present;
2101 file->state = msifs_overwrite;
2102 comp->Cost += file->FileSize - file_size;
2105 return ERROR_SUCCESS;
2109 * A lot is done in this function aside from just the costing.
2110 * The costing needs to be implemented at some point but for now I am going
2111 * to focus on the directory building
2114 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2116 static const WCHAR ExecSeqQuery[] =
2117 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2118 '`','D','i','r','e','c','t','o','r','y','`',0};
2119 static const WCHAR ConditionQuery[] =
2120 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2121 '`','C','o','n','d','i','t','i','o','n','`',0};
2122 static const WCHAR szCosting[] =
2123 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2124 static const WCHAR szlevel[] =
2125 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2126 static const WCHAR szOutOfDiskSpace[] =
2127 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2129 UINT rc = ERROR_SUCCESS;
2133 TRACE("Building Directory properties\n");
2135 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2136 if (rc == ERROR_SUCCESS)
2138 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2140 msiobj_release(&view->hdr);
2143 /* read components states from the registry */
2144 ACTION_GetComponentInstallStates(package);
2145 ACTION_GetFeatureInstallStates(package);
2147 TRACE("Calculating file install states\n");
2148 set_file_install_states( package );
2150 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2152 TRACE("Evaluating feature conditions\n");
2154 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2155 if (rc == ERROR_SUCCESS)
2157 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2158 msiobj_release( &view->hdr );
2161 TRACE("Evaluating component conditions\n");
2163 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2165 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2167 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2168 comp->Enabled = FALSE;
2171 comp->Enabled = TRUE;
2174 msi_set_property( package->db, szCosting, szOne );
2175 /* set default run level if not set */
2176 level = msi_dup_property( package->db, szlevel );
2178 msi_set_property( package->db, szlevel, szOne );
2181 /* FIXME: check volume disk space */
2182 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2184 return MSI_SetFeatureStates(package);
2187 /* OK this value is "interpreted" and then formatted based on the
2188 first few characters */
2189 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2194 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2200 LPWSTR deformated = NULL;
2203 deformat_string(package, &value[2], &deformated);
2205 /* binary value type */
2209 *size = (strlenW(ptr)/2)+1;
2211 *size = strlenW(ptr)/2;
2213 data = msi_alloc(*size);
2219 /* if uneven pad with a zero in front */
2225 data[count] = (BYTE)strtol(byte,NULL,0);
2227 TRACE("Uneven byte count\n");
2235 data[count] = (BYTE)strtol(byte,NULL,0);
2238 msi_free(deformated);
2240 TRACE("Data %i bytes(%i)\n",*size,count);
2247 deformat_string(package, &value[1], &deformated);
2250 *size = sizeof(DWORD);
2251 data = msi_alloc(*size);
2257 if ( (*p < '0') || (*p > '9') )
2263 if (deformated[0] == '-')
2266 TRACE("DWORD %i\n",*(LPDWORD)data);
2268 msi_free(deformated);
2273 static const WCHAR szMulti[] = {'[','~',']',0};
2282 *type=REG_EXPAND_SZ;
2290 if (strstrW(value,szMulti))
2291 *type = REG_MULTI_SZ;
2293 /* remove initial delimiter */
2294 if (!strncmpW(value, szMulti, 3))
2297 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2299 /* add double NULL terminator */
2300 if (*type == REG_MULTI_SZ)
2302 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2303 data = msi_realloc_zero(data, *size);
2309 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2316 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2318 *root_key = HKEY_LOCAL_MACHINE;
2323 *root_key = HKEY_CURRENT_USER;
2328 *root_key = HKEY_CLASSES_ROOT;
2332 *root_key = HKEY_CURRENT_USER;
2336 *root_key = HKEY_LOCAL_MACHINE;
2340 *root_key = HKEY_USERS;
2344 ERR("Unknown root %i\n", root);
2351 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2353 MSIPACKAGE *package = param;
2354 LPSTR value_data = NULL;
2355 HKEY root_key, hkey;
2358 LPCWSTR szRoot, component, name, key, value;
2363 BOOL check_first = FALSE;
2366 ui_progress(package,2,0,0,0);
2373 component = MSI_RecordGetString(row, 6);
2374 comp = get_loaded_component(package,component);
2376 return ERROR_SUCCESS;
2378 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2380 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2381 comp->Action = comp->Installed;
2382 return ERROR_SUCCESS;
2384 comp->Action = INSTALLSTATE_LOCAL;
2386 name = MSI_RecordGetString(row, 4);
2387 if( MSI_RecordIsNull(row,5) && name )
2389 /* null values can have special meanings */
2390 if (name[0]=='-' && name[1] == 0)
2391 return ERROR_SUCCESS;
2392 else if ((name[0]=='+' && name[1] == 0) ||
2393 (name[0] == '*' && name[1] == 0))
2398 root = MSI_RecordGetInteger(row,2);
2399 key = MSI_RecordGetString(row, 3);
2401 szRoot = get_root_key( package, root, &root_key );
2403 return ERROR_SUCCESS;
2405 deformat_string(package, key , &deformated);
2406 size = strlenW(deformated) + strlenW(szRoot) + 1;
2407 uikey = msi_alloc(size*sizeof(WCHAR));
2408 strcpyW(uikey,szRoot);
2409 strcatW(uikey,deformated);
2411 if (RegCreateKeyW( root_key, deformated, &hkey))
2413 ERR("Could not create key %s\n",debugstr_w(deformated));
2414 msi_free(deformated);
2416 return ERROR_SUCCESS;
2418 msi_free(deformated);
2420 value = MSI_RecordGetString(row,5);
2422 value_data = parse_value(package, value, &type, &size);
2425 value_data = (LPSTR)strdupW(szEmpty);
2426 size = sizeof(szEmpty);
2430 deformat_string(package, name, &deformated);
2434 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2436 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2441 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2442 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2444 TRACE("value %s of %s checked already exists\n",
2445 debugstr_w(deformated), debugstr_w(uikey));
2449 TRACE("Checked and setting value %s of %s\n",
2450 debugstr_w(deformated), debugstr_w(uikey));
2451 if (deformated || size)
2452 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2457 uirow = MSI_CreateRecord(3);
2458 MSI_RecordSetStringW(uirow,2,deformated);
2459 MSI_RecordSetStringW(uirow,1,uikey);
2460 if (type == REG_SZ || type == REG_EXPAND_SZ)
2461 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2462 ui_actiondata(package,szWriteRegistryValues,uirow);
2463 msiobj_release( &uirow->hdr );
2465 msi_free(value_data);
2466 msi_free(deformated);
2469 return ERROR_SUCCESS;
2472 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2476 static const WCHAR ExecSeqQuery[] =
2477 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2478 '`','R','e','g','i','s','t','r','y','`',0 };
2480 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2481 if (rc != ERROR_SUCCESS)
2482 return ERROR_SUCCESS;
2484 /* increment progress bar each time action data is sent */
2485 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2487 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2489 msiobj_release(&view->hdr);
2493 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2497 DWORD num_subkeys, num_values;
2501 if ((res = RegDeleteTreeW( hkey_root, key )))
2503 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2508 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2510 if ((res = RegDeleteValueW( hkey, value )))
2512 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2514 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2515 NULL, NULL, NULL, NULL );
2516 RegCloseKey( hkey );
2518 if (!res && !num_subkeys && !num_values)
2520 TRACE("Removing empty key %s\n", debugstr_w(key));
2521 RegDeleteKeyW( hkey_root, key );
2525 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2529 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2531 MSIPACKAGE *package = param;
2532 LPCWSTR component, name, key_str, root_key_str;
2533 LPWSTR deformated_key, deformated_name, ui_key_str;
2536 BOOL delete_key = FALSE;
2541 ui_progress( package, 2, 0, 0, 0 );
2543 component = MSI_RecordGetString( row, 6 );
2544 comp = get_loaded_component( package, component );
2546 return ERROR_SUCCESS;
2548 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2550 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2551 comp->Action = comp->Installed;
2552 return ERROR_SUCCESS;
2554 comp->Action = INSTALLSTATE_ABSENT;
2556 name = MSI_RecordGetString( row, 4 );
2557 if (MSI_RecordIsNull( row, 5 ) && name )
2559 if (name[0] == '+' && !name[1])
2560 return ERROR_SUCCESS;
2561 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2568 root = MSI_RecordGetInteger( row, 2 );
2569 key_str = MSI_RecordGetString( row, 3 );
2571 root_key_str = get_root_key( package, root, &hkey_root );
2573 return ERROR_SUCCESS;
2575 deformat_string( package, key_str, &deformated_key );
2576 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2577 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2578 strcpyW( ui_key_str, root_key_str );
2579 strcatW( ui_key_str, deformated_key );
2581 deformat_string( package, name, &deformated_name );
2583 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2584 msi_free( deformated_key );
2586 uirow = MSI_CreateRecord( 2 );
2587 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2588 MSI_RecordSetStringW( uirow, 2, deformated_name );
2590 ui_actiondata( package, szRemoveRegistryValues, uirow );
2591 msiobj_release( &uirow->hdr );
2593 msi_free( ui_key_str );
2594 msi_free( deformated_name );
2595 return ERROR_SUCCESS;
2598 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2600 MSIPACKAGE *package = param;
2601 LPCWSTR component, name, key_str, root_key_str;
2602 LPWSTR deformated_key, deformated_name, ui_key_str;
2605 BOOL delete_key = FALSE;
2610 ui_progress( package, 2, 0, 0, 0 );
2612 component = MSI_RecordGetString( row, 5 );
2613 comp = get_loaded_component( package, component );
2615 return ERROR_SUCCESS;
2617 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2619 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2620 comp->Action = comp->Installed;
2621 return ERROR_SUCCESS;
2623 comp->Action = INSTALLSTATE_LOCAL;
2625 if ((name = MSI_RecordGetString( row, 4 )))
2627 if (name[0] == '-' && !name[1])
2634 root = MSI_RecordGetInteger( row, 2 );
2635 key_str = MSI_RecordGetString( row, 3 );
2637 root_key_str = get_root_key( package, root, &hkey_root );
2639 return ERROR_SUCCESS;
2641 deformat_string( package, key_str, &deformated_key );
2642 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2643 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2644 strcpyW( ui_key_str, root_key_str );
2645 strcatW( ui_key_str, deformated_key );
2647 deformat_string( package, name, &deformated_name );
2649 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2650 msi_free( deformated_key );
2652 uirow = MSI_CreateRecord( 2 );
2653 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2654 MSI_RecordSetStringW( uirow, 2, deformated_name );
2656 ui_actiondata( package, szRemoveRegistryValues, uirow );
2657 msiobj_release( &uirow->hdr );
2659 msi_free( ui_key_str );
2660 msi_free( deformated_name );
2661 return ERROR_SUCCESS;
2664 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2668 static const WCHAR registry_query[] =
2669 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2670 '`','R','e','g','i','s','t','r','y','`',0 };
2671 static const WCHAR remove_registry_query[] =
2672 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2673 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2675 /* increment progress bar each time action data is sent */
2676 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2678 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2679 if (rc == ERROR_SUCCESS)
2681 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2682 msiobj_release( &view->hdr );
2683 if (rc != ERROR_SUCCESS)
2687 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2688 if (rc == ERROR_SUCCESS)
2690 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2691 msiobj_release( &view->hdr );
2692 if (rc != ERROR_SUCCESS)
2696 return ERROR_SUCCESS;
2699 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2701 package->script->CurrentlyScripting = TRUE;
2703 return ERROR_SUCCESS;
2707 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2712 static const WCHAR q1[]=
2713 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2714 '`','R','e','g','i','s','t','r','y','`',0};
2717 MSIFEATURE *feature;
2720 TRACE("InstallValidate\n");
2722 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2723 if (rc == ERROR_SUCCESS)
2725 MSI_IterateRecords( view, &progress, NULL, package );
2726 msiobj_release( &view->hdr );
2727 total += progress * REG_PROGRESS_VALUE;
2730 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2731 total += COMPONENT_PROGRESS_VALUE;
2733 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2734 total += file->FileSize;
2736 ui_progress(package,0,total,0,0);
2738 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2740 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2741 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2742 feature->ActionRequest);
2745 return ERROR_SUCCESS;
2748 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2750 MSIPACKAGE* package = param;
2751 LPCWSTR cond = NULL;
2752 LPCWSTR message = NULL;
2755 static const WCHAR title[]=
2756 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2758 cond = MSI_RecordGetString(row,1);
2760 r = MSI_EvaluateConditionW(package,cond);
2761 if (r == MSICONDITION_FALSE)
2763 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2766 message = MSI_RecordGetString(row,2);
2767 deformat_string(package,message,&deformated);
2768 MessageBoxW(NULL,deformated,title,MB_OK);
2769 msi_free(deformated);
2772 return ERROR_INSTALL_FAILURE;
2775 return ERROR_SUCCESS;
2778 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2781 MSIQUERY * view = NULL;
2782 static const WCHAR ExecSeqQuery[] =
2783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2784 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2786 TRACE("Checking launch conditions\n");
2788 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2789 if (rc != ERROR_SUCCESS)
2790 return ERROR_SUCCESS;
2792 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2793 msiobj_release(&view->hdr);
2798 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2802 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2804 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2806 MSIRECORD * row = 0;
2808 LPWSTR deformated,buffer,deformated_name;
2810 static const WCHAR ExecSeqQuery[] =
2811 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2812 '`','R','e','g','i','s','t','r','y','`',' ',
2813 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2814 ' ','=',' ' ,'\'','%','s','\'',0 };
2815 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2816 static const WCHAR fmt2[]=
2817 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2819 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2823 root = MSI_RecordGetInteger(row,2);
2824 key = MSI_RecordGetString(row, 3);
2825 name = MSI_RecordGetString(row, 4);
2826 deformat_string(package, key , &deformated);
2827 deformat_string(package, name, &deformated_name);
2829 len = strlenW(deformated) + 6;
2830 if (deformated_name)
2831 len+=strlenW(deformated_name);
2833 buffer = msi_alloc( len *sizeof(WCHAR));
2835 if (deformated_name)
2836 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2838 sprintfW(buffer,fmt,root,deformated);
2840 msi_free(deformated);
2841 msi_free(deformated_name);
2842 msiobj_release(&row->hdr);
2846 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2848 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2853 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2856 return strdupW( file->TargetPath );
2861 static HKEY openSharedDLLsKey(void)
2864 static const WCHAR path[] =
2865 {'S','o','f','t','w','a','r','e','\\',
2866 'M','i','c','r','o','s','o','f','t','\\',
2867 'W','i','n','d','o','w','s','\\',
2868 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2869 'S','h','a','r','e','d','D','L','L','s',0};
2871 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2875 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2880 DWORD sz = sizeof(count);
2883 hkey = openSharedDLLsKey();
2884 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2885 if (rc != ERROR_SUCCESS)
2891 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2895 hkey = openSharedDLLsKey();
2897 msi_reg_set_val_dword( hkey, path, count );
2899 RegDeleteValueW(hkey,path);
2905 * Return TRUE if the count should be written out and FALSE if not
2907 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2909 MSIFEATURE *feature;
2913 /* only refcount DLLs */
2914 if (comp->KeyPath == NULL ||
2915 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2916 comp->Attributes & msidbComponentAttributesODBCDataSource)
2920 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2921 write = (count > 0);
2923 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2927 /* increment counts */
2928 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2932 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2935 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2937 if ( cl->component == comp )
2942 /* decrement counts */
2943 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2947 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2950 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2952 if ( cl->component == comp )
2957 /* ref count all the files in the component */
2962 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2964 if (file->Component == comp)
2965 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2969 /* add a count for permanent */
2970 if (comp->Attributes & msidbComponentAttributesPermanent)
2973 comp->RefCount = count;
2976 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2979 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2981 WCHAR squished_pc[GUID_SIZE];
2982 WCHAR squished_cc[GUID_SIZE];
2989 squash_guid(package->ProductCode,squished_pc);
2990 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2992 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2996 ui_progress(package,2,0,0,0);
2997 if (!comp->ComponentId)
3000 squash_guid(comp->ComponentId,squished_cc);
3002 msi_free(comp->FullKeypath);
3003 comp->FullKeypath = resolve_keypath( package, comp );
3005 ACTION_RefCountComponent( package, comp );
3007 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
3008 debugstr_w(comp->Component),
3009 debugstr_w(squished_cc),
3010 debugstr_w(comp->FullKeypath),
3013 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3014 comp->ActionRequest == INSTALLSTATE_SOURCE)
3016 if (!comp->FullKeypath)
3019 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3020 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3023 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3026 if (rc != ERROR_SUCCESS)
3029 if (comp->Attributes & msidbComponentAttributesPermanent)
3031 static const WCHAR szPermKey[] =
3032 { '0','0','0','0','0','0','0','0','0','0','0','0',
3033 '0','0','0','0','0','0','0','0','0','0','0','0',
3034 '0','0','0','0','0','0','0','0',0 };
3036 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3039 if (comp->Action == INSTALLSTATE_LOCAL)
3040 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3046 WCHAR source[MAX_PATH];
3047 WCHAR base[MAX_PATH];
3050 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3051 static const WCHAR query[] = {
3052 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3053 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3054 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3055 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3056 '`','D','i','s','k','I','d','`',0};
3058 file = get_loaded_file(package, comp->KeyPath);
3062 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3063 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3064 ptr2 = strrchrW(source, '\\') + 1;
3065 msiobj_release(&row->hdr);
3067 lstrcpyW(base, package->PackagePath);
3068 ptr = strrchrW(base, '\\');
3071 sourcepath = resolve_file_source(package, file);
3072 ptr = sourcepath + lstrlenW(base);
3073 lstrcpyW(ptr2, ptr);
3074 msi_free(sourcepath);
3076 msi_reg_set_val_str(hkey, squished_pc, source);
3080 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3082 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3083 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3085 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3087 comp->Action = comp->ActionRequest;
3090 uirow = MSI_CreateRecord(3);
3091 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3092 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3093 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3094 ui_actiondata(package,szProcessComponents,uirow);
3095 msiobj_release( &uirow->hdr );
3098 return ERROR_SUCCESS;
3109 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3110 LPWSTR lpszName, LONG_PTR lParam)
3113 typelib_struct *tl_struct = (typelib_struct*) lParam;
3114 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3118 if (!IS_INTRESOURCE(lpszName))
3120 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3124 sz = strlenW(tl_struct->source)+4;
3125 sz *= sizeof(WCHAR);
3127 if ((INT_PTR)lpszName == 1)
3128 tl_struct->path = strdupW(tl_struct->source);
3131 tl_struct->path = msi_alloc(sz);
3132 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3135 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3136 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3139 msi_free(tl_struct->path);
3140 tl_struct->path = NULL;
3145 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3146 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3148 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3152 msi_free(tl_struct->path);
3153 tl_struct->path = NULL;
3155 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3156 ITypeLib_Release(tl_struct->ptLib);
3161 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3163 MSIPACKAGE* package = param;
3167 typelib_struct tl_struct;
3172 component = MSI_RecordGetString(row,3);
3173 comp = get_loaded_component(package,component);
3175 return ERROR_SUCCESS;
3177 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3179 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3180 comp->Action = comp->Installed;
3181 return ERROR_SUCCESS;
3183 comp->Action = INSTALLSTATE_LOCAL;
3185 file = get_loaded_file( package, comp->KeyPath );
3187 return ERROR_SUCCESS;
3189 ui_actiondata( package, szRegisterTypeLibraries, row );
3191 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3195 guid = MSI_RecordGetString(row,1);
3196 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3197 tl_struct.source = strdupW( file->TargetPath );
3198 tl_struct.path = NULL;
3200 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3201 (LONG_PTR)&tl_struct);
3209 helpid = MSI_RecordGetString(row,6);
3212 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3213 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3217 ERR("Failed to register type library %s\n",
3218 debugstr_w(tl_struct.path));
3220 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3222 ITypeLib_Release(tl_struct.ptLib);
3223 msi_free(tl_struct.path);
3226 ERR("Failed to load type library %s\n",
3227 debugstr_w(tl_struct.source));
3229 FreeLibrary(module);
3230 msi_free(tl_struct.source);
3234 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3237 ERR("Failed to load type library: %08x\n", hr);
3238 return ERROR_INSTALL_FAILURE;
3241 ITypeLib_Release(tlib);
3244 return ERROR_SUCCESS;
3247 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3250 * OK this is a bit confusing.. I am given a _Component key and I believe
3251 * that the file that is being registered as a type library is the "key file
3252 * of that component" which I interpret to mean "The file in the KeyPath of
3257 static const WCHAR Query[] =
3258 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3259 '`','T','y','p','e','L','i','b','`',0};
3261 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3262 if (rc != ERROR_SUCCESS)
3263 return ERROR_SUCCESS;
3265 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3266 msiobj_release(&view->hdr);
3270 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3272 MSIPACKAGE *package = param;
3273 LPCWSTR component, guid;
3281 component = MSI_RecordGetString( row, 3 );
3282 comp = get_loaded_component( package, component );
3284 return ERROR_SUCCESS;
3286 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3288 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3289 comp->Action = comp->Installed;
3290 return ERROR_SUCCESS;
3292 comp->Action = INSTALLSTATE_ABSENT;
3294 ui_actiondata( package, szUnregisterTypeLibraries, row );
3296 guid = MSI_RecordGetString( row, 1 );
3297 CLSIDFromString( (LPCWSTR)guid, &libid );
3298 version = MSI_RecordGetInteger( row, 4 );
3299 language = MSI_RecordGetInteger( row, 2 );
3302 syskind = SYS_WIN64;
3304 syskind = SYS_WIN32;
3307 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3310 WARN("Failed to unregister typelib: %08x\n", hr);
3313 return ERROR_SUCCESS;
3316 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3320 static const WCHAR query[] =
3321 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3322 '`','T','y','p','e','L','i','b','`',0};
3324 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3325 if (rc != ERROR_SUCCESS)
3326 return ERROR_SUCCESS;
3328 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3329 msiobj_release( &view->hdr );
3333 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3335 static const WCHAR szlnk[] = {'.','l','n','k',0};
3336 LPCWSTR directory, extension;
3337 LPWSTR link_folder, link_file, filename;
3339 directory = MSI_RecordGetString( row, 2 );
3340 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3342 /* may be needed because of a bug somewhere else */
3343 create_full_pathW( link_folder );
3345 filename = msi_dup_record_field( row, 3 );
3346 reduce_to_longfilename( filename );
3348 extension = strchrW( filename, '.' );
3349 if (!extension || strcmpiW( extension, szlnk ))
3351 int len = strlenW( filename );
3352 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3353 memcpy( filename + len, szlnk, sizeof(szlnk) );
3355 link_file = build_directory_name( 2, link_folder, filename );
3356 msi_free( link_folder );
3357 msi_free( filename );
3362 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3364 MSIPACKAGE *package = param;
3365 LPWSTR link_file, deformated, path;
3366 LPCWSTR component, target;
3368 IShellLinkW *sl = NULL;
3369 IPersistFile *pf = NULL;
3372 component = MSI_RecordGetString(row, 4);
3373 comp = get_loaded_component(package, component);
3375 return ERROR_SUCCESS;
3377 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3379 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3380 comp->Action = comp->Installed;
3381 return ERROR_SUCCESS;
3383 comp->Action = INSTALLSTATE_LOCAL;
3385 ui_actiondata(package,szCreateShortcuts,row);
3387 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3388 &IID_IShellLinkW, (LPVOID *) &sl );
3392 ERR("CLSID_ShellLink not available\n");
3396 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3399 ERR("QueryInterface(IID_IPersistFile) failed\n");
3403 target = MSI_RecordGetString(row, 5);
3404 if (strchrW(target, '['))
3406 deformat_string(package, target, &deformated);
3407 IShellLinkW_SetPath(sl,deformated);
3408 msi_free(deformated);
3412 FIXME("poorly handled shortcut format, advertised shortcut\n");
3413 IShellLinkW_SetPath(sl,comp->FullKeypath);
3416 if (!MSI_RecordIsNull(row,6))
3418 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3419 deformat_string(package, arguments, &deformated);
3420 IShellLinkW_SetArguments(sl,deformated);
3421 msi_free(deformated);
3424 if (!MSI_RecordIsNull(row,7))
3426 LPCWSTR description = MSI_RecordGetString(row, 7);
3427 IShellLinkW_SetDescription(sl, description);
3430 if (!MSI_RecordIsNull(row,8))
3431 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3433 if (!MSI_RecordIsNull(row,9))
3436 LPCWSTR icon = MSI_RecordGetString(row, 9);
3438 path = build_icon_path(package, icon);
3439 index = MSI_RecordGetInteger(row,10);
3441 /* no value means 0 */
3442 if (index == MSI_NULL_INTEGER)
3445 IShellLinkW_SetIconLocation(sl, path, index);
3449 if (!MSI_RecordIsNull(row,11))
3450 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3452 if (!MSI_RecordIsNull(row,12))
3454 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3455 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3457 IShellLinkW_SetWorkingDirectory(sl, path);
3461 link_file = get_link_file(package, row);
3463 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3464 IPersistFile_Save(pf, link_file, FALSE);
3466 msi_free(link_file);
3470 IPersistFile_Release( pf );
3472 IShellLinkW_Release( sl );
3474 return ERROR_SUCCESS;
3477 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3482 static const WCHAR Query[] =
3483 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3484 '`','S','h','o','r','t','c','u','t','`',0};
3486 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3487 if (rc != ERROR_SUCCESS)
3488 return ERROR_SUCCESS;
3490 res = CoInitialize( NULL );
3492 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3493 msiobj_release(&view->hdr);
3501 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3503 MSIPACKAGE *package = param;
3508 component = MSI_RecordGetString( row, 4 );
3509 comp = get_loaded_component( package, component );
3511 return ERROR_SUCCESS;
3513 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3515 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3516 comp->Action = comp->Installed;
3517 return ERROR_SUCCESS;
3519 comp->Action = INSTALLSTATE_ABSENT;
3521 ui_actiondata( package, szRemoveShortcuts, row );
3523 link_file = get_link_file( package, row );
3525 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3526 if (!DeleteFileW( link_file ))
3528 WARN("Failed to remove shortcut file %u\n", GetLastError());
3530 msi_free( link_file );
3532 return ERROR_SUCCESS;
3535 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3539 static const WCHAR query[] =
3540 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3541 '`','S','h','o','r','t','c','u','t','`',0};
3543 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3544 if (rc != ERROR_SUCCESS)
3545 return ERROR_SUCCESS;
3547 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3548 msiobj_release( &view->hdr );
3553 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3555 MSIPACKAGE* package = param;
3563 FileName = MSI_RecordGetString(row,1);
3566 ERR("Unable to get FileName\n");
3567 return ERROR_SUCCESS;
3570 FilePath = build_icon_path(package,FileName);
3572 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3574 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3575 FILE_ATTRIBUTE_NORMAL, NULL);
3577 if (the_file == INVALID_HANDLE_VALUE)
3579 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3581 return ERROR_SUCCESS;
3588 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3589 if (rc != ERROR_SUCCESS)
3591 ERR("Failed to get stream\n");
3592 CloseHandle(the_file);
3593 DeleteFileW(FilePath);
3596 WriteFile(the_file,buffer,sz,&write,NULL);
3597 } while (sz == 1024);
3600 CloseHandle(the_file);
3602 return ERROR_SUCCESS;
3605 static UINT msi_publish_icons(MSIPACKAGE *package)
3610 static const WCHAR query[]= {
3611 'S','E','L','E','C','T',' ','*',' ',
3612 'F','R','O','M',' ','`','I','c','o','n','`',0};
3614 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3615 if (r == ERROR_SUCCESS)
3617 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3618 msiobj_release(&view->hdr);
3621 return ERROR_SUCCESS;
3624 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3630 MSISOURCELISTINFO *info;
3632 r = RegCreateKeyW(hkey, szSourceList, &source);
3633 if (r != ERROR_SUCCESS)
3636 RegCloseKey(source);
3638 buffer = strrchrW(package->PackagePath, '\\') + 1;
3639 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3640 package->Context, MSICODE_PRODUCT,
3641 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3642 if (r != ERROR_SUCCESS)
3645 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3646 package->Context, MSICODE_PRODUCT,
3647 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3648 if (r != ERROR_SUCCESS)
3651 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3652 package->Context, MSICODE_PRODUCT,
3653 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3654 if (r != ERROR_SUCCESS)
3657 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3659 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3660 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3661 info->options, info->value);
3663 MsiSourceListSetInfoW(package->ProductCode, NULL,
3664 info->context, info->options,
3665 info->property, info->value);
3668 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3670 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3671 disk->context, disk->options,
3672 disk->disk_id, disk->volume_label, disk->disk_prompt);
3675 return ERROR_SUCCESS;
3678 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3680 MSIHANDLE hdb, suminfo;
3681 WCHAR guids[MAX_PATH];
3682 WCHAR packcode[SQUISH_GUID_SIZE];
3689 static const WCHAR szProductLanguage[] =
3690 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3691 static const WCHAR szARPProductIcon[] =
3692 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3693 static const WCHAR szProductVersion[] =
3694 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3695 static const WCHAR szAssignment[] =
3696 {'A','s','s','i','g','n','m','e','n','t',0};
3697 static const WCHAR szAdvertiseFlags[] =
3698 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3699 static const WCHAR szClients[] =
3700 {'C','l','i','e','n','t','s',0};
3701 static const WCHAR szColon[] = {':',0};
3703 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3704 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3707 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3708 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3711 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3713 buffer = msi_dup_property(package->db, szARPProductIcon);
3716 LPWSTR path = build_icon_path(package,buffer);
3717 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3722 buffer = msi_dup_property(package->db, szProductVersion);
3725 DWORD verdword = msi_version_str_to_dword(buffer);
3726 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3730 msi_reg_set_val_dword(hkey, szAssignment, 0);
3731 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3732 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3733 msi_reg_set_val_str(hkey, szClients, szColon);
3735 hdb = alloc_msihandle(&package->db->hdr);
3737 return ERROR_NOT_ENOUGH_MEMORY;
3739 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3740 MsiCloseHandle(hdb);
3741 if (r != ERROR_SUCCESS)
3745 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3746 NULL, guids, &size);
3747 if (r != ERROR_SUCCESS)
3750 ptr = strchrW(guids, ';');
3752 squash_guid(guids, packcode);
3753 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3756 MsiCloseHandle(suminfo);
3757 return ERROR_SUCCESS;
3760 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3765 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3767 static const WCHAR szUpgradeCode[] =
3768 {'U','p','g','r','a','d','e','C','o','d','e',0};
3770 upgrade = msi_dup_property(package->db, szUpgradeCode);
3772 return ERROR_SUCCESS;
3774 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3776 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3777 if (r != ERROR_SUCCESS)
3782 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3783 if (r != ERROR_SUCCESS)
3787 squash_guid(package->ProductCode, squashed_pc);
3788 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3797 static BOOL msi_check_publish(MSIPACKAGE *package)
3799 MSIFEATURE *feature;
3801 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3803 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3810 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3812 MSIFEATURE *feature;
3814 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3816 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3823 static UINT msi_publish_patches( MSIPACKAGE *package, HKEY prodkey )
3825 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3826 WCHAR patch_squashed[GUID_SIZE];
3827 HKEY patches_key = NULL, product_patches_key;
3829 MSIPATCHINFO *patch;
3831 WCHAR *p, *all_patches = NULL;
3834 res = RegCreateKeyExW( prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3835 if (res != ERROR_SUCCESS)
3836 return ERROR_FUNCTION_FAILED;
3838 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3839 if (r != ERROR_SUCCESS)
3842 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3844 squash_guid( patch->patchcode, patch_squashed );
3845 len += strlenW( patch_squashed ) + 1;
3848 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3852 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3856 squash_guid( patch->patchcode, p );
3857 p += strlenW( p ) + 1;
3859 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3860 (const BYTE *)patch->transforms,
3861 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3862 if (res != ERROR_SUCCESS)
3865 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3866 if (r != ERROR_SUCCESS)
3869 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3870 (const BYTE *)patch->localfile,
3871 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3872 RegCloseKey( patch_key );
3873 if (res != ERROR_SUCCESS)
3876 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3877 RegCloseKey( patch_key );
3878 if (res != ERROR_SUCCESS)
3882 all_patches[len] = 0;
3883 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3884 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3885 if (res != ERROR_SUCCESS)
3888 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3889 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3890 if (res != ERROR_SUCCESS)
3891 r = ERROR_FUNCTION_FAILED;
3894 RegCloseKey( product_patches_key );
3895 RegCloseKey( patches_key );
3896 msi_free( all_patches );
3901 * 99% of the work done here is only done for
3902 * advertised installs. However this is where the
3903 * Icon table is processed and written out
3904 * so that is what I am going to do here.
3906 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3909 HKEY hukey = NULL, hudkey = NULL;
3912 /* FIXME: also need to publish if the product is in advertise mode */
3913 if (!msi_check_publish(package))
3914 return ERROR_SUCCESS;
3916 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3918 if (rc != ERROR_SUCCESS)
3921 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3922 NULL, &hudkey, TRUE);
3923 if (rc != ERROR_SUCCESS)
3926 rc = msi_publish_upgrade_code(package);
3927 if (rc != ERROR_SUCCESS)
3930 if (!list_empty(&package->patches))
3932 rc = msi_publish_patches(package, hukey);
3933 if (rc != ERROR_SUCCESS)
3937 rc = msi_publish_product_properties(package, hukey);
3938 if (rc != ERROR_SUCCESS)
3941 rc = msi_publish_sourcelist(package, hukey);
3942 if (rc != ERROR_SUCCESS)
3945 rc = msi_publish_icons(package);
3948 uirow = MSI_CreateRecord( 1 );
3949 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3950 ui_actiondata( package, szPublishProduct, uirow );
3951 msiobj_release( &uirow->hdr );
3954 RegCloseKey(hudkey);
3959 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3961 WCHAR *filename, *ptr, *folder, *ret;
3962 const WCHAR *dirprop;
3964 filename = msi_dup_record_field( row, 2 );
3965 if (filename && (ptr = strchrW( filename, '|' )))
3970 dirprop = MSI_RecordGetString( row, 3 );
3973 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3975 folder = msi_dup_property( package->db, dirprop );
3978 folder = msi_dup_property( package->db, szWindowsFolder );
3982 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3983 msi_free( filename );
3987 ret = build_directory_name( 2, folder, ptr );
3989 msi_free( filename );
3994 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3996 MSIPACKAGE *package = param;
3997 LPCWSTR component, section, key, value, identifier;
3998 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4003 component = MSI_RecordGetString(row, 8);
4004 comp = get_loaded_component(package,component);
4006 return ERROR_SUCCESS;
4008 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4010 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4011 comp->Action = comp->Installed;
4012 return ERROR_SUCCESS;
4014 comp->Action = INSTALLSTATE_LOCAL;
4016 identifier = MSI_RecordGetString(row,1);
4017 section = MSI_RecordGetString(row,4);
4018 key = MSI_RecordGetString(row,5);
4019 value = MSI_RecordGetString(row,6);
4020 action = MSI_RecordGetInteger(row,7);
4022 deformat_string(package,section,&deformated_section);
4023 deformat_string(package,key,&deformated_key);
4024 deformat_string(package,value,&deformated_value);
4026 fullname = get_ini_file_name(package, row);
4030 TRACE("Adding value %s to section %s in %s\n",
4031 debugstr_w(deformated_key), debugstr_w(deformated_section),
4032 debugstr_w(fullname));
4033 WritePrivateProfileStringW(deformated_section, deformated_key,
4034 deformated_value, fullname);
4036 else if (action == 1)
4039 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4040 returned, 10, fullname);
4041 if (returned[0] == 0)
4043 TRACE("Adding value %s to section %s in %s\n",
4044 debugstr_w(deformated_key), debugstr_w(deformated_section),
4045 debugstr_w(fullname));
4047 WritePrivateProfileStringW(deformated_section, deformated_key,
4048 deformated_value, fullname);
4051 else if (action == 3)
4052 FIXME("Append to existing section not yet implemented\n");
4054 uirow = MSI_CreateRecord(4);
4055 MSI_RecordSetStringW(uirow,1,identifier);
4056 MSI_RecordSetStringW(uirow,2,deformated_section);
4057 MSI_RecordSetStringW(uirow,3,deformated_key);
4058 MSI_RecordSetStringW(uirow,4,deformated_value);
4059 ui_actiondata(package,szWriteIniValues,uirow);
4060 msiobj_release( &uirow->hdr );
4063 msi_free(deformated_key);
4064 msi_free(deformated_value);
4065 msi_free(deformated_section);
4066 return ERROR_SUCCESS;
4069 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4073 static const WCHAR ExecSeqQuery[] =
4074 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4075 '`','I','n','i','F','i','l','e','`',0};
4077 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4078 if (rc != ERROR_SUCCESS)
4080 TRACE("no IniFile table\n");
4081 return ERROR_SUCCESS;
4084 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4085 msiobj_release(&view->hdr);
4089 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4091 MSIPACKAGE *package = param;
4092 LPCWSTR component, section, key, value, identifier;
4093 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4098 component = MSI_RecordGetString( row, 8 );
4099 comp = get_loaded_component( package, component );
4101 return ERROR_SUCCESS;
4103 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4105 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4106 comp->Action = comp->Installed;
4107 return ERROR_SUCCESS;
4109 comp->Action = INSTALLSTATE_ABSENT;
4111 identifier = MSI_RecordGetString( row, 1 );
4112 section = MSI_RecordGetString( row, 4 );
4113 key = MSI_RecordGetString( row, 5 );
4114 value = MSI_RecordGetString( row, 6 );
4115 action = MSI_RecordGetInteger( row, 7 );
4117 deformat_string( package, section, &deformated_section );
4118 deformat_string( package, key, &deformated_key );
4119 deformat_string( package, value, &deformated_value );
4121 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4123 filename = get_ini_file_name( package, row );
4125 TRACE("Removing key %s from section %s in %s\n",
4126 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4128 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4130 WARN("Unable to remove key %u\n", GetLastError());
4132 msi_free( filename );
4135 FIXME("Unsupported action %d\n", action);
4138 uirow = MSI_CreateRecord( 4 );
4139 MSI_RecordSetStringW( uirow, 1, identifier );
4140 MSI_RecordSetStringW( uirow, 2, deformated_section );
4141 MSI_RecordSetStringW( uirow, 3, deformated_key );
4142 MSI_RecordSetStringW( uirow, 4, deformated_value );
4143 ui_actiondata( package, szRemoveIniValues, uirow );
4144 msiobj_release( &uirow->hdr );
4146 msi_free( deformated_key );
4147 msi_free( deformated_value );
4148 msi_free( deformated_section );
4149 return ERROR_SUCCESS;
4152 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4154 MSIPACKAGE *package = param;
4155 LPCWSTR component, section, key, value, identifier;
4156 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4161 component = MSI_RecordGetString( row, 8 );
4162 comp = get_loaded_component( package, component );
4164 return ERROR_SUCCESS;
4166 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4168 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4169 comp->Action = comp->Installed;
4170 return ERROR_SUCCESS;
4172 comp->Action = INSTALLSTATE_LOCAL;
4174 identifier = MSI_RecordGetString( row, 1 );
4175 section = MSI_RecordGetString( row, 4 );
4176 key = MSI_RecordGetString( row, 5 );
4177 value = MSI_RecordGetString( row, 6 );
4178 action = MSI_RecordGetInteger( row, 7 );
4180 deformat_string( package, section, &deformated_section );
4181 deformat_string( package, key, &deformated_key );
4182 deformat_string( package, value, &deformated_value );
4184 if (action == msidbIniFileActionRemoveLine)
4186 filename = get_ini_file_name( package, row );
4188 TRACE("Removing key %s from section %s in %s\n",
4189 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4191 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4193 WARN("Unable to remove key %u\n", GetLastError());
4195 msi_free( filename );
4198 FIXME("Unsupported action %d\n", action);
4200 uirow = MSI_CreateRecord( 4 );
4201 MSI_RecordSetStringW( uirow, 1, identifier );
4202 MSI_RecordSetStringW( uirow, 2, deformated_section );
4203 MSI_RecordSetStringW( uirow, 3, deformated_key );
4204 MSI_RecordSetStringW( uirow, 4, deformated_value );
4205 ui_actiondata( package, szRemoveIniValues, uirow );
4206 msiobj_release( &uirow->hdr );
4208 msi_free( deformated_key );
4209 msi_free( deformated_value );
4210 msi_free( deformated_section );
4211 return ERROR_SUCCESS;
4214 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4218 static const WCHAR query[] =
4219 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4220 '`','I','n','i','F','i','l','e','`',0};
4221 static const WCHAR remove_query[] =
4222 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4223 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4225 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4226 if (rc == ERROR_SUCCESS)
4228 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4229 msiobj_release( &view->hdr );
4230 if (rc != ERROR_SUCCESS)
4234 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4235 if (rc == ERROR_SUCCESS)
4237 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4238 msiobj_release( &view->hdr );
4239 if (rc != ERROR_SUCCESS)
4243 return ERROR_SUCCESS;
4246 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4248 MSIPACKAGE *package = param;
4253 static const WCHAR ExeStr[] =
4254 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4255 static const WCHAR close[] = {'\"',0};
4257 PROCESS_INFORMATION info;
4261 memset(&si,0,sizeof(STARTUPINFOW));
4263 filename = MSI_RecordGetString(row,1);
4264 file = get_loaded_file( package, filename );
4268 ERR("Unable to find file id %s\n",debugstr_w(filename));
4269 return ERROR_SUCCESS;
4272 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4274 FullName = msi_alloc(len*sizeof(WCHAR));
4275 strcpyW(FullName,ExeStr);
4276 strcatW( FullName, file->TargetPath );
4277 strcatW(FullName,close);
4279 TRACE("Registering %s\n",debugstr_w(FullName));
4280 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4285 CloseHandle(info.hThread);
4286 msi_dialog_check_messages(info.hProcess);
4287 CloseHandle(info.hProcess);
4290 uirow = MSI_CreateRecord( 2 );
4291 MSI_RecordSetStringW( uirow, 1, filename );
4292 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4293 ui_actiondata( package, szSelfRegModules, uirow );
4294 msiobj_release( &uirow->hdr );
4296 msi_free( FullName );
4297 return ERROR_SUCCESS;
4300 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4304 static const WCHAR ExecSeqQuery[] =
4305 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4306 '`','S','e','l','f','R','e','g','`',0};
4308 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4309 if (rc != ERROR_SUCCESS)
4311 TRACE("no SelfReg table\n");
4312 return ERROR_SUCCESS;
4315 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4316 msiobj_release(&view->hdr);
4318 return ERROR_SUCCESS;
4321 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4323 static const WCHAR regsvr32[] =
4324 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4325 static const WCHAR close[] = {'\"',0};
4326 MSIPACKAGE *package = param;
4332 PROCESS_INFORMATION pi;
4336 memset( &si, 0, sizeof(STARTUPINFOW) );
4338 filename = MSI_RecordGetString( row, 1 );
4339 file = get_loaded_file( package, filename );
4343 ERR("Unable to find file id %s\n", debugstr_w(filename));
4344 return ERROR_SUCCESS;
4347 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4349 cmdline = msi_alloc( len * sizeof(WCHAR) );
4350 strcpyW( cmdline, regsvr32 );
4351 strcatW( cmdline, file->TargetPath );
4352 strcatW( cmdline, close );
4354 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4356 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4359 CloseHandle( pi.hThread );
4360 msi_dialog_check_messages( pi.hProcess );
4361 CloseHandle( pi.hProcess );
4364 uirow = MSI_CreateRecord( 2 );
4365 MSI_RecordSetStringW( uirow, 1, filename );
4366 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4367 ui_actiondata( package, szSelfUnregModules, uirow );
4368 msiobj_release( &uirow->hdr );
4370 msi_free( cmdline );
4371 return ERROR_SUCCESS;
4374 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4378 static const WCHAR query[] =
4379 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4380 '`','S','e','l','f','R','e','g','`',0};
4382 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4383 if (rc != ERROR_SUCCESS)
4385 TRACE("no SelfReg table\n");
4386 return ERROR_SUCCESS;
4389 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4390 msiobj_release( &view->hdr );
4392 return ERROR_SUCCESS;
4395 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4397 MSIFEATURE *feature;
4399 HKEY hkey = NULL, userdata = NULL;
4401 if (!msi_check_publish(package))
4402 return ERROR_SUCCESS;
4404 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4406 if (rc != ERROR_SUCCESS)
4409 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4411 if (rc != ERROR_SUCCESS)
4414 /* here the guids are base 85 encoded */
4415 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4421 BOOL absent = FALSE;
4424 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4425 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4426 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4429 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4433 if (feature->Feature_Parent)
4434 size += strlenW( feature->Feature_Parent )+2;
4436 data = msi_alloc(size * sizeof(WCHAR));
4439 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4441 MSICOMPONENT* component = cl->component;
4445 if (component->ComponentId)
4447 TRACE("From %s\n",debugstr_w(component->ComponentId));
4448 CLSIDFromString(component->ComponentId, &clsid);
4449 encode_base85_guid(&clsid,buf);
4450 TRACE("to %s\n",debugstr_w(buf));
4455 if (feature->Feature_Parent)
4457 static const WCHAR sep[] = {'\2',0};
4459 strcatW(data,feature->Feature_Parent);
4462 msi_reg_set_val_str( userdata, feature->Feature, data );
4466 if (feature->Feature_Parent)
4467 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4470 size += sizeof(WCHAR);
4471 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4472 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4476 size += 2*sizeof(WCHAR);
4477 data = msi_alloc(size);
4480 if (feature->Feature_Parent)
4481 strcpyW( &data[1], feature->Feature_Parent );
4482 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4488 uirow = MSI_CreateRecord( 1 );
4489 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4490 ui_actiondata( package, szPublishFeatures, uirow);
4491 msiobj_release( &uirow->hdr );
4492 /* FIXME: call ui_progress? */
4497 RegCloseKey(userdata);
4501 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4507 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4509 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4511 if (r == ERROR_SUCCESS)
4513 RegDeleteValueW(hkey, feature->Feature);
4517 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4519 if (r == ERROR_SUCCESS)
4521 RegDeleteValueW(hkey, feature->Feature);
4525 uirow = MSI_CreateRecord( 1 );
4526 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4527 ui_actiondata( package, szUnpublishFeatures, uirow );
4528 msiobj_release( &uirow->hdr );
4530 return ERROR_SUCCESS;
4533 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4535 MSIFEATURE *feature;
4537 if (!msi_check_unpublish(package))
4538 return ERROR_SUCCESS;
4540 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4542 msi_unpublish_feature(package, feature);
4545 return ERROR_SUCCESS;
4548 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4552 WCHAR date[9], *val, *buffer;
4553 const WCHAR *prop, *key;
4555 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4556 static const WCHAR szWindowsInstaller[] =
4557 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4558 static const WCHAR modpath_fmt[] =
4559 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4560 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4561 static const WCHAR szModifyPath[] =
4562 {'M','o','d','i','f','y','P','a','t','h',0};
4563 static const WCHAR szUninstallString[] =
4564 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4565 static const WCHAR szEstimatedSize[] =
4566 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4567 static const WCHAR szProductLanguage[] =
4568 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4569 static const WCHAR szProductVersion[] =
4570 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4571 static const WCHAR szDisplayVersion[] =
4572 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4573 static const WCHAR szInstallSource[] =
4574 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4575 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4576 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4577 static const WCHAR szAuthorizedCDFPrefix[] =
4578 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4579 static const WCHAR szARPCONTACT[] =
4580 {'A','R','P','C','O','N','T','A','C','T',0};
4581 static const WCHAR szContact[] =
4582 {'C','o','n','t','a','c','t',0};
4583 static const WCHAR szARPCOMMENTS[] =
4584 {'A','R','P','C','O','M','M','E','N','T','S',0};
4585 static const WCHAR szComments[] =
4586 {'C','o','m','m','e','n','t','s',0};
4587 static const WCHAR szProductName[] =
4588 {'P','r','o','d','u','c','t','N','a','m','e',0};
4589 static const WCHAR szDisplayName[] =
4590 {'D','i','s','p','l','a','y','N','a','m','e',0};
4591 static const WCHAR szARPHELPLINK[] =
4592 {'A','R','P','H','E','L','P','L','I','N','K',0};
4593 static const WCHAR szHelpLink[] =
4594 {'H','e','l','p','L','i','n','k',0};
4595 static const WCHAR szARPHELPTELEPHONE[] =
4596 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4597 static const WCHAR szHelpTelephone[] =
4598 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4599 static const WCHAR szARPINSTALLLOCATION[] =
4600 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4601 static const WCHAR szInstallLocation[] =
4602 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4603 static const WCHAR szManufacturer[] =
4604 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4605 static const WCHAR szPublisher[] =
4606 {'P','u','b','l','i','s','h','e','r',0};
4607 static const WCHAR szARPREADME[] =
4608 {'A','R','P','R','E','A','D','M','E',0};
4609 static const WCHAR szReadme[] =
4610 {'R','e','a','d','M','e',0};
4611 static const WCHAR szARPSIZE[] =
4612 {'A','R','P','S','I','Z','E',0};
4613 static const WCHAR szSize[] =
4614 {'S','i','z','e',0};
4615 static const WCHAR szARPURLINFOABOUT[] =
4616 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4617 static const WCHAR szURLInfoAbout[] =
4618 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4619 static const WCHAR szARPURLUPDATEINFO[] =
4620 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4621 static const WCHAR szURLUpdateInfo[] =
4622 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4624 static const WCHAR *propval[] = {
4625 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4626 szARPCONTACT, szContact,
4627 szARPCOMMENTS, szComments,
4628 szProductName, szDisplayName,
4629 szARPHELPLINK, szHelpLink,
4630 szARPHELPTELEPHONE, szHelpTelephone,
4631 szARPINSTALLLOCATION, szInstallLocation,
4632 cszSourceDir, szInstallSource,
4633 szManufacturer, szPublisher,
4634 szARPREADME, szReadme,
4636 szARPURLINFOABOUT, szURLInfoAbout,
4637 szARPURLUPDATEINFO, szURLUpdateInfo,
4640 const WCHAR **p = propval;
4646 val = msi_dup_property(package->db, prop);
4647 msi_reg_set_val_str(hkey, key, val);
4651 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4653 size = deformat_string(package, modpath_fmt, &buffer);
4654 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4655 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4658 /* FIXME: Write real Estimated Size when we have it */
4659 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4661 GetLocalTime(&systime);
4662 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4663 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4665 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4666 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4668 buffer = msi_dup_property(package->db, szProductVersion);
4669 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4672 DWORD verdword = msi_version_str_to_dword(buffer);
4674 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4675 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4676 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4680 return ERROR_SUCCESS;
4683 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4685 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4687 LPWSTR upgrade_code;
4692 static const WCHAR szUpgradeCode[] = {
4693 'U','p','g','r','a','d','e','C','o','d','e',0};
4695 /* FIXME: also need to publish if the product is in advertise mode */
4696 if (!msi_check_publish(package))
4697 return ERROR_SUCCESS;
4699 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4700 if (rc != ERROR_SUCCESS)
4703 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4704 NULL, &props, TRUE);
4705 if (rc != ERROR_SUCCESS)
4708 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4709 msi_free( package->db->localfile );
4710 package->db->localfile = NULL;
4712 rc = msi_publish_install_properties(package, hkey);
4713 if (rc != ERROR_SUCCESS)
4716 rc = msi_publish_install_properties(package, props);
4717 if (rc != ERROR_SUCCESS)
4720 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4723 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4724 squash_guid(package->ProductCode, squashed_pc);
4725 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4726 RegCloseKey(upgrade);
4727 msi_free(upgrade_code);
4731 uirow = MSI_CreateRecord( 1 );
4732 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4733 ui_actiondata( package, szRegisterProduct, uirow );
4734 msiobj_release( &uirow->hdr );
4737 return ERROR_SUCCESS;
4740 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4742 return execute_script(package,INSTALL_SCRIPT);
4745 static UINT msi_unpublish_product(MSIPACKAGE *package)
4748 LPWSTR remove = NULL;
4749 LPWSTR *features = NULL;
4750 BOOL full_uninstall = TRUE;
4751 MSIFEATURE *feature;
4752 MSIPATCHINFO *patch;
4754 static const WCHAR szUpgradeCode[] =
4755 {'U','p','g','r','a','d','e','C','o','d','e',0};
4757 remove = msi_dup_property(package->db, szRemove);
4759 return ERROR_SUCCESS;
4761 features = msi_split_string(remove, ',');
4765 ERR("REMOVE feature list is empty!\n");
4766 return ERROR_FUNCTION_FAILED;
4769 if (!lstrcmpW(features[0], szAll))
4770 full_uninstall = TRUE;
4773 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4775 if (feature->Action != INSTALLSTATE_ABSENT)
4776 full_uninstall = FALSE;
4780 if (!full_uninstall)
4783 MSIREG_DeleteProductKey(package->ProductCode);
4784 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4785 MSIREG_DeleteUninstallKey(package->ProductCode);
4787 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4789 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4790 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4794 MSIREG_DeleteUserProductKey(package->ProductCode);
4795 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4798 upgrade = msi_dup_property(package->db, szUpgradeCode);
4801 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4805 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4807 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4813 return ERROR_SUCCESS;
4816 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4820 rc = msi_unpublish_product(package);
4821 if (rc != ERROR_SUCCESS)
4824 /* turn off scheduling */
4825 package->script->CurrentlyScripting= FALSE;
4827 /* first do the same as an InstallExecute */
4828 rc = ACTION_InstallExecute(package);
4829 if (rc != ERROR_SUCCESS)
4832 /* then handle Commit Actions */
4833 rc = execute_script(package,COMMIT_SCRIPT);
4838 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4840 static const WCHAR RunOnce[] = {
4841 'S','o','f','t','w','a','r','e','\\',
4842 'M','i','c','r','o','s','o','f','t','\\',
4843 'W','i','n','d','o','w','s','\\',
4844 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4845 'R','u','n','O','n','c','e',0};
4846 static const WCHAR InstallRunOnce[] = {
4847 'S','o','f','t','w','a','r','e','\\',
4848 'M','i','c','r','o','s','o','f','t','\\',
4849 'W','i','n','d','o','w','s','\\',
4850 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4851 'I','n','s','t','a','l','l','e','r','\\',
4852 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4854 static const WCHAR msiexec_fmt[] = {
4856 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4857 '\"','%','s','\"',0};
4858 static const WCHAR install_fmt[] = {
4859 '/','I',' ','\"','%','s','\"',' ',
4860 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4861 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4862 WCHAR buffer[256], sysdir[MAX_PATH];
4864 WCHAR squished_pc[100];
4866 squash_guid(package->ProductCode,squished_pc);
4868 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4869 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4870 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4873 msi_reg_set_val_str( hkey, squished_pc, buffer );
4876 TRACE("Reboot command %s\n",debugstr_w(buffer));
4878 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4879 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4881 msi_reg_set_val_str( hkey, squished_pc, buffer );
4884 return ERROR_INSTALL_SUSPEND;
4887 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4893 * We are currently doing what should be done here in the top level Install
4894 * however for Administrative and uninstalls this step will be needed
4896 if (!package->PackagePath)
4897 return ERROR_SUCCESS;
4899 msi_set_sourcedir_props(package, TRUE);
4901 attrib = GetFileAttributesW(package->db->path);
4902 if (attrib == INVALID_FILE_ATTRIBUTES)
4908 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4909 package->Context, MSICODE_PRODUCT,
4910 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4911 if (rc == ERROR_MORE_DATA)
4913 prompt = msi_alloc(size * sizeof(WCHAR));
4914 MsiSourceListGetInfoW(package->ProductCode, NULL,
4915 package->Context, MSICODE_PRODUCT,
4916 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4919 prompt = strdupW(package->db->path);
4921 msg = generate_error_string(package,1302,1,prompt);
4922 while(attrib == INVALID_FILE_ATTRIBUTES)
4924 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4927 rc = ERROR_INSTALL_USEREXIT;
4930 attrib = GetFileAttributesW(package->db->path);
4936 return ERROR_SUCCESS;
4941 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4944 LPWSTR buffer, productid = NULL;
4945 UINT i, rc = ERROR_SUCCESS;
4948 static const WCHAR szPropKeys[][80] =
4950 {'P','r','o','d','u','c','t','I','D',0},
4951 {'U','S','E','R','N','A','M','E',0},
4952 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4956 static const WCHAR szRegKeys[][80] =
4958 {'P','r','o','d','u','c','t','I','D',0},
4959 {'R','e','g','O','w','n','e','r',0},
4960 {'R','e','g','C','o','m','p','a','n','y',0},
4964 if (msi_check_unpublish(package))
4966 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4970 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
4974 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4976 if (rc != ERROR_SUCCESS)
4979 for( i = 0; szPropKeys[i][0]; i++ )
4981 buffer = msi_dup_property( package->db, szPropKeys[i] );
4982 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4987 uirow = MSI_CreateRecord( 1 );
4988 MSI_RecordSetStringW( uirow, 1, productid );
4989 ui_actiondata( package, szRegisterUser, uirow );
4990 msiobj_release( &uirow->hdr );
4992 msi_free(productid);
4998 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5002 package->script->InWhatSequence |= SEQUENCE_EXEC;
5003 rc = ACTION_ProcessExecSequence(package,FALSE);
5008 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5010 MSIPACKAGE *package = param;
5011 LPCWSTR compgroupid, component, feature, qualifier, text;
5012 LPWSTR advertise = NULL, output = NULL;
5020 feature = MSI_RecordGetString(rec, 5);
5021 feat = get_loaded_feature(package, feature);
5023 return ERROR_SUCCESS;
5025 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5026 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5027 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5029 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5030 feat->Action = feat->Installed;
5031 return ERROR_SUCCESS;
5034 component = MSI_RecordGetString(rec, 3);
5035 comp = get_loaded_component(package, component);
5037 return ERROR_SUCCESS;
5039 compgroupid = MSI_RecordGetString(rec,1);
5040 qualifier = MSI_RecordGetString(rec,2);
5042 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5043 if (rc != ERROR_SUCCESS)
5046 text = MSI_RecordGetString(rec,4);
5047 advertise = create_component_advertise_string(package, comp, feature);
5049 sz = strlenW(advertise);
5052 sz += lstrlenW(text);
5055 sz *= sizeof(WCHAR);
5057 output = msi_alloc_zero(sz);
5058 strcpyW(output,advertise);
5059 msi_free(advertise);
5062 strcatW(output,text);
5064 msi_reg_set_val_multi_str( hkey, qualifier, output );
5071 uirow = MSI_CreateRecord( 2 );
5072 MSI_RecordSetStringW( uirow, 1, compgroupid );
5073 MSI_RecordSetStringW( uirow, 2, qualifier);
5074 ui_actiondata( package, szPublishComponents, uirow);
5075 msiobj_release( &uirow->hdr );
5076 /* FIXME: call ui_progress? */
5082 * At present I am ignorning the advertised components part of this and only
5083 * focusing on the qualified component sets
5085 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5089 static const WCHAR ExecSeqQuery[] =
5090 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5091 '`','P','u','b','l','i','s','h',
5092 'C','o','m','p','o','n','e','n','t','`',0};
5094 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5095 if (rc != ERROR_SUCCESS)
5096 return ERROR_SUCCESS;
5098 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5099 msiobj_release(&view->hdr);
5104 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5106 static const WCHAR szInstallerComponents[] = {
5107 'S','o','f','t','w','a','r','e','\\',
5108 'M','i','c','r','o','s','o','f','t','\\',
5109 'I','n','s','t','a','l','l','e','r','\\',
5110 'C','o','m','p','o','n','e','n','t','s','\\',0};
5112 MSIPACKAGE *package = param;
5113 LPCWSTR compgroupid, component, feature, qualifier;
5117 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5120 feature = MSI_RecordGetString( rec, 5 );
5121 feat = get_loaded_feature( package, feature );
5123 return ERROR_SUCCESS;
5125 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5127 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5128 feat->Action = feat->Installed;
5129 return ERROR_SUCCESS;
5132 component = MSI_RecordGetString( rec, 3 );
5133 comp = get_loaded_component( package, component );
5135 return ERROR_SUCCESS;
5137 compgroupid = MSI_RecordGetString( rec, 1 );
5138 qualifier = MSI_RecordGetString( rec, 2 );
5140 squash_guid( compgroupid, squashed );
5141 strcpyW( keypath, szInstallerComponents );
5142 strcatW( keypath, squashed );
5144 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5145 if (res != ERROR_SUCCESS)
5147 WARN("Unable to delete component key %d\n", res);
5150 uirow = MSI_CreateRecord( 2 );
5151 MSI_RecordSetStringW( uirow, 1, compgroupid );
5152 MSI_RecordSetStringW( uirow, 2, qualifier );
5153 ui_actiondata( package, szUnpublishComponents, uirow );
5154 msiobj_release( &uirow->hdr );
5156 return ERROR_SUCCESS;
5159 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5163 static const WCHAR query[] =
5164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5165 '`','P','u','b','l','i','s','h',
5166 'C','o','m','p','o','n','e','n','t','`',0};
5168 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5169 if (rc != ERROR_SUCCESS)
5170 return ERROR_SUCCESS;
5172 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5173 msiobj_release( &view->hdr );
5178 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5180 MSIPACKAGE *package = param;
5183 SC_HANDLE hscm, service = NULL;
5184 LPCWSTR comp, depends, pass;
5185 LPWSTR name = NULL, disp = NULL;
5186 LPCWSTR load_order, serv_name, key;
5187 DWORD serv_type, start_type;
5190 static const WCHAR query[] =
5191 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5192 '`','C','o','m','p','o','n','e','n','t','`',' ',
5193 'W','H','E','R','E',' ',
5194 '`','C','o','m','p','o','n','e','n','t','`',' ',
5195 '=','\'','%','s','\'',0};
5197 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5200 ERR("Failed to open the SC Manager!\n");
5204 start_type = MSI_RecordGetInteger(rec, 5);
5205 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5208 depends = MSI_RecordGetString(rec, 8);
5209 if (depends && *depends)
5210 FIXME("Dependency list unhandled!\n");
5212 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5213 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5214 serv_type = MSI_RecordGetInteger(rec, 4);
5215 err_control = MSI_RecordGetInteger(rec, 6);
5216 load_order = MSI_RecordGetString(rec, 7);
5217 serv_name = MSI_RecordGetString(rec, 9);
5218 pass = MSI_RecordGetString(rec, 10);
5219 comp = MSI_RecordGetString(rec, 12);
5221 /* fetch the service path */
5222 row = MSI_QueryGetRecord(package->db, query, comp);
5225 ERR("Control query failed!\n");
5229 key = MSI_RecordGetString(row, 6);
5231 file = get_loaded_file(package, key);
5232 msiobj_release(&row->hdr);
5235 ERR("Failed to load the service file\n");
5239 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5240 start_type, err_control, file->TargetPath,
5241 load_order, NULL, NULL, serv_name, pass);
5244 if (GetLastError() != ERROR_SERVICE_EXISTS)
5245 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5249 CloseServiceHandle(service);
5250 CloseServiceHandle(hscm);
5254 return ERROR_SUCCESS;
5257 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5261 static const WCHAR ExecSeqQuery[] =
5262 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5263 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5265 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5266 if (rc != ERROR_SUCCESS)
5267 return ERROR_SUCCESS;
5269 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5270 msiobj_release(&view->hdr);
5275 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5276 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5278 LPCWSTR *vector, *temp_vector;
5282 static const WCHAR separator[] = {'[','~',']',0};
5285 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5290 vector = msi_alloc(sizeof(LPWSTR));
5298 vector[*numargs - 1] = p;
5300 if ((q = strstrW(p, separator)))
5304 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5310 vector = temp_vector;
5319 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5321 MSIPACKAGE *package = param;
5324 SC_HANDLE scm = NULL, service = NULL;
5325 LPCWSTR component, *vector = NULL;
5326 LPWSTR name, args, display_name = NULL;
5327 DWORD event, numargs, len;
5328 UINT r = ERROR_FUNCTION_FAILED;
5330 component = MSI_RecordGetString(rec, 6);
5331 comp = get_loaded_component(package, component);
5333 return ERROR_SUCCESS;
5335 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5337 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5338 comp->Action = comp->Installed;
5339 return ERROR_SUCCESS;
5341 comp->Action = INSTALLSTATE_LOCAL;
5343 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5344 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5345 event = MSI_RecordGetInteger(rec, 3);
5347 if (!(event & msidbServiceControlEventStart))
5353 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5356 ERR("Failed to open the service control manager\n");
5361 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5362 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5364 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5365 GetServiceDisplayNameW( scm, name, display_name, &len );
5368 service = OpenServiceW(scm, name, SERVICE_START);
5371 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5375 vector = msi_service_args_to_vector(args, &numargs);
5377 if (!StartServiceW(service, numargs, vector) &&
5378 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5380 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5387 uirow = MSI_CreateRecord( 2 );
5388 MSI_RecordSetStringW( uirow, 1, display_name );
5389 MSI_RecordSetStringW( uirow, 2, name );
5390 ui_actiondata( package, szStartServices, uirow );
5391 msiobj_release( &uirow->hdr );
5393 CloseServiceHandle(service);
5394 CloseServiceHandle(scm);
5399 msi_free(display_name);
5403 static UINT ACTION_StartServices( MSIPACKAGE *package )
5408 static const WCHAR query[] = {
5409 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5410 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5412 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5413 if (rc != ERROR_SUCCESS)
5414 return ERROR_SUCCESS;
5416 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5417 msiobj_release(&view->hdr);
5422 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5424 DWORD i, needed, count;
5425 ENUM_SERVICE_STATUSW *dependencies;
5429 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5430 0, &needed, &count))
5433 if (GetLastError() != ERROR_MORE_DATA)
5436 dependencies = msi_alloc(needed);
5440 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5441 needed, &needed, &count))
5444 for (i = 0; i < count; i++)
5446 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5447 SERVICE_STOP | SERVICE_QUERY_STATUS);
5451 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5458 msi_free(dependencies);
5462 static UINT stop_service( LPCWSTR name )
5464 SC_HANDLE scm = NULL, service = NULL;
5465 SERVICE_STATUS status;
5466 SERVICE_STATUS_PROCESS ssp;
5469 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5472 WARN("Failed to open the SCM: %d\n", GetLastError());
5476 service = OpenServiceW(scm, name,
5478 SERVICE_QUERY_STATUS |
5479 SERVICE_ENUMERATE_DEPENDENTS);
5482 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5486 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5487 sizeof(SERVICE_STATUS_PROCESS), &needed))
5489 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5493 if (ssp.dwCurrentState == SERVICE_STOPPED)
5496 stop_service_dependents(scm, service);
5498 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5499 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5502 CloseServiceHandle(service);
5503 CloseServiceHandle(scm);
5505 return ERROR_SUCCESS;
5508 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5510 MSIPACKAGE *package = param;
5514 LPWSTR name = NULL, display_name = NULL;
5518 event = MSI_RecordGetInteger( rec, 3 );
5519 if (!(event & msidbServiceControlEventStop))
5520 return ERROR_SUCCESS;
5522 component = MSI_RecordGetString( rec, 6 );
5523 comp = get_loaded_component( package, component );
5525 return ERROR_SUCCESS;
5527 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5529 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5530 comp->Action = comp->Installed;
5531 return ERROR_SUCCESS;
5533 comp->Action = INSTALLSTATE_ABSENT;
5535 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5538 ERR("Failed to open the service control manager\n");
5543 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5544 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5546 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5547 GetServiceDisplayNameW( scm, name, display_name, &len );
5549 CloseServiceHandle( scm );
5551 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5552 stop_service( name );
5555 uirow = MSI_CreateRecord( 2 );
5556 MSI_RecordSetStringW( uirow, 1, display_name );
5557 MSI_RecordSetStringW( uirow, 2, name );
5558 ui_actiondata( package, szStopServices, uirow );
5559 msiobj_release( &uirow->hdr );
5562 msi_free( display_name );
5563 return ERROR_SUCCESS;
5566 static UINT ACTION_StopServices( MSIPACKAGE *package )
5571 static const WCHAR query[] = {
5572 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5573 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5575 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5576 if (rc != ERROR_SUCCESS)
5577 return ERROR_SUCCESS;
5579 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5580 msiobj_release(&view->hdr);
5585 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5587 MSIPACKAGE *package = param;
5591 LPWSTR name = NULL, display_name = NULL;
5593 SC_HANDLE scm = NULL, service = NULL;
5595 event = MSI_RecordGetInteger( rec, 3 );
5596 if (!(event & msidbServiceControlEventDelete))
5597 return ERROR_SUCCESS;
5599 component = MSI_RecordGetString(rec, 6);
5600 comp = get_loaded_component(package, component);
5602 return ERROR_SUCCESS;
5604 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5606 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5607 comp->Action = comp->Installed;
5608 return ERROR_SUCCESS;
5610 comp->Action = INSTALLSTATE_ABSENT;
5612 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5613 stop_service( name );
5615 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5618 WARN("Failed to open the SCM: %d\n", GetLastError());
5623 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5624 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5626 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5627 GetServiceDisplayNameW( scm, name, display_name, &len );
5630 service = OpenServiceW( scm, name, DELETE );
5633 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5637 if (!DeleteService( service ))
5638 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5641 uirow = MSI_CreateRecord( 2 );
5642 MSI_RecordSetStringW( uirow, 1, display_name );
5643 MSI_RecordSetStringW( uirow, 2, name );
5644 ui_actiondata( package, szDeleteServices, uirow );
5645 msiobj_release( &uirow->hdr );
5647 CloseServiceHandle( service );
5648 CloseServiceHandle( scm );
5650 msi_free( display_name );
5652 return ERROR_SUCCESS;
5655 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5660 static const WCHAR query[] = {
5661 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5662 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5664 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5665 if (rc != ERROR_SUCCESS)
5666 return ERROR_SUCCESS;
5668 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5669 msiobj_release( &view->hdr );
5674 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5678 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5680 if (!lstrcmpW(file->File, filename))
5687 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5689 MSIPACKAGE *package = param;
5690 LPWSTR driver, driver_path, ptr;
5691 WCHAR outpath[MAX_PATH];
5692 MSIFILE *driver_file, *setup_file;
5696 UINT r = ERROR_SUCCESS;
5698 static const WCHAR driver_fmt[] = {
5699 'D','r','i','v','e','r','=','%','s',0};
5700 static const WCHAR setup_fmt[] = {
5701 'S','e','t','u','p','=','%','s',0};
5702 static const WCHAR usage_fmt[] = {
5703 'F','i','l','e','U','s','a','g','e','=','1',0};
5705 desc = MSI_RecordGetString(rec, 3);
5707 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5708 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5712 ERR("ODBC Driver entry not found!\n");
5713 return ERROR_FUNCTION_FAILED;
5716 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5718 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5719 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5721 driver = msi_alloc(len * sizeof(WCHAR));
5723 return ERROR_OUTOFMEMORY;
5726 lstrcpyW(ptr, desc);
5727 ptr += lstrlenW(ptr) + 1;
5729 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5734 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5738 lstrcpyW(ptr, usage_fmt);
5739 ptr += lstrlenW(ptr) + 1;
5742 driver_path = strdupW(driver_file->TargetPath);
5743 ptr = strrchrW(driver_path, '\\');
5744 if (ptr) *ptr = '\0';
5746 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5747 NULL, ODBC_INSTALL_COMPLETE, &usage))
5749 ERR("Failed to install SQL driver!\n");
5750 r = ERROR_FUNCTION_FAILED;
5753 uirow = MSI_CreateRecord( 5 );
5754 MSI_RecordSetStringW( uirow, 1, desc );
5755 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5756 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5757 ui_actiondata( package, szInstallODBC, uirow );
5758 msiobj_release( &uirow->hdr );
5761 msi_free(driver_path);
5766 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5768 MSIPACKAGE *package = param;
5769 LPWSTR translator, translator_path, ptr;
5770 WCHAR outpath[MAX_PATH];
5771 MSIFILE *translator_file, *setup_file;
5775 UINT r = ERROR_SUCCESS;
5777 static const WCHAR translator_fmt[] = {
5778 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5779 static const WCHAR setup_fmt[] = {
5780 'S','e','t','u','p','=','%','s',0};
5782 desc = MSI_RecordGetString(rec, 3);
5784 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5785 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5787 if (!translator_file)
5789 ERR("ODBC Translator entry not found!\n");
5790 return ERROR_FUNCTION_FAILED;
5793 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5795 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5797 translator = msi_alloc(len * sizeof(WCHAR));
5799 return ERROR_OUTOFMEMORY;
5802 lstrcpyW(ptr, desc);
5803 ptr += lstrlenW(ptr) + 1;
5805 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5810 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5815 translator_path = strdupW(translator_file->TargetPath);
5816 ptr = strrchrW(translator_path, '\\');
5817 if (ptr) *ptr = '\0';
5819 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5820 NULL, ODBC_INSTALL_COMPLETE, &usage))
5822 ERR("Failed to install SQL translator!\n");
5823 r = ERROR_FUNCTION_FAILED;
5826 uirow = MSI_CreateRecord( 5 );
5827 MSI_RecordSetStringW( uirow, 1, desc );
5828 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5829 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5830 ui_actiondata( package, szInstallODBC, uirow );
5831 msiobj_release( &uirow->hdr );
5833 msi_free(translator);
5834 msi_free(translator_path);
5839 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5841 MSIPACKAGE *package = param;
5843 LPCWSTR desc, driver;
5844 WORD request = ODBC_ADD_SYS_DSN;
5847 UINT r = ERROR_SUCCESS;
5850 static const WCHAR attrs_fmt[] = {
5851 'D','S','N','=','%','s',0 };
5853 desc = MSI_RecordGetString(rec, 3);
5854 driver = MSI_RecordGetString(rec, 4);
5855 registration = MSI_RecordGetInteger(rec, 5);
5857 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5858 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5860 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5861 attrs = msi_alloc(len * sizeof(WCHAR));
5863 return ERROR_OUTOFMEMORY;
5865 len = sprintfW(attrs, attrs_fmt, desc);
5868 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5870 ERR("Failed to install SQL data source!\n");
5871 r = ERROR_FUNCTION_FAILED;
5874 uirow = MSI_CreateRecord( 5 );
5875 MSI_RecordSetStringW( uirow, 1, desc );
5876 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5877 MSI_RecordSetInteger( uirow, 3, request );
5878 ui_actiondata( package, szInstallODBC, uirow );
5879 msiobj_release( &uirow->hdr );
5886 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5891 static const WCHAR driver_query[] = {
5892 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5893 'O','D','B','C','D','r','i','v','e','r',0 };
5895 static const WCHAR translator_query[] = {
5896 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5897 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5899 static const WCHAR source_query[] = {
5900 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5901 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5903 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5904 if (rc != ERROR_SUCCESS)
5905 return ERROR_SUCCESS;
5907 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5908 msiobj_release(&view->hdr);
5910 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5911 if (rc != ERROR_SUCCESS)
5912 return ERROR_SUCCESS;
5914 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5915 msiobj_release(&view->hdr);
5917 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5918 if (rc != ERROR_SUCCESS)
5919 return ERROR_SUCCESS;
5921 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5922 msiobj_release(&view->hdr);
5927 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5929 MSIPACKAGE *package = param;
5934 desc = MSI_RecordGetString( rec, 3 );
5935 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5937 WARN("Failed to remove ODBC driver\n");
5941 FIXME("Usage count reached 0\n");
5944 uirow = MSI_CreateRecord( 2 );
5945 MSI_RecordSetStringW( uirow, 1, desc );
5946 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5947 ui_actiondata( package, szRemoveODBC, uirow );
5948 msiobj_release( &uirow->hdr );
5950 return ERROR_SUCCESS;
5953 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5955 MSIPACKAGE *package = param;
5960 desc = MSI_RecordGetString( rec, 3 );
5961 if (!SQLRemoveTranslatorW( desc, &usage ))
5963 WARN("Failed to remove ODBC translator\n");
5967 FIXME("Usage count reached 0\n");
5970 uirow = MSI_CreateRecord( 2 );
5971 MSI_RecordSetStringW( uirow, 1, desc );
5972 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5973 ui_actiondata( package, szRemoveODBC, uirow );
5974 msiobj_release( &uirow->hdr );
5976 return ERROR_SUCCESS;
5979 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5981 MSIPACKAGE *package = param;
5984 LPCWSTR desc, driver;
5985 WORD request = ODBC_REMOVE_SYS_DSN;
5989 static const WCHAR attrs_fmt[] = {
5990 'D','S','N','=','%','s',0 };
5992 desc = MSI_RecordGetString( rec, 3 );
5993 driver = MSI_RecordGetString( rec, 4 );
5994 registration = MSI_RecordGetInteger( rec, 5 );
5996 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5997 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5999 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6000 attrs = msi_alloc( len * sizeof(WCHAR) );
6002 return ERROR_OUTOFMEMORY;
6004 FIXME("Use ODBCSourceAttribute table\n");
6006 len = sprintfW( attrs, attrs_fmt, desc );
6009 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6011 WARN("Failed to remove ODBC data source\n");
6015 uirow = MSI_CreateRecord( 3 );
6016 MSI_RecordSetStringW( uirow, 1, desc );
6017 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6018 MSI_RecordSetInteger( uirow, 3, request );
6019 ui_actiondata( package, szRemoveODBC, uirow );
6020 msiobj_release( &uirow->hdr );
6022 return ERROR_SUCCESS;
6025 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6030 static const WCHAR driver_query[] = {
6031 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6032 'O','D','B','C','D','r','i','v','e','r',0 };
6034 static const WCHAR translator_query[] = {
6035 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6036 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6038 static const WCHAR source_query[] = {
6039 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6040 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6042 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6043 if (rc != ERROR_SUCCESS)
6044 return ERROR_SUCCESS;
6046 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6047 msiobj_release( &view->hdr );
6049 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6050 if (rc != ERROR_SUCCESS)
6051 return ERROR_SUCCESS;
6053 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6054 msiobj_release( &view->hdr );
6056 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6057 if (rc != ERROR_SUCCESS)
6058 return ERROR_SUCCESS;
6060 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6061 msiobj_release( &view->hdr );
6066 #define ENV_ACT_SETALWAYS 0x1
6067 #define ENV_ACT_SETABSENT 0x2
6068 #define ENV_ACT_REMOVE 0x4
6069 #define ENV_ACT_REMOVEMATCH 0x8
6071 #define ENV_MOD_MACHINE 0x20000000
6072 #define ENV_MOD_APPEND 0x40000000
6073 #define ENV_MOD_PREFIX 0x80000000
6074 #define ENV_MOD_MASK 0xC0000000
6076 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6078 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6080 LPCWSTR cptr = *name;
6082 static const WCHAR prefix[] = {'[','~',']',0};
6083 static const int prefix_len = 3;
6089 *flags |= ENV_ACT_SETALWAYS;
6090 else if (*cptr == '+')
6091 *flags |= ENV_ACT_SETABSENT;
6092 else if (*cptr == '-')
6093 *flags |= ENV_ACT_REMOVE;
6094 else if (*cptr == '!')
6095 *flags |= ENV_ACT_REMOVEMATCH;
6096 else if (*cptr == '*')
6097 *flags |= ENV_MOD_MACHINE;
6107 ERR("Missing environment variable\n");
6108 return ERROR_FUNCTION_FAILED;
6113 LPCWSTR ptr = *value;
6114 if (!strncmpW(ptr, prefix, prefix_len))
6116 if (ptr[prefix_len] == szSemiColon[0])
6118 *flags |= ENV_MOD_APPEND;
6119 *value += lstrlenW(prefix);
6126 else if (lstrlenW(*value) >= prefix_len)
6128 ptr += lstrlenW(ptr) - prefix_len;
6129 if (!lstrcmpW(ptr, prefix))
6131 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6133 *flags |= ENV_MOD_PREFIX;
6134 /* the "[~]" will be removed by deformat_string */;
6144 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6145 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6146 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6147 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6149 ERR("Invalid flags: %08x\n", *flags);
6150 return ERROR_FUNCTION_FAILED;
6154 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6156 return ERROR_SUCCESS;
6159 static UINT open_env_key( DWORD flags, HKEY *key )
6161 static const WCHAR user_env[] =
6162 {'E','n','v','i','r','o','n','m','e','n','t',0};
6163 static const WCHAR machine_env[] =
6164 {'S','y','s','t','e','m','\\',
6165 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6166 'C','o','n','t','r','o','l','\\',
6167 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6168 'E','n','v','i','r','o','n','m','e','n','t',0};
6173 if (flags & ENV_MOD_MACHINE)
6176 root = HKEY_LOCAL_MACHINE;
6181 root = HKEY_CURRENT_USER;
6184 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6185 if (res != ERROR_SUCCESS)
6187 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6188 return ERROR_FUNCTION_FAILED;
6191 return ERROR_SUCCESS;
6194 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6196 MSIPACKAGE *package = param;
6197 LPCWSTR name, value, component;
6198 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6199 DWORD flags, type, size;
6206 component = MSI_RecordGetString(rec, 4);
6207 comp = get_loaded_component(package, component);
6209 return ERROR_SUCCESS;
6211 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6213 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6214 comp->Action = comp->Installed;
6215 return ERROR_SUCCESS;
6217 comp->Action = INSTALLSTATE_LOCAL;
6219 name = MSI_RecordGetString(rec, 2);
6220 value = MSI_RecordGetString(rec, 3);
6222 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6224 res = env_parse_flags(&name, &value, &flags);
6225 if (res != ERROR_SUCCESS || !value)
6228 if (value && !deformat_string(package, value, &deformatted))
6230 res = ERROR_OUTOFMEMORY;
6234 value = deformatted;
6236 res = open_env_key( flags, &env );
6237 if (res != ERROR_SUCCESS)
6240 if (flags & ENV_MOD_MACHINE)
6241 action |= 0x20000000;
6245 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6246 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6247 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6250 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6254 /* Nothing to do. */
6257 res = ERROR_SUCCESS;
6261 /* If we are appending but the string was empty, strip ; */
6262 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6264 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6265 newval = strdupW(value);
6268 res = ERROR_OUTOFMEMORY;
6276 /* Contrary to MSDN, +-variable to [~];path works */
6277 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6279 res = ERROR_SUCCESS;
6283 data = msi_alloc(size);
6287 return ERROR_OUTOFMEMORY;
6290 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6291 if (res != ERROR_SUCCESS)
6294 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6297 res = RegDeleteValueW(env, name);
6298 if (res != ERROR_SUCCESS)
6299 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6303 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6304 if (flags & ENV_MOD_MASK)
6308 if (flags & ENV_MOD_APPEND) multiplier++;
6309 if (flags & ENV_MOD_PREFIX) multiplier++;
6310 mod_size = lstrlenW(value) * multiplier;
6311 size += mod_size * sizeof(WCHAR);
6314 newval = msi_alloc(size);
6318 res = ERROR_OUTOFMEMORY;
6322 if (flags & ENV_MOD_PREFIX)
6324 lstrcpyW(newval, value);
6325 ptr = newval + lstrlenW(value);
6326 action |= 0x80000000;
6329 lstrcpyW(ptr, data);
6331 if (flags & ENV_MOD_APPEND)
6333 lstrcatW(newval, value);
6334 action |= 0x40000000;
6337 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6338 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6341 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6345 uirow = MSI_CreateRecord( 3 );
6346 MSI_RecordSetStringW( uirow, 1, name );
6347 MSI_RecordSetStringW( uirow, 2, newval );
6348 MSI_RecordSetInteger( uirow, 3, action );
6349 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6350 msiobj_release( &uirow->hdr );
6352 if (env) RegCloseKey(env);
6353 msi_free(deformatted);
6359 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6363 static const WCHAR ExecSeqQuery[] =
6364 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6365 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6366 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6367 if (rc != ERROR_SUCCESS)
6368 return ERROR_SUCCESS;
6370 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6371 msiobj_release(&view->hdr);
6376 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6378 MSIPACKAGE *package = param;
6379 LPCWSTR name, value, component;
6380 LPWSTR deformatted = NULL;
6389 component = MSI_RecordGetString( rec, 4 );
6390 comp = get_loaded_component( package, component );
6392 return ERROR_SUCCESS;
6394 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6396 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6397 comp->Action = comp->Installed;
6398 return ERROR_SUCCESS;
6400 comp->Action = INSTALLSTATE_ABSENT;
6402 name = MSI_RecordGetString( rec, 2 );
6403 value = MSI_RecordGetString( rec, 3 );
6405 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6407 r = env_parse_flags( &name, &value, &flags );
6408 if (r != ERROR_SUCCESS)
6411 if (!(flags & ENV_ACT_REMOVE))
6413 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6414 return ERROR_SUCCESS;
6417 if (value && !deformat_string( package, value, &deformatted ))
6418 return ERROR_OUTOFMEMORY;
6420 value = deformatted;
6422 r = open_env_key( flags, &env );
6423 if (r != ERROR_SUCCESS)
6429 if (flags & ENV_MOD_MACHINE)
6430 action |= 0x20000000;
6432 TRACE("Removing %s\n", debugstr_w(name));
6434 res = RegDeleteValueW( env, name );
6435 if (res != ERROR_SUCCESS)
6437 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6442 uirow = MSI_CreateRecord( 3 );
6443 MSI_RecordSetStringW( uirow, 1, name );
6444 MSI_RecordSetStringW( uirow, 2, value );
6445 MSI_RecordSetInteger( uirow, 3, action );
6446 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6447 msiobj_release( &uirow->hdr );
6449 if (env) RegCloseKey( env );
6450 msi_free( deformatted );
6454 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6458 static const WCHAR query[] =
6459 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6460 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6462 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6463 if (rc != ERROR_SUCCESS)
6464 return ERROR_SUCCESS;
6466 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6467 msiobj_release( &view->hdr );
6472 typedef struct tagMSIASSEMBLY
6475 MSICOMPONENT *component;
6476 MSIFEATURE *feature;
6480 LPWSTR display_name;
6485 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6487 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6488 LPVOID pvReserved, HMODULE *phModDll);
6490 static BOOL init_functionpointers(void)
6496 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6498 hmscoree = LoadLibraryA("mscoree.dll");
6501 WARN("mscoree.dll not available\n");
6505 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6506 if (!pLoadLibraryShim)
6508 WARN("LoadLibraryShim not available\n");
6509 FreeLibrary(hmscoree);
6513 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6516 WARN("fusion.dll not available\n");
6517 FreeLibrary(hmscoree);
6521 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6523 FreeLibrary(hmscoree);
6527 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6530 IAssemblyCache *cache;
6533 UINT r = ERROR_FUNCTION_FAILED;
6535 TRACE("installing assembly: %s\n", debugstr_w(path));
6537 uirow = MSI_CreateRecord( 2 );
6538 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6539 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6540 msiobj_release( &uirow->hdr );
6542 if (assembly->feature)
6543 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6545 if (assembly->manifest)
6546 FIXME("Manifest unhandled\n");
6548 if (assembly->application)
6550 FIXME("Assembly should be privately installed\n");
6551 return ERROR_SUCCESS;
6554 if (assembly->attributes == msidbAssemblyAttributesWin32)
6556 FIXME("Win32 assemblies not handled\n");
6557 return ERROR_SUCCESS;
6560 hr = pCreateAssemblyCache(&cache, 0);
6564 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6566 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6571 IAssemblyCache_Release(cache);
6575 typedef struct tagASSEMBLY_LIST
6577 MSIPACKAGE *package;
6578 IAssemblyCache *cache;
6579 struct list *assemblies;
6582 typedef struct tagASSEMBLY_NAME
6590 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6592 ASSEMBLY_NAME *asmname = param;
6593 LPCWSTR name = MSI_RecordGetString(rec, 2);
6594 LPWSTR val = msi_dup_record_field(rec, 3);
6596 static const WCHAR Name[] = {'N','a','m','e',0};
6597 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6598 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6599 static const WCHAR PublicKeyToken[] = {
6600 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6602 if (!strcmpiW(name, Name))
6603 asmname->name = val;
6604 else if (!strcmpiW(name, Version))
6605 asmname->version = val;
6606 else if (!strcmpiW(name, Culture))
6607 asmname->culture = val;
6608 else if (!strcmpiW(name, PublicKeyToken))
6609 asmname->pubkeytoken = val;
6613 return ERROR_SUCCESS;
6616 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6620 *size = lstrlenW(append) + 1;
6621 *str = msi_alloc((*size) * sizeof(WCHAR));
6622 lstrcpyW(*str, append);
6626 (*size) += lstrlenW(append);
6627 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6628 lstrcatW(*str, append);
6631 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6633 static const WCHAR separator[] = {',',' ',0};
6634 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6635 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6636 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6637 static const WCHAR query[] = {
6638 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6639 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6640 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6641 '=','\'','%','s','\'',0};
6644 LPWSTR display_name;
6648 display_name = NULL;
6649 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6651 r = MSI_OpenQuery( db, &view, query, comp->Component );
6652 if (r != ERROR_SUCCESS)
6655 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6656 msiobj_release( &view->hdr );
6660 ERR("No assembly name specified!\n");
6664 append_str( &display_name, &size, name.name );
6668 append_str( &display_name, &size, separator );
6669 append_str( &display_name, &size, Version );
6670 append_str( &display_name, &size, name.version );
6674 append_str( &display_name, &size, separator );
6675 append_str( &display_name, &size, Culture );
6676 append_str( &display_name, &size, name.culture );
6678 if (name.pubkeytoken)
6680 append_str( &display_name, &size, separator );
6681 append_str( &display_name, &size, PublicKeyToken );
6682 append_str( &display_name, &size, name.pubkeytoken );
6685 msi_free( name.name );
6686 msi_free( name.version );
6687 msi_free( name.culture );
6688 msi_free( name.pubkeytoken );
6690 return display_name;
6693 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6695 ASSEMBLY_INFO asminfo;
6700 disp = get_assembly_display_name( db, comp );
6704 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6705 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6707 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6709 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6715 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6717 ASSEMBLY_LIST *list = param;
6718 MSIASSEMBLY *assembly;
6721 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6723 return ERROR_OUTOFMEMORY;
6725 component = MSI_RecordGetString(rec, 1);
6726 assembly->component = get_loaded_component(list->package, component);
6727 if (!assembly->component)
6728 return ERROR_SUCCESS;
6730 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6731 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6733 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6734 assembly->component->Action = assembly->component->Installed;
6735 return ERROR_SUCCESS;
6737 assembly->component->Action = assembly->component->ActionRequest;
6739 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6740 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6742 if (!assembly->file)
6744 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6745 return ERROR_FUNCTION_FAILED;
6748 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6749 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6750 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6752 if (assembly->application)
6755 DWORD size = sizeof(version)/sizeof(WCHAR);
6757 /* FIXME: we should probably check the manifest file here */
6759 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6760 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6762 assembly->installed = TRUE;
6766 assembly->installed = check_assembly_installed(list->package->db,
6768 assembly->component);
6770 list_add_head(list->assemblies, &assembly->entry);
6771 return ERROR_SUCCESS;
6774 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6776 IAssemblyCache *cache = NULL;
6782 static const WCHAR query[] =
6783 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6784 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6786 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6787 if (r != ERROR_SUCCESS)
6788 return ERROR_SUCCESS;
6790 hr = pCreateAssemblyCache(&cache, 0);
6792 return ERROR_FUNCTION_FAILED;
6794 list.package = package;
6796 list.assemblies = assemblies;
6798 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6799 msiobj_release(&view->hdr);
6801 IAssemblyCache_Release(cache);
6806 static void free_assemblies(struct list *assemblies)
6808 struct list *item, *cursor;
6810 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6812 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6814 list_remove(&assembly->entry);
6815 msi_free(assembly->application);
6816 msi_free(assembly->manifest);
6817 msi_free(assembly->display_name);
6822 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6824 MSIASSEMBLY *assembly;
6826 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6828 if (!lstrcmpW(assembly->file->File, file))
6838 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6839 LPWSTR *path, DWORD *attrs, PVOID user)
6841 MSIASSEMBLY *assembly;
6842 WCHAR temppath[MAX_PATH];
6843 struct list *assemblies = user;
6846 if (!find_assembly(assemblies, file, &assembly))
6849 GetTempPathW(MAX_PATH, temppath);
6850 PathAddBackslashW(temppath);
6851 lstrcatW(temppath, assembly->file->FileName);
6853 if (action == MSICABEXTRACT_BEGINEXTRACT)
6855 if (assembly->installed)
6858 *path = strdupW(temppath);
6859 *attrs = assembly->file->Attributes;
6861 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6863 assembly->installed = TRUE;
6865 r = install_assembly(package, assembly, temppath);
6866 if (r != ERROR_SUCCESS)
6867 ERR("Failed to install assembly\n");
6873 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6876 struct list assemblies = LIST_INIT(assemblies);
6877 MSIASSEMBLY *assembly;
6880 if (!init_functionpointers() || !pCreateAssemblyCache)
6881 return ERROR_FUNCTION_FAILED;
6883 r = load_assemblies(package, &assemblies);
6884 if (r != ERROR_SUCCESS)
6887 if (list_empty(&assemblies))
6890 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6893 r = ERROR_OUTOFMEMORY;
6897 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6899 if (assembly->installed && !mi->is_continuous)
6902 if (assembly->file->IsCompressed)
6904 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
6908 r = ready_media(package, assembly->file, mi);
6909 if (r != ERROR_SUCCESS)
6911 ERR("Failed to ready media\n");
6916 data.package = package;
6917 data.cb = installassembly_cb;
6918 data.user = &assemblies;
6920 if (!msi_cabextract(package, mi, &data))
6922 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6923 r = ERROR_FUNCTION_FAILED;
6930 LPWSTR source = resolve_file_source(package, assembly->file);
6932 r = install_assembly(package, assembly, source);
6933 if (r != ERROR_SUCCESS)
6934 ERR("Failed to install assembly\n");
6939 /* FIXME: write Installer assembly reg values */
6943 free_assemblies(&assemblies);
6947 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6949 LPWSTR key, template, id;
6950 UINT r = ERROR_SUCCESS;
6952 id = msi_dup_property( package->db, szProductID );
6956 return ERROR_SUCCESS;
6958 template = msi_dup_property( package->db, szPIDTemplate );
6959 key = msi_dup_property( package->db, szPIDKEY );
6961 if (key && template)
6963 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6964 r = msi_set_property( package->db, szProductID, key );
6966 msi_free( template );
6971 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6974 package->need_reboot = 1;
6975 return ERROR_SUCCESS;
6978 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6980 static const WCHAR szAvailableFreeReg[] =
6981 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6983 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6985 TRACE("%p %d kilobytes\n", package, space);
6987 uirow = MSI_CreateRecord( 1 );
6988 MSI_RecordSetInteger( uirow, 1, space );
6989 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6990 msiobj_release( &uirow->hdr );
6992 return ERROR_SUCCESS;
6995 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6997 FIXME("%p\n", package);
6998 return ERROR_SUCCESS;
7001 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7003 FIXME("%p\n", package);
7004 return ERROR_SUCCESS;
7007 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7012 static const WCHAR driver_query[] = {
7013 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7014 'O','D','B','C','D','r','i','v','e','r',0 };
7016 static const WCHAR translator_query[] = {
7017 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7018 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7020 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7021 if (r == ERROR_SUCCESS)
7024 r = MSI_IterateRecords( view, &count, NULL, package );
7025 msiobj_release( &view->hdr );
7026 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7029 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7030 if (r == ERROR_SUCCESS)
7033 r = MSI_IterateRecords( view, &count, NULL, package );
7034 msiobj_release( &view->hdr );
7035 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7038 return ERROR_SUCCESS;
7041 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7042 LPCSTR action, LPCWSTR table )
7044 static const WCHAR query[] = {
7045 'S','E','L','E','C','T',' ','*',' ',
7046 'F','R','O','M',' ','`','%','s','`',0 };
7047 MSIQUERY *view = NULL;
7051 r = MSI_OpenQuery( package->db, &view, query, table );
7052 if (r == ERROR_SUCCESS)
7054 r = MSI_IterateRecords(view, &count, NULL, package);
7055 msiobj_release(&view->hdr);
7059 FIXME("%s -> %u ignored %s table values\n",
7060 action, count, debugstr_w(table));
7062 return ERROR_SUCCESS;
7065 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7067 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7068 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7071 static UINT ACTION_BindImage( MSIPACKAGE *package )
7073 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7074 return msi_unimplemented_action_stub( package, "BindImage", table );
7077 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7079 static const WCHAR table[] = {
7080 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7081 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7084 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7086 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7087 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7090 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7092 static const WCHAR table[] = {
7093 'M','s','i','A','s','s','e','m','b','l','y',0 };
7094 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7097 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7099 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7100 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7103 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7105 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7106 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7109 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7111 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7112 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7115 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7117 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7118 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7121 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7123 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7124 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7127 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7131 const WCHAR *action;
7132 UINT (*handler)(MSIPACKAGE *);
7136 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7137 { szAppSearch, ACTION_AppSearch },
7138 { szBindImage, ACTION_BindImage },
7139 { szCCPSearch, ACTION_CCPSearch },
7140 { szCostFinalize, ACTION_CostFinalize },
7141 { szCostInitialize, ACTION_CostInitialize },
7142 { szCreateFolders, ACTION_CreateFolders },
7143 { szCreateShortcuts, ACTION_CreateShortcuts },
7144 { szDeleteServices, ACTION_DeleteServices },
7145 { szDisableRollback, ACTION_DisableRollback },
7146 { szDuplicateFiles, ACTION_DuplicateFiles },
7147 { szExecuteAction, ACTION_ExecuteAction },
7148 { szFileCost, ACTION_FileCost },
7149 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7150 { szForceReboot, ACTION_ForceReboot },
7151 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7152 { szInstallExecute, ACTION_InstallExecute },
7153 { szInstallExecuteAgain, ACTION_InstallExecute },
7154 { szInstallFiles, ACTION_InstallFiles},
7155 { szInstallFinalize, ACTION_InstallFinalize },
7156 { szInstallInitialize, ACTION_InstallInitialize },
7157 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7158 { szInstallValidate, ACTION_InstallValidate },
7159 { szIsolateComponents, ACTION_IsolateComponents },
7160 { szLaunchConditions, ACTION_LaunchConditions },
7161 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7162 { szMoveFiles, ACTION_MoveFiles },
7163 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7164 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7165 { szInstallODBC, ACTION_InstallODBC },
7166 { szInstallServices, ACTION_InstallServices },
7167 { szPatchFiles, ACTION_PatchFiles },
7168 { szProcessComponents, ACTION_ProcessComponents },
7169 { szPublishComponents, ACTION_PublishComponents },
7170 { szPublishFeatures, ACTION_PublishFeatures },
7171 { szPublishProduct, ACTION_PublishProduct },
7172 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7173 { szRegisterComPlus, ACTION_RegisterComPlus},
7174 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7175 { szRegisterFonts, ACTION_RegisterFonts },
7176 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7177 { szRegisterProduct, ACTION_RegisterProduct },
7178 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7179 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7180 { szRegisterUser, ACTION_RegisterUser },
7181 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7182 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7183 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7184 { szRemoveFiles, ACTION_RemoveFiles },
7185 { szRemoveFolders, ACTION_RemoveFolders },
7186 { szRemoveIniValues, ACTION_RemoveIniValues },
7187 { szRemoveODBC, ACTION_RemoveODBC },
7188 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7189 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7190 { szResolveSource, ACTION_ResolveSource },
7191 { szRMCCPSearch, ACTION_RMCCPSearch },
7192 { szScheduleReboot, ACTION_ScheduleReboot },
7193 { szSelfRegModules, ACTION_SelfRegModules },
7194 { szSelfUnregModules, ACTION_SelfUnregModules },
7195 { szSetODBCFolders, ACTION_SetODBCFolders },
7196 { szStartServices, ACTION_StartServices },
7197 { szStopServices, ACTION_StopServices },
7198 { szUnpublishComponents, ACTION_UnpublishComponents },
7199 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7200 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7201 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7202 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7203 { szUnregisterFonts, ACTION_UnregisterFonts },
7204 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7205 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7206 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7207 { szValidateProductID, ACTION_ValidateProductID },
7208 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7209 { szWriteIniValues, ACTION_WriteIniValues },
7210 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7214 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7215 UINT* rc, BOOL force )
7221 if (!run && !package->script->CurrentlyScripting)
7226 if (strcmpW(action,szInstallFinalize) == 0 ||
7227 strcmpW(action,szInstallExecute) == 0 ||
7228 strcmpW(action,szInstallExecuteAgain) == 0)
7233 while (StandardActions[i].action != NULL)
7235 if (strcmpW(StandardActions[i].action, action)==0)
7239 ui_actioninfo(package, action, TRUE, 0);
7240 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7241 ui_actioninfo(package, action, FALSE, *rc);
7245 ui_actionstart(package, action);
7246 if (StandardActions[i].handler)
7248 *rc = StandardActions[i].handler(package);
7252 FIXME("unhandled standard action %s\n",debugstr_w(action));
7253 *rc = ERROR_SUCCESS;
7264 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7266 UINT rc = ERROR_SUCCESS;
7269 TRACE("Performing action (%s)\n", debugstr_w(action));
7271 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7274 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7278 WARN("unhandled msi action %s\n", debugstr_w(action));
7279 rc = ERROR_FUNCTION_NOT_CALLED;
7285 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7287 UINT rc = ERROR_SUCCESS;
7288 BOOL handled = FALSE;
7290 TRACE("Performing action (%s)\n", debugstr_w(action));
7292 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7295 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7297 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7302 WARN("unhandled msi action %s\n", debugstr_w(action));
7303 rc = ERROR_FUNCTION_NOT_CALLED;
7309 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7311 UINT rc = ERROR_SUCCESS;
7314 static const WCHAR ExecSeqQuery[] =
7315 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7316 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7317 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7318 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7319 static const WCHAR UISeqQuery[] =
7320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7321 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7322 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7323 ' ', '=',' ','%','i',0};
7325 if (needs_ui_sequence(package))
7326 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7328 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7332 LPCWSTR action, cond;
7334 TRACE("Running the actions\n");
7336 /* check conditions */
7337 cond = MSI_RecordGetString(row, 2);
7339 /* this is a hack to skip errors in the condition code */
7340 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7342 msiobj_release(&row->hdr);
7343 return ERROR_SUCCESS;
7346 action = MSI_RecordGetString(row, 1);
7349 ERR("failed to fetch action\n");
7350 msiobj_release(&row->hdr);
7351 return ERROR_FUNCTION_FAILED;
7354 if (needs_ui_sequence(package))
7355 rc = ACTION_PerformUIAction(package, action, -1);
7357 rc = ACTION_PerformAction(package, action, -1, FALSE);
7359 msiobj_release(&row->hdr);
7365 /****************************************************
7366 * TOP level entry points
7367 *****************************************************/
7369 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7370 LPCWSTR szCommandLine )
7375 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7376 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7378 msi_set_property( package->db, szAction, szInstall );
7380 package->script->InWhatSequence = SEQUENCE_INSTALL;
7387 dir = strdupW(szPackagePath);
7388 p = strrchrW(dir, '\\');
7392 file = szPackagePath + (p - dir);
7397 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7398 GetCurrentDirectoryW(MAX_PATH, dir);
7399 lstrcatW(dir, szBackSlash);
7400 file = szPackagePath;
7403 msi_free( package->PackagePath );
7404 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7405 if (!package->PackagePath)
7408 return ERROR_OUTOFMEMORY;
7411 lstrcpyW(package->PackagePath, dir);
7412 lstrcatW(package->PackagePath, file);
7415 msi_set_sourcedir_props(package, FALSE);
7418 msi_parse_command_line( package, szCommandLine, FALSE );
7420 msi_apply_transforms( package );
7421 msi_apply_patches( package );
7423 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7425 TRACE("setting reinstall property\n");
7426 msi_set_property( package->db, szReinstall, szAll );
7429 /* properties may have been added by a transform */
7430 msi_clone_properties( package );
7431 msi_set_context( package );
7433 if (needs_ui_sequence( package))
7435 package->script->InWhatSequence |= SEQUENCE_UI;
7436 rc = ACTION_ProcessUISequence(package);
7437 ui_exists = ui_sequence_exists(package);
7438 if (rc == ERROR_SUCCESS || !ui_exists)
7440 package->script->InWhatSequence |= SEQUENCE_EXEC;
7441 rc = ACTION_ProcessExecSequence(package, ui_exists);
7445 rc = ACTION_ProcessExecSequence(package, FALSE);
7447 package->script->CurrentlyScripting = FALSE;
7449 /* process the ending type action */
7450 if (rc == ERROR_SUCCESS)
7451 ACTION_PerformActionSequence(package, -1);
7452 else if (rc == ERROR_INSTALL_USEREXIT)
7453 ACTION_PerformActionSequence(package, -2);
7454 else if (rc == ERROR_INSTALL_SUSPEND)
7455 ACTION_PerformActionSequence(package, -4);
7457 ACTION_PerformActionSequence(package, -3);
7459 /* finish up running custom actions */
7460 ACTION_FinishCustomActions(package);
7462 if (rc == ERROR_SUCCESS && package->need_reboot)
7463 return ERROR_SUCCESS_REBOOT_REQUIRED;