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 patch->state = MSIPATCHSTATE_APPLIED;
571 list_add_tail( &package->patches, &patch->entry );
572 return ERROR_SUCCESS;
575 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
577 static const WCHAR dotmsp[] = {'.','m','s','p',0};
578 MSIDATABASE *patch_db = NULL;
579 WCHAR localfile[MAX_PATH];
581 MSIPATCHINFO *patch = NULL;
582 UINT r = ERROR_SUCCESS;
584 TRACE("%p %s\n", package, debugstr_w( file ) );
586 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
587 if ( r != ERROR_SUCCESS )
589 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
593 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
596 msiobj_release( &patch_db->hdr );
597 return ERROR_FUNCTION_FAILED;
600 r = msi_check_patch_applicable( package, si );
601 if (r != ERROR_SUCCESS)
603 TRACE("patch not applicable\n");
608 r = msi_parse_patch_summary( si, &patch );
609 if ( r != ERROR_SUCCESS )
612 r = msi_get_local_package_name( localfile, dotmsp );
613 if ( r != ERROR_SUCCESS )
616 TRACE("copying to local package %s\n", debugstr_w(localfile));
618 if (!CopyFileW( file, localfile, FALSE ))
620 ERR("Unable to copy package (%s -> %s) (error %u)\n",
621 debugstr_w(file), debugstr_w(localfile), GetLastError());
625 patch->localfile = strdupW( localfile );
627 r = msi_apply_patch_db( package, patch_db, patch );
628 if ( r != ERROR_SUCCESS )
629 WARN("patch failed to apply %u\n", r);
632 msiobj_release( &si->hdr );
633 msiobj_release( &patch_db->hdr );
634 if (patch && r != ERROR_SUCCESS)
636 if (patch->localfile)
637 DeleteFileW( patch->localfile );
639 msi_free( patch->patchcode );
640 msi_free( patch->transforms );
641 msi_free( patch->localfile );
647 /* get the PATCH property, and apply all the patches it specifies */
648 static UINT msi_apply_patches( MSIPACKAGE *package )
650 LPWSTR patch_list, *patches;
651 UINT i, r = ERROR_SUCCESS;
653 patch_list = msi_dup_property( package->db, szPatch );
655 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
657 patches = msi_split_string( patch_list, ';' );
658 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
659 r = msi_apply_patch_package( package, patches[i] );
662 msi_free( patch_list );
667 static UINT msi_apply_transforms( MSIPACKAGE *package )
669 static const WCHAR szTransforms[] = {
670 'T','R','A','N','S','F','O','R','M','S',0 };
671 LPWSTR xform_list, *xforms;
672 UINT i, r = ERROR_SUCCESS;
674 xform_list = msi_dup_property( package->db, szTransforms );
675 xforms = msi_split_string( xform_list, ';' );
677 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
679 if (xforms[i][0] == ':')
680 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
682 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
686 msi_free( xform_list );
691 static BOOL ui_sequence_exists( MSIPACKAGE *package )
696 static const WCHAR ExecSeqQuery [] =
697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
698 '`','I','n','s','t','a','l','l',
699 'U','I','S','e','q','u','e','n','c','e','`',
700 ' ','W','H','E','R','E',' ',
701 '`','S','e','q','u','e','n','c','e','`',' ',
702 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
703 '`','S','e','q','u','e','n','c','e','`',0};
705 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
706 if (rc == ERROR_SUCCESS)
708 msiobj_release(&view->hdr);
715 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
717 LPWSTR source, check;
719 if (msi_get_property_int( package->db, szInstalled, 0 ))
723 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
724 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
732 db = msi_dup_property( package->db, szOriginalDatabase );
734 return ERROR_OUTOFMEMORY;
736 p = strrchrW( db, '\\' );
739 p = strrchrW( db, '/' );
743 return ERROR_SUCCESS;
748 source = msi_alloc( len * sizeof(WCHAR) );
749 lstrcpynW( source, db, len );
753 check = msi_dup_property( package->db, cszSourceDir );
754 if (!check || replace)
756 UINT r = msi_set_property( package->db, cszSourceDir, source );
757 if (r == ERROR_SUCCESS)
758 msi_reset_folders( package, TRUE );
762 check = msi_dup_property( package->db, cszSOURCEDIR );
763 if (!check || replace)
764 msi_set_property( package->db, cszSOURCEDIR, source );
769 return ERROR_SUCCESS;
772 static BOOL needs_ui_sequence(MSIPACKAGE *package)
774 INT level = msi_get_property_int(package->db, szUILevel, 0);
775 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
778 UINT msi_set_context(MSIPACKAGE *package)
782 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
784 num = msi_get_property_int(package->db, szAllUsers, 0);
785 if (num == 1 || num == 2)
786 package->Context = MSIINSTALLCONTEXT_MACHINE;
788 return ERROR_SUCCESS;
791 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
794 LPCWSTR cond, action;
795 MSIPACKAGE *package = param;
797 action = MSI_RecordGetString(row,1);
800 ERR("Error is retrieving action name\n");
801 return ERROR_FUNCTION_FAILED;
804 /* check conditions */
805 cond = MSI_RecordGetString(row,2);
807 /* this is a hack to skip errors in the condition code */
808 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
810 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
811 return ERROR_SUCCESS;
814 if (needs_ui_sequence(package))
815 rc = ACTION_PerformUIAction(package, action, -1);
817 rc = ACTION_PerformAction(package, action, -1, FALSE);
819 msi_dialog_check_messages( NULL );
821 if (package->CurrentInstallState != ERROR_SUCCESS)
822 rc = package->CurrentInstallState;
824 if (rc == ERROR_FUNCTION_NOT_CALLED)
827 if (rc != ERROR_SUCCESS)
828 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
833 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
837 static const WCHAR query[] =
838 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
840 ' ','W','H','E','R','E',' ',
841 '`','S','e','q','u','e','n','c','e','`',' ',
842 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
843 '`','S','e','q','u','e','n','c','e','`',0};
845 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
847 r = MSI_OpenQuery( package->db, &view, query, szTable );
848 if (r == ERROR_SUCCESS)
850 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
851 msiobj_release(&view->hdr);
857 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
861 static const WCHAR ExecSeqQuery[] =
862 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
863 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
864 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
865 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
866 'O','R','D','E','R',' ', 'B','Y',' ',
867 '`','S','e','q','u','e','n','c','e','`',0 };
868 static const WCHAR IVQuery[] =
869 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
870 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
871 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
872 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
873 ' ','\'', 'I','n','s','t','a','l','l',
874 'V','a','l','i','d','a','t','e','\'', 0};
877 if (package->script->ExecuteSequenceRun)
879 TRACE("Execute Sequence already Run\n");
880 return ERROR_SUCCESS;
883 package->script->ExecuteSequenceRun = TRUE;
885 /* get the sequence number */
888 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
890 return ERROR_FUNCTION_FAILED;
891 seq = MSI_RecordGetInteger(row,1);
892 msiobj_release(&row->hdr);
895 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
896 if (rc == ERROR_SUCCESS)
898 TRACE("Running the actions\n");
900 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
901 msiobj_release(&view->hdr);
907 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
911 static const WCHAR ExecSeqQuery [] =
912 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
913 '`','I','n','s','t','a','l','l',
914 'U','I','S','e','q','u','e','n','c','e','`',
915 ' ','W','H','E','R','E',' ',
916 '`','S','e','q','u','e','n','c','e','`',' ',
917 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
918 '`','S','e','q','u','e','n','c','e','`',0};
920 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
921 if (rc == ERROR_SUCCESS)
923 TRACE("Running the actions\n");
925 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
926 msiobj_release(&view->hdr);
932 /********************************************************
933 * ACTION helper functions and functions that perform the actions
934 *******************************************************/
935 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
936 UINT* rc, UINT script, BOOL force )
941 arc = ACTION_CustomAction(package, action, script, force);
943 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
952 * Actual Action Handlers
955 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
957 MSIPACKAGE *package = param;
958 LPCWSTR dir, component;
964 component = MSI_RecordGetString(row, 2);
965 comp = get_loaded_component(package, component);
967 return ERROR_SUCCESS;
971 TRACE("component is disabled\n");
972 return ERROR_SUCCESS;
975 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
977 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
978 comp->Action = comp->Installed;
979 return ERROR_SUCCESS;
981 comp->Action = INSTALLSTATE_LOCAL;
983 dir = MSI_RecordGetString(row,1);
986 ERR("Unable to get folder id\n");
987 return ERROR_SUCCESS;
990 uirow = MSI_CreateRecord(1);
991 MSI_RecordSetStringW(uirow, 1, dir);
992 ui_actiondata(package, szCreateFolders, uirow);
993 msiobj_release(&uirow->hdr);
995 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
998 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
999 return ERROR_SUCCESS;
1002 TRACE("Folder is %s\n",debugstr_w(full_path));
1004 if (folder->State == 0)
1005 create_full_pathW(full_path);
1009 msi_free(full_path);
1010 return ERROR_SUCCESS;
1013 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1015 static const WCHAR ExecSeqQuery[] =
1016 {'S','E','L','E','C','T',' ',
1017 '`','D','i','r','e','c','t','o','r','y','_','`',
1018 ' ','F','R','O','M',' ',
1019 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1023 /* create all the empty folders specified in the CreateFolder table */
1024 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1025 if (rc != ERROR_SUCCESS)
1026 return ERROR_SUCCESS;
1028 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1029 msiobj_release(&view->hdr);
1034 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1036 MSIPACKAGE *package = param;
1037 LPCWSTR dir, component;
1043 component = MSI_RecordGetString(row, 2);
1044 comp = get_loaded_component(package, component);
1046 return ERROR_SUCCESS;
1050 TRACE("component is disabled\n");
1051 return ERROR_SUCCESS;
1054 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1056 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1057 comp->Action = comp->Installed;
1058 return ERROR_SUCCESS;
1060 comp->Action = INSTALLSTATE_ABSENT;
1062 dir = MSI_RecordGetString( row, 1 );
1065 ERR("Unable to get folder id\n");
1066 return ERROR_SUCCESS;
1069 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1072 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1073 return ERROR_SUCCESS;
1076 TRACE("folder is %s\n", debugstr_w(full_path));
1078 uirow = MSI_CreateRecord( 1 );
1079 MSI_RecordSetStringW( uirow, 1, dir );
1080 ui_actiondata( package, szRemoveFolders, uirow );
1081 msiobj_release( &uirow->hdr );
1083 RemoveDirectoryW( full_path );
1086 msi_free( full_path );
1087 return ERROR_SUCCESS;
1090 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1092 static const WCHAR query[] =
1093 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1094 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1099 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1100 if (rc != ERROR_SUCCESS)
1101 return ERROR_SUCCESS;
1103 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1104 msiobj_release( &view->hdr );
1109 static UINT load_component( MSIRECORD *row, LPVOID param )
1111 MSIPACKAGE *package = param;
1114 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1116 return ERROR_FUNCTION_FAILED;
1118 list_add_tail( &package->components, &comp->entry );
1120 /* fill in the data */
1121 comp->Component = msi_dup_record_field( row, 1 );
1123 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1125 comp->ComponentId = msi_dup_record_field( row, 2 );
1126 comp->Directory = msi_dup_record_field( row, 3 );
1127 comp->Attributes = MSI_RecordGetInteger(row,4);
1128 comp->Condition = msi_dup_record_field( row, 5 );
1129 comp->KeyPath = msi_dup_record_field( row, 6 );
1131 comp->Installed = INSTALLSTATE_UNKNOWN;
1132 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1134 return ERROR_SUCCESS;
1137 static UINT load_all_components( MSIPACKAGE *package )
1139 static const WCHAR query[] = {
1140 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1141 '`','C','o','m','p','o','n','e','n','t','`',0 };
1145 if (!list_empty(&package->components))
1146 return ERROR_SUCCESS;
1148 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1149 if (r != ERROR_SUCCESS)
1152 r = MSI_IterateRecords(view, NULL, load_component, package);
1153 msiobj_release(&view->hdr);
1158 MSIPACKAGE *package;
1159 MSIFEATURE *feature;
1162 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1166 cl = msi_alloc( sizeof (*cl) );
1168 return ERROR_NOT_ENOUGH_MEMORY;
1169 cl->component = comp;
1170 list_add_tail( &feature->Components, &cl->entry );
1172 return ERROR_SUCCESS;
1175 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1179 fl = msi_alloc( sizeof(*fl) );
1181 return ERROR_NOT_ENOUGH_MEMORY;
1182 fl->feature = child;
1183 list_add_tail( &parent->Children, &fl->entry );
1185 return ERROR_SUCCESS;
1188 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1190 _ilfs* ilfs = param;
1194 component = MSI_RecordGetString(row,1);
1196 /* check to see if the component is already loaded */
1197 comp = get_loaded_component( ilfs->package, component );
1200 ERR("unknown component %s\n", debugstr_w(component));
1201 return ERROR_FUNCTION_FAILED;
1204 add_feature_component( ilfs->feature, comp );
1205 comp->Enabled = TRUE;
1207 return ERROR_SUCCESS;
1210 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1212 MSIFEATURE *feature;
1217 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1219 if ( !lstrcmpW( feature->Feature, name ) )
1226 static UINT load_feature(MSIRECORD * row, LPVOID param)
1228 MSIPACKAGE* package = param;
1229 MSIFEATURE* feature;
1230 static const WCHAR Query1[] =
1231 {'S','E','L','E','C','T',' ',
1232 '`','C','o','m','p','o','n','e','n','t','_','`',
1233 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1234 'C','o','m','p','o','n','e','n','t','s','`',' ',
1235 'W','H','E','R','E',' ',
1236 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1241 /* fill in the data */
1243 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1245 return ERROR_NOT_ENOUGH_MEMORY;
1247 list_init( &feature->Children );
1248 list_init( &feature->Components );
1250 feature->Feature = msi_dup_record_field( row, 1 );
1252 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1254 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1255 feature->Title = msi_dup_record_field( row, 3 );
1256 feature->Description = msi_dup_record_field( row, 4 );
1258 if (!MSI_RecordIsNull(row,5))
1259 feature->Display = MSI_RecordGetInteger(row,5);
1261 feature->Level= MSI_RecordGetInteger(row,6);
1262 feature->Directory = msi_dup_record_field( row, 7 );
1263 feature->Attributes = MSI_RecordGetInteger(row,8);
1265 feature->Installed = INSTALLSTATE_UNKNOWN;
1266 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1268 list_add_tail( &package->features, &feature->entry );
1270 /* load feature components */
1272 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1273 if (rc != ERROR_SUCCESS)
1274 return ERROR_SUCCESS;
1276 ilfs.package = package;
1277 ilfs.feature = feature;
1279 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1280 msiobj_release(&view->hdr);
1282 return ERROR_SUCCESS;
1285 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1287 MSIPACKAGE* package = param;
1288 MSIFEATURE *parent, *child;
1290 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1292 return ERROR_FUNCTION_FAILED;
1294 if (!child->Feature_Parent)
1295 return ERROR_SUCCESS;
1297 parent = find_feature_by_name( package, child->Feature_Parent );
1299 return ERROR_FUNCTION_FAILED;
1301 add_feature_child( parent, child );
1302 return ERROR_SUCCESS;
1305 static UINT load_all_features( MSIPACKAGE *package )
1307 static const WCHAR query[] = {
1308 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1309 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1310 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1314 if (!list_empty(&package->features))
1315 return ERROR_SUCCESS;
1317 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1318 if (r != ERROR_SUCCESS)
1321 r = MSI_IterateRecords( view, NULL, load_feature, package );
1322 if (r != ERROR_SUCCESS)
1325 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1326 msiobj_release( &view->hdr );
1331 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1342 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1344 static const WCHAR query[] = {
1345 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1346 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1347 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1348 MSIQUERY *view = NULL;
1349 MSIRECORD *row = NULL;
1352 TRACE("%s\n", debugstr_w(file->File));
1354 r = MSI_OpenQuery(package->db, &view, query, file->File);
1355 if (r != ERROR_SUCCESS)
1358 r = MSI_ViewExecute(view, NULL);
1359 if (r != ERROR_SUCCESS)
1362 r = MSI_ViewFetch(view, &row);
1363 if (r != ERROR_SUCCESS)
1366 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1367 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1368 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1369 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1370 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1373 if (view) msiobj_release(&view->hdr);
1374 if (row) msiobj_release(&row->hdr);
1378 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1381 static const WCHAR query[] = {
1382 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1383 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1384 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1386 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1389 WARN("query failed\n");
1390 return ERROR_FUNCTION_FAILED;
1393 file->disk_id = MSI_RecordGetInteger( row, 1 );
1394 msiobj_release( &row->hdr );
1395 return ERROR_SUCCESS;
1398 static UINT load_file(MSIRECORD *row, LPVOID param)
1400 MSIPACKAGE* package = param;
1404 /* fill in the data */
1406 file = msi_alloc_zero( sizeof (MSIFILE) );
1408 return ERROR_NOT_ENOUGH_MEMORY;
1410 file->File = msi_dup_record_field( row, 1 );
1412 component = MSI_RecordGetString( row, 2 );
1413 file->Component = get_loaded_component( package, component );
1415 if (!file->Component)
1417 WARN("Component not found: %s\n", debugstr_w(component));
1418 msi_free(file->File);
1420 return ERROR_SUCCESS;
1423 file->FileName = msi_dup_record_field( row, 3 );
1424 reduce_to_longfilename( file->FileName );
1426 file->ShortName = msi_dup_record_field( row, 3 );
1427 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1429 file->FileSize = MSI_RecordGetInteger( row, 4 );
1430 file->Version = msi_dup_record_field( row, 5 );
1431 file->Language = msi_dup_record_field( row, 6 );
1432 file->Attributes = MSI_RecordGetInteger( row, 7 );
1433 file->Sequence = MSI_RecordGetInteger( row, 8 );
1435 file->state = msifs_invalid;
1437 /* if the compressed bits are not set in the file attributes,
1438 * then read the information from the package word count property
1440 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1442 file->IsCompressed = FALSE;
1444 else if (file->Attributes &
1445 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1447 file->IsCompressed = TRUE;
1449 else if (file->Attributes & msidbFileAttributesNoncompressed)
1451 file->IsCompressed = FALSE;
1455 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1458 load_file_hash(package, file);
1459 load_file_disk_id(package, file);
1461 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1463 list_add_tail( &package->files, &file->entry );
1465 return ERROR_SUCCESS;
1468 static UINT load_all_files(MSIPACKAGE *package)
1472 static const WCHAR Query[] =
1473 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1474 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1475 '`','S','e','q','u','e','n','c','e','`', 0};
1477 if (!list_empty(&package->files))
1478 return ERROR_SUCCESS;
1480 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1481 if (rc != ERROR_SUCCESS)
1482 return ERROR_SUCCESS;
1484 rc = MSI_IterateRecords(view, NULL, load_file, package);
1485 msiobj_release(&view->hdr);
1487 return ERROR_SUCCESS;
1490 static UINT load_folder( MSIRECORD *row, LPVOID param )
1492 MSIPACKAGE *package = param;
1493 static WCHAR szEmpty[] = { 0 };
1494 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1497 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1499 return ERROR_NOT_ENOUGH_MEMORY;
1501 folder->Directory = msi_dup_record_field( row, 1 );
1503 TRACE("%s\n", debugstr_w(folder->Directory));
1505 p = msi_dup_record_field(row, 3);
1507 /* split src and target dir */
1509 src_short = folder_split_path( p, ':' );
1511 /* split the long and short paths */
1512 tgt_long = folder_split_path( tgt_short, '|' );
1513 src_long = folder_split_path( src_short, '|' );
1515 /* check for no-op dirs */
1516 if (!lstrcmpW(szDot, tgt_short))
1517 tgt_short = szEmpty;
1518 if (!lstrcmpW(szDot, src_short))
1519 src_short = szEmpty;
1522 tgt_long = tgt_short;
1525 src_short = tgt_short;
1526 src_long = tgt_long;
1530 src_long = src_short;
1532 /* FIXME: use the target short path too */
1533 folder->TargetDefault = strdupW(tgt_long);
1534 folder->SourceShortPath = strdupW(src_short);
1535 folder->SourceLongPath = strdupW(src_long);
1538 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1539 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1540 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1542 folder->Parent = msi_dup_record_field( row, 2 );
1544 folder->Property = msi_dup_property( package->db, folder->Directory );
1546 list_add_tail( &package->folders, &folder->entry );
1548 TRACE("returning %p\n", folder);
1550 return ERROR_SUCCESS;
1553 static UINT load_all_folders( MSIPACKAGE *package )
1555 static const WCHAR query[] = {
1556 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1557 '`','D','i','r','e','c','t','o','r','y','`',0 };
1561 if (!list_empty(&package->folders))
1562 return ERROR_SUCCESS;
1564 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1565 if (r != ERROR_SUCCESS)
1568 r = MSI_IterateRecords(view, NULL, load_folder, package);
1569 msiobj_release(&view->hdr);
1574 * I am not doing any of the costing functionality yet.
1575 * Mostly looking at doing the Component and Feature loading
1577 * The native MSI does A LOT of modification to tables here. Mostly adding
1578 * a lot of temporary columns to the Feature and Component tables.
1580 * note: Native msi also tracks the short filename. But I am only going to
1581 * track the long ones. Also looking at this directory table
1582 * it appears that the directory table does not get the parents
1583 * resolved base on property only based on their entries in the
1586 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1588 static const WCHAR szCosting[] =
1589 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1591 msi_set_property( package->db, szCosting, szZero );
1592 msi_set_property( package->db, cszRootDrive, c_colon );
1594 load_all_folders( package );
1595 load_all_components( package );
1596 load_all_features( package );
1597 load_all_files( package );
1599 return ERROR_SUCCESS;
1602 static UINT execute_script(MSIPACKAGE *package, UINT script )
1605 UINT rc = ERROR_SUCCESS;
1607 TRACE("Executing Script %i\n",script);
1609 if (!package->script)
1611 ERR("no script!\n");
1612 return ERROR_FUNCTION_FAILED;
1615 for (i = 0; i < package->script->ActionCount[script]; i++)
1618 action = package->script->Actions[script][i];
1619 ui_actionstart(package, action);
1620 TRACE("Executing Action (%s)\n",debugstr_w(action));
1621 rc = ACTION_PerformAction(package, action, script, TRUE);
1622 if (rc != ERROR_SUCCESS)
1625 msi_free_action_script(package, script);
1629 static UINT ACTION_FileCost(MSIPACKAGE *package)
1631 return ERROR_SUCCESS;
1634 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1640 state = MsiQueryProductStateW(package->ProductCode);
1642 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1644 if (!comp->ComponentId)
1647 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1648 comp->Installed = INSTALLSTATE_ABSENT;
1651 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1652 package->Context, comp->ComponentId,
1654 if (r != ERROR_SUCCESS)
1655 comp->Installed = INSTALLSTATE_ABSENT;
1660 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1662 MSIFEATURE *feature;
1665 state = MsiQueryProductStateW(package->ProductCode);
1667 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1669 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1670 feature->Installed = INSTALLSTATE_ABSENT;
1673 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1679 static BOOL process_state_property(MSIPACKAGE* package, int level,
1680 LPCWSTR property, INSTALLSTATE state)
1683 MSIFEATURE *feature;
1685 override = msi_dup_property( package->db, property );
1689 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1691 if (lstrcmpW(property, szRemove) &&
1692 (feature->Level <= 0 || feature->Level > level))
1695 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1697 if (strcmpiW(override, szAll)==0)
1698 msi_feature_set_state(package, feature, state);
1701 LPWSTR ptr = override;
1702 LPWSTR ptr2 = strchrW(override,',');
1706 int len = ptr2 - ptr;
1708 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1709 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1711 msi_feature_set_state(package, feature, state);
1717 ptr2 = strchrW(ptr,',');
1729 static BOOL process_overrides( MSIPACKAGE *package, int level )
1731 static const WCHAR szAddLocal[] =
1732 {'A','D','D','L','O','C','A','L',0};
1733 static const WCHAR szAddSource[] =
1734 {'A','D','D','S','O','U','R','C','E',0};
1735 static const WCHAR szAdvertise[] =
1736 {'A','D','V','E','R','T','I','S','E',0};
1739 /* all these activation/deactivation things happen in order and things
1740 * later on the list override things earlier on the list.
1742 * 0 INSTALLLEVEL processing
1755 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1756 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1757 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1758 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1759 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1762 msi_set_property( package->db, szPreselected, szOne );
1767 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1770 static const WCHAR szlevel[] =
1771 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1772 MSICOMPONENT* component;
1773 MSIFEATURE *feature;
1775 TRACE("Checking Install Level\n");
1777 level = msi_get_property_int(package->db, szlevel, 1);
1779 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1781 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1783 BOOL feature_state = ((feature->Level > 0) &&
1784 (feature->Level <= level));
1786 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1788 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1789 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1790 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1791 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1793 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1797 /* disable child features of unselected parent features */
1798 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1802 if (feature->Level > 0 && feature->Level <= level)
1805 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1806 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1811 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1813 BOOL selected = feature->Level > 0 && feature->Level <= level;
1815 if (selected && feature->Action == INSTALLSTATE_UNKNOWN)
1817 msi_feature_set_state(package, feature, feature->Installed);
1823 * now we want to enable or disable components based on feature
1825 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1829 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1830 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1831 feature->ActionRequest, feature->Action);
1833 if (!feature->Level)
1836 /* features with components that have compressed files are made local */
1837 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1839 if (cl->component->ForceLocalState &&
1840 feature->Action == INSTALLSTATE_SOURCE)
1842 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1847 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1849 component = cl->component;
1851 switch (feature->Action)
1853 case INSTALLSTATE_ABSENT:
1854 component->anyAbsent = 1;
1856 case INSTALLSTATE_ADVERTISED:
1857 component->hasAdvertiseFeature = 1;
1859 case INSTALLSTATE_SOURCE:
1860 component->hasSourceFeature = 1;
1862 case INSTALLSTATE_LOCAL:
1863 component->hasLocalFeature = 1;
1865 case INSTALLSTATE_DEFAULT:
1866 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1867 component->hasAdvertiseFeature = 1;
1868 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1869 component->hasSourceFeature = 1;
1871 component->hasLocalFeature = 1;
1879 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1881 /* check if it's local or source */
1882 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1883 (component->hasLocalFeature || component->hasSourceFeature))
1885 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1886 !component->ForceLocalState)
1887 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1889 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1893 /* if any feature is local, the component must be local too */
1894 if (component->hasLocalFeature)
1896 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1900 if (component->hasSourceFeature)
1902 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1906 if (component->hasAdvertiseFeature)
1908 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1912 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1913 if (component->anyAbsent)
1914 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1917 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1919 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1921 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1922 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1925 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1926 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1929 return ERROR_SUCCESS;
1932 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1934 MSIPACKAGE *package = param;
1939 name = MSI_RecordGetString(row,1);
1941 f = get_loaded_folder(package, name);
1942 if (!f) return ERROR_SUCCESS;
1944 /* reset the ResolvedTarget */
1945 msi_free(f->ResolvedTarget);
1946 f->ResolvedTarget = NULL;
1948 /* This helper function now does ALL the work */
1949 TRACE("Dir %s ...\n",debugstr_w(name));
1950 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1951 TRACE("resolves to %s\n",debugstr_w(path));
1954 return ERROR_SUCCESS;
1957 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1959 MSIPACKAGE *package = param;
1961 MSIFEATURE *feature;
1963 name = MSI_RecordGetString( row, 1 );
1965 feature = get_loaded_feature( package, name );
1967 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1971 Condition = MSI_RecordGetString(row,3);
1973 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1975 int level = MSI_RecordGetInteger(row,2);
1976 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1977 feature->Level = level;
1980 return ERROR_SUCCESS;
1983 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1985 static const WCHAR name[] = {'\\',0};
1986 VS_FIXEDFILEINFO *ret;
1988 DWORD versize, handle;
1991 TRACE("%s\n", debugstr_w(filename));
1993 versize = GetFileVersionInfoSizeW( filename, &handle );
1997 version = msi_alloc( versize );
2001 GetFileVersionInfoW( filename, 0, versize, version );
2003 if (!VerQueryValueW( version, name, (LPVOID *)&ret, &sz ))
2005 msi_free( version );
2009 msi_free( version );
2013 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2017 msi_parse_version_string( version, &ms, &ls );
2019 if (fi->dwFileVersionMS > ms) return 1;
2020 else if (fi->dwFileVersionMS < ms) return -1;
2021 else if (fi->dwFileVersionLS > ls) return 1;
2022 else if (fi->dwFileVersionLS < ls) return -1;
2026 static DWORD get_disk_file_size( LPCWSTR filename )
2031 TRACE("%s\n", debugstr_w(filename));
2033 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2034 if (file == INVALID_HANDLE_VALUE)
2035 return INVALID_FILE_SIZE;
2037 size = GetFileSize( file, NULL );
2038 CloseHandle( file );
2042 static BOOL hash_matches( MSIFILE *file )
2045 MSIFILEHASHINFO hash;
2047 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2048 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2049 if (r != ERROR_SUCCESS)
2052 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2055 static UINT set_file_install_states( MSIPACKAGE *package )
2057 VS_FIXEDFILEINFO *file_version;
2060 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2062 MSICOMPONENT* comp = file->Component;
2069 if (file->IsCompressed)
2070 comp->ForceLocalState = TRUE;
2072 /* calculate target */
2073 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2074 msi_free(file->TargetPath);
2076 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2078 file->TargetPath = build_directory_name(2, p, file->FileName);
2081 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2083 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2085 file->state = msifs_missing;
2086 comp->Cost += file->FileSize;
2089 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2091 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2092 HIWORD(file_version->dwFileVersionMS),
2093 LOWORD(file_version->dwFileVersionMS),
2094 HIWORD(file_version->dwFileVersionLS),
2095 LOWORD(file_version->dwFileVersionLS));
2097 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2099 file->state = msifs_overwrite;
2100 comp->Cost += file->FileSize;
2104 TRACE("Destination file version equal or greater, not overwriting\n");
2105 file->state = msifs_present;
2107 msi_free( file_version );
2110 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2112 file->state = msifs_overwrite;
2113 comp->Cost += file->FileSize - file_size;
2116 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2118 TRACE("File hashes match, not overwriting\n");
2119 file->state = msifs_present;
2122 file->state = msifs_overwrite;
2123 comp->Cost += file->FileSize - file_size;
2126 return ERROR_SUCCESS;
2130 * A lot is done in this function aside from just the costing.
2131 * The costing needs to be implemented at some point but for now I am going
2132 * to focus on the directory building
2135 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2137 static const WCHAR ExecSeqQuery[] =
2138 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2139 '`','D','i','r','e','c','t','o','r','y','`',0};
2140 static const WCHAR ConditionQuery[] =
2141 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2142 '`','C','o','n','d','i','t','i','o','n','`',0};
2143 static const WCHAR szCosting[] =
2144 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2145 static const WCHAR szlevel[] =
2146 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2147 static const WCHAR szOutOfDiskSpace[] =
2148 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2150 UINT rc = ERROR_SUCCESS;
2154 TRACE("Building Directory properties\n");
2156 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2157 if (rc == ERROR_SUCCESS)
2159 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2161 msiobj_release(&view->hdr);
2164 /* read components states from the registry */
2165 ACTION_GetComponentInstallStates(package);
2166 ACTION_GetFeatureInstallStates(package);
2168 TRACE("Calculating file install states\n");
2169 set_file_install_states( package );
2171 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2173 TRACE("Evaluating feature conditions\n");
2175 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2176 if (rc == ERROR_SUCCESS)
2178 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2179 msiobj_release( &view->hdr );
2182 TRACE("Evaluating component conditions\n");
2184 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2186 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2188 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2189 comp->Enabled = FALSE;
2192 comp->Enabled = TRUE;
2195 msi_set_property( package->db, szCosting, szOne );
2196 /* set default run level if not set */
2197 level = msi_dup_property( package->db, szlevel );
2199 msi_set_property( package->db, szlevel, szOne );
2202 /* FIXME: check volume disk space */
2203 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2205 return MSI_SetFeatureStates(package);
2208 /* OK this value is "interpreted" and then formatted based on the
2209 first few characters */
2210 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2215 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2221 LPWSTR deformated = NULL;
2224 deformat_string(package, &value[2], &deformated);
2226 /* binary value type */
2230 *size = (strlenW(ptr)/2)+1;
2232 *size = strlenW(ptr)/2;
2234 data = msi_alloc(*size);
2240 /* if uneven pad with a zero in front */
2246 data[count] = (BYTE)strtol(byte,NULL,0);
2248 TRACE("Uneven byte count\n");
2256 data[count] = (BYTE)strtol(byte,NULL,0);
2259 msi_free(deformated);
2261 TRACE("Data %i bytes(%i)\n",*size,count);
2268 deformat_string(package, &value[1], &deformated);
2271 *size = sizeof(DWORD);
2272 data = msi_alloc(*size);
2278 if ( (*p < '0') || (*p > '9') )
2284 if (deformated[0] == '-')
2287 TRACE("DWORD %i\n",*(LPDWORD)data);
2289 msi_free(deformated);
2294 static const WCHAR szMulti[] = {'[','~',']',0};
2303 *type=REG_EXPAND_SZ;
2311 if (strstrW(value,szMulti))
2312 *type = REG_MULTI_SZ;
2314 /* remove initial delimiter */
2315 if (!strncmpW(value, szMulti, 3))
2318 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2320 /* add double NULL terminator */
2321 if (*type == REG_MULTI_SZ)
2323 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2324 data = msi_realloc_zero(data, *size);
2330 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2337 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2339 *root_key = HKEY_LOCAL_MACHINE;
2344 *root_key = HKEY_CURRENT_USER;
2349 *root_key = HKEY_CLASSES_ROOT;
2353 *root_key = HKEY_CURRENT_USER;
2357 *root_key = HKEY_LOCAL_MACHINE;
2361 *root_key = HKEY_USERS;
2365 ERR("Unknown root %i\n", root);
2372 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2374 MSIPACKAGE *package = param;
2375 LPSTR value_data = NULL;
2376 HKEY root_key, hkey;
2379 LPCWSTR szRoot, component, name, key, value;
2384 BOOL check_first = FALSE;
2387 ui_progress(package,2,0,0,0);
2389 component = MSI_RecordGetString(row, 6);
2390 comp = get_loaded_component(package,component);
2392 return ERROR_SUCCESS;
2396 TRACE("component is disabled\n");
2397 return ERROR_SUCCESS;
2400 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2402 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2403 comp->Action = comp->Installed;
2404 return ERROR_SUCCESS;
2406 comp->Action = INSTALLSTATE_LOCAL;
2408 name = MSI_RecordGetString(row, 4);
2409 if( MSI_RecordIsNull(row,5) && name )
2411 /* null values can have special meanings */
2412 if (name[0]=='-' && name[1] == 0)
2413 return ERROR_SUCCESS;
2414 else if ((name[0]=='+' && name[1] == 0) ||
2415 (name[0] == '*' && name[1] == 0))
2420 root = MSI_RecordGetInteger(row,2);
2421 key = MSI_RecordGetString(row, 3);
2423 szRoot = get_root_key( package, root, &root_key );
2425 return ERROR_SUCCESS;
2427 deformat_string(package, key , &deformated);
2428 size = strlenW(deformated) + strlenW(szRoot) + 1;
2429 uikey = msi_alloc(size*sizeof(WCHAR));
2430 strcpyW(uikey,szRoot);
2431 strcatW(uikey,deformated);
2433 if (RegCreateKeyW( root_key, deformated, &hkey))
2435 ERR("Could not create key %s\n",debugstr_w(deformated));
2436 msi_free(deformated);
2438 return ERROR_SUCCESS;
2440 msi_free(deformated);
2442 value = MSI_RecordGetString(row,5);
2444 value_data = parse_value(package, value, &type, &size);
2447 value_data = (LPSTR)strdupW(szEmpty);
2448 size = sizeof(szEmpty);
2452 deformat_string(package, name, &deformated);
2456 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2458 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2463 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2464 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2466 TRACE("value %s of %s checked already exists\n",
2467 debugstr_w(deformated), debugstr_w(uikey));
2471 TRACE("Checked and setting value %s of %s\n",
2472 debugstr_w(deformated), debugstr_w(uikey));
2473 if (deformated || size)
2474 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2479 uirow = MSI_CreateRecord(3);
2480 MSI_RecordSetStringW(uirow,2,deformated);
2481 MSI_RecordSetStringW(uirow,1,uikey);
2482 if (type == REG_SZ || type == REG_EXPAND_SZ)
2483 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2484 ui_actiondata(package,szWriteRegistryValues,uirow);
2485 msiobj_release( &uirow->hdr );
2487 msi_free(value_data);
2488 msi_free(deformated);
2491 return ERROR_SUCCESS;
2494 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2498 static const WCHAR ExecSeqQuery[] =
2499 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2500 '`','R','e','g','i','s','t','r','y','`',0 };
2502 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2503 if (rc != ERROR_SUCCESS)
2504 return ERROR_SUCCESS;
2506 /* increment progress bar each time action data is sent */
2507 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2509 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2511 msiobj_release(&view->hdr);
2515 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2519 DWORD num_subkeys, num_values;
2523 if ((res = RegDeleteTreeW( hkey_root, key )))
2525 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2530 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2532 if ((res = RegDeleteValueW( hkey, value )))
2534 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2536 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2537 NULL, NULL, NULL, NULL );
2538 RegCloseKey( hkey );
2540 if (!res && !num_subkeys && !num_values)
2542 TRACE("Removing empty key %s\n", debugstr_w(key));
2543 RegDeleteKeyW( hkey_root, key );
2547 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2551 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2553 MSIPACKAGE *package = param;
2554 LPCWSTR component, name, key_str, root_key_str;
2555 LPWSTR deformated_key, deformated_name, ui_key_str;
2558 BOOL delete_key = FALSE;
2563 ui_progress( package, 2, 0, 0, 0 );
2565 component = MSI_RecordGetString( row, 6 );
2566 comp = get_loaded_component( package, component );
2568 return ERROR_SUCCESS;
2572 TRACE("component is disabled\n");
2573 return ERROR_SUCCESS;
2576 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2578 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2579 comp->Action = comp->Installed;
2580 return ERROR_SUCCESS;
2582 comp->Action = INSTALLSTATE_ABSENT;
2584 name = MSI_RecordGetString( row, 4 );
2585 if (MSI_RecordIsNull( row, 5 ) && name )
2587 if (name[0] == '+' && !name[1])
2588 return ERROR_SUCCESS;
2589 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2596 root = MSI_RecordGetInteger( row, 2 );
2597 key_str = MSI_RecordGetString( row, 3 );
2599 root_key_str = get_root_key( package, root, &hkey_root );
2601 return ERROR_SUCCESS;
2603 deformat_string( package, key_str, &deformated_key );
2604 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2605 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2606 strcpyW( ui_key_str, root_key_str );
2607 strcatW( ui_key_str, deformated_key );
2609 deformat_string( package, name, &deformated_name );
2611 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2612 msi_free( deformated_key );
2614 uirow = MSI_CreateRecord( 2 );
2615 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2616 MSI_RecordSetStringW( uirow, 2, deformated_name );
2618 ui_actiondata( package, szRemoveRegistryValues, uirow );
2619 msiobj_release( &uirow->hdr );
2621 msi_free( ui_key_str );
2622 msi_free( deformated_name );
2623 return ERROR_SUCCESS;
2626 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2628 MSIPACKAGE *package = param;
2629 LPCWSTR component, name, key_str, root_key_str;
2630 LPWSTR deformated_key, deformated_name, ui_key_str;
2633 BOOL delete_key = FALSE;
2638 ui_progress( package, 2, 0, 0, 0 );
2640 component = MSI_RecordGetString( row, 5 );
2641 comp = get_loaded_component( package, component );
2643 return ERROR_SUCCESS;
2647 TRACE("component is disabled\n");
2648 return ERROR_SUCCESS;
2651 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2653 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2654 comp->Action = comp->Installed;
2655 return ERROR_SUCCESS;
2657 comp->Action = INSTALLSTATE_LOCAL;
2659 if ((name = MSI_RecordGetString( row, 4 )))
2661 if (name[0] == '-' && !name[1])
2668 root = MSI_RecordGetInteger( row, 2 );
2669 key_str = MSI_RecordGetString( row, 3 );
2671 root_key_str = get_root_key( package, root, &hkey_root );
2673 return ERROR_SUCCESS;
2675 deformat_string( package, key_str, &deformated_key );
2676 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2677 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2678 strcpyW( ui_key_str, root_key_str );
2679 strcatW( ui_key_str, deformated_key );
2681 deformat_string( package, name, &deformated_name );
2683 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2684 msi_free( deformated_key );
2686 uirow = MSI_CreateRecord( 2 );
2687 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2688 MSI_RecordSetStringW( uirow, 2, deformated_name );
2690 ui_actiondata( package, szRemoveRegistryValues, uirow );
2691 msiobj_release( &uirow->hdr );
2693 msi_free( ui_key_str );
2694 msi_free( deformated_name );
2695 return ERROR_SUCCESS;
2698 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2702 static const WCHAR registry_query[] =
2703 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2704 '`','R','e','g','i','s','t','r','y','`',0 };
2705 static const WCHAR remove_registry_query[] =
2706 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2707 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2709 /* increment progress bar each time action data is sent */
2710 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2712 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2713 if (rc == ERROR_SUCCESS)
2715 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2716 msiobj_release( &view->hdr );
2717 if (rc != ERROR_SUCCESS)
2721 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2722 if (rc == ERROR_SUCCESS)
2724 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2725 msiobj_release( &view->hdr );
2726 if (rc != ERROR_SUCCESS)
2730 return ERROR_SUCCESS;
2733 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2735 package->script->CurrentlyScripting = TRUE;
2737 return ERROR_SUCCESS;
2741 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2746 static const WCHAR q1[]=
2747 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2748 '`','R','e','g','i','s','t','r','y','`',0};
2751 MSIFEATURE *feature;
2754 TRACE("InstallValidate\n");
2756 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2757 if (rc == ERROR_SUCCESS)
2759 MSI_IterateRecords( view, &progress, NULL, package );
2760 msiobj_release( &view->hdr );
2761 total += progress * REG_PROGRESS_VALUE;
2764 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2765 total += COMPONENT_PROGRESS_VALUE;
2767 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2768 total += file->FileSize;
2770 ui_progress(package,0,total,0,0);
2772 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2774 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2775 debugstr_w(feature->Feature), feature->Installed,
2776 feature->ActionRequest, feature->Action);
2779 return ERROR_SUCCESS;
2782 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2784 MSIPACKAGE* package = param;
2785 LPCWSTR cond = NULL;
2786 LPCWSTR message = NULL;
2789 static const WCHAR title[]=
2790 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2792 cond = MSI_RecordGetString(row,1);
2794 r = MSI_EvaluateConditionW(package,cond);
2795 if (r == MSICONDITION_FALSE)
2797 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2800 message = MSI_RecordGetString(row,2);
2801 deformat_string(package,message,&deformated);
2802 MessageBoxW(NULL,deformated,title,MB_OK);
2803 msi_free(deformated);
2806 return ERROR_INSTALL_FAILURE;
2809 return ERROR_SUCCESS;
2812 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2815 MSIQUERY * view = NULL;
2816 static const WCHAR ExecSeqQuery[] =
2817 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2818 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2820 TRACE("Checking launch conditions\n");
2822 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2823 if (rc != ERROR_SUCCESS)
2824 return ERROR_SUCCESS;
2826 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2827 msiobj_release(&view->hdr);
2832 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2836 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2838 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2840 MSIRECORD * row = 0;
2842 LPWSTR deformated,buffer,deformated_name;
2844 static const WCHAR ExecSeqQuery[] =
2845 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2846 '`','R','e','g','i','s','t','r','y','`',' ',
2847 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2848 ' ','=',' ' ,'\'','%','s','\'',0 };
2849 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2850 static const WCHAR fmt2[]=
2851 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2853 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2857 root = MSI_RecordGetInteger(row,2);
2858 key = MSI_RecordGetString(row, 3);
2859 name = MSI_RecordGetString(row, 4);
2860 deformat_string(package, key , &deformated);
2861 deformat_string(package, name, &deformated_name);
2863 len = strlenW(deformated) + 6;
2864 if (deformated_name)
2865 len+=strlenW(deformated_name);
2867 buffer = msi_alloc( len *sizeof(WCHAR));
2869 if (deformated_name)
2870 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2872 sprintfW(buffer,fmt,root,deformated);
2874 msi_free(deformated);
2875 msi_free(deformated_name);
2876 msiobj_release(&row->hdr);
2880 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2882 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2887 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2890 return strdupW( file->TargetPath );
2895 static HKEY openSharedDLLsKey(void)
2898 static const WCHAR path[] =
2899 {'S','o','f','t','w','a','r','e','\\',
2900 'M','i','c','r','o','s','o','f','t','\\',
2901 'W','i','n','d','o','w','s','\\',
2902 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2903 'S','h','a','r','e','d','D','L','L','s',0};
2905 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2909 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2914 DWORD sz = sizeof(count);
2917 hkey = openSharedDLLsKey();
2918 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2919 if (rc != ERROR_SUCCESS)
2925 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2929 hkey = openSharedDLLsKey();
2931 msi_reg_set_val_dword( hkey, path, count );
2933 RegDeleteValueW(hkey,path);
2939 * Return TRUE if the count should be written out and FALSE if not
2941 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2943 MSIFEATURE *feature;
2947 /* only refcount DLLs */
2948 if (comp->KeyPath == NULL ||
2949 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2950 comp->Attributes & msidbComponentAttributesODBCDataSource)
2954 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2955 write = (count > 0);
2957 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2961 /* increment counts */
2962 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2966 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2969 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2971 if ( cl->component == comp )
2976 /* decrement counts */
2977 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2981 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2984 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2986 if ( cl->component == comp )
2991 /* ref count all the files in the component */
2996 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2998 if (file->Component == comp)
2999 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3003 /* add a count for permanent */
3004 if (comp->Attributes & msidbComponentAttributesPermanent)
3007 comp->RefCount = count;
3010 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3013 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3015 WCHAR squished_pc[GUID_SIZE];
3016 WCHAR squished_cc[GUID_SIZE];
3023 squash_guid(package->ProductCode,squished_pc);
3024 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3026 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3030 ui_progress(package,2,0,0,0);
3031 if (!comp->ComponentId)
3034 squash_guid(comp->ComponentId,squished_cc);
3036 msi_free(comp->FullKeypath);
3037 comp->FullKeypath = resolve_keypath( package, comp );
3039 ACTION_RefCountComponent( package, comp );
3041 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3042 debugstr_w(comp->Component),
3043 debugstr_w(squished_cc),
3044 debugstr_w(comp->FullKeypath),
3046 comp->ActionRequest);
3048 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3049 comp->ActionRequest == INSTALLSTATE_SOURCE)
3051 if (!comp->FullKeypath)
3054 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3055 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3058 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3061 if (rc != ERROR_SUCCESS)
3064 if (comp->Attributes & msidbComponentAttributesPermanent)
3066 static const WCHAR szPermKey[] =
3067 { '0','0','0','0','0','0','0','0','0','0','0','0',
3068 '0','0','0','0','0','0','0','0','0','0','0','0',
3069 '0','0','0','0','0','0','0','0',0 };
3071 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3074 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3075 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3081 WCHAR source[MAX_PATH];
3082 WCHAR base[MAX_PATH];
3085 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3086 static const WCHAR query[] = {
3087 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3088 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3089 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3090 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3091 '`','D','i','s','k','I','d','`',0};
3093 file = get_loaded_file(package, comp->KeyPath);
3097 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3098 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3099 ptr2 = strrchrW(source, '\\') + 1;
3100 msiobj_release(&row->hdr);
3102 lstrcpyW(base, package->PackagePath);
3103 ptr = strrchrW(base, '\\');
3106 sourcepath = resolve_file_source(package, file);
3107 ptr = sourcepath + lstrlenW(base);
3108 lstrcpyW(ptr2, ptr);
3109 msi_free(sourcepath);
3111 msi_reg_set_val_str(hkey, squished_pc, source);
3115 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3117 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3118 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3120 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3122 comp->Action = comp->ActionRequest;
3125 uirow = MSI_CreateRecord(3);
3126 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3127 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3128 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3129 ui_actiondata(package,szProcessComponents,uirow);
3130 msiobj_release( &uirow->hdr );
3133 return ERROR_SUCCESS;
3144 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3145 LPWSTR lpszName, LONG_PTR lParam)
3148 typelib_struct *tl_struct = (typelib_struct*) lParam;
3149 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3153 if (!IS_INTRESOURCE(lpszName))
3155 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3159 sz = strlenW(tl_struct->source)+4;
3160 sz *= sizeof(WCHAR);
3162 if ((INT_PTR)lpszName == 1)
3163 tl_struct->path = strdupW(tl_struct->source);
3166 tl_struct->path = msi_alloc(sz);
3167 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3170 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3171 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3174 msi_free(tl_struct->path);
3175 tl_struct->path = NULL;
3180 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3181 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3183 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3187 msi_free(tl_struct->path);
3188 tl_struct->path = NULL;
3190 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3191 ITypeLib_Release(tl_struct->ptLib);
3196 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3198 MSIPACKAGE* package = param;
3202 typelib_struct tl_struct;
3207 component = MSI_RecordGetString(row,3);
3208 comp = get_loaded_component(package,component);
3210 return ERROR_SUCCESS;
3214 TRACE("component is disabled\n");
3215 return ERROR_SUCCESS;
3218 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3220 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3221 comp->Action = comp->Installed;
3222 return ERROR_SUCCESS;
3224 comp->Action = INSTALLSTATE_LOCAL;
3226 file = get_loaded_file( package, comp->KeyPath );
3228 return ERROR_SUCCESS;
3230 ui_actiondata( package, szRegisterTypeLibraries, row );
3232 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3236 guid = MSI_RecordGetString(row,1);
3237 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3238 tl_struct.source = strdupW( file->TargetPath );
3239 tl_struct.path = NULL;
3241 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3242 (LONG_PTR)&tl_struct);
3250 helpid = MSI_RecordGetString(row,6);
3253 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3254 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3258 ERR("Failed to register type library %s\n",
3259 debugstr_w(tl_struct.path));
3261 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3263 ITypeLib_Release(tl_struct.ptLib);
3264 msi_free(tl_struct.path);
3267 ERR("Failed to load type library %s\n",
3268 debugstr_w(tl_struct.source));
3270 FreeLibrary(module);
3271 msi_free(tl_struct.source);
3275 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3278 ERR("Failed to load type library: %08x\n", hr);
3279 return ERROR_INSTALL_FAILURE;
3282 ITypeLib_Release(tlib);
3285 return ERROR_SUCCESS;
3288 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3291 * OK this is a bit confusing.. I am given a _Component key and I believe
3292 * that the file that is being registered as a type library is the "key file
3293 * of that component" which I interpret to mean "The file in the KeyPath of
3298 static const WCHAR Query[] =
3299 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3300 '`','T','y','p','e','L','i','b','`',0};
3302 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3303 if (rc != ERROR_SUCCESS)
3304 return ERROR_SUCCESS;
3306 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3307 msiobj_release(&view->hdr);
3311 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3313 MSIPACKAGE *package = param;
3314 LPCWSTR component, guid;
3322 component = MSI_RecordGetString( row, 3 );
3323 comp = get_loaded_component( package, component );
3325 return ERROR_SUCCESS;
3329 TRACE("component is disabled\n");
3330 return ERROR_SUCCESS;
3333 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3335 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3336 comp->Action = comp->Installed;
3337 return ERROR_SUCCESS;
3339 comp->Action = INSTALLSTATE_ABSENT;
3341 ui_actiondata( package, szUnregisterTypeLibraries, row );
3343 guid = MSI_RecordGetString( row, 1 );
3344 CLSIDFromString( (LPCWSTR)guid, &libid );
3345 version = MSI_RecordGetInteger( row, 4 );
3346 language = MSI_RecordGetInteger( row, 2 );
3349 syskind = SYS_WIN64;
3351 syskind = SYS_WIN32;
3354 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3357 WARN("Failed to unregister typelib: %08x\n", hr);
3360 return ERROR_SUCCESS;
3363 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3367 static const WCHAR query[] =
3368 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3369 '`','T','y','p','e','L','i','b','`',0};
3371 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3372 if (rc != ERROR_SUCCESS)
3373 return ERROR_SUCCESS;
3375 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3376 msiobj_release( &view->hdr );
3380 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3382 static const WCHAR szlnk[] = {'.','l','n','k',0};
3383 LPCWSTR directory, extension;
3384 LPWSTR link_folder, link_file, filename;
3386 directory = MSI_RecordGetString( row, 2 );
3387 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3389 /* may be needed because of a bug somewhere else */
3390 create_full_pathW( link_folder );
3392 filename = msi_dup_record_field( row, 3 );
3393 reduce_to_longfilename( filename );
3395 extension = strchrW( filename, '.' );
3396 if (!extension || strcmpiW( extension, szlnk ))
3398 int len = strlenW( filename );
3399 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3400 memcpy( filename + len, szlnk, sizeof(szlnk) );
3402 link_file = build_directory_name( 2, link_folder, filename );
3403 msi_free( link_folder );
3404 msi_free( filename );
3409 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3411 MSIPACKAGE *package = param;
3412 LPWSTR link_file, deformated, path;
3413 LPCWSTR component, target;
3415 IShellLinkW *sl = NULL;
3416 IPersistFile *pf = NULL;
3419 component = MSI_RecordGetString(row, 4);
3420 comp = get_loaded_component(package, component);
3422 return ERROR_SUCCESS;
3426 TRACE("component is disabled\n");
3427 return ERROR_SUCCESS;
3430 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3432 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3433 comp->Action = comp->Installed;
3434 return ERROR_SUCCESS;
3436 comp->Action = INSTALLSTATE_LOCAL;
3438 ui_actiondata(package,szCreateShortcuts,row);
3440 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3441 &IID_IShellLinkW, (LPVOID *) &sl );
3445 ERR("CLSID_ShellLink not available\n");
3449 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3452 ERR("QueryInterface(IID_IPersistFile) failed\n");
3456 target = MSI_RecordGetString(row, 5);
3457 if (strchrW(target, '['))
3459 deformat_string(package, target, &deformated);
3460 IShellLinkW_SetPath(sl,deformated);
3461 msi_free(deformated);
3465 FIXME("poorly handled shortcut format, advertised shortcut\n");
3466 IShellLinkW_SetPath(sl,comp->FullKeypath);
3469 if (!MSI_RecordIsNull(row,6))
3471 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3472 deformat_string(package, arguments, &deformated);
3473 IShellLinkW_SetArguments(sl,deformated);
3474 msi_free(deformated);
3477 if (!MSI_RecordIsNull(row,7))
3479 LPCWSTR description = MSI_RecordGetString(row, 7);
3480 IShellLinkW_SetDescription(sl, description);
3483 if (!MSI_RecordIsNull(row,8))
3484 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3486 if (!MSI_RecordIsNull(row,9))
3489 LPCWSTR icon = MSI_RecordGetString(row, 9);
3491 path = build_icon_path(package, icon);
3492 index = MSI_RecordGetInteger(row,10);
3494 /* no value means 0 */
3495 if (index == MSI_NULL_INTEGER)
3498 IShellLinkW_SetIconLocation(sl, path, index);
3502 if (!MSI_RecordIsNull(row,11))
3503 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3505 if (!MSI_RecordIsNull(row,12))
3507 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3508 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3510 IShellLinkW_SetWorkingDirectory(sl, path);
3514 link_file = get_link_file(package, row);
3516 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3517 IPersistFile_Save(pf, link_file, FALSE);
3519 msi_free(link_file);
3523 IPersistFile_Release( pf );
3525 IShellLinkW_Release( sl );
3527 return ERROR_SUCCESS;
3530 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3535 static const WCHAR Query[] =
3536 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3537 '`','S','h','o','r','t','c','u','t','`',0};
3539 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3540 if (rc != ERROR_SUCCESS)
3541 return ERROR_SUCCESS;
3543 res = CoInitialize( NULL );
3545 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3546 msiobj_release(&view->hdr);
3554 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3556 MSIPACKAGE *package = param;
3561 component = MSI_RecordGetString( row, 4 );
3562 comp = get_loaded_component( package, component );
3564 return ERROR_SUCCESS;
3568 TRACE("component is disabled\n");
3569 return ERROR_SUCCESS;
3572 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3574 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3575 comp->Action = comp->Installed;
3576 return ERROR_SUCCESS;
3578 comp->Action = INSTALLSTATE_ABSENT;
3580 ui_actiondata( package, szRemoveShortcuts, row );
3582 link_file = get_link_file( package, row );
3584 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3585 if (!DeleteFileW( link_file ))
3587 WARN("Failed to remove shortcut file %u\n", GetLastError());
3589 msi_free( link_file );
3591 return ERROR_SUCCESS;
3594 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3598 static const WCHAR query[] =
3599 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3600 '`','S','h','o','r','t','c','u','t','`',0};
3602 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3603 if (rc != ERROR_SUCCESS)
3604 return ERROR_SUCCESS;
3606 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3607 msiobj_release( &view->hdr );
3612 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3614 MSIPACKAGE* package = param;
3622 FileName = MSI_RecordGetString(row,1);
3625 ERR("Unable to get FileName\n");
3626 return ERROR_SUCCESS;
3629 FilePath = build_icon_path(package,FileName);
3631 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3633 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3634 FILE_ATTRIBUTE_NORMAL, NULL);
3636 if (the_file == INVALID_HANDLE_VALUE)
3638 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3640 return ERROR_SUCCESS;
3647 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3648 if (rc != ERROR_SUCCESS)
3650 ERR("Failed to get stream\n");
3651 CloseHandle(the_file);
3652 DeleteFileW(FilePath);
3655 WriteFile(the_file,buffer,sz,&write,NULL);
3656 } while (sz == 1024);
3659 CloseHandle(the_file);
3661 return ERROR_SUCCESS;
3664 static UINT msi_publish_icons(MSIPACKAGE *package)
3669 static const WCHAR query[]= {
3670 'S','E','L','E','C','T',' ','*',' ',
3671 'F','R','O','M',' ','`','I','c','o','n','`',0};
3673 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3674 if (r == ERROR_SUCCESS)
3676 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3677 msiobj_release(&view->hdr);
3680 return ERROR_SUCCESS;
3683 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3689 MSISOURCELISTINFO *info;
3691 r = RegCreateKeyW(hkey, szSourceList, &source);
3692 if (r != ERROR_SUCCESS)
3695 RegCloseKey(source);
3697 buffer = strrchrW(package->PackagePath, '\\') + 1;
3698 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3699 package->Context, MSICODE_PRODUCT,
3700 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3701 if (r != ERROR_SUCCESS)
3704 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3705 package->Context, MSICODE_PRODUCT,
3706 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3707 if (r != ERROR_SUCCESS)
3710 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3711 package->Context, MSICODE_PRODUCT,
3712 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3713 if (r != ERROR_SUCCESS)
3716 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3718 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3719 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3720 info->options, info->value);
3722 MsiSourceListSetInfoW(package->ProductCode, NULL,
3723 info->context, info->options,
3724 info->property, info->value);
3727 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3729 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3730 disk->context, disk->options,
3731 disk->disk_id, disk->volume_label, disk->disk_prompt);
3734 return ERROR_SUCCESS;
3737 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3739 MSIHANDLE hdb, suminfo;
3740 WCHAR guids[MAX_PATH];
3741 WCHAR packcode[SQUISH_GUID_SIZE];
3748 static const WCHAR szProductLanguage[] =
3749 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3750 static const WCHAR szARPProductIcon[] =
3751 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3752 static const WCHAR szProductVersion[] =
3753 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3754 static const WCHAR szAssignment[] =
3755 {'A','s','s','i','g','n','m','e','n','t',0};
3756 static const WCHAR szAdvertiseFlags[] =
3757 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3758 static const WCHAR szClients[] =
3759 {'C','l','i','e','n','t','s',0};
3760 static const WCHAR szColon[] = {':',0};
3762 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3763 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3766 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3767 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3770 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3772 buffer = msi_dup_property(package->db, szARPProductIcon);
3775 LPWSTR path = build_icon_path(package,buffer);
3776 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3781 buffer = msi_dup_property(package->db, szProductVersion);
3784 DWORD verdword = msi_version_str_to_dword(buffer);
3785 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3789 msi_reg_set_val_dword(hkey, szAssignment, 0);
3790 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3791 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3792 msi_reg_set_val_str(hkey, szClients, szColon);
3794 hdb = alloc_msihandle(&package->db->hdr);
3796 return ERROR_NOT_ENOUGH_MEMORY;
3798 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3799 MsiCloseHandle(hdb);
3800 if (r != ERROR_SUCCESS)
3804 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3805 NULL, guids, &size);
3806 if (r != ERROR_SUCCESS)
3809 ptr = strchrW(guids, ';');
3811 squash_guid(guids, packcode);
3812 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3815 MsiCloseHandle(suminfo);
3816 return ERROR_SUCCESS;
3819 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3824 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3826 upgrade = msi_dup_property(package->db, szUpgradeCode);
3828 return ERROR_SUCCESS;
3830 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3832 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3833 if (r != ERROR_SUCCESS)
3838 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3839 if (r != ERROR_SUCCESS)
3843 squash_guid(package->ProductCode, squashed_pc);
3844 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3853 static BOOL msi_check_publish(MSIPACKAGE *package)
3855 MSIFEATURE *feature;
3857 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3859 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3866 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3868 MSIFEATURE *feature;
3870 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3872 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3879 static UINT msi_publish_patches( MSIPACKAGE *package )
3881 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3882 WCHAR patch_squashed[GUID_SIZE];
3883 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
3885 MSIPATCHINFO *patch;
3887 WCHAR *p, *all_patches = NULL;
3890 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, FALSE );
3891 if (r != ERROR_SUCCESS)
3892 return ERROR_FUNCTION_FAILED;
3894 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3895 if (res != ERROR_SUCCESS)
3897 r = ERROR_FUNCTION_FAILED;
3901 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3902 if (r != ERROR_SUCCESS)
3905 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3907 squash_guid( patch->patchcode, patch_squashed );
3908 len += strlenW( patch_squashed ) + 1;
3911 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3915 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3919 squash_guid( patch->patchcode, p );
3920 p += strlenW( p ) + 1;
3922 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3923 (const BYTE *)patch->transforms,
3924 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3925 if (res != ERROR_SUCCESS)
3928 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3929 if (r != ERROR_SUCCESS)
3932 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3933 (const BYTE *)patch->localfile,
3934 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3935 RegCloseKey( patch_key );
3936 if (res != ERROR_SUCCESS)
3939 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3940 if (res != ERROR_SUCCESS)
3943 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
3944 RegCloseKey( patch_key );
3945 if (res != ERROR_SUCCESS)
3949 all_patches[len] = 0;
3950 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3951 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3952 if (res != ERROR_SUCCESS)
3955 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3956 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3957 if (res != ERROR_SUCCESS)
3958 r = ERROR_FUNCTION_FAILED;
3961 RegCloseKey( product_patches_key );
3962 RegCloseKey( patches_key );
3963 RegCloseKey( product_key );
3964 msi_free( all_patches );
3969 * 99% of the work done here is only done for
3970 * advertised installs. However this is where the
3971 * Icon table is processed and written out
3972 * so that is what I am going to do here.
3974 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3977 HKEY hukey = NULL, hudkey = NULL;
3980 if (!list_empty(&package->patches))
3982 rc = msi_publish_patches(package);
3983 if (rc != ERROR_SUCCESS)
3987 /* FIXME: also need to publish if the product is in advertise mode */
3988 if (!msi_check_publish(package))
3989 return ERROR_SUCCESS;
3991 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3993 if (rc != ERROR_SUCCESS)
3996 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3997 NULL, &hudkey, TRUE);
3998 if (rc != ERROR_SUCCESS)
4001 rc = msi_publish_upgrade_code(package);
4002 if (rc != ERROR_SUCCESS)
4005 rc = msi_publish_product_properties(package, hukey);
4006 if (rc != ERROR_SUCCESS)
4009 rc = msi_publish_sourcelist(package, hukey);
4010 if (rc != ERROR_SUCCESS)
4013 rc = msi_publish_icons(package);
4016 uirow = MSI_CreateRecord( 1 );
4017 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4018 ui_actiondata( package, szPublishProduct, uirow );
4019 msiobj_release( &uirow->hdr );
4022 RegCloseKey(hudkey);
4027 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4029 WCHAR *filename, *ptr, *folder, *ret;
4030 const WCHAR *dirprop;
4032 filename = msi_dup_record_field( row, 2 );
4033 if (filename && (ptr = strchrW( filename, '|' )))
4038 dirprop = MSI_RecordGetString( row, 3 );
4041 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4043 folder = msi_dup_property( package->db, dirprop );
4046 folder = msi_dup_property( package->db, szWindowsFolder );
4050 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4051 msi_free( filename );
4055 ret = build_directory_name( 2, folder, ptr );
4057 msi_free( filename );
4062 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4064 MSIPACKAGE *package = param;
4065 LPCWSTR component, section, key, value, identifier;
4066 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4071 component = MSI_RecordGetString(row, 8);
4072 comp = get_loaded_component(package,component);
4074 return ERROR_SUCCESS;
4078 TRACE("component is disabled\n");
4079 return ERROR_SUCCESS;
4082 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4084 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4085 comp->Action = comp->Installed;
4086 return ERROR_SUCCESS;
4088 comp->Action = INSTALLSTATE_LOCAL;
4090 identifier = MSI_RecordGetString(row,1);
4091 section = MSI_RecordGetString(row,4);
4092 key = MSI_RecordGetString(row,5);
4093 value = MSI_RecordGetString(row,6);
4094 action = MSI_RecordGetInteger(row,7);
4096 deformat_string(package,section,&deformated_section);
4097 deformat_string(package,key,&deformated_key);
4098 deformat_string(package,value,&deformated_value);
4100 fullname = get_ini_file_name(package, row);
4104 TRACE("Adding value %s to section %s in %s\n",
4105 debugstr_w(deformated_key), debugstr_w(deformated_section),
4106 debugstr_w(fullname));
4107 WritePrivateProfileStringW(deformated_section, deformated_key,
4108 deformated_value, fullname);
4110 else if (action == 1)
4113 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4114 returned, 10, fullname);
4115 if (returned[0] == 0)
4117 TRACE("Adding value %s to section %s in %s\n",
4118 debugstr_w(deformated_key), debugstr_w(deformated_section),
4119 debugstr_w(fullname));
4121 WritePrivateProfileStringW(deformated_section, deformated_key,
4122 deformated_value, fullname);
4125 else if (action == 3)
4126 FIXME("Append to existing section not yet implemented\n");
4128 uirow = MSI_CreateRecord(4);
4129 MSI_RecordSetStringW(uirow,1,identifier);
4130 MSI_RecordSetStringW(uirow,2,deformated_section);
4131 MSI_RecordSetStringW(uirow,3,deformated_key);
4132 MSI_RecordSetStringW(uirow,4,deformated_value);
4133 ui_actiondata(package,szWriteIniValues,uirow);
4134 msiobj_release( &uirow->hdr );
4137 msi_free(deformated_key);
4138 msi_free(deformated_value);
4139 msi_free(deformated_section);
4140 return ERROR_SUCCESS;
4143 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4147 static const WCHAR ExecSeqQuery[] =
4148 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4149 '`','I','n','i','F','i','l','e','`',0};
4151 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4152 if (rc != ERROR_SUCCESS)
4154 TRACE("no IniFile table\n");
4155 return ERROR_SUCCESS;
4158 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4159 msiobj_release(&view->hdr);
4163 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4165 MSIPACKAGE *package = param;
4166 LPCWSTR component, section, key, value, identifier;
4167 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4172 component = MSI_RecordGetString( row, 8 );
4173 comp = get_loaded_component( package, component );
4175 return ERROR_SUCCESS;
4179 TRACE("component is disabled\n");
4180 return ERROR_SUCCESS;
4183 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4185 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4186 comp->Action = comp->Installed;
4187 return ERROR_SUCCESS;
4189 comp->Action = INSTALLSTATE_ABSENT;
4191 identifier = MSI_RecordGetString( row, 1 );
4192 section = MSI_RecordGetString( row, 4 );
4193 key = MSI_RecordGetString( row, 5 );
4194 value = MSI_RecordGetString( row, 6 );
4195 action = MSI_RecordGetInteger( row, 7 );
4197 deformat_string( package, section, &deformated_section );
4198 deformat_string( package, key, &deformated_key );
4199 deformat_string( package, value, &deformated_value );
4201 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4203 filename = get_ini_file_name( package, row );
4205 TRACE("Removing key %s from section %s in %s\n",
4206 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4208 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4210 WARN("Unable to remove key %u\n", GetLastError());
4212 msi_free( filename );
4215 FIXME("Unsupported action %d\n", action);
4218 uirow = MSI_CreateRecord( 4 );
4219 MSI_RecordSetStringW( uirow, 1, identifier );
4220 MSI_RecordSetStringW( uirow, 2, deformated_section );
4221 MSI_RecordSetStringW( uirow, 3, deformated_key );
4222 MSI_RecordSetStringW( uirow, 4, deformated_value );
4223 ui_actiondata( package, szRemoveIniValues, uirow );
4224 msiobj_release( &uirow->hdr );
4226 msi_free( deformated_key );
4227 msi_free( deformated_value );
4228 msi_free( deformated_section );
4229 return ERROR_SUCCESS;
4232 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4234 MSIPACKAGE *package = param;
4235 LPCWSTR component, section, key, value, identifier;
4236 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4241 component = MSI_RecordGetString( row, 8 );
4242 comp = get_loaded_component( package, component );
4244 return ERROR_SUCCESS;
4248 TRACE("component is disabled\n");
4249 return ERROR_SUCCESS;
4252 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4254 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4255 comp->Action = comp->Installed;
4256 return ERROR_SUCCESS;
4258 comp->Action = INSTALLSTATE_LOCAL;
4260 identifier = MSI_RecordGetString( row, 1 );
4261 section = MSI_RecordGetString( row, 4 );
4262 key = MSI_RecordGetString( row, 5 );
4263 value = MSI_RecordGetString( row, 6 );
4264 action = MSI_RecordGetInteger( row, 7 );
4266 deformat_string( package, section, &deformated_section );
4267 deformat_string( package, key, &deformated_key );
4268 deformat_string( package, value, &deformated_value );
4270 if (action == msidbIniFileActionRemoveLine)
4272 filename = get_ini_file_name( package, row );
4274 TRACE("Removing key %s from section %s in %s\n",
4275 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4277 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4279 WARN("Unable to remove key %u\n", GetLastError());
4281 msi_free( filename );
4284 FIXME("Unsupported action %d\n", action);
4286 uirow = MSI_CreateRecord( 4 );
4287 MSI_RecordSetStringW( uirow, 1, identifier );
4288 MSI_RecordSetStringW( uirow, 2, deformated_section );
4289 MSI_RecordSetStringW( uirow, 3, deformated_key );
4290 MSI_RecordSetStringW( uirow, 4, deformated_value );
4291 ui_actiondata( package, szRemoveIniValues, uirow );
4292 msiobj_release( &uirow->hdr );
4294 msi_free( deformated_key );
4295 msi_free( deformated_value );
4296 msi_free( deformated_section );
4297 return ERROR_SUCCESS;
4300 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4304 static const WCHAR query[] =
4305 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4306 '`','I','n','i','F','i','l','e','`',0};
4307 static const WCHAR remove_query[] =
4308 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4309 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4311 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4312 if (rc == ERROR_SUCCESS)
4314 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4315 msiobj_release( &view->hdr );
4316 if (rc != ERROR_SUCCESS)
4320 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4321 if (rc == ERROR_SUCCESS)
4323 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4324 msiobj_release( &view->hdr );
4325 if (rc != ERROR_SUCCESS)
4329 return ERROR_SUCCESS;
4332 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4334 MSIPACKAGE *package = param;
4339 static const WCHAR ExeStr[] =
4340 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4341 static const WCHAR close[] = {'\"',0};
4343 PROCESS_INFORMATION info;
4347 memset(&si,0,sizeof(STARTUPINFOW));
4349 filename = MSI_RecordGetString(row,1);
4350 file = get_loaded_file( package, filename );
4354 ERR("Unable to find file id %s\n",debugstr_w(filename));
4355 return ERROR_SUCCESS;
4358 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4360 FullName = msi_alloc(len*sizeof(WCHAR));
4361 strcpyW(FullName,ExeStr);
4362 strcatW( FullName, file->TargetPath );
4363 strcatW(FullName,close);
4365 TRACE("Registering %s\n",debugstr_w(FullName));
4366 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4371 CloseHandle(info.hThread);
4372 msi_dialog_check_messages(info.hProcess);
4373 CloseHandle(info.hProcess);
4376 uirow = MSI_CreateRecord( 2 );
4377 MSI_RecordSetStringW( uirow, 1, filename );
4378 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4379 ui_actiondata( package, szSelfRegModules, uirow );
4380 msiobj_release( &uirow->hdr );
4382 msi_free( FullName );
4383 return ERROR_SUCCESS;
4386 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4390 static const WCHAR ExecSeqQuery[] =
4391 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4392 '`','S','e','l','f','R','e','g','`',0};
4394 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4395 if (rc != ERROR_SUCCESS)
4397 TRACE("no SelfReg table\n");
4398 return ERROR_SUCCESS;
4401 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4402 msiobj_release(&view->hdr);
4404 return ERROR_SUCCESS;
4407 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4409 static const WCHAR regsvr32[] =
4410 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4411 static const WCHAR close[] = {'\"',0};
4412 MSIPACKAGE *package = param;
4418 PROCESS_INFORMATION pi;
4422 memset( &si, 0, sizeof(STARTUPINFOW) );
4424 filename = MSI_RecordGetString( row, 1 );
4425 file = get_loaded_file( package, filename );
4429 ERR("Unable to find file id %s\n", debugstr_w(filename));
4430 return ERROR_SUCCESS;
4433 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4435 cmdline = msi_alloc( len * sizeof(WCHAR) );
4436 strcpyW( cmdline, regsvr32 );
4437 strcatW( cmdline, file->TargetPath );
4438 strcatW( cmdline, close );
4440 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4442 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4445 CloseHandle( pi.hThread );
4446 msi_dialog_check_messages( pi.hProcess );
4447 CloseHandle( pi.hProcess );
4450 uirow = MSI_CreateRecord( 2 );
4451 MSI_RecordSetStringW( uirow, 1, filename );
4452 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4453 ui_actiondata( package, szSelfUnregModules, uirow );
4454 msiobj_release( &uirow->hdr );
4456 msi_free( cmdline );
4457 return ERROR_SUCCESS;
4460 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4464 static const WCHAR query[] =
4465 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4466 '`','S','e','l','f','R','e','g','`',0};
4468 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4469 if (rc != ERROR_SUCCESS)
4471 TRACE("no SelfReg table\n");
4472 return ERROR_SUCCESS;
4475 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4476 msiobj_release( &view->hdr );
4478 return ERROR_SUCCESS;
4481 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4483 MSIFEATURE *feature;
4485 HKEY hkey = NULL, userdata = NULL;
4487 if (!msi_check_publish(package))
4488 return ERROR_SUCCESS;
4490 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4492 if (rc != ERROR_SUCCESS)
4495 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4497 if (rc != ERROR_SUCCESS)
4500 /* here the guids are base 85 encoded */
4501 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4507 BOOL absent = FALSE;
4510 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4511 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4512 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4515 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4519 if (feature->Feature_Parent)
4520 size += strlenW( feature->Feature_Parent )+2;
4522 data = msi_alloc(size * sizeof(WCHAR));
4525 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4527 MSICOMPONENT* component = cl->component;
4531 if (component->ComponentId)
4533 TRACE("From %s\n",debugstr_w(component->ComponentId));
4534 CLSIDFromString(component->ComponentId, &clsid);
4535 encode_base85_guid(&clsid,buf);
4536 TRACE("to %s\n",debugstr_w(buf));
4541 if (feature->Feature_Parent)
4543 static const WCHAR sep[] = {'\2',0};
4545 strcatW(data,feature->Feature_Parent);
4548 msi_reg_set_val_str( userdata, feature->Feature, data );
4552 if (feature->Feature_Parent)
4553 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4556 size += sizeof(WCHAR);
4557 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4558 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4562 size += 2*sizeof(WCHAR);
4563 data = msi_alloc(size);
4566 if (feature->Feature_Parent)
4567 strcpyW( &data[1], feature->Feature_Parent );
4568 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4574 uirow = MSI_CreateRecord( 1 );
4575 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4576 ui_actiondata( package, szPublishFeatures, uirow);
4577 msiobj_release( &uirow->hdr );
4578 /* FIXME: call ui_progress? */
4583 RegCloseKey(userdata);
4587 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4593 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4595 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4597 if (r == ERROR_SUCCESS)
4599 RegDeleteValueW(hkey, feature->Feature);
4603 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4605 if (r == ERROR_SUCCESS)
4607 RegDeleteValueW(hkey, feature->Feature);
4611 uirow = MSI_CreateRecord( 1 );
4612 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4613 ui_actiondata( package, szUnpublishFeatures, uirow );
4614 msiobj_release( &uirow->hdr );
4616 return ERROR_SUCCESS;
4619 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4621 MSIFEATURE *feature;
4623 if (!msi_check_unpublish(package))
4624 return ERROR_SUCCESS;
4626 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4628 msi_unpublish_feature(package, feature);
4631 return ERROR_SUCCESS;
4634 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4638 WCHAR date[9], *val, *buffer;
4639 const WCHAR *prop, *key;
4641 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4642 static const WCHAR szWindowsInstaller[] =
4643 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4644 static const WCHAR modpath_fmt[] =
4645 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4646 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4647 static const WCHAR szModifyPath[] =
4648 {'M','o','d','i','f','y','P','a','t','h',0};
4649 static const WCHAR szUninstallString[] =
4650 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4651 static const WCHAR szEstimatedSize[] =
4652 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4653 static const WCHAR szProductLanguage[] =
4654 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4655 static const WCHAR szProductVersion[] =
4656 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4657 static const WCHAR szDisplayVersion[] =
4658 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4659 static const WCHAR szInstallSource[] =
4660 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4661 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4662 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4663 static const WCHAR szAuthorizedCDFPrefix[] =
4664 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4665 static const WCHAR szARPCONTACT[] =
4666 {'A','R','P','C','O','N','T','A','C','T',0};
4667 static const WCHAR szContact[] =
4668 {'C','o','n','t','a','c','t',0};
4669 static const WCHAR szARPCOMMENTS[] =
4670 {'A','R','P','C','O','M','M','E','N','T','S',0};
4671 static const WCHAR szComments[] =
4672 {'C','o','m','m','e','n','t','s',0};
4673 static const WCHAR szProductName[] =
4674 {'P','r','o','d','u','c','t','N','a','m','e',0};
4675 static const WCHAR szDisplayName[] =
4676 {'D','i','s','p','l','a','y','N','a','m','e',0};
4677 static const WCHAR szARPHELPLINK[] =
4678 {'A','R','P','H','E','L','P','L','I','N','K',0};
4679 static const WCHAR szHelpLink[] =
4680 {'H','e','l','p','L','i','n','k',0};
4681 static const WCHAR szARPHELPTELEPHONE[] =
4682 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4683 static const WCHAR szHelpTelephone[] =
4684 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4685 static const WCHAR szARPINSTALLLOCATION[] =
4686 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4687 static const WCHAR szInstallLocation[] =
4688 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4689 static const WCHAR szManufacturer[] =
4690 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4691 static const WCHAR szPublisher[] =
4692 {'P','u','b','l','i','s','h','e','r',0};
4693 static const WCHAR szARPREADME[] =
4694 {'A','R','P','R','E','A','D','M','E',0};
4695 static const WCHAR szReadme[] =
4696 {'R','e','a','d','M','e',0};
4697 static const WCHAR szARPSIZE[] =
4698 {'A','R','P','S','I','Z','E',0};
4699 static const WCHAR szSize[] =
4700 {'S','i','z','e',0};
4701 static const WCHAR szARPURLINFOABOUT[] =
4702 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4703 static const WCHAR szURLInfoAbout[] =
4704 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4705 static const WCHAR szARPURLUPDATEINFO[] =
4706 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4707 static const WCHAR szURLUpdateInfo[] =
4708 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4710 static const WCHAR *propval[] = {
4711 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4712 szARPCONTACT, szContact,
4713 szARPCOMMENTS, szComments,
4714 szProductName, szDisplayName,
4715 szARPHELPLINK, szHelpLink,
4716 szARPHELPTELEPHONE, szHelpTelephone,
4717 szARPINSTALLLOCATION, szInstallLocation,
4718 cszSourceDir, szInstallSource,
4719 szManufacturer, szPublisher,
4720 szARPREADME, szReadme,
4722 szARPURLINFOABOUT, szURLInfoAbout,
4723 szARPURLUPDATEINFO, szURLUpdateInfo,
4726 const WCHAR **p = propval;
4732 val = msi_dup_property(package->db, prop);
4733 msi_reg_set_val_str(hkey, key, val);
4737 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4739 size = deformat_string(package, modpath_fmt, &buffer);
4740 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4741 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4744 /* FIXME: Write real Estimated Size when we have it */
4745 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4747 GetLocalTime(&systime);
4748 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4749 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4751 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4752 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4754 buffer = msi_dup_property(package->db, szProductVersion);
4755 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4758 DWORD verdword = msi_version_str_to_dword(buffer);
4760 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4761 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4762 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4766 return ERROR_SUCCESS;
4769 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4771 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4773 LPWSTR upgrade_code;
4778 /* FIXME: also need to publish if the product is in advertise mode */
4779 if (!msi_check_publish(package))
4780 return ERROR_SUCCESS;
4782 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4783 if (rc != ERROR_SUCCESS)
4786 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4787 NULL, &props, TRUE);
4788 if (rc != ERROR_SUCCESS)
4791 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4792 msi_free( package->db->localfile );
4793 package->db->localfile = NULL;
4795 rc = msi_publish_install_properties(package, hkey);
4796 if (rc != ERROR_SUCCESS)
4799 rc = msi_publish_install_properties(package, props);
4800 if (rc != ERROR_SUCCESS)
4803 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4806 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4807 squash_guid(package->ProductCode, squashed_pc);
4808 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4809 RegCloseKey(upgrade);
4810 msi_free(upgrade_code);
4814 uirow = MSI_CreateRecord( 1 );
4815 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4816 ui_actiondata( package, szRegisterProduct, uirow );
4817 msiobj_release( &uirow->hdr );
4820 return ERROR_SUCCESS;
4823 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4825 return execute_script(package,INSTALL_SCRIPT);
4828 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4830 WCHAR *upgrade, **features;
4831 BOOL full_uninstall = TRUE;
4832 MSIFEATURE *feature;
4833 MSIPATCHINFO *patch;
4835 static const WCHAR szUpgradeCode[] =
4836 {'U','p','g','r','a','d','e','C','o','d','e',0};
4838 features = msi_split_string(remove, ',');
4841 ERR("REMOVE feature list is empty!\n");
4842 return ERROR_FUNCTION_FAILED;
4845 if (!lstrcmpW(features[0], szAll))
4846 full_uninstall = TRUE;
4849 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4851 if (feature->Action != INSTALLSTATE_ABSENT)
4852 full_uninstall = FALSE;
4857 if (!full_uninstall)
4858 return ERROR_SUCCESS;
4860 MSIREG_DeleteProductKey(package->ProductCode);
4861 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4862 MSIREG_DeleteUninstallKey(package->ProductCode);
4864 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4866 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4867 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4871 MSIREG_DeleteUserProductKey(package->ProductCode);
4872 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4875 upgrade = msi_dup_property(package->db, szUpgradeCode);
4878 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4882 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4884 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4887 return ERROR_SUCCESS;
4890 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4895 /* turn off scheduling */
4896 package->script->CurrentlyScripting= FALSE;
4898 /* first do the same as an InstallExecute */
4899 rc = ACTION_InstallExecute(package);
4900 if (rc != ERROR_SUCCESS)
4903 /* then handle Commit Actions */
4904 rc = execute_script(package,COMMIT_SCRIPT);
4905 if (rc != ERROR_SUCCESS)
4908 remove = msi_dup_property(package->db, szRemove);
4910 rc = msi_unpublish_product(package, remove);
4916 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4918 static const WCHAR RunOnce[] = {
4919 'S','o','f','t','w','a','r','e','\\',
4920 'M','i','c','r','o','s','o','f','t','\\',
4921 'W','i','n','d','o','w','s','\\',
4922 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4923 'R','u','n','O','n','c','e',0};
4924 static const WCHAR InstallRunOnce[] = {
4925 'S','o','f','t','w','a','r','e','\\',
4926 'M','i','c','r','o','s','o','f','t','\\',
4927 'W','i','n','d','o','w','s','\\',
4928 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4929 'I','n','s','t','a','l','l','e','r','\\',
4930 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4932 static const WCHAR msiexec_fmt[] = {
4934 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4935 '\"','%','s','\"',0};
4936 static const WCHAR install_fmt[] = {
4937 '/','I',' ','\"','%','s','\"',' ',
4938 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4939 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4940 WCHAR buffer[256], sysdir[MAX_PATH];
4942 WCHAR squished_pc[100];
4944 squash_guid(package->ProductCode,squished_pc);
4946 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4947 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4948 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4951 msi_reg_set_val_str( hkey, squished_pc, buffer );
4954 TRACE("Reboot command %s\n",debugstr_w(buffer));
4956 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4957 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4959 msi_reg_set_val_str( hkey, squished_pc, buffer );
4962 return ERROR_INSTALL_SUSPEND;
4965 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4971 * We are currently doing what should be done here in the top level Install
4972 * however for Administrative and uninstalls this step will be needed
4974 if (!package->PackagePath)
4975 return ERROR_SUCCESS;
4977 msi_set_sourcedir_props(package, TRUE);
4979 attrib = GetFileAttributesW(package->db->path);
4980 if (attrib == INVALID_FILE_ATTRIBUTES)
4986 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4987 package->Context, MSICODE_PRODUCT,
4988 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4989 if (rc == ERROR_MORE_DATA)
4991 prompt = msi_alloc(size * sizeof(WCHAR));
4992 MsiSourceListGetInfoW(package->ProductCode, NULL,
4993 package->Context, MSICODE_PRODUCT,
4994 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4997 prompt = strdupW(package->db->path);
4999 msg = generate_error_string(package,1302,1,prompt);
5000 while(attrib == INVALID_FILE_ATTRIBUTES)
5002 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5005 rc = ERROR_INSTALL_USEREXIT;
5008 attrib = GetFileAttributesW(package->db->path);
5014 return ERROR_SUCCESS;
5019 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5022 LPWSTR buffer, productid = NULL;
5023 UINT i, rc = ERROR_SUCCESS;
5026 static const WCHAR szPropKeys[][80] =
5028 {'P','r','o','d','u','c','t','I','D',0},
5029 {'U','S','E','R','N','A','M','E',0},
5030 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5034 static const WCHAR szRegKeys[][80] =
5036 {'P','r','o','d','u','c','t','I','D',0},
5037 {'R','e','g','O','w','n','e','r',0},
5038 {'R','e','g','C','o','m','p','a','n','y',0},
5042 if (msi_check_unpublish(package))
5044 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5048 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5052 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5054 if (rc != ERROR_SUCCESS)
5057 for( i = 0; szPropKeys[i][0]; i++ )
5059 buffer = msi_dup_property( package->db, szPropKeys[i] );
5060 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5065 uirow = MSI_CreateRecord( 1 );
5066 MSI_RecordSetStringW( uirow, 1, productid );
5067 ui_actiondata( package, szRegisterUser, uirow );
5068 msiobj_release( &uirow->hdr );
5070 msi_free(productid);
5076 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5080 package->script->InWhatSequence |= SEQUENCE_EXEC;
5081 rc = ACTION_ProcessExecSequence(package,FALSE);
5086 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5088 MSIPACKAGE *package = param;
5089 LPCWSTR compgroupid, component, feature, qualifier, text;
5090 LPWSTR advertise = NULL, output = NULL;
5098 feature = MSI_RecordGetString(rec, 5);
5099 feat = get_loaded_feature(package, feature);
5101 return ERROR_SUCCESS;
5103 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5104 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5105 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5107 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5108 feat->Action = feat->Installed;
5109 return ERROR_SUCCESS;
5112 component = MSI_RecordGetString(rec, 3);
5113 comp = get_loaded_component(package, component);
5115 return ERROR_SUCCESS;
5117 compgroupid = MSI_RecordGetString(rec,1);
5118 qualifier = MSI_RecordGetString(rec,2);
5120 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5121 if (rc != ERROR_SUCCESS)
5124 text = MSI_RecordGetString(rec,4);
5125 advertise = create_component_advertise_string(package, comp, feature);
5127 sz = strlenW(advertise);
5130 sz += lstrlenW(text);
5133 sz *= sizeof(WCHAR);
5135 output = msi_alloc_zero(sz);
5136 strcpyW(output,advertise);
5137 msi_free(advertise);
5140 strcatW(output,text);
5142 msi_reg_set_val_multi_str( hkey, qualifier, output );
5149 uirow = MSI_CreateRecord( 2 );
5150 MSI_RecordSetStringW( uirow, 1, compgroupid );
5151 MSI_RecordSetStringW( uirow, 2, qualifier);
5152 ui_actiondata( package, szPublishComponents, uirow);
5153 msiobj_release( &uirow->hdr );
5154 /* FIXME: call ui_progress? */
5160 * At present I am ignorning the advertised components part of this and only
5161 * focusing on the qualified component sets
5163 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5167 static const WCHAR ExecSeqQuery[] =
5168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5169 '`','P','u','b','l','i','s','h',
5170 'C','o','m','p','o','n','e','n','t','`',0};
5172 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5173 if (rc != ERROR_SUCCESS)
5174 return ERROR_SUCCESS;
5176 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5177 msiobj_release(&view->hdr);
5182 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5184 static const WCHAR szInstallerComponents[] = {
5185 'S','o','f','t','w','a','r','e','\\',
5186 'M','i','c','r','o','s','o','f','t','\\',
5187 'I','n','s','t','a','l','l','e','r','\\',
5188 'C','o','m','p','o','n','e','n','t','s','\\',0};
5190 MSIPACKAGE *package = param;
5191 LPCWSTR compgroupid, component, feature, qualifier;
5195 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5198 feature = MSI_RecordGetString( rec, 5 );
5199 feat = get_loaded_feature( package, feature );
5201 return ERROR_SUCCESS;
5203 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5205 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5206 feat->Action = feat->Installed;
5207 return ERROR_SUCCESS;
5210 component = MSI_RecordGetString( rec, 3 );
5211 comp = get_loaded_component( package, component );
5213 return ERROR_SUCCESS;
5215 compgroupid = MSI_RecordGetString( rec, 1 );
5216 qualifier = MSI_RecordGetString( rec, 2 );
5218 squash_guid( compgroupid, squashed );
5219 strcpyW( keypath, szInstallerComponents );
5220 strcatW( keypath, squashed );
5222 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5223 if (res != ERROR_SUCCESS)
5225 WARN("Unable to delete component key %d\n", res);
5228 uirow = MSI_CreateRecord( 2 );
5229 MSI_RecordSetStringW( uirow, 1, compgroupid );
5230 MSI_RecordSetStringW( uirow, 2, qualifier );
5231 ui_actiondata( package, szUnpublishComponents, uirow );
5232 msiobj_release( &uirow->hdr );
5234 return ERROR_SUCCESS;
5237 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5241 static const WCHAR query[] =
5242 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5243 '`','P','u','b','l','i','s','h',
5244 'C','o','m','p','o','n','e','n','t','`',0};
5246 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5247 if (rc != ERROR_SUCCESS)
5248 return ERROR_SUCCESS;
5250 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5251 msiobj_release( &view->hdr );
5256 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5258 MSIPACKAGE *package = param;
5261 SC_HANDLE hscm, service = NULL;
5262 LPCWSTR comp, depends, pass;
5263 LPWSTR name = NULL, disp = NULL;
5264 LPCWSTR load_order, serv_name, key;
5265 DWORD serv_type, start_type;
5268 static const WCHAR query[] =
5269 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5270 '`','C','o','m','p','o','n','e','n','t','`',' ',
5271 'W','H','E','R','E',' ',
5272 '`','C','o','m','p','o','n','e','n','t','`',' ',
5273 '=','\'','%','s','\'',0};
5275 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5278 ERR("Failed to open the SC Manager!\n");
5282 start_type = MSI_RecordGetInteger(rec, 5);
5283 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5286 depends = MSI_RecordGetString(rec, 8);
5287 if (depends && *depends)
5288 FIXME("Dependency list unhandled!\n");
5290 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5291 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5292 serv_type = MSI_RecordGetInteger(rec, 4);
5293 err_control = MSI_RecordGetInteger(rec, 6);
5294 load_order = MSI_RecordGetString(rec, 7);
5295 serv_name = MSI_RecordGetString(rec, 9);
5296 pass = MSI_RecordGetString(rec, 10);
5297 comp = MSI_RecordGetString(rec, 12);
5299 /* fetch the service path */
5300 row = MSI_QueryGetRecord(package->db, query, comp);
5303 ERR("Control query failed!\n");
5307 key = MSI_RecordGetString(row, 6);
5309 file = get_loaded_file(package, key);
5310 msiobj_release(&row->hdr);
5313 ERR("Failed to load the service file\n");
5317 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5318 start_type, err_control, file->TargetPath,
5319 load_order, NULL, NULL, serv_name, pass);
5322 if (GetLastError() != ERROR_SERVICE_EXISTS)
5323 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5327 CloseServiceHandle(service);
5328 CloseServiceHandle(hscm);
5332 return ERROR_SUCCESS;
5335 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5339 static const WCHAR ExecSeqQuery[] =
5340 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5341 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5343 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5344 if (rc != ERROR_SUCCESS)
5345 return ERROR_SUCCESS;
5347 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5348 msiobj_release(&view->hdr);
5353 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5354 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5356 LPCWSTR *vector, *temp_vector;
5360 static const WCHAR separator[] = {'[','~',']',0};
5363 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5368 vector = msi_alloc(sizeof(LPWSTR));
5376 vector[*numargs - 1] = p;
5378 if ((q = strstrW(p, separator)))
5382 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5388 vector = temp_vector;
5397 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5399 MSIPACKAGE *package = param;
5402 SC_HANDLE scm = NULL, service = NULL;
5403 LPCWSTR component, *vector = NULL;
5404 LPWSTR name, args, display_name = NULL;
5405 DWORD event, numargs, len;
5406 UINT r = ERROR_FUNCTION_FAILED;
5408 component = MSI_RecordGetString(rec, 6);
5409 comp = get_loaded_component(package, component);
5411 return ERROR_SUCCESS;
5415 TRACE("component is disabled\n");
5416 return ERROR_SUCCESS;
5419 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5421 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5422 comp->Action = comp->Installed;
5423 return ERROR_SUCCESS;
5425 comp->Action = INSTALLSTATE_LOCAL;
5427 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5428 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5429 event = MSI_RecordGetInteger(rec, 3);
5431 if (!(event & msidbServiceControlEventStart))
5437 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5440 ERR("Failed to open the service control manager\n");
5445 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5446 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5448 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5449 GetServiceDisplayNameW( scm, name, display_name, &len );
5452 service = OpenServiceW(scm, name, SERVICE_START);
5455 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5459 vector = msi_service_args_to_vector(args, &numargs);
5461 if (!StartServiceW(service, numargs, vector) &&
5462 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5464 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5471 uirow = MSI_CreateRecord( 2 );
5472 MSI_RecordSetStringW( uirow, 1, display_name );
5473 MSI_RecordSetStringW( uirow, 2, name );
5474 ui_actiondata( package, szStartServices, uirow );
5475 msiobj_release( &uirow->hdr );
5477 CloseServiceHandle(service);
5478 CloseServiceHandle(scm);
5483 msi_free(display_name);
5487 static UINT ACTION_StartServices( MSIPACKAGE *package )
5492 static const WCHAR query[] = {
5493 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5494 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5496 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5497 if (rc != ERROR_SUCCESS)
5498 return ERROR_SUCCESS;
5500 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5501 msiobj_release(&view->hdr);
5506 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5508 DWORD i, needed, count;
5509 ENUM_SERVICE_STATUSW *dependencies;
5513 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5514 0, &needed, &count))
5517 if (GetLastError() != ERROR_MORE_DATA)
5520 dependencies = msi_alloc(needed);
5524 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5525 needed, &needed, &count))
5528 for (i = 0; i < count; i++)
5530 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5531 SERVICE_STOP | SERVICE_QUERY_STATUS);
5535 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5542 msi_free(dependencies);
5546 static UINT stop_service( LPCWSTR name )
5548 SC_HANDLE scm = NULL, service = NULL;
5549 SERVICE_STATUS status;
5550 SERVICE_STATUS_PROCESS ssp;
5553 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5556 WARN("Failed to open the SCM: %d\n", GetLastError());
5560 service = OpenServiceW(scm, name,
5562 SERVICE_QUERY_STATUS |
5563 SERVICE_ENUMERATE_DEPENDENTS);
5566 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5570 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5571 sizeof(SERVICE_STATUS_PROCESS), &needed))
5573 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5577 if (ssp.dwCurrentState == SERVICE_STOPPED)
5580 stop_service_dependents(scm, service);
5582 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5583 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5586 CloseServiceHandle(service);
5587 CloseServiceHandle(scm);
5589 return ERROR_SUCCESS;
5592 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5594 MSIPACKAGE *package = param;
5598 LPWSTR name = NULL, display_name = NULL;
5602 event = MSI_RecordGetInteger( rec, 3 );
5603 if (!(event & msidbServiceControlEventStop))
5604 return ERROR_SUCCESS;
5606 component = MSI_RecordGetString( rec, 6 );
5607 comp = get_loaded_component( package, component );
5609 return ERROR_SUCCESS;
5613 TRACE("component is disabled\n");
5614 return ERROR_SUCCESS;
5617 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5619 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5620 comp->Action = comp->Installed;
5621 return ERROR_SUCCESS;
5623 comp->Action = INSTALLSTATE_ABSENT;
5625 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5628 ERR("Failed to open the service control manager\n");
5633 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5634 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5636 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5637 GetServiceDisplayNameW( scm, name, display_name, &len );
5639 CloseServiceHandle( scm );
5641 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5642 stop_service( name );
5645 uirow = MSI_CreateRecord( 2 );
5646 MSI_RecordSetStringW( uirow, 1, display_name );
5647 MSI_RecordSetStringW( uirow, 2, name );
5648 ui_actiondata( package, szStopServices, uirow );
5649 msiobj_release( &uirow->hdr );
5652 msi_free( display_name );
5653 return ERROR_SUCCESS;
5656 static UINT ACTION_StopServices( MSIPACKAGE *package )
5661 static const WCHAR query[] = {
5662 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5663 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5665 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5666 if (rc != ERROR_SUCCESS)
5667 return ERROR_SUCCESS;
5669 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5670 msiobj_release(&view->hdr);
5675 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5677 MSIPACKAGE *package = param;
5681 LPWSTR name = NULL, display_name = NULL;
5683 SC_HANDLE scm = NULL, service = NULL;
5685 event = MSI_RecordGetInteger( rec, 3 );
5686 if (!(event & msidbServiceControlEventDelete))
5687 return ERROR_SUCCESS;
5689 component = MSI_RecordGetString(rec, 6);
5690 comp = get_loaded_component(package, component);
5692 return ERROR_SUCCESS;
5696 TRACE("component is disabled\n");
5697 return ERROR_SUCCESS;
5700 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5702 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5703 comp->Action = comp->Installed;
5704 return ERROR_SUCCESS;
5706 comp->Action = INSTALLSTATE_ABSENT;
5708 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5709 stop_service( name );
5711 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5714 WARN("Failed to open the SCM: %d\n", GetLastError());
5719 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5720 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5722 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5723 GetServiceDisplayNameW( scm, name, display_name, &len );
5726 service = OpenServiceW( scm, name, DELETE );
5729 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5733 if (!DeleteService( service ))
5734 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5737 uirow = MSI_CreateRecord( 2 );
5738 MSI_RecordSetStringW( uirow, 1, display_name );
5739 MSI_RecordSetStringW( uirow, 2, name );
5740 ui_actiondata( package, szDeleteServices, uirow );
5741 msiobj_release( &uirow->hdr );
5743 CloseServiceHandle( service );
5744 CloseServiceHandle( scm );
5746 msi_free( display_name );
5748 return ERROR_SUCCESS;
5751 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5756 static const WCHAR query[] = {
5757 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5758 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5760 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5761 if (rc != ERROR_SUCCESS)
5762 return ERROR_SUCCESS;
5764 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5765 msiobj_release( &view->hdr );
5770 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5774 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5776 if (!lstrcmpW(file->File, filename))
5783 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5785 MSIPACKAGE *package = param;
5786 LPWSTR driver, driver_path, ptr;
5787 WCHAR outpath[MAX_PATH];
5788 MSIFILE *driver_file, *setup_file;
5792 UINT r = ERROR_SUCCESS;
5794 static const WCHAR driver_fmt[] = {
5795 'D','r','i','v','e','r','=','%','s',0};
5796 static const WCHAR setup_fmt[] = {
5797 'S','e','t','u','p','=','%','s',0};
5798 static const WCHAR usage_fmt[] = {
5799 'F','i','l','e','U','s','a','g','e','=','1',0};
5801 desc = MSI_RecordGetString(rec, 3);
5803 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5804 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5808 ERR("ODBC Driver entry not found!\n");
5809 return ERROR_FUNCTION_FAILED;
5812 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5814 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5815 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5817 driver = msi_alloc(len * sizeof(WCHAR));
5819 return ERROR_OUTOFMEMORY;
5822 lstrcpyW(ptr, desc);
5823 ptr += lstrlenW(ptr) + 1;
5825 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5830 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5834 lstrcpyW(ptr, usage_fmt);
5835 ptr += lstrlenW(ptr) + 1;
5838 driver_path = strdupW(driver_file->TargetPath);
5839 ptr = strrchrW(driver_path, '\\');
5840 if (ptr) *ptr = '\0';
5842 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5843 NULL, ODBC_INSTALL_COMPLETE, &usage))
5845 ERR("Failed to install SQL driver!\n");
5846 r = ERROR_FUNCTION_FAILED;
5849 uirow = MSI_CreateRecord( 5 );
5850 MSI_RecordSetStringW( uirow, 1, desc );
5851 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5852 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5853 ui_actiondata( package, szInstallODBC, uirow );
5854 msiobj_release( &uirow->hdr );
5857 msi_free(driver_path);
5862 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5864 MSIPACKAGE *package = param;
5865 LPWSTR translator, translator_path, ptr;
5866 WCHAR outpath[MAX_PATH];
5867 MSIFILE *translator_file, *setup_file;
5871 UINT r = ERROR_SUCCESS;
5873 static const WCHAR translator_fmt[] = {
5874 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5875 static const WCHAR setup_fmt[] = {
5876 'S','e','t','u','p','=','%','s',0};
5878 desc = MSI_RecordGetString(rec, 3);
5880 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5881 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5883 if (!translator_file)
5885 ERR("ODBC Translator entry not found!\n");
5886 return ERROR_FUNCTION_FAILED;
5889 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5891 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5893 translator = msi_alloc(len * sizeof(WCHAR));
5895 return ERROR_OUTOFMEMORY;
5898 lstrcpyW(ptr, desc);
5899 ptr += lstrlenW(ptr) + 1;
5901 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5906 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5911 translator_path = strdupW(translator_file->TargetPath);
5912 ptr = strrchrW(translator_path, '\\');
5913 if (ptr) *ptr = '\0';
5915 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5916 NULL, ODBC_INSTALL_COMPLETE, &usage))
5918 ERR("Failed to install SQL translator!\n");
5919 r = ERROR_FUNCTION_FAILED;
5922 uirow = MSI_CreateRecord( 5 );
5923 MSI_RecordSetStringW( uirow, 1, desc );
5924 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5925 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5926 ui_actiondata( package, szInstallODBC, uirow );
5927 msiobj_release( &uirow->hdr );
5929 msi_free(translator);
5930 msi_free(translator_path);
5935 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5937 MSIPACKAGE *package = param;
5939 LPCWSTR desc, driver;
5940 WORD request = ODBC_ADD_SYS_DSN;
5943 UINT r = ERROR_SUCCESS;
5946 static const WCHAR attrs_fmt[] = {
5947 'D','S','N','=','%','s',0 };
5949 desc = MSI_RecordGetString(rec, 3);
5950 driver = MSI_RecordGetString(rec, 4);
5951 registration = MSI_RecordGetInteger(rec, 5);
5953 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5954 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5956 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5957 attrs = msi_alloc(len * sizeof(WCHAR));
5959 return ERROR_OUTOFMEMORY;
5961 len = sprintfW(attrs, attrs_fmt, desc);
5964 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5966 ERR("Failed to install SQL data source!\n");
5967 r = ERROR_FUNCTION_FAILED;
5970 uirow = MSI_CreateRecord( 5 );
5971 MSI_RecordSetStringW( uirow, 1, desc );
5972 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5973 MSI_RecordSetInteger( uirow, 3, request );
5974 ui_actiondata( package, szInstallODBC, uirow );
5975 msiobj_release( &uirow->hdr );
5982 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5987 static const WCHAR driver_query[] = {
5988 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5989 'O','D','B','C','D','r','i','v','e','r',0 };
5991 static const WCHAR translator_query[] = {
5992 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5993 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5995 static const WCHAR source_query[] = {
5996 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5997 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5999 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6000 if (rc != ERROR_SUCCESS)
6001 return ERROR_SUCCESS;
6003 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6004 msiobj_release(&view->hdr);
6006 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6007 if (rc != ERROR_SUCCESS)
6008 return ERROR_SUCCESS;
6010 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6011 msiobj_release(&view->hdr);
6013 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6014 if (rc != ERROR_SUCCESS)
6015 return ERROR_SUCCESS;
6017 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6018 msiobj_release(&view->hdr);
6023 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6025 MSIPACKAGE *package = param;
6030 desc = MSI_RecordGetString( rec, 3 );
6031 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6033 WARN("Failed to remove ODBC driver\n");
6037 FIXME("Usage count reached 0\n");
6040 uirow = MSI_CreateRecord( 2 );
6041 MSI_RecordSetStringW( uirow, 1, desc );
6042 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6043 ui_actiondata( package, szRemoveODBC, uirow );
6044 msiobj_release( &uirow->hdr );
6046 return ERROR_SUCCESS;
6049 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6051 MSIPACKAGE *package = param;
6056 desc = MSI_RecordGetString( rec, 3 );
6057 if (!SQLRemoveTranslatorW( desc, &usage ))
6059 WARN("Failed to remove ODBC translator\n");
6063 FIXME("Usage count reached 0\n");
6066 uirow = MSI_CreateRecord( 2 );
6067 MSI_RecordSetStringW( uirow, 1, desc );
6068 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6069 ui_actiondata( package, szRemoveODBC, uirow );
6070 msiobj_release( &uirow->hdr );
6072 return ERROR_SUCCESS;
6075 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6077 MSIPACKAGE *package = param;
6080 LPCWSTR desc, driver;
6081 WORD request = ODBC_REMOVE_SYS_DSN;
6085 static const WCHAR attrs_fmt[] = {
6086 'D','S','N','=','%','s',0 };
6088 desc = MSI_RecordGetString( rec, 3 );
6089 driver = MSI_RecordGetString( rec, 4 );
6090 registration = MSI_RecordGetInteger( rec, 5 );
6092 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6093 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6095 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6096 attrs = msi_alloc( len * sizeof(WCHAR) );
6098 return ERROR_OUTOFMEMORY;
6100 FIXME("Use ODBCSourceAttribute table\n");
6102 len = sprintfW( attrs, attrs_fmt, desc );
6105 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6107 WARN("Failed to remove ODBC data source\n");
6111 uirow = MSI_CreateRecord( 3 );
6112 MSI_RecordSetStringW( uirow, 1, desc );
6113 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6114 MSI_RecordSetInteger( uirow, 3, request );
6115 ui_actiondata( package, szRemoveODBC, uirow );
6116 msiobj_release( &uirow->hdr );
6118 return ERROR_SUCCESS;
6121 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6126 static const WCHAR driver_query[] = {
6127 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6128 'O','D','B','C','D','r','i','v','e','r',0 };
6130 static const WCHAR translator_query[] = {
6131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6132 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6134 static const WCHAR source_query[] = {
6135 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6136 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6138 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6139 if (rc != ERROR_SUCCESS)
6140 return ERROR_SUCCESS;
6142 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6143 msiobj_release( &view->hdr );
6145 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6146 if (rc != ERROR_SUCCESS)
6147 return ERROR_SUCCESS;
6149 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6150 msiobj_release( &view->hdr );
6152 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6153 if (rc != ERROR_SUCCESS)
6154 return ERROR_SUCCESS;
6156 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6157 msiobj_release( &view->hdr );
6162 #define ENV_ACT_SETALWAYS 0x1
6163 #define ENV_ACT_SETABSENT 0x2
6164 #define ENV_ACT_REMOVE 0x4
6165 #define ENV_ACT_REMOVEMATCH 0x8
6167 #define ENV_MOD_MACHINE 0x20000000
6168 #define ENV_MOD_APPEND 0x40000000
6169 #define ENV_MOD_PREFIX 0x80000000
6170 #define ENV_MOD_MASK 0xC0000000
6172 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6174 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6176 LPCWSTR cptr = *name;
6178 static const WCHAR prefix[] = {'[','~',']',0};
6179 static const int prefix_len = 3;
6185 *flags |= ENV_ACT_SETALWAYS;
6186 else if (*cptr == '+')
6187 *flags |= ENV_ACT_SETABSENT;
6188 else if (*cptr == '-')
6189 *flags |= ENV_ACT_REMOVE;
6190 else if (*cptr == '!')
6191 *flags |= ENV_ACT_REMOVEMATCH;
6192 else if (*cptr == '*')
6193 *flags |= ENV_MOD_MACHINE;
6203 ERR("Missing environment variable\n");
6204 return ERROR_FUNCTION_FAILED;
6209 LPCWSTR ptr = *value;
6210 if (!strncmpW(ptr, prefix, prefix_len))
6212 if (ptr[prefix_len] == szSemiColon[0])
6214 *flags |= ENV_MOD_APPEND;
6215 *value += lstrlenW(prefix);
6222 else if (lstrlenW(*value) >= prefix_len)
6224 ptr += lstrlenW(ptr) - prefix_len;
6225 if (!lstrcmpW(ptr, prefix))
6227 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6229 *flags |= ENV_MOD_PREFIX;
6230 /* the "[~]" will be removed by deformat_string */;
6240 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6241 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6242 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6243 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6245 ERR("Invalid flags: %08x\n", *flags);
6246 return ERROR_FUNCTION_FAILED;
6250 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6252 return ERROR_SUCCESS;
6255 static UINT open_env_key( DWORD flags, HKEY *key )
6257 static const WCHAR user_env[] =
6258 {'E','n','v','i','r','o','n','m','e','n','t',0};
6259 static const WCHAR machine_env[] =
6260 {'S','y','s','t','e','m','\\',
6261 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6262 'C','o','n','t','r','o','l','\\',
6263 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6264 'E','n','v','i','r','o','n','m','e','n','t',0};
6269 if (flags & ENV_MOD_MACHINE)
6272 root = HKEY_LOCAL_MACHINE;
6277 root = HKEY_CURRENT_USER;
6280 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6281 if (res != ERROR_SUCCESS)
6283 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6284 return ERROR_FUNCTION_FAILED;
6287 return ERROR_SUCCESS;
6290 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6292 MSIPACKAGE *package = param;
6293 LPCWSTR name, value, component;
6294 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6295 DWORD flags, type, size;
6302 component = MSI_RecordGetString(rec, 4);
6303 comp = get_loaded_component(package, component);
6305 return ERROR_SUCCESS;
6309 TRACE("component is disabled\n");
6310 return ERROR_SUCCESS;
6313 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6315 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6316 comp->Action = comp->Installed;
6317 return ERROR_SUCCESS;
6319 comp->Action = INSTALLSTATE_LOCAL;
6321 name = MSI_RecordGetString(rec, 2);
6322 value = MSI_RecordGetString(rec, 3);
6324 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6326 res = env_parse_flags(&name, &value, &flags);
6327 if (res != ERROR_SUCCESS || !value)
6330 if (value && !deformat_string(package, value, &deformatted))
6332 res = ERROR_OUTOFMEMORY;
6336 value = deformatted;
6338 res = open_env_key( flags, &env );
6339 if (res != ERROR_SUCCESS)
6342 if (flags & ENV_MOD_MACHINE)
6343 action |= 0x20000000;
6347 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6348 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6349 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6352 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6356 /* Nothing to do. */
6359 res = ERROR_SUCCESS;
6363 /* If we are appending but the string was empty, strip ; */
6364 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6366 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6367 newval = strdupW(value);
6370 res = ERROR_OUTOFMEMORY;
6378 /* Contrary to MSDN, +-variable to [~];path works */
6379 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6381 res = ERROR_SUCCESS;
6385 data = msi_alloc(size);
6389 return ERROR_OUTOFMEMORY;
6392 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6393 if (res != ERROR_SUCCESS)
6396 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6399 res = RegDeleteValueW(env, name);
6400 if (res != ERROR_SUCCESS)
6401 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6405 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6406 if (flags & ENV_MOD_MASK)
6410 if (flags & ENV_MOD_APPEND) multiplier++;
6411 if (flags & ENV_MOD_PREFIX) multiplier++;
6412 mod_size = lstrlenW(value) * multiplier;
6413 size += mod_size * sizeof(WCHAR);
6416 newval = msi_alloc(size);
6420 res = ERROR_OUTOFMEMORY;
6424 if (flags & ENV_MOD_PREFIX)
6426 lstrcpyW(newval, value);
6427 ptr = newval + lstrlenW(value);
6428 action |= 0x80000000;
6431 lstrcpyW(ptr, data);
6433 if (flags & ENV_MOD_APPEND)
6435 lstrcatW(newval, value);
6436 action |= 0x40000000;
6439 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6440 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6443 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6447 uirow = MSI_CreateRecord( 3 );
6448 MSI_RecordSetStringW( uirow, 1, name );
6449 MSI_RecordSetStringW( uirow, 2, newval );
6450 MSI_RecordSetInteger( uirow, 3, action );
6451 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6452 msiobj_release( &uirow->hdr );
6454 if (env) RegCloseKey(env);
6455 msi_free(deformatted);
6461 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6465 static const WCHAR ExecSeqQuery[] =
6466 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6467 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6468 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6469 if (rc != ERROR_SUCCESS)
6470 return ERROR_SUCCESS;
6472 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6473 msiobj_release(&view->hdr);
6478 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6480 MSIPACKAGE *package = param;
6481 LPCWSTR name, value, component;
6482 LPWSTR deformatted = NULL;
6491 component = MSI_RecordGetString( rec, 4 );
6492 comp = get_loaded_component( package, component );
6494 return ERROR_SUCCESS;
6498 TRACE("component is disabled\n");
6499 return ERROR_SUCCESS;
6502 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6504 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6505 comp->Action = comp->Installed;
6506 return ERROR_SUCCESS;
6508 comp->Action = INSTALLSTATE_ABSENT;
6510 name = MSI_RecordGetString( rec, 2 );
6511 value = MSI_RecordGetString( rec, 3 );
6513 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6515 r = env_parse_flags( &name, &value, &flags );
6516 if (r != ERROR_SUCCESS)
6519 if (!(flags & ENV_ACT_REMOVE))
6521 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6522 return ERROR_SUCCESS;
6525 if (value && !deformat_string( package, value, &deformatted ))
6526 return ERROR_OUTOFMEMORY;
6528 value = deformatted;
6530 r = open_env_key( flags, &env );
6531 if (r != ERROR_SUCCESS)
6537 if (flags & ENV_MOD_MACHINE)
6538 action |= 0x20000000;
6540 TRACE("Removing %s\n", debugstr_w(name));
6542 res = RegDeleteValueW( env, name );
6543 if (res != ERROR_SUCCESS)
6545 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6550 uirow = MSI_CreateRecord( 3 );
6551 MSI_RecordSetStringW( uirow, 1, name );
6552 MSI_RecordSetStringW( uirow, 2, value );
6553 MSI_RecordSetInteger( uirow, 3, action );
6554 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6555 msiobj_release( &uirow->hdr );
6557 if (env) RegCloseKey( env );
6558 msi_free( deformatted );
6562 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6566 static const WCHAR query[] =
6567 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6568 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6570 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6571 if (rc != ERROR_SUCCESS)
6572 return ERROR_SUCCESS;
6574 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6575 msiobj_release( &view->hdr );
6580 typedef struct tagMSIASSEMBLY
6583 MSICOMPONENT *component;
6584 MSIFEATURE *feature;
6588 LPWSTR display_name;
6593 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6595 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6596 LPVOID pvReserved, HMODULE *phModDll);
6598 static BOOL init_functionpointers(void)
6604 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6606 hmscoree = LoadLibraryA("mscoree.dll");
6609 WARN("mscoree.dll not available\n");
6613 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6614 if (!pLoadLibraryShim)
6616 WARN("LoadLibraryShim not available\n");
6617 FreeLibrary(hmscoree);
6621 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6624 WARN("fusion.dll not available\n");
6625 FreeLibrary(hmscoree);
6629 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6631 FreeLibrary(hmscoree);
6635 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6638 IAssemblyCache *cache;
6641 UINT r = ERROR_FUNCTION_FAILED;
6643 TRACE("installing assembly: %s\n", debugstr_w(path));
6645 uirow = MSI_CreateRecord( 2 );
6646 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6647 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6648 msiobj_release( &uirow->hdr );
6650 if (assembly->feature)
6651 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6653 if (assembly->manifest)
6654 FIXME("Manifest unhandled\n");
6656 if (assembly->application)
6658 FIXME("Assembly should be privately installed\n");
6659 return ERROR_SUCCESS;
6662 if (assembly->attributes == msidbAssemblyAttributesWin32)
6664 FIXME("Win32 assemblies not handled\n");
6665 return ERROR_SUCCESS;
6668 hr = pCreateAssemblyCache(&cache, 0);
6672 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6674 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6679 IAssemblyCache_Release(cache);
6683 typedef struct tagASSEMBLY_LIST
6685 MSIPACKAGE *package;
6686 IAssemblyCache *cache;
6687 struct list *assemblies;
6690 typedef struct tagASSEMBLY_NAME
6698 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6700 ASSEMBLY_NAME *asmname = param;
6701 LPCWSTR name = MSI_RecordGetString(rec, 2);
6702 LPWSTR val = msi_dup_record_field(rec, 3);
6704 static const WCHAR Name[] = {'N','a','m','e',0};
6705 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6706 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6707 static const WCHAR PublicKeyToken[] = {
6708 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6710 if (!strcmpiW(name, Name))
6711 asmname->name = val;
6712 else if (!strcmpiW(name, Version))
6713 asmname->version = val;
6714 else if (!strcmpiW(name, Culture))
6715 asmname->culture = val;
6716 else if (!strcmpiW(name, PublicKeyToken))
6717 asmname->pubkeytoken = val;
6721 return ERROR_SUCCESS;
6724 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6728 *size = lstrlenW(append) + 1;
6729 *str = msi_alloc((*size) * sizeof(WCHAR));
6730 lstrcpyW(*str, append);
6734 (*size) += lstrlenW(append);
6735 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6736 lstrcatW(*str, append);
6739 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6741 static const WCHAR separator[] = {',',' ',0};
6742 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6743 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6744 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6745 static const WCHAR query[] = {
6746 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6747 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6748 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6749 '=','\'','%','s','\'',0};
6752 LPWSTR display_name;
6756 display_name = NULL;
6757 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6759 r = MSI_OpenQuery( db, &view, query, comp->Component );
6760 if (r != ERROR_SUCCESS)
6763 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6764 msiobj_release( &view->hdr );
6768 ERR("No assembly name specified!\n");
6772 append_str( &display_name, &size, name.name );
6776 append_str( &display_name, &size, separator );
6777 append_str( &display_name, &size, Version );
6778 append_str( &display_name, &size, name.version );
6782 append_str( &display_name, &size, separator );
6783 append_str( &display_name, &size, Culture );
6784 append_str( &display_name, &size, name.culture );
6786 if (name.pubkeytoken)
6788 append_str( &display_name, &size, separator );
6789 append_str( &display_name, &size, PublicKeyToken );
6790 append_str( &display_name, &size, name.pubkeytoken );
6793 msi_free( name.name );
6794 msi_free( name.version );
6795 msi_free( name.culture );
6796 msi_free( name.pubkeytoken );
6798 return display_name;
6801 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6803 ASSEMBLY_INFO asminfo;
6808 disp = get_assembly_display_name( db, comp );
6812 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6813 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6815 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6817 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6823 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6825 ASSEMBLY_LIST *list = param;
6826 MSIASSEMBLY *assembly;
6829 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6831 return ERROR_OUTOFMEMORY;
6833 component = MSI_RecordGetString(rec, 1);
6834 assembly->component = get_loaded_component(list->package, component);
6835 if (!assembly->component)
6836 return ERROR_SUCCESS;
6838 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6839 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6841 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6842 assembly->component->Action = assembly->component->Installed;
6843 return ERROR_SUCCESS;
6845 assembly->component->Action = assembly->component->ActionRequest;
6847 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6848 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6850 if (!assembly->file)
6852 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6853 return ERROR_FUNCTION_FAILED;
6856 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6857 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6858 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6860 if (assembly->application)
6863 DWORD size = sizeof(version)/sizeof(WCHAR);
6865 /* FIXME: we should probably check the manifest file here */
6867 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6868 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6870 assembly->installed = TRUE;
6874 assembly->installed = check_assembly_installed(list->package->db,
6876 assembly->component);
6878 list_add_head(list->assemblies, &assembly->entry);
6879 return ERROR_SUCCESS;
6882 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6884 IAssemblyCache *cache = NULL;
6890 static const WCHAR query[] =
6891 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6892 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6894 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6895 if (r != ERROR_SUCCESS)
6896 return ERROR_SUCCESS;
6898 hr = pCreateAssemblyCache(&cache, 0);
6900 return ERROR_FUNCTION_FAILED;
6902 list.package = package;
6904 list.assemblies = assemblies;
6906 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6907 msiobj_release(&view->hdr);
6909 IAssemblyCache_Release(cache);
6914 static void free_assemblies(struct list *assemblies)
6916 struct list *item, *cursor;
6918 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6920 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6922 list_remove(&assembly->entry);
6923 msi_free(assembly->application);
6924 msi_free(assembly->manifest);
6925 msi_free(assembly->display_name);
6930 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6932 MSIASSEMBLY *assembly;
6934 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6936 if (!lstrcmpW(assembly->file->File, file))
6946 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6947 LPWSTR *path, DWORD *attrs, PVOID user)
6949 MSIASSEMBLY *assembly;
6950 WCHAR temppath[MAX_PATH];
6951 struct list *assemblies = user;
6954 if (!find_assembly(assemblies, file, &assembly))
6957 GetTempPathW(MAX_PATH, temppath);
6958 PathAddBackslashW(temppath);
6959 lstrcatW(temppath, assembly->file->FileName);
6961 if (action == MSICABEXTRACT_BEGINEXTRACT)
6963 if (assembly->installed)
6966 *path = strdupW(temppath);
6967 *attrs = assembly->file->Attributes;
6969 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6971 assembly->installed = TRUE;
6973 r = install_assembly(package, assembly, temppath);
6974 if (r != ERROR_SUCCESS)
6975 ERR("Failed to install assembly\n");
6981 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6984 struct list assemblies = LIST_INIT(assemblies);
6985 MSIASSEMBLY *assembly;
6988 if (!init_functionpointers() || !pCreateAssemblyCache)
6989 return ERROR_FUNCTION_FAILED;
6991 r = load_assemblies(package, &assemblies);
6992 if (r != ERROR_SUCCESS)
6995 if (list_empty(&assemblies))
6998 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
7001 r = ERROR_OUTOFMEMORY;
7005 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
7007 if (assembly->installed && !mi->is_continuous)
7010 if (assembly->file->IsCompressed)
7012 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
7016 r = ready_media(package, assembly->file, mi);
7017 if (r != ERROR_SUCCESS)
7019 ERR("Failed to ready media\n");
7024 data.package = package;
7025 data.cb = installassembly_cb;
7026 data.user = &assemblies;
7028 if (!msi_cabextract(package, mi, &data))
7030 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7031 r = ERROR_FUNCTION_FAILED;
7038 LPWSTR source = resolve_file_source(package, assembly->file);
7040 r = install_assembly(package, assembly, source);
7041 if (r != ERROR_SUCCESS)
7042 ERR("Failed to install assembly\n");
7047 /* FIXME: write Installer assembly reg values */
7051 free_assemblies(&assemblies);
7055 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7057 LPWSTR key, template, id;
7058 UINT r = ERROR_SUCCESS;
7060 id = msi_dup_property( package->db, szProductID );
7064 return ERROR_SUCCESS;
7066 template = msi_dup_property( package->db, szPIDTemplate );
7067 key = msi_dup_property( package->db, szPIDKEY );
7069 if (key && template)
7071 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7072 r = msi_set_property( package->db, szProductID, key );
7074 msi_free( template );
7079 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7082 package->need_reboot = 1;
7083 return ERROR_SUCCESS;
7086 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7088 static const WCHAR szAvailableFreeReg[] =
7089 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7091 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7093 TRACE("%p %d kilobytes\n", package, space);
7095 uirow = MSI_CreateRecord( 1 );
7096 MSI_RecordSetInteger( uirow, 1, space );
7097 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7098 msiobj_release( &uirow->hdr );
7100 return ERROR_SUCCESS;
7103 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7105 FIXME("%p\n", package);
7106 return ERROR_SUCCESS;
7109 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7111 FIXME("%p\n", package);
7112 return ERROR_SUCCESS;
7115 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7120 static const WCHAR driver_query[] = {
7121 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7122 'O','D','B','C','D','r','i','v','e','r',0 };
7124 static const WCHAR translator_query[] = {
7125 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7126 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7128 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7129 if (r == ERROR_SUCCESS)
7132 r = MSI_IterateRecords( view, &count, NULL, package );
7133 msiobj_release( &view->hdr );
7134 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7137 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7138 if (r == ERROR_SUCCESS)
7141 r = MSI_IterateRecords( view, &count, NULL, package );
7142 msiobj_release( &view->hdr );
7143 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7146 return ERROR_SUCCESS;
7149 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7150 LPCSTR action, LPCWSTR table )
7152 static const WCHAR query[] = {
7153 'S','E','L','E','C','T',' ','*',' ',
7154 'F','R','O','M',' ','`','%','s','`',0 };
7155 MSIQUERY *view = NULL;
7159 r = MSI_OpenQuery( package->db, &view, query, table );
7160 if (r == ERROR_SUCCESS)
7162 r = MSI_IterateRecords(view, &count, NULL, package);
7163 msiobj_release(&view->hdr);
7167 FIXME("%s -> %u ignored %s table values\n",
7168 action, count, debugstr_w(table));
7170 return ERROR_SUCCESS;
7173 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7175 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7176 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7179 static UINT ACTION_BindImage( MSIPACKAGE *package )
7181 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7182 return msi_unimplemented_action_stub( package, "BindImage", table );
7185 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7187 static const WCHAR table[] = {
7188 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7189 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7192 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7194 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7195 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7198 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7200 static const WCHAR table[] = {
7201 'M','s','i','A','s','s','e','m','b','l','y',0 };
7202 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7205 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7207 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7208 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7211 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7213 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7214 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7217 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7219 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7220 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7223 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7225 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7226 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7229 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7231 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7232 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7235 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7239 const WCHAR *action;
7240 UINT (*handler)(MSIPACKAGE *);
7244 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7245 { szAppSearch, ACTION_AppSearch },
7246 { szBindImage, ACTION_BindImage },
7247 { szCCPSearch, ACTION_CCPSearch },
7248 { szCostFinalize, ACTION_CostFinalize },
7249 { szCostInitialize, ACTION_CostInitialize },
7250 { szCreateFolders, ACTION_CreateFolders },
7251 { szCreateShortcuts, ACTION_CreateShortcuts },
7252 { szDeleteServices, ACTION_DeleteServices },
7253 { szDisableRollback, ACTION_DisableRollback },
7254 { szDuplicateFiles, ACTION_DuplicateFiles },
7255 { szExecuteAction, ACTION_ExecuteAction },
7256 { szFileCost, ACTION_FileCost },
7257 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7258 { szForceReboot, ACTION_ForceReboot },
7259 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7260 { szInstallExecute, ACTION_InstallExecute },
7261 { szInstallExecuteAgain, ACTION_InstallExecute },
7262 { szInstallFiles, ACTION_InstallFiles},
7263 { szInstallFinalize, ACTION_InstallFinalize },
7264 { szInstallInitialize, ACTION_InstallInitialize },
7265 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7266 { szInstallValidate, ACTION_InstallValidate },
7267 { szIsolateComponents, ACTION_IsolateComponents },
7268 { szLaunchConditions, ACTION_LaunchConditions },
7269 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7270 { szMoveFiles, ACTION_MoveFiles },
7271 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7272 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7273 { szInstallODBC, ACTION_InstallODBC },
7274 { szInstallServices, ACTION_InstallServices },
7275 { szPatchFiles, ACTION_PatchFiles },
7276 { szProcessComponents, ACTION_ProcessComponents },
7277 { szPublishComponents, ACTION_PublishComponents },
7278 { szPublishFeatures, ACTION_PublishFeatures },
7279 { szPublishProduct, ACTION_PublishProduct },
7280 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7281 { szRegisterComPlus, ACTION_RegisterComPlus},
7282 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7283 { szRegisterFonts, ACTION_RegisterFonts },
7284 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7285 { szRegisterProduct, ACTION_RegisterProduct },
7286 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7287 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7288 { szRegisterUser, ACTION_RegisterUser },
7289 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7290 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7291 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7292 { szRemoveFiles, ACTION_RemoveFiles },
7293 { szRemoveFolders, ACTION_RemoveFolders },
7294 { szRemoveIniValues, ACTION_RemoveIniValues },
7295 { szRemoveODBC, ACTION_RemoveODBC },
7296 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7297 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7298 { szResolveSource, ACTION_ResolveSource },
7299 { szRMCCPSearch, ACTION_RMCCPSearch },
7300 { szScheduleReboot, ACTION_ScheduleReboot },
7301 { szSelfRegModules, ACTION_SelfRegModules },
7302 { szSelfUnregModules, ACTION_SelfUnregModules },
7303 { szSetODBCFolders, ACTION_SetODBCFolders },
7304 { szStartServices, ACTION_StartServices },
7305 { szStopServices, ACTION_StopServices },
7306 { szUnpublishComponents, ACTION_UnpublishComponents },
7307 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7308 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7309 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7310 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7311 { szUnregisterFonts, ACTION_UnregisterFonts },
7312 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7313 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7314 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7315 { szValidateProductID, ACTION_ValidateProductID },
7316 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7317 { szWriteIniValues, ACTION_WriteIniValues },
7318 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7322 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7323 UINT* rc, BOOL force )
7329 if (!run && !package->script->CurrentlyScripting)
7334 if (strcmpW(action,szInstallFinalize) == 0 ||
7335 strcmpW(action,szInstallExecute) == 0 ||
7336 strcmpW(action,szInstallExecuteAgain) == 0)
7341 while (StandardActions[i].action != NULL)
7343 if (strcmpW(StandardActions[i].action, action)==0)
7347 ui_actioninfo(package, action, TRUE, 0);
7348 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7349 ui_actioninfo(package, action, FALSE, *rc);
7353 ui_actionstart(package, action);
7354 if (StandardActions[i].handler)
7356 *rc = StandardActions[i].handler(package);
7360 FIXME("unhandled standard action %s\n",debugstr_w(action));
7361 *rc = ERROR_SUCCESS;
7372 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7374 UINT rc = ERROR_SUCCESS;
7377 TRACE("Performing action (%s)\n", debugstr_w(action));
7379 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7382 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7386 WARN("unhandled msi action %s\n", debugstr_w(action));
7387 rc = ERROR_FUNCTION_NOT_CALLED;
7393 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7395 UINT rc = ERROR_SUCCESS;
7396 BOOL handled = FALSE;
7398 TRACE("Performing action (%s)\n", debugstr_w(action));
7400 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7403 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7405 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7410 WARN("unhandled msi action %s\n", debugstr_w(action));
7411 rc = ERROR_FUNCTION_NOT_CALLED;
7417 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7419 UINT rc = ERROR_SUCCESS;
7422 static const WCHAR ExecSeqQuery[] =
7423 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7424 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7425 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7426 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7427 static const WCHAR UISeqQuery[] =
7428 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7429 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7430 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7431 ' ', '=',' ','%','i',0};
7433 if (needs_ui_sequence(package))
7434 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7436 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7440 LPCWSTR action, cond;
7442 TRACE("Running the actions\n");
7444 /* check conditions */
7445 cond = MSI_RecordGetString(row, 2);
7447 /* this is a hack to skip errors in the condition code */
7448 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7450 msiobj_release(&row->hdr);
7451 return ERROR_SUCCESS;
7454 action = MSI_RecordGetString(row, 1);
7457 ERR("failed to fetch action\n");
7458 msiobj_release(&row->hdr);
7459 return ERROR_FUNCTION_FAILED;
7462 if (needs_ui_sequence(package))
7463 rc = ACTION_PerformUIAction(package, action, -1);
7465 rc = ACTION_PerformAction(package, action, -1, FALSE);
7467 msiobj_release(&row->hdr);
7473 /****************************************************
7474 * TOP level entry points
7475 *****************************************************/
7477 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7478 LPCWSTR szCommandLine )
7483 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7484 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7486 msi_set_property( package->db, szAction, szInstall );
7488 package->script->InWhatSequence = SEQUENCE_INSTALL;
7495 dir = strdupW(szPackagePath);
7496 p = strrchrW(dir, '\\');
7500 file = szPackagePath + (p - dir);
7505 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7506 GetCurrentDirectoryW(MAX_PATH, dir);
7507 lstrcatW(dir, szBackSlash);
7508 file = szPackagePath;
7511 msi_free( package->PackagePath );
7512 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7513 if (!package->PackagePath)
7516 return ERROR_OUTOFMEMORY;
7519 lstrcpyW(package->PackagePath, dir);
7520 lstrcatW(package->PackagePath, file);
7523 msi_set_sourcedir_props(package, FALSE);
7526 msi_parse_command_line( package, szCommandLine, FALSE );
7528 msi_apply_transforms( package );
7529 msi_apply_patches( package );
7531 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7533 TRACE("setting reinstall property\n");
7534 msi_set_property( package->db, szReinstall, szAll );
7537 /* properties may have been added by a transform */
7538 msi_clone_properties( package );
7539 msi_set_context( package );
7541 if (needs_ui_sequence( package))
7543 package->script->InWhatSequence |= SEQUENCE_UI;
7544 rc = ACTION_ProcessUISequence(package);
7545 ui_exists = ui_sequence_exists(package);
7546 if (rc == ERROR_SUCCESS || !ui_exists)
7548 package->script->InWhatSequence |= SEQUENCE_EXEC;
7549 rc = ACTION_ProcessExecSequence(package, ui_exists);
7553 rc = ACTION_ProcessExecSequence(package, FALSE);
7555 package->script->CurrentlyScripting = FALSE;
7557 /* process the ending type action */
7558 if (rc == ERROR_SUCCESS)
7559 ACTION_PerformActionSequence(package, -1);
7560 else if (rc == ERROR_INSTALL_USEREXIT)
7561 ACTION_PerformActionSequence(package, -2);
7562 else if (rc == ERROR_INSTALL_SUSPEND)
7563 ACTION_PerformActionSequence(package, -4);
7565 ACTION_PerformActionSequence(package, -3);
7567 /* finish up running custom actions */
7568 ACTION_FinishCustomActions(package);
7570 if (rc == ERROR_SUCCESS && package->need_reboot)
7571 return ERROR_SUCCESS_REBOOT_REQUIRED;