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 (!strcmpW( 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 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);
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 msi_set_property(package->db, cszSourceDir, NULL);
902 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
903 msiobj_release(&view->hdr);
909 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
913 static const WCHAR ExecSeqQuery [] =
914 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
915 '`','I','n','s','t','a','l','l',
916 'U','I','S','e','q','u','e','n','c','e','`',
917 ' ','W','H','E','R','E',' ',
918 '`','S','e','q','u','e','n','c','e','`',' ',
919 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
920 '`','S','e','q','u','e','n','c','e','`',0};
922 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
923 if (rc == ERROR_SUCCESS)
925 TRACE("Running the actions\n");
927 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
928 msiobj_release(&view->hdr);
934 /********************************************************
935 * ACTION helper functions and functions that perform the actions
936 *******************************************************/
937 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
938 UINT* rc, UINT script, BOOL force )
943 arc = ACTION_CustomAction(package, action, script, force);
945 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
954 * Actual Action Handlers
957 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
959 MSIPACKAGE *package = param;
960 LPCWSTR dir, component;
966 component = MSI_RecordGetString(row, 2);
968 return ERROR_SUCCESS;
970 comp = get_loaded_component(package, component);
972 return ERROR_SUCCESS;
976 TRACE("component is disabled\n");
977 return ERROR_SUCCESS;
980 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
982 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
983 comp->Action = comp->Installed;
984 return ERROR_SUCCESS;
986 comp->Action = INSTALLSTATE_LOCAL;
988 dir = MSI_RecordGetString(row,1);
991 ERR("Unable to get folder id\n");
992 return ERROR_SUCCESS;
995 uirow = MSI_CreateRecord(1);
996 MSI_RecordSetStringW(uirow, 1, dir);
997 ui_actiondata(package, szCreateFolders, uirow);
998 msiobj_release(&uirow->hdr);
1000 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1003 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1004 return ERROR_SUCCESS;
1007 TRACE("Folder is %s\n",debugstr_w(full_path));
1009 if (folder->State == 0)
1010 create_full_pathW(full_path);
1014 msi_free(full_path);
1015 return ERROR_SUCCESS;
1018 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1020 static const WCHAR ExecSeqQuery[] =
1021 {'S','E','L','E','C','T',' ',
1022 '`','D','i','r','e','c','t','o','r','y','_','`',
1023 ' ','F','R','O','M',' ',
1024 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1028 /* create all the empty folders specified in the CreateFolder table */
1029 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1030 if (rc != ERROR_SUCCESS)
1031 return ERROR_SUCCESS;
1033 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1034 msiobj_release(&view->hdr);
1039 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1041 MSIPACKAGE *package = param;
1042 LPCWSTR dir, component;
1048 component = MSI_RecordGetString(row, 2);
1050 return ERROR_SUCCESS;
1052 comp = get_loaded_component(package, component);
1054 return ERROR_SUCCESS;
1058 TRACE("component is disabled\n");
1059 return ERROR_SUCCESS;
1062 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1064 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1065 comp->Action = comp->Installed;
1066 return ERROR_SUCCESS;
1068 comp->Action = INSTALLSTATE_ABSENT;
1070 dir = MSI_RecordGetString( row, 1 );
1073 ERR("Unable to get folder id\n");
1074 return ERROR_SUCCESS;
1077 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1080 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1081 return ERROR_SUCCESS;
1084 TRACE("folder is %s\n", debugstr_w(full_path));
1086 uirow = MSI_CreateRecord( 1 );
1087 MSI_RecordSetStringW( uirow, 1, dir );
1088 ui_actiondata( package, szRemoveFolders, uirow );
1089 msiobj_release( &uirow->hdr );
1091 RemoveDirectoryW( full_path );
1094 msi_free( full_path );
1095 return ERROR_SUCCESS;
1098 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1100 static const WCHAR query[] =
1101 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1102 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1107 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1108 if (rc != ERROR_SUCCESS)
1109 return ERROR_SUCCESS;
1111 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1112 msiobj_release( &view->hdr );
1117 static UINT load_component( MSIRECORD *row, LPVOID param )
1119 MSIPACKAGE *package = param;
1122 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1124 return ERROR_FUNCTION_FAILED;
1126 list_add_tail( &package->components, &comp->entry );
1128 /* fill in the data */
1129 comp->Component = msi_dup_record_field( row, 1 );
1131 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1133 comp->ComponentId = msi_dup_record_field( row, 2 );
1134 comp->Directory = msi_dup_record_field( row, 3 );
1135 comp->Attributes = MSI_RecordGetInteger(row,4);
1136 comp->Condition = msi_dup_record_field( row, 5 );
1137 comp->KeyPath = msi_dup_record_field( row, 6 );
1139 comp->Installed = INSTALLSTATE_UNKNOWN;
1140 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1142 return ERROR_SUCCESS;
1145 static UINT load_all_components( MSIPACKAGE *package )
1147 static const WCHAR query[] = {
1148 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1149 '`','C','o','m','p','o','n','e','n','t','`',0 };
1153 if (!list_empty(&package->components))
1154 return ERROR_SUCCESS;
1156 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1157 if (r != ERROR_SUCCESS)
1160 r = MSI_IterateRecords(view, NULL, load_component, package);
1161 msiobj_release(&view->hdr);
1166 MSIPACKAGE *package;
1167 MSIFEATURE *feature;
1170 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1174 cl = msi_alloc( sizeof (*cl) );
1176 return ERROR_NOT_ENOUGH_MEMORY;
1177 cl->component = comp;
1178 list_add_tail( &feature->Components, &cl->entry );
1180 return ERROR_SUCCESS;
1183 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1187 fl = msi_alloc( sizeof(*fl) );
1189 return ERROR_NOT_ENOUGH_MEMORY;
1190 fl->feature = child;
1191 list_add_tail( &parent->Children, &fl->entry );
1193 return ERROR_SUCCESS;
1196 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1198 _ilfs* ilfs = param;
1202 component = MSI_RecordGetString(row,1);
1204 /* check to see if the component is already loaded */
1205 comp = get_loaded_component( ilfs->package, component );
1208 ERR("unknown component %s\n", debugstr_w(component));
1209 return ERROR_FUNCTION_FAILED;
1212 add_feature_component( ilfs->feature, comp );
1213 comp->Enabled = TRUE;
1215 return ERROR_SUCCESS;
1218 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1220 MSIFEATURE *feature;
1225 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1227 if ( !strcmpW( feature->Feature, name ) )
1234 static UINT load_feature(MSIRECORD * row, LPVOID param)
1236 MSIPACKAGE* package = param;
1237 MSIFEATURE* feature;
1238 static const WCHAR Query1[] =
1239 {'S','E','L','E','C','T',' ',
1240 '`','C','o','m','p','o','n','e','n','t','_','`',
1241 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1242 'C','o','m','p','o','n','e','n','t','s','`',' ',
1243 'W','H','E','R','E',' ',
1244 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1249 /* fill in the data */
1251 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1253 return ERROR_NOT_ENOUGH_MEMORY;
1255 list_init( &feature->Children );
1256 list_init( &feature->Components );
1258 feature->Feature = msi_dup_record_field( row, 1 );
1260 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1262 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1263 feature->Title = msi_dup_record_field( row, 3 );
1264 feature->Description = msi_dup_record_field( row, 4 );
1266 if (!MSI_RecordIsNull(row,5))
1267 feature->Display = MSI_RecordGetInteger(row,5);
1269 feature->Level= MSI_RecordGetInteger(row,6);
1270 feature->Directory = msi_dup_record_field( row, 7 );
1271 feature->Attributes = MSI_RecordGetInteger(row,8);
1273 feature->Installed = INSTALLSTATE_UNKNOWN;
1274 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1276 list_add_tail( &package->features, &feature->entry );
1278 /* load feature components */
1280 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1281 if (rc != ERROR_SUCCESS)
1282 return ERROR_SUCCESS;
1284 ilfs.package = package;
1285 ilfs.feature = feature;
1287 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1288 msiobj_release(&view->hdr);
1290 return ERROR_SUCCESS;
1293 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1295 MSIPACKAGE* package = param;
1296 MSIFEATURE *parent, *child;
1298 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1300 return ERROR_FUNCTION_FAILED;
1302 if (!child->Feature_Parent)
1303 return ERROR_SUCCESS;
1305 parent = find_feature_by_name( package, child->Feature_Parent );
1307 return ERROR_FUNCTION_FAILED;
1309 add_feature_child( parent, child );
1310 return ERROR_SUCCESS;
1313 static UINT load_all_features( MSIPACKAGE *package )
1315 static const WCHAR query[] = {
1316 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1317 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1318 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1322 if (!list_empty(&package->features))
1323 return ERROR_SUCCESS;
1325 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1326 if (r != ERROR_SUCCESS)
1329 r = MSI_IterateRecords( view, NULL, load_feature, package );
1330 if (r != ERROR_SUCCESS)
1333 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1334 msiobj_release( &view->hdr );
1339 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1350 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1352 static const WCHAR query[] = {
1353 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1354 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1355 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1356 MSIQUERY *view = NULL;
1357 MSIRECORD *row = NULL;
1360 TRACE("%s\n", debugstr_w(file->File));
1362 r = MSI_OpenQuery(package->db, &view, query, file->File);
1363 if (r != ERROR_SUCCESS)
1366 r = MSI_ViewExecute(view, NULL);
1367 if (r != ERROR_SUCCESS)
1370 r = MSI_ViewFetch(view, &row);
1371 if (r != ERROR_SUCCESS)
1374 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1375 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1376 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1377 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1378 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1381 if (view) msiobj_release(&view->hdr);
1382 if (row) msiobj_release(&row->hdr);
1386 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1389 static const WCHAR query[] = {
1390 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1391 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1392 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1394 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1397 WARN("query failed\n");
1398 return ERROR_FUNCTION_FAILED;
1401 file->disk_id = MSI_RecordGetInteger( row, 1 );
1402 msiobj_release( &row->hdr );
1403 return ERROR_SUCCESS;
1406 static UINT load_file(MSIRECORD *row, LPVOID param)
1408 MSIPACKAGE* package = param;
1412 /* fill in the data */
1414 file = msi_alloc_zero( sizeof (MSIFILE) );
1416 return ERROR_NOT_ENOUGH_MEMORY;
1418 file->File = msi_dup_record_field( row, 1 );
1420 component = MSI_RecordGetString( row, 2 );
1421 file->Component = get_loaded_component( package, component );
1423 if (!file->Component)
1425 WARN("Component not found: %s\n", debugstr_w(component));
1426 msi_free(file->File);
1428 return ERROR_SUCCESS;
1431 file->FileName = msi_dup_record_field( row, 3 );
1432 reduce_to_longfilename( file->FileName );
1434 file->ShortName = msi_dup_record_field( row, 3 );
1435 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1437 file->FileSize = MSI_RecordGetInteger( row, 4 );
1438 file->Version = msi_dup_record_field( row, 5 );
1439 file->Language = msi_dup_record_field( row, 6 );
1440 file->Attributes = MSI_RecordGetInteger( row, 7 );
1441 file->Sequence = MSI_RecordGetInteger( row, 8 );
1443 file->state = msifs_invalid;
1445 /* if the compressed bits are not set in the file attributes,
1446 * then read the information from the package word count property
1448 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1450 file->IsCompressed = FALSE;
1452 else if (file->Attributes &
1453 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1455 file->IsCompressed = TRUE;
1457 else if (file->Attributes & msidbFileAttributesNoncompressed)
1459 file->IsCompressed = FALSE;
1463 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1466 load_file_hash(package, file);
1467 load_file_disk_id(package, file);
1469 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1471 list_add_tail( &package->files, &file->entry );
1473 return ERROR_SUCCESS;
1476 static UINT load_all_files(MSIPACKAGE *package)
1480 static const WCHAR Query[] =
1481 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1482 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1483 '`','S','e','q','u','e','n','c','e','`', 0};
1485 if (!list_empty(&package->files))
1486 return ERROR_SUCCESS;
1488 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1489 if (rc != ERROR_SUCCESS)
1490 return ERROR_SUCCESS;
1492 rc = MSI_IterateRecords(view, NULL, load_file, package);
1493 msiobj_release(&view->hdr);
1495 return ERROR_SUCCESS;
1498 static UINT load_folder( MSIRECORD *row, LPVOID param )
1500 MSIPACKAGE *package = param;
1501 static WCHAR szEmpty[] = { 0 };
1502 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1505 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1507 return ERROR_NOT_ENOUGH_MEMORY;
1509 folder->Directory = msi_dup_record_field( row, 1 );
1511 TRACE("%s\n", debugstr_w(folder->Directory));
1513 p = msi_dup_record_field(row, 3);
1515 /* split src and target dir */
1517 src_short = folder_split_path( p, ':' );
1519 /* split the long and short paths */
1520 tgt_long = folder_split_path( tgt_short, '|' );
1521 src_long = folder_split_path( src_short, '|' );
1523 /* check for no-op dirs */
1524 if (tgt_short && !strcmpW( szDot, tgt_short ))
1525 tgt_short = szEmpty;
1526 if (src_short && !strcmpW( szDot, src_short ))
1527 src_short = szEmpty;
1530 tgt_long = tgt_short;
1533 src_short = tgt_short;
1534 src_long = tgt_long;
1538 src_long = src_short;
1540 /* FIXME: use the target short path too */
1541 folder->TargetDefault = strdupW(tgt_long);
1542 folder->SourceShortPath = strdupW(src_short);
1543 folder->SourceLongPath = strdupW(src_long);
1546 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1547 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1548 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1550 folder->Parent = msi_dup_record_field( row, 2 );
1552 folder->Property = msi_dup_property( package->db, folder->Directory );
1554 list_add_tail( &package->folders, &folder->entry );
1556 TRACE("returning %p\n", folder);
1558 return ERROR_SUCCESS;
1561 static UINT load_all_folders( MSIPACKAGE *package )
1563 static const WCHAR query[] = {
1564 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1565 '`','D','i','r','e','c','t','o','r','y','`',0 };
1569 if (!list_empty(&package->folders))
1570 return ERROR_SUCCESS;
1572 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1573 if (r != ERROR_SUCCESS)
1576 r = MSI_IterateRecords(view, NULL, load_folder, package);
1577 msiobj_release(&view->hdr);
1582 * I am not doing any of the costing functionality yet.
1583 * Mostly looking at doing the Component and Feature loading
1585 * The native MSI does A LOT of modification to tables here. Mostly adding
1586 * a lot of temporary columns to the Feature and Component tables.
1588 * note: Native msi also tracks the short filename. But I am only going to
1589 * track the long ones. Also looking at this directory table
1590 * it appears that the directory table does not get the parents
1591 * resolved base on property only based on their entries in the
1594 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1596 static const WCHAR szCosting[] =
1597 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1599 msi_set_property( package->db, szCosting, szZero );
1600 msi_set_property( package->db, cszRootDrive, c_colon );
1602 load_all_folders( package );
1603 load_all_components( package );
1604 load_all_features( package );
1605 load_all_files( package );
1607 return ERROR_SUCCESS;
1610 static UINT execute_script(MSIPACKAGE *package, UINT script )
1613 UINT rc = ERROR_SUCCESS;
1615 TRACE("Executing Script %i\n",script);
1617 if (!package->script)
1619 ERR("no script!\n");
1620 return ERROR_FUNCTION_FAILED;
1623 for (i = 0; i < package->script->ActionCount[script]; i++)
1626 action = package->script->Actions[script][i];
1627 ui_actionstart(package, action);
1628 TRACE("Executing Action (%s)\n",debugstr_w(action));
1629 rc = ACTION_PerformAction(package, action, script);
1630 if (rc != ERROR_SUCCESS)
1633 msi_free_action_script(package, script);
1637 static UINT ACTION_FileCost(MSIPACKAGE *package)
1639 return ERROR_SUCCESS;
1642 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1648 state = MsiQueryProductStateW(package->ProductCode);
1650 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1652 if (!comp->ComponentId)
1655 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1656 comp->Installed = INSTALLSTATE_ABSENT;
1659 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1660 package->Context, comp->ComponentId,
1662 if (r != ERROR_SUCCESS)
1663 comp->Installed = INSTALLSTATE_ABSENT;
1668 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1670 MSIFEATURE *feature;
1673 state = MsiQueryProductStateW(package->ProductCode);
1675 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1677 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1678 feature->Installed = INSTALLSTATE_ABSENT;
1681 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1687 static BOOL process_state_property(MSIPACKAGE* package, int level,
1688 LPCWSTR property, INSTALLSTATE state)
1691 MSIFEATURE *feature;
1693 override = msi_dup_property( package->db, property );
1697 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1699 if (strcmpW( property, szRemove ) &&
1700 (feature->Level <= 0 || feature->Level > level))
1703 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1705 if (!strcmpiW( override, szAll ))
1706 msi_feature_set_state(package, feature, state);
1709 LPWSTR ptr = override;
1710 LPWSTR ptr2 = strchrW(override,',');
1714 int len = ptr2 - ptr;
1716 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1717 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1719 msi_feature_set_state(package, feature, state);
1725 ptr2 = strchrW(ptr,',');
1737 static BOOL process_overrides( MSIPACKAGE *package, int level )
1739 static const WCHAR szAddLocal[] =
1740 {'A','D','D','L','O','C','A','L',0};
1741 static const WCHAR szAddSource[] =
1742 {'A','D','D','S','O','U','R','C','E',0};
1743 static const WCHAR szAdvertise[] =
1744 {'A','D','V','E','R','T','I','S','E',0};
1747 /* all these activation/deactivation things happen in order and things
1748 * later on the list override things earlier on the list.
1750 * 0 INSTALLLEVEL processing
1763 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1764 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1765 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1766 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1767 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1770 msi_set_property( package->db, szPreselected, szOne );
1775 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1778 static const WCHAR szlevel[] =
1779 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1780 MSICOMPONENT* component;
1781 MSIFEATURE *feature;
1783 TRACE("Checking Install Level\n");
1785 level = msi_get_property_int(package->db, szlevel, 1);
1787 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1789 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1791 BOOL feature_state = ((feature->Level > 0) &&
1792 (feature->Level <= level));
1794 if (feature_state && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1796 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1797 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1798 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1799 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1801 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1805 /* disable child features of unselected parent features */
1806 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1810 if (feature->Level > 0 && feature->Level <= level)
1813 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1814 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1819 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1821 BOOL selected = feature->Level > 0 && feature->Level <= level;
1823 if (selected && feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1825 msi_feature_set_state(package, feature, feature->Installed);
1831 * now we want to enable or disable components based on feature
1833 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1837 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1838 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1839 feature->ActionRequest, feature->Action);
1841 if (!feature->Level)
1844 /* features with components that have compressed files are made local */
1845 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1847 if (cl->component->ForceLocalState &&
1848 feature->ActionRequest == INSTALLSTATE_SOURCE)
1850 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1855 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1857 component = cl->component;
1859 switch (feature->ActionRequest)
1861 case INSTALLSTATE_ABSENT:
1862 component->anyAbsent = 1;
1864 case INSTALLSTATE_ADVERTISED:
1865 component->hasAdvertiseFeature = 1;
1867 case INSTALLSTATE_SOURCE:
1868 component->hasSourceFeature = 1;
1870 case INSTALLSTATE_LOCAL:
1871 component->hasLocalFeature = 1;
1873 case INSTALLSTATE_DEFAULT:
1874 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1875 component->hasAdvertiseFeature = 1;
1876 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1877 component->hasSourceFeature = 1;
1879 component->hasLocalFeature = 1;
1887 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1889 /* check if it's local or source */
1890 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1891 (component->hasLocalFeature || component->hasSourceFeature))
1893 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1894 !component->ForceLocalState)
1895 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1897 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1901 /* if any feature is local, the component must be local too */
1902 if (component->hasLocalFeature)
1904 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1908 if (component->hasSourceFeature)
1910 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1914 if (component->hasAdvertiseFeature)
1916 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1920 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1921 if (component->anyAbsent)
1922 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1925 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1927 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1929 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1930 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1933 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1934 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1937 return ERROR_SUCCESS;
1940 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1942 MSIPACKAGE *package = param;
1947 name = MSI_RecordGetString(row,1);
1949 f = get_loaded_folder(package, name);
1950 if (!f) return ERROR_SUCCESS;
1952 /* reset the ResolvedTarget */
1953 msi_free(f->ResolvedTarget);
1954 f->ResolvedTarget = NULL;
1956 /* This helper function now does ALL the work */
1957 TRACE("Dir %s ...\n",debugstr_w(name));
1958 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1959 TRACE("resolves to %s\n",debugstr_w(path));
1962 return ERROR_SUCCESS;
1965 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1967 MSIPACKAGE *package = param;
1969 MSIFEATURE *feature;
1971 name = MSI_RecordGetString( row, 1 );
1973 feature = get_loaded_feature( package, name );
1975 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1979 Condition = MSI_RecordGetString(row,3);
1981 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1983 int level = MSI_RecordGetInteger(row,2);
1984 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1985 feature->Level = level;
1988 return ERROR_SUCCESS;
1991 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1993 static const WCHAR name[] = {'\\',0};
1994 VS_FIXEDFILEINFO *ret;
1996 DWORD versize, handle;
1999 TRACE("%s\n", debugstr_w(filename));
2001 versize = GetFileVersionInfoSizeW( filename, &handle );
2005 version = msi_alloc( versize );
2009 GetFileVersionInfoW( filename, 0, versize, version );
2011 if (!VerQueryValueW( version, name, (LPVOID *)&ret, &sz ))
2013 msi_free( version );
2017 msi_free( version );
2021 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2025 msi_parse_version_string( version, &ms, &ls );
2027 if (fi->dwFileVersionMS > ms) return 1;
2028 else if (fi->dwFileVersionMS < ms) return -1;
2029 else if (fi->dwFileVersionLS > ls) return 1;
2030 else if (fi->dwFileVersionLS < ls) return -1;
2034 static DWORD get_disk_file_size( LPCWSTR filename )
2039 TRACE("%s\n", debugstr_w(filename));
2041 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2042 if (file == INVALID_HANDLE_VALUE)
2043 return INVALID_FILE_SIZE;
2045 size = GetFileSize( file, NULL );
2046 CloseHandle( file );
2050 static BOOL hash_matches( MSIFILE *file )
2053 MSIFILEHASHINFO hash;
2055 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2056 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2057 if (r != ERROR_SUCCESS)
2060 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2063 static UINT set_file_install_states( MSIPACKAGE *package )
2065 VS_FIXEDFILEINFO *file_version;
2068 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2070 MSICOMPONENT* comp = file->Component;
2077 if (file->IsCompressed)
2078 comp->ForceLocalState = TRUE;
2080 /* calculate target */
2081 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2082 msi_free(file->TargetPath);
2084 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2086 file->TargetPath = build_directory_name(2, p, file->FileName);
2089 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2091 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2093 file->state = msifs_missing;
2094 comp->Cost += file->FileSize;
2097 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2099 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2100 HIWORD(file_version->dwFileVersionMS),
2101 LOWORD(file_version->dwFileVersionMS),
2102 HIWORD(file_version->dwFileVersionLS),
2103 LOWORD(file_version->dwFileVersionLS));
2105 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2107 file->state = msifs_overwrite;
2108 comp->Cost += file->FileSize;
2112 TRACE("Destination file version equal or greater, not overwriting\n");
2113 file->state = msifs_present;
2115 msi_free( file_version );
2118 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2120 file->state = msifs_overwrite;
2121 comp->Cost += file->FileSize - file_size;
2124 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2126 TRACE("File hashes match, not overwriting\n");
2127 file->state = msifs_present;
2130 file->state = msifs_overwrite;
2131 comp->Cost += file->FileSize - file_size;
2134 return ERROR_SUCCESS;
2138 * A lot is done in this function aside from just the costing.
2139 * The costing needs to be implemented at some point but for now I am going
2140 * to focus on the directory building
2143 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2145 static const WCHAR ExecSeqQuery[] =
2146 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2147 '`','D','i','r','e','c','t','o','r','y','`',0};
2148 static const WCHAR ConditionQuery[] =
2149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2150 '`','C','o','n','d','i','t','i','o','n','`',0};
2151 static const WCHAR szCosting[] =
2152 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2153 static const WCHAR szlevel[] =
2154 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2155 static const WCHAR szOutOfDiskSpace[] =
2156 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2158 UINT rc = ERROR_SUCCESS;
2162 TRACE("Building Directory properties\n");
2164 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2165 if (rc == ERROR_SUCCESS)
2167 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2169 msiobj_release(&view->hdr);
2172 /* read components states from the registry */
2173 ACTION_GetComponentInstallStates(package);
2174 ACTION_GetFeatureInstallStates(package);
2176 TRACE("Calculating file install states\n");
2177 set_file_install_states( package );
2179 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2181 TRACE("Evaluating feature conditions\n");
2183 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2184 if (rc == ERROR_SUCCESS)
2186 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2187 msiobj_release( &view->hdr );
2190 TRACE("Evaluating component conditions\n");
2192 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2194 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2196 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2197 comp->Enabled = FALSE;
2200 comp->Enabled = TRUE;
2203 msi_set_property( package->db, szCosting, szOne );
2204 /* set default run level if not set */
2205 level = msi_dup_property( package->db, szlevel );
2207 msi_set_property( package->db, szlevel, szOne );
2210 /* FIXME: check volume disk space */
2211 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2213 return MSI_SetFeatureStates(package);
2216 /* OK this value is "interpreted" and then formatted based on the
2217 first few characters */
2218 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2223 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2229 LPWSTR deformated = NULL;
2232 deformat_string(package, &value[2], &deformated);
2234 /* binary value type */
2238 *size = (strlenW(ptr)/2)+1;
2240 *size = strlenW(ptr)/2;
2242 data = msi_alloc(*size);
2248 /* if uneven pad with a zero in front */
2254 data[count] = (BYTE)strtol(byte,NULL,0);
2256 TRACE("Uneven byte count\n");
2264 data[count] = (BYTE)strtol(byte,NULL,0);
2267 msi_free(deformated);
2269 TRACE("Data %i bytes(%i)\n",*size,count);
2276 deformat_string(package, &value[1], &deformated);
2279 *size = sizeof(DWORD);
2280 data = msi_alloc(*size);
2286 if ( (*p < '0') || (*p > '9') )
2292 if (deformated[0] == '-')
2295 TRACE("DWORD %i\n",*(LPDWORD)data);
2297 msi_free(deformated);
2302 static const WCHAR szMulti[] = {'[','~',']',0};
2311 *type=REG_EXPAND_SZ;
2319 if (strstrW(value, szMulti))
2320 *type = REG_MULTI_SZ;
2322 /* remove initial delimiter */
2323 if (!strncmpW(value, szMulti, 3))
2326 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2328 /* add double NULL terminator */
2329 if (*type == REG_MULTI_SZ)
2331 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2332 data = msi_realloc_zero(data, *size);
2338 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2345 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2347 *root_key = HKEY_LOCAL_MACHINE;
2352 *root_key = HKEY_CURRENT_USER;
2357 *root_key = HKEY_CLASSES_ROOT;
2361 *root_key = HKEY_CURRENT_USER;
2365 *root_key = HKEY_LOCAL_MACHINE;
2369 *root_key = HKEY_USERS;
2373 ERR("Unknown root %i\n", root);
2380 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2382 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2383 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2385 if (is_64bit && package->platform == PLATFORM_INTEL &&
2386 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2391 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2392 path_32node = msi_alloc( size );
2396 memcpy( path_32node, path, len * sizeof(WCHAR) );
2397 path_32node[len] = 0;
2398 strcatW( path_32node, szWow6432Node );
2399 strcatW( path_32node, szBackSlash );
2400 strcatW( path_32node, path + len );
2404 return strdupW( path );
2407 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2409 MSIPACKAGE *package = param;
2410 LPSTR value_data = NULL;
2411 HKEY root_key, hkey;
2413 LPWSTR deformated, uikey, keypath;
2414 LPCWSTR szRoot, component, name, key, value;
2418 BOOL check_first = FALSE;
2421 ui_progress(package,2,0,0,0);
2423 component = MSI_RecordGetString(row, 6);
2424 comp = get_loaded_component(package,component);
2426 return ERROR_SUCCESS;
2430 TRACE("component is disabled\n");
2431 return ERROR_SUCCESS;
2434 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2436 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2437 comp->Action = comp->Installed;
2438 return ERROR_SUCCESS;
2440 comp->Action = INSTALLSTATE_LOCAL;
2442 name = MSI_RecordGetString(row, 4);
2443 if( MSI_RecordIsNull(row,5) && name )
2445 /* null values can have special meanings */
2446 if (name[0]=='-' && name[1] == 0)
2447 return ERROR_SUCCESS;
2448 else if ((name[0]=='+' && name[1] == 0) ||
2449 (name[0] == '*' && name[1] == 0))
2454 root = MSI_RecordGetInteger(row,2);
2455 key = MSI_RecordGetString(row, 3);
2457 szRoot = get_root_key( package, root, &root_key );
2459 return ERROR_SUCCESS;
2461 deformat_string(package, key , &deformated);
2462 size = strlenW(deformated) + strlenW(szRoot) + 1;
2463 uikey = msi_alloc(size*sizeof(WCHAR));
2464 strcpyW(uikey,szRoot);
2465 strcatW(uikey,deformated);
2467 keypath = get_keypath( package, root_key, deformated );
2468 msi_free( deformated );
2469 if (RegCreateKeyW( root_key, keypath, &hkey ))
2471 ERR("Could not create key %s\n", debugstr_w(keypath));
2473 return ERROR_SUCCESS;
2476 value = MSI_RecordGetString(row,5);
2478 value_data = parse_value(package, value, &type, &size);
2481 value_data = (LPSTR)strdupW(szEmpty);
2482 size = sizeof(szEmpty);
2486 deformat_string(package, name, &deformated);
2490 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2492 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2497 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2498 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2500 TRACE("value %s of %s checked already exists\n",
2501 debugstr_w(deformated), debugstr_w(uikey));
2505 TRACE("Checked and setting value %s of %s\n",
2506 debugstr_w(deformated), debugstr_w(uikey));
2507 if (deformated || size)
2508 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2513 uirow = MSI_CreateRecord(3);
2514 MSI_RecordSetStringW(uirow,2,deformated);
2515 MSI_RecordSetStringW(uirow,1,uikey);
2516 if (type == REG_SZ || type == REG_EXPAND_SZ)
2517 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2518 ui_actiondata(package,szWriteRegistryValues,uirow);
2519 msiobj_release( &uirow->hdr );
2521 msi_free(value_data);
2522 msi_free(deformated);
2525 return ERROR_SUCCESS;
2528 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2532 static const WCHAR ExecSeqQuery[] =
2533 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2534 '`','R','e','g','i','s','t','r','y','`',0 };
2536 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2537 if (rc != ERROR_SUCCESS)
2538 return ERROR_SUCCESS;
2540 /* increment progress bar each time action data is sent */
2541 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2543 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2545 msiobj_release(&view->hdr);
2549 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2553 DWORD num_subkeys, num_values;
2557 if ((res = RegDeleteTreeW( hkey_root, key )))
2559 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2564 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2566 if ((res = RegDeleteValueW( hkey, value )))
2568 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2570 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2571 NULL, NULL, NULL, NULL );
2572 RegCloseKey( hkey );
2574 if (!res && !num_subkeys && !num_values)
2576 TRACE("Removing empty key %s\n", debugstr_w(key));
2577 RegDeleteKeyW( hkey_root, key );
2581 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2585 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2587 MSIPACKAGE *package = param;
2588 LPCWSTR component, name, key_str, root_key_str;
2589 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2592 BOOL delete_key = FALSE;
2597 ui_progress( package, 2, 0, 0, 0 );
2599 component = MSI_RecordGetString( row, 6 );
2600 comp = get_loaded_component( package, component );
2602 return ERROR_SUCCESS;
2606 TRACE("component is disabled\n");
2607 return ERROR_SUCCESS;
2610 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2612 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2613 comp->Action = comp->Installed;
2614 return ERROR_SUCCESS;
2616 comp->Action = INSTALLSTATE_ABSENT;
2618 name = MSI_RecordGetString( row, 4 );
2619 if (MSI_RecordIsNull( row, 5 ) && name )
2621 if (name[0] == '+' && !name[1])
2622 return ERROR_SUCCESS;
2623 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2630 root = MSI_RecordGetInteger( row, 2 );
2631 key_str = MSI_RecordGetString( row, 3 );
2633 root_key_str = get_root_key( package, root, &hkey_root );
2635 return ERROR_SUCCESS;
2637 deformat_string( package, key_str, &deformated_key );
2638 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2639 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2640 strcpyW( ui_key_str, root_key_str );
2641 strcatW( ui_key_str, deformated_key );
2643 deformat_string( package, name, &deformated_name );
2645 keypath = get_keypath( package, hkey_root, deformated_key );
2646 msi_free( deformated_key );
2647 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2648 msi_free( keypath );
2650 uirow = MSI_CreateRecord( 2 );
2651 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2652 MSI_RecordSetStringW( uirow, 2, deformated_name );
2654 ui_actiondata( package, szRemoveRegistryValues, uirow );
2655 msiobj_release( &uirow->hdr );
2657 msi_free( ui_key_str );
2658 msi_free( deformated_name );
2659 return ERROR_SUCCESS;
2662 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2664 MSIPACKAGE *package = param;
2665 LPCWSTR component, name, key_str, root_key_str;
2666 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2669 BOOL delete_key = FALSE;
2674 ui_progress( package, 2, 0, 0, 0 );
2676 component = MSI_RecordGetString( row, 5 );
2677 comp = get_loaded_component( package, component );
2679 return ERROR_SUCCESS;
2683 TRACE("component is disabled\n");
2684 return ERROR_SUCCESS;
2687 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2689 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2690 comp->Action = comp->Installed;
2691 return ERROR_SUCCESS;
2693 comp->Action = INSTALLSTATE_LOCAL;
2695 if ((name = MSI_RecordGetString( row, 4 )))
2697 if (name[0] == '-' && !name[1])
2704 root = MSI_RecordGetInteger( row, 2 );
2705 key_str = MSI_RecordGetString( row, 3 );
2707 root_key_str = get_root_key( package, root, &hkey_root );
2709 return ERROR_SUCCESS;
2711 deformat_string( package, key_str, &deformated_key );
2712 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2713 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2714 strcpyW( ui_key_str, root_key_str );
2715 strcatW( ui_key_str, deformated_key );
2717 deformat_string( package, name, &deformated_name );
2719 keypath = get_keypath( package, hkey_root, deformated_key );
2720 msi_free( deformated_key );
2721 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2722 msi_free( keypath );
2724 uirow = MSI_CreateRecord( 2 );
2725 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2726 MSI_RecordSetStringW( uirow, 2, deformated_name );
2728 ui_actiondata( package, szRemoveRegistryValues, uirow );
2729 msiobj_release( &uirow->hdr );
2731 msi_free( ui_key_str );
2732 msi_free( deformated_name );
2733 return ERROR_SUCCESS;
2736 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2740 static const WCHAR registry_query[] =
2741 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2742 '`','R','e','g','i','s','t','r','y','`',0 };
2743 static const WCHAR remove_registry_query[] =
2744 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2745 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2747 /* increment progress bar each time action data is sent */
2748 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2750 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2751 if (rc == ERROR_SUCCESS)
2753 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2754 msiobj_release( &view->hdr );
2755 if (rc != ERROR_SUCCESS)
2759 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2760 if (rc == ERROR_SUCCESS)
2762 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2763 msiobj_release( &view->hdr );
2764 if (rc != ERROR_SUCCESS)
2768 return ERROR_SUCCESS;
2771 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2773 package->script->CurrentlyScripting = TRUE;
2775 return ERROR_SUCCESS;
2779 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2784 static const WCHAR q1[]=
2785 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2786 '`','R','e','g','i','s','t','r','y','`',0};
2789 MSIFEATURE *feature;
2792 TRACE("InstallValidate\n");
2794 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2795 if (rc == ERROR_SUCCESS)
2797 MSI_IterateRecords( view, &progress, NULL, package );
2798 msiobj_release( &view->hdr );
2799 total += progress * REG_PROGRESS_VALUE;
2802 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2803 total += COMPONENT_PROGRESS_VALUE;
2805 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2806 total += file->FileSize;
2808 ui_progress(package,0,total,0,0);
2810 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2812 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2813 debugstr_w(feature->Feature), feature->Installed,
2814 feature->ActionRequest, feature->Action);
2817 return ERROR_SUCCESS;
2820 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2822 MSIPACKAGE* package = param;
2823 LPCWSTR cond = NULL;
2824 LPCWSTR message = NULL;
2827 static const WCHAR title[]=
2828 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2830 cond = MSI_RecordGetString(row,1);
2832 r = MSI_EvaluateConditionW(package,cond);
2833 if (r == MSICONDITION_FALSE)
2835 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2838 message = MSI_RecordGetString(row,2);
2839 deformat_string(package,message,&deformated);
2840 MessageBoxW(NULL,deformated,title,MB_OK);
2841 msi_free(deformated);
2844 return ERROR_INSTALL_FAILURE;
2847 return ERROR_SUCCESS;
2850 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2853 MSIQUERY * view = NULL;
2854 static const WCHAR ExecSeqQuery[] =
2855 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2856 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2858 TRACE("Checking launch conditions\n");
2860 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2861 if (rc != ERROR_SUCCESS)
2862 return ERROR_SUCCESS;
2864 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2865 msiobj_release(&view->hdr);
2870 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2874 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2876 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2878 MSIRECORD * row = 0;
2880 LPWSTR deformated,buffer,deformated_name;
2882 static const WCHAR ExecSeqQuery[] =
2883 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2884 '`','R','e','g','i','s','t','r','y','`',' ',
2885 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2886 ' ','=',' ' ,'\'','%','s','\'',0 };
2887 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2888 static const WCHAR fmt2[]=
2889 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2891 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2895 root = MSI_RecordGetInteger(row,2);
2896 key = MSI_RecordGetString(row, 3);
2897 name = MSI_RecordGetString(row, 4);
2898 deformat_string(package, key , &deformated);
2899 deformat_string(package, name, &deformated_name);
2901 len = strlenW(deformated) + 6;
2902 if (deformated_name)
2903 len+=strlenW(deformated_name);
2905 buffer = msi_alloc( len *sizeof(WCHAR));
2907 if (deformated_name)
2908 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2910 sprintfW(buffer,fmt,root,deformated);
2912 msi_free(deformated);
2913 msi_free(deformated_name);
2914 msiobj_release(&row->hdr);
2918 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2920 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2925 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2928 return strdupW( file->TargetPath );
2933 static HKEY openSharedDLLsKey(void)
2936 static const WCHAR path[] =
2937 {'S','o','f','t','w','a','r','e','\\',
2938 'M','i','c','r','o','s','o','f','t','\\',
2939 'W','i','n','d','o','w','s','\\',
2940 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2941 'S','h','a','r','e','d','D','L','L','s',0};
2943 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2947 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2952 DWORD sz = sizeof(count);
2955 hkey = openSharedDLLsKey();
2956 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2957 if (rc != ERROR_SUCCESS)
2963 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2967 hkey = openSharedDLLsKey();
2969 msi_reg_set_val_dword( hkey, path, count );
2971 RegDeleteValueW(hkey,path);
2977 * Return TRUE if the count should be written out and FALSE if not
2979 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2981 MSIFEATURE *feature;
2985 /* only refcount DLLs */
2986 if (comp->KeyPath == NULL ||
2987 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2988 comp->Attributes & msidbComponentAttributesODBCDataSource)
2992 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2993 write = (count > 0);
2995 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2999 /* increment counts */
3000 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3004 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3007 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3009 if ( cl->component == comp )
3014 /* decrement counts */
3015 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3019 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3022 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3024 if ( cl->component == comp )
3029 /* ref count all the files in the component */
3034 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3036 if (file->Component == comp)
3037 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3041 /* add a count for permanent */
3042 if (comp->Attributes & msidbComponentAttributesPermanent)
3045 comp->RefCount = count;
3048 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3051 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3053 WCHAR squished_pc[GUID_SIZE];
3054 WCHAR squished_cc[GUID_SIZE];
3061 squash_guid(package->ProductCode,squished_pc);
3062 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3064 msi_set_sourcedir_props(package, FALSE);
3066 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3070 ui_progress(package,2,0,0,0);
3071 if (!comp->ComponentId)
3074 squash_guid(comp->ComponentId,squished_cc);
3076 msi_free(comp->FullKeypath);
3077 comp->FullKeypath = resolve_keypath( package, comp );
3079 ACTION_RefCountComponent( package, comp );
3081 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3082 debugstr_w(comp->Component),
3083 debugstr_w(squished_cc),
3084 debugstr_w(comp->FullKeypath),
3086 comp->ActionRequest);
3088 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3089 comp->ActionRequest == INSTALLSTATE_SOURCE)
3091 if (!comp->FullKeypath)
3094 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3095 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3098 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3101 if (rc != ERROR_SUCCESS)
3104 if (comp->Attributes & msidbComponentAttributesPermanent)
3106 static const WCHAR szPermKey[] =
3107 { '0','0','0','0','0','0','0','0','0','0','0','0',
3108 '0','0','0','0','0','0','0','0','0','0','0','0',
3109 '0','0','0','0','0','0','0','0',0 };
3111 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3114 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3115 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3121 WCHAR source[MAX_PATH];
3122 WCHAR base[MAX_PATH];
3125 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3126 static const WCHAR query[] = {
3127 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3128 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3129 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3130 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3131 '`','D','i','s','k','I','d','`',0};
3133 file = get_loaded_file(package, comp->KeyPath);
3137 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3138 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3139 ptr2 = strrchrW(source, '\\') + 1;
3140 msiobj_release(&row->hdr);
3142 lstrcpyW(base, package->PackagePath);
3143 ptr = strrchrW(base, '\\');
3146 sourcepath = resolve_file_source(package, file);
3147 ptr = sourcepath + lstrlenW(base);
3148 lstrcpyW(ptr2, ptr);
3149 msi_free(sourcepath);
3151 msi_reg_set_val_str(hkey, squished_pc, source);
3155 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3157 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3158 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3160 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3162 comp->Action = comp->ActionRequest;
3165 uirow = MSI_CreateRecord(3);
3166 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3167 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3168 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3169 ui_actiondata(package,szProcessComponents,uirow);
3170 msiobj_release( &uirow->hdr );
3173 return ERROR_SUCCESS;
3184 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3185 LPWSTR lpszName, LONG_PTR lParam)
3188 typelib_struct *tl_struct = (typelib_struct*) lParam;
3189 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3193 if (!IS_INTRESOURCE(lpszName))
3195 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3199 sz = strlenW(tl_struct->source)+4;
3200 sz *= sizeof(WCHAR);
3202 if ((INT_PTR)lpszName == 1)
3203 tl_struct->path = strdupW(tl_struct->source);
3206 tl_struct->path = msi_alloc(sz);
3207 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3210 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3211 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3214 msi_free(tl_struct->path);
3215 tl_struct->path = NULL;
3220 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3221 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3223 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3227 msi_free(tl_struct->path);
3228 tl_struct->path = NULL;
3230 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3231 ITypeLib_Release(tl_struct->ptLib);
3236 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3238 MSIPACKAGE* package = param;
3242 typelib_struct tl_struct;
3247 component = MSI_RecordGetString(row,3);
3248 comp = get_loaded_component(package,component);
3250 return ERROR_SUCCESS;
3254 TRACE("component is disabled\n");
3255 return ERROR_SUCCESS;
3258 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3260 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3261 comp->Action = comp->Installed;
3262 return ERROR_SUCCESS;
3264 comp->Action = INSTALLSTATE_LOCAL;
3266 file = get_loaded_file( package, comp->KeyPath );
3268 return ERROR_SUCCESS;
3270 ui_actiondata( package, szRegisterTypeLibraries, row );
3272 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3276 guid = MSI_RecordGetString(row,1);
3277 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3278 tl_struct.source = strdupW( file->TargetPath );
3279 tl_struct.path = NULL;
3281 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3282 (LONG_PTR)&tl_struct);
3290 helpid = MSI_RecordGetString(row,6);
3293 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3294 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3298 ERR("Failed to register type library %s\n",
3299 debugstr_w(tl_struct.path));
3301 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3303 ITypeLib_Release(tl_struct.ptLib);
3304 msi_free(tl_struct.path);
3307 ERR("Failed to load type library %s\n",
3308 debugstr_w(tl_struct.source));
3310 FreeLibrary(module);
3311 msi_free(tl_struct.source);
3315 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3318 ERR("Failed to load type library: %08x\n", hr);
3319 return ERROR_INSTALL_FAILURE;
3322 ITypeLib_Release(tlib);
3325 return ERROR_SUCCESS;
3328 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3331 * OK this is a bit confusing.. I am given a _Component key and I believe
3332 * that the file that is being registered as a type library is the "key file
3333 * of that component" which I interpret to mean "The file in the KeyPath of
3338 static const WCHAR Query[] =
3339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3340 '`','T','y','p','e','L','i','b','`',0};
3342 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3343 if (rc != ERROR_SUCCESS)
3344 return ERROR_SUCCESS;
3346 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3347 msiobj_release(&view->hdr);
3351 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3353 MSIPACKAGE *package = param;
3354 LPCWSTR component, guid;
3362 component = MSI_RecordGetString( row, 3 );
3363 comp = get_loaded_component( package, component );
3365 return ERROR_SUCCESS;
3369 TRACE("component is disabled\n");
3370 return ERROR_SUCCESS;
3373 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3375 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3376 comp->Action = comp->Installed;
3377 return ERROR_SUCCESS;
3379 comp->Action = INSTALLSTATE_ABSENT;
3381 ui_actiondata( package, szUnregisterTypeLibraries, row );
3383 guid = MSI_RecordGetString( row, 1 );
3384 CLSIDFromString( (LPCWSTR)guid, &libid );
3385 version = MSI_RecordGetInteger( row, 4 );
3386 language = MSI_RecordGetInteger( row, 2 );
3389 syskind = SYS_WIN64;
3391 syskind = SYS_WIN32;
3394 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3397 WARN("Failed to unregister typelib: %08x\n", hr);
3400 return ERROR_SUCCESS;
3403 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3407 static const WCHAR query[] =
3408 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3409 '`','T','y','p','e','L','i','b','`',0};
3411 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3412 if (rc != ERROR_SUCCESS)
3413 return ERROR_SUCCESS;
3415 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3416 msiobj_release( &view->hdr );
3420 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3422 static const WCHAR szlnk[] = {'.','l','n','k',0};
3423 LPCWSTR directory, extension;
3424 LPWSTR link_folder, link_file, filename;
3426 directory = MSI_RecordGetString( row, 2 );
3427 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3429 /* may be needed because of a bug somewhere else */
3430 create_full_pathW( link_folder );
3432 filename = msi_dup_record_field( row, 3 );
3433 reduce_to_longfilename( filename );
3435 extension = strchrW( filename, '.' );
3436 if (!extension || strcmpiW( extension, szlnk ))
3438 int len = strlenW( filename );
3439 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3440 memcpy( filename + len, szlnk, sizeof(szlnk) );
3442 link_file = build_directory_name( 2, link_folder, filename );
3443 msi_free( link_folder );
3444 msi_free( filename );
3449 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3451 MSIPACKAGE *package = param;
3452 LPWSTR link_file, deformated, path;
3453 LPCWSTR component, target;
3455 IShellLinkW *sl = NULL;
3456 IPersistFile *pf = NULL;
3459 component = MSI_RecordGetString(row, 4);
3460 comp = get_loaded_component(package, component);
3462 return ERROR_SUCCESS;
3466 TRACE("component is disabled\n");
3467 return ERROR_SUCCESS;
3470 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3472 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3473 comp->Action = comp->Installed;
3474 return ERROR_SUCCESS;
3476 comp->Action = INSTALLSTATE_LOCAL;
3478 ui_actiondata(package,szCreateShortcuts,row);
3480 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3481 &IID_IShellLinkW, (LPVOID *) &sl );
3485 ERR("CLSID_ShellLink not available\n");
3489 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3492 ERR("QueryInterface(IID_IPersistFile) failed\n");
3496 target = MSI_RecordGetString(row, 5);
3497 if (strchrW(target, '['))
3499 deformat_string(package, target, &deformated);
3500 IShellLinkW_SetPath(sl,deformated);
3501 msi_free(deformated);
3505 FIXME("poorly handled shortcut format, advertised shortcut\n");
3506 IShellLinkW_SetPath(sl,comp->FullKeypath);
3509 if (!MSI_RecordIsNull(row,6))
3511 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3512 deformat_string(package, arguments, &deformated);
3513 IShellLinkW_SetArguments(sl,deformated);
3514 msi_free(deformated);
3517 if (!MSI_RecordIsNull(row,7))
3519 LPCWSTR description = MSI_RecordGetString(row, 7);
3520 IShellLinkW_SetDescription(sl, description);
3523 if (!MSI_RecordIsNull(row,8))
3524 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3526 if (!MSI_RecordIsNull(row,9))
3529 LPCWSTR icon = MSI_RecordGetString(row, 9);
3531 path = build_icon_path(package, icon);
3532 index = MSI_RecordGetInteger(row,10);
3534 /* no value means 0 */
3535 if (index == MSI_NULL_INTEGER)
3538 IShellLinkW_SetIconLocation(sl, path, index);
3542 if (!MSI_RecordIsNull(row,11))
3543 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3545 if (!MSI_RecordIsNull(row,12))
3547 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3548 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3550 IShellLinkW_SetWorkingDirectory(sl, path);
3554 link_file = get_link_file(package, row);
3556 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3557 IPersistFile_Save(pf, link_file, FALSE);
3559 msi_free(link_file);
3563 IPersistFile_Release( pf );
3565 IShellLinkW_Release( sl );
3567 return ERROR_SUCCESS;
3570 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3575 static const WCHAR Query[] =
3576 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3577 '`','S','h','o','r','t','c','u','t','`',0};
3579 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3580 if (rc != ERROR_SUCCESS)
3581 return ERROR_SUCCESS;
3583 res = CoInitialize( NULL );
3585 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3586 msiobj_release(&view->hdr);
3594 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3596 MSIPACKAGE *package = param;
3601 component = MSI_RecordGetString( row, 4 );
3602 comp = get_loaded_component( package, component );
3604 return ERROR_SUCCESS;
3608 TRACE("component is disabled\n");
3609 return ERROR_SUCCESS;
3612 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3614 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3615 comp->Action = comp->Installed;
3616 return ERROR_SUCCESS;
3618 comp->Action = INSTALLSTATE_ABSENT;
3620 ui_actiondata( package, szRemoveShortcuts, row );
3622 link_file = get_link_file( package, row );
3624 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3625 if (!DeleteFileW( link_file ))
3627 WARN("Failed to remove shortcut file %u\n", GetLastError());
3629 msi_free( link_file );
3631 return ERROR_SUCCESS;
3634 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3638 static const WCHAR query[] =
3639 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3640 '`','S','h','o','r','t','c','u','t','`',0};
3642 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3643 if (rc != ERROR_SUCCESS)
3644 return ERROR_SUCCESS;
3646 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3647 msiobj_release( &view->hdr );
3652 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3654 MSIPACKAGE* package = param;
3662 FileName = MSI_RecordGetString(row,1);
3665 ERR("Unable to get FileName\n");
3666 return ERROR_SUCCESS;
3669 FilePath = build_icon_path(package,FileName);
3671 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3673 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3674 FILE_ATTRIBUTE_NORMAL, NULL);
3676 if (the_file == INVALID_HANDLE_VALUE)
3678 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3680 return ERROR_SUCCESS;
3687 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3688 if (rc != ERROR_SUCCESS)
3690 ERR("Failed to get stream\n");
3691 CloseHandle(the_file);
3692 DeleteFileW(FilePath);
3695 WriteFile(the_file,buffer,sz,&write,NULL);
3696 } while (sz == 1024);
3699 CloseHandle(the_file);
3701 return ERROR_SUCCESS;
3704 static UINT msi_publish_icons(MSIPACKAGE *package)
3709 static const WCHAR query[]= {
3710 'S','E','L','E','C','T',' ','*',' ',
3711 'F','R','O','M',' ','`','I','c','o','n','`',0};
3713 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3714 if (r == ERROR_SUCCESS)
3716 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3717 msiobj_release(&view->hdr);
3720 return ERROR_SUCCESS;
3723 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3729 MSISOURCELISTINFO *info;
3731 r = RegCreateKeyW(hkey, szSourceList, &source);
3732 if (r != ERROR_SUCCESS)
3735 RegCloseKey(source);
3737 buffer = strrchrW(package->PackagePath, '\\') + 1;
3738 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3739 package->Context, MSICODE_PRODUCT,
3740 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3741 if (r != ERROR_SUCCESS)
3744 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3745 package->Context, MSICODE_PRODUCT,
3746 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3747 if (r != ERROR_SUCCESS)
3750 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3751 package->Context, MSICODE_PRODUCT,
3752 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3753 if (r != ERROR_SUCCESS)
3756 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3758 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3759 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3760 info->options, info->value);
3762 MsiSourceListSetInfoW(package->ProductCode, NULL,
3763 info->context, info->options,
3764 info->property, info->value);
3767 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3769 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3770 disk->context, disk->options,
3771 disk->disk_id, disk->volume_label, disk->disk_prompt);
3774 return ERROR_SUCCESS;
3777 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3779 MSIHANDLE hdb, suminfo;
3780 WCHAR guids[MAX_PATH];
3781 WCHAR packcode[SQUISH_GUID_SIZE];
3788 static const WCHAR szProductLanguage[] =
3789 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3790 static const WCHAR szARPProductIcon[] =
3791 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3792 static const WCHAR szProductVersion[] =
3793 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3794 static const WCHAR szAssignment[] =
3795 {'A','s','s','i','g','n','m','e','n','t',0};
3796 static const WCHAR szAdvertiseFlags[] =
3797 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3798 static const WCHAR szClients[] =
3799 {'C','l','i','e','n','t','s',0};
3800 static const WCHAR szColon[] = {':',0};
3802 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3803 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3806 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3807 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3810 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3812 buffer = msi_dup_property(package->db, szARPProductIcon);
3815 LPWSTR path = build_icon_path(package,buffer);
3816 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3821 buffer = msi_dup_property(package->db, szProductVersion);
3824 DWORD verdword = msi_version_str_to_dword(buffer);
3825 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3829 msi_reg_set_val_dword(hkey, szAssignment, 0);
3830 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3831 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3832 msi_reg_set_val_str(hkey, szClients, szColon);
3834 hdb = alloc_msihandle(&package->db->hdr);
3836 return ERROR_NOT_ENOUGH_MEMORY;
3838 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3839 MsiCloseHandle(hdb);
3840 if (r != ERROR_SUCCESS)
3844 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3845 NULL, guids, &size);
3846 if (r != ERROR_SUCCESS)
3849 ptr = strchrW(guids, ';');
3851 squash_guid(guids, packcode);
3852 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3855 MsiCloseHandle(suminfo);
3856 return ERROR_SUCCESS;
3859 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3864 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3866 upgrade = msi_dup_property(package->db, szUpgradeCode);
3868 return ERROR_SUCCESS;
3870 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3872 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3873 if (r != ERROR_SUCCESS)
3878 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3879 if (r != ERROR_SUCCESS)
3883 squash_guid(package->ProductCode, squashed_pc);
3884 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3893 static BOOL msi_check_publish(MSIPACKAGE *package)
3895 MSIFEATURE *feature;
3897 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3899 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3906 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3908 MSIFEATURE *feature;
3910 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3912 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3919 static UINT msi_publish_patches( MSIPACKAGE *package )
3921 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3922 WCHAR patch_squashed[GUID_SIZE];
3923 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
3925 MSIPATCHINFO *patch;
3927 WCHAR *p, *all_patches = NULL;
3930 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
3931 if (r != ERROR_SUCCESS)
3932 return ERROR_FUNCTION_FAILED;
3934 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3935 if (res != ERROR_SUCCESS)
3937 r = ERROR_FUNCTION_FAILED;
3941 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3942 if (r != ERROR_SUCCESS)
3945 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3947 squash_guid( patch->patchcode, patch_squashed );
3948 len += strlenW( patch_squashed ) + 1;
3951 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3955 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3959 squash_guid( patch->patchcode, p );
3960 p += strlenW( p ) + 1;
3962 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3963 (const BYTE *)patch->transforms,
3964 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3965 if (res != ERROR_SUCCESS)
3968 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3969 if (r != ERROR_SUCCESS)
3972 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3973 (const BYTE *)patch->localfile,
3974 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3975 RegCloseKey( patch_key );
3976 if (res != ERROR_SUCCESS)
3979 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3980 if (res != ERROR_SUCCESS)
3983 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
3984 RegCloseKey( patch_key );
3985 if (res != ERROR_SUCCESS)
3989 all_patches[len] = 0;
3990 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3991 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3992 if (res != ERROR_SUCCESS)
3995 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3996 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3997 if (res != ERROR_SUCCESS)
3998 r = ERROR_FUNCTION_FAILED;
4001 RegCloseKey( product_patches_key );
4002 RegCloseKey( patches_key );
4003 RegCloseKey( product_key );
4004 msi_free( all_patches );
4009 * 99% of the work done here is only done for
4010 * advertised installs. However this is where the
4011 * Icon table is processed and written out
4012 * so that is what I am going to do here.
4014 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4017 HKEY hukey = NULL, hudkey = NULL;
4020 if (!list_empty(&package->patches))
4022 rc = msi_publish_patches(package);
4023 if (rc != ERROR_SUCCESS)
4027 /* FIXME: also need to publish if the product is in advertise mode */
4028 if (!msi_check_publish(package))
4029 return ERROR_SUCCESS;
4031 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4033 if (rc != ERROR_SUCCESS)
4036 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4037 NULL, &hudkey, TRUE);
4038 if (rc != ERROR_SUCCESS)
4041 rc = msi_publish_upgrade_code(package);
4042 if (rc != ERROR_SUCCESS)
4045 rc = msi_publish_product_properties(package, hukey);
4046 if (rc != ERROR_SUCCESS)
4049 rc = msi_publish_sourcelist(package, hukey);
4050 if (rc != ERROR_SUCCESS)
4053 rc = msi_publish_icons(package);
4056 uirow = MSI_CreateRecord( 1 );
4057 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4058 ui_actiondata( package, szPublishProduct, uirow );
4059 msiobj_release( &uirow->hdr );
4062 RegCloseKey(hudkey);
4067 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4069 WCHAR *filename, *ptr, *folder, *ret;
4070 const WCHAR *dirprop;
4072 filename = msi_dup_record_field( row, 2 );
4073 if (filename && (ptr = strchrW( filename, '|' )))
4078 dirprop = MSI_RecordGetString( row, 3 );
4081 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4083 folder = msi_dup_property( package->db, dirprop );
4086 folder = msi_dup_property( package->db, szWindowsFolder );
4090 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4091 msi_free( filename );
4095 ret = build_directory_name( 2, folder, ptr );
4097 msi_free( filename );
4102 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4104 MSIPACKAGE *package = param;
4105 LPCWSTR component, section, key, value, identifier;
4106 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4111 component = MSI_RecordGetString(row, 8);
4112 comp = get_loaded_component(package,component);
4114 return ERROR_SUCCESS;
4118 TRACE("component is disabled\n");
4119 return ERROR_SUCCESS;
4122 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4124 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4125 comp->Action = comp->Installed;
4126 return ERROR_SUCCESS;
4128 comp->Action = INSTALLSTATE_LOCAL;
4130 identifier = MSI_RecordGetString(row,1);
4131 section = MSI_RecordGetString(row,4);
4132 key = MSI_RecordGetString(row,5);
4133 value = MSI_RecordGetString(row,6);
4134 action = MSI_RecordGetInteger(row,7);
4136 deformat_string(package,section,&deformated_section);
4137 deformat_string(package,key,&deformated_key);
4138 deformat_string(package,value,&deformated_value);
4140 fullname = get_ini_file_name(package, row);
4144 TRACE("Adding value %s to section %s in %s\n",
4145 debugstr_w(deformated_key), debugstr_w(deformated_section),
4146 debugstr_w(fullname));
4147 WritePrivateProfileStringW(deformated_section, deformated_key,
4148 deformated_value, fullname);
4150 else if (action == 1)
4153 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4154 returned, 10, fullname);
4155 if (returned[0] == 0)
4157 TRACE("Adding value %s to section %s in %s\n",
4158 debugstr_w(deformated_key), debugstr_w(deformated_section),
4159 debugstr_w(fullname));
4161 WritePrivateProfileStringW(deformated_section, deformated_key,
4162 deformated_value, fullname);
4165 else if (action == 3)
4166 FIXME("Append to existing section not yet implemented\n");
4168 uirow = MSI_CreateRecord(4);
4169 MSI_RecordSetStringW(uirow,1,identifier);
4170 MSI_RecordSetStringW(uirow,2,deformated_section);
4171 MSI_RecordSetStringW(uirow,3,deformated_key);
4172 MSI_RecordSetStringW(uirow,4,deformated_value);
4173 ui_actiondata(package,szWriteIniValues,uirow);
4174 msiobj_release( &uirow->hdr );
4177 msi_free(deformated_key);
4178 msi_free(deformated_value);
4179 msi_free(deformated_section);
4180 return ERROR_SUCCESS;
4183 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4187 static const WCHAR ExecSeqQuery[] =
4188 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4189 '`','I','n','i','F','i','l','e','`',0};
4191 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4192 if (rc != ERROR_SUCCESS)
4194 TRACE("no IniFile table\n");
4195 return ERROR_SUCCESS;
4198 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4199 msiobj_release(&view->hdr);
4203 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4205 MSIPACKAGE *package = param;
4206 LPCWSTR component, section, key, value, identifier;
4207 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4212 component = MSI_RecordGetString( row, 8 );
4213 comp = get_loaded_component( package, component );
4215 return ERROR_SUCCESS;
4219 TRACE("component is disabled\n");
4220 return ERROR_SUCCESS;
4223 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4225 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4226 comp->Action = comp->Installed;
4227 return ERROR_SUCCESS;
4229 comp->Action = INSTALLSTATE_ABSENT;
4231 identifier = MSI_RecordGetString( row, 1 );
4232 section = MSI_RecordGetString( row, 4 );
4233 key = MSI_RecordGetString( row, 5 );
4234 value = MSI_RecordGetString( row, 6 );
4235 action = MSI_RecordGetInteger( row, 7 );
4237 deformat_string( package, section, &deformated_section );
4238 deformat_string( package, key, &deformated_key );
4239 deformat_string( package, value, &deformated_value );
4241 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4243 filename = get_ini_file_name( package, row );
4245 TRACE("Removing key %s from section %s in %s\n",
4246 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4248 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4250 WARN("Unable to remove key %u\n", GetLastError());
4252 msi_free( filename );
4255 FIXME("Unsupported action %d\n", action);
4258 uirow = MSI_CreateRecord( 4 );
4259 MSI_RecordSetStringW( uirow, 1, identifier );
4260 MSI_RecordSetStringW( uirow, 2, deformated_section );
4261 MSI_RecordSetStringW( uirow, 3, deformated_key );
4262 MSI_RecordSetStringW( uirow, 4, deformated_value );
4263 ui_actiondata( package, szRemoveIniValues, uirow );
4264 msiobj_release( &uirow->hdr );
4266 msi_free( deformated_key );
4267 msi_free( deformated_value );
4268 msi_free( deformated_section );
4269 return ERROR_SUCCESS;
4272 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4274 MSIPACKAGE *package = param;
4275 LPCWSTR component, section, key, value, identifier;
4276 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4281 component = MSI_RecordGetString( row, 8 );
4282 comp = get_loaded_component( package, component );
4284 return ERROR_SUCCESS;
4288 TRACE("component is disabled\n");
4289 return ERROR_SUCCESS;
4292 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4294 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4295 comp->Action = comp->Installed;
4296 return ERROR_SUCCESS;
4298 comp->Action = INSTALLSTATE_LOCAL;
4300 identifier = MSI_RecordGetString( row, 1 );
4301 section = MSI_RecordGetString( row, 4 );
4302 key = MSI_RecordGetString( row, 5 );
4303 value = MSI_RecordGetString( row, 6 );
4304 action = MSI_RecordGetInteger( row, 7 );
4306 deformat_string( package, section, &deformated_section );
4307 deformat_string( package, key, &deformated_key );
4308 deformat_string( package, value, &deformated_value );
4310 if (action == msidbIniFileActionRemoveLine)
4312 filename = get_ini_file_name( package, row );
4314 TRACE("Removing key %s from section %s in %s\n",
4315 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4317 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4319 WARN("Unable to remove key %u\n", GetLastError());
4321 msi_free( filename );
4324 FIXME("Unsupported action %d\n", action);
4326 uirow = MSI_CreateRecord( 4 );
4327 MSI_RecordSetStringW( uirow, 1, identifier );
4328 MSI_RecordSetStringW( uirow, 2, deformated_section );
4329 MSI_RecordSetStringW( uirow, 3, deformated_key );
4330 MSI_RecordSetStringW( uirow, 4, deformated_value );
4331 ui_actiondata( package, szRemoveIniValues, uirow );
4332 msiobj_release( &uirow->hdr );
4334 msi_free( deformated_key );
4335 msi_free( deformated_value );
4336 msi_free( deformated_section );
4337 return ERROR_SUCCESS;
4340 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4344 static const WCHAR query[] =
4345 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4346 '`','I','n','i','F','i','l','e','`',0};
4347 static const WCHAR remove_query[] =
4348 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4349 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4351 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4352 if (rc == ERROR_SUCCESS)
4354 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4355 msiobj_release( &view->hdr );
4356 if (rc != ERROR_SUCCESS)
4360 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4361 if (rc == ERROR_SUCCESS)
4363 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4364 msiobj_release( &view->hdr );
4365 if (rc != ERROR_SUCCESS)
4369 return ERROR_SUCCESS;
4372 static void register_dll( const WCHAR *dll, BOOL unregister )
4376 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4379 HRESULT (WINAPI *func_ptr)( void );
4380 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4382 func_ptr = (void *)GetProcAddress( hmod, func );
4385 HRESULT hr = func_ptr();
4387 WARN("failed to register dll 0x%08x\n", hr);
4390 WARN("entry point %s not found\n", func);
4391 FreeLibrary( hmod );
4394 WARN("failed to load library %u\n", GetLastError());
4397 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4399 MSIPACKAGE *package = param;
4404 filename = MSI_RecordGetString(row,1);
4405 file = get_loaded_file( package, filename );
4409 ERR("Unable to find file id %s\n",debugstr_w(filename));
4410 return ERROR_SUCCESS;
4413 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4415 register_dll( file->TargetPath, FALSE );
4417 uirow = MSI_CreateRecord( 2 );
4418 MSI_RecordSetStringW( uirow, 1, filename );
4419 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4420 ui_actiondata( package, szSelfRegModules, uirow );
4421 msiobj_release( &uirow->hdr );
4423 return ERROR_SUCCESS;
4426 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4430 static const WCHAR ExecSeqQuery[] =
4431 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4432 '`','S','e','l','f','R','e','g','`',0};
4434 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4435 if (rc != ERROR_SUCCESS)
4437 TRACE("no SelfReg table\n");
4438 return ERROR_SUCCESS;
4441 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4442 msiobj_release(&view->hdr);
4444 return ERROR_SUCCESS;
4447 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4449 MSIPACKAGE *package = param;
4454 filename = MSI_RecordGetString( row, 1 );
4455 file = get_loaded_file( package, filename );
4459 ERR("Unable to find file id %s\n", debugstr_w(filename));
4460 return ERROR_SUCCESS;
4463 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4465 register_dll( file->TargetPath, TRUE );
4467 uirow = MSI_CreateRecord( 2 );
4468 MSI_RecordSetStringW( uirow, 1, filename );
4469 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4470 ui_actiondata( package, szSelfUnregModules, uirow );
4471 msiobj_release( &uirow->hdr );
4473 return ERROR_SUCCESS;
4476 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4480 static const WCHAR query[] =
4481 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4482 '`','S','e','l','f','R','e','g','`',0};
4484 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4485 if (rc != ERROR_SUCCESS)
4487 TRACE("no SelfReg table\n");
4488 return ERROR_SUCCESS;
4491 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4492 msiobj_release( &view->hdr );
4494 return ERROR_SUCCESS;
4497 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4499 MSIFEATURE *feature;
4501 HKEY hkey = NULL, userdata = NULL;
4503 if (!msi_check_publish(package))
4504 return ERROR_SUCCESS;
4506 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4508 if (rc != ERROR_SUCCESS)
4511 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4513 if (rc != ERROR_SUCCESS)
4516 /* here the guids are base 85 encoded */
4517 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4523 BOOL absent = FALSE;
4526 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4527 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4528 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4531 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4535 if (feature->Feature_Parent)
4536 size += strlenW( feature->Feature_Parent )+2;
4538 data = msi_alloc(size * sizeof(WCHAR));
4541 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4543 MSICOMPONENT* component = cl->component;
4547 if (component->ComponentId)
4549 TRACE("From %s\n",debugstr_w(component->ComponentId));
4550 CLSIDFromString(component->ComponentId, &clsid);
4551 encode_base85_guid(&clsid,buf);
4552 TRACE("to %s\n",debugstr_w(buf));
4557 if (feature->Feature_Parent)
4559 static const WCHAR sep[] = {'\2',0};
4561 strcatW(data,feature->Feature_Parent);
4564 msi_reg_set_val_str( userdata, feature->Feature, data );
4568 if (feature->Feature_Parent)
4569 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4572 size += sizeof(WCHAR);
4573 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4574 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4578 size += 2*sizeof(WCHAR);
4579 data = msi_alloc(size);
4582 if (feature->Feature_Parent)
4583 strcpyW( &data[1], feature->Feature_Parent );
4584 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4590 uirow = MSI_CreateRecord( 1 );
4591 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4592 ui_actiondata( package, szPublishFeatures, uirow);
4593 msiobj_release( &uirow->hdr );
4594 /* FIXME: call ui_progress? */
4599 RegCloseKey(userdata);
4603 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4609 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4611 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4613 if (r == ERROR_SUCCESS)
4615 RegDeleteValueW(hkey, feature->Feature);
4619 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4621 if (r == ERROR_SUCCESS)
4623 RegDeleteValueW(hkey, feature->Feature);
4627 uirow = MSI_CreateRecord( 1 );
4628 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4629 ui_actiondata( package, szUnpublishFeatures, uirow );
4630 msiobj_release( &uirow->hdr );
4632 return ERROR_SUCCESS;
4635 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4637 MSIFEATURE *feature;
4639 if (!msi_check_unpublish(package))
4640 return ERROR_SUCCESS;
4642 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4644 msi_unpublish_feature(package, feature);
4647 return ERROR_SUCCESS;
4650 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4654 WCHAR date[9], *val, *buffer;
4655 const WCHAR *prop, *key;
4657 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4658 static const WCHAR szWindowsInstaller[] =
4659 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4660 static const WCHAR modpath_fmt[] =
4661 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4662 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4663 static const WCHAR szModifyPath[] =
4664 {'M','o','d','i','f','y','P','a','t','h',0};
4665 static const WCHAR szUninstallString[] =
4666 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4667 static const WCHAR szEstimatedSize[] =
4668 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4669 static const WCHAR szProductLanguage[] =
4670 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4671 static const WCHAR szProductVersion[] =
4672 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4673 static const WCHAR szDisplayVersion[] =
4674 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4675 static const WCHAR szInstallSource[] =
4676 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4677 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4678 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4679 static const WCHAR szAuthorizedCDFPrefix[] =
4680 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4681 static const WCHAR szARPCONTACT[] =
4682 {'A','R','P','C','O','N','T','A','C','T',0};
4683 static const WCHAR szContact[] =
4684 {'C','o','n','t','a','c','t',0};
4685 static const WCHAR szARPCOMMENTS[] =
4686 {'A','R','P','C','O','M','M','E','N','T','S',0};
4687 static const WCHAR szComments[] =
4688 {'C','o','m','m','e','n','t','s',0};
4689 static const WCHAR szProductName[] =
4690 {'P','r','o','d','u','c','t','N','a','m','e',0};
4691 static const WCHAR szDisplayName[] =
4692 {'D','i','s','p','l','a','y','N','a','m','e',0};
4693 static const WCHAR szARPHELPLINK[] =
4694 {'A','R','P','H','E','L','P','L','I','N','K',0};
4695 static const WCHAR szHelpLink[] =
4696 {'H','e','l','p','L','i','n','k',0};
4697 static const WCHAR szARPHELPTELEPHONE[] =
4698 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4699 static const WCHAR szHelpTelephone[] =
4700 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4701 static const WCHAR szARPINSTALLLOCATION[] =
4702 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4703 static const WCHAR szInstallLocation[] =
4704 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4705 static const WCHAR szManufacturer[] =
4706 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4707 static const WCHAR szPublisher[] =
4708 {'P','u','b','l','i','s','h','e','r',0};
4709 static const WCHAR szARPREADME[] =
4710 {'A','R','P','R','E','A','D','M','E',0};
4711 static const WCHAR szReadme[] =
4712 {'R','e','a','d','M','e',0};
4713 static const WCHAR szARPSIZE[] =
4714 {'A','R','P','S','I','Z','E',0};
4715 static const WCHAR szSize[] =
4716 {'S','i','z','e',0};
4717 static const WCHAR szARPURLINFOABOUT[] =
4718 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4719 static const WCHAR szURLInfoAbout[] =
4720 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4721 static const WCHAR szARPURLUPDATEINFO[] =
4722 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4723 static const WCHAR szURLUpdateInfo[] =
4724 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4726 static const WCHAR *propval[] = {
4727 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4728 szARPCONTACT, szContact,
4729 szARPCOMMENTS, szComments,
4730 szProductName, szDisplayName,
4731 szARPHELPLINK, szHelpLink,
4732 szARPHELPTELEPHONE, szHelpTelephone,
4733 szARPINSTALLLOCATION, szInstallLocation,
4734 cszSourceDir, szInstallSource,
4735 szManufacturer, szPublisher,
4736 szARPREADME, szReadme,
4738 szARPURLINFOABOUT, szURLInfoAbout,
4739 szARPURLUPDATEINFO, szURLUpdateInfo,
4742 const WCHAR **p = propval;
4748 val = msi_dup_property(package->db, prop);
4749 msi_reg_set_val_str(hkey, key, val);
4753 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4755 size = deformat_string(package, modpath_fmt, &buffer);
4756 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4757 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4760 /* FIXME: Write real Estimated Size when we have it */
4761 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4763 GetLocalTime(&systime);
4764 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4765 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4767 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4768 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4770 buffer = msi_dup_property(package->db, szProductVersion);
4771 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4774 DWORD verdword = msi_version_str_to_dword(buffer);
4776 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4777 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4778 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4782 return ERROR_SUCCESS;
4785 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4787 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4789 LPWSTR upgrade_code;
4794 /* FIXME: also need to publish if the product is in advertise mode */
4795 if (!msi_check_publish(package))
4796 return ERROR_SUCCESS;
4798 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4799 if (rc != ERROR_SUCCESS)
4802 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4803 NULL, &props, TRUE);
4804 if (rc != ERROR_SUCCESS)
4807 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4808 msi_free( package->db->localfile );
4809 package->db->localfile = NULL;
4811 rc = msi_publish_install_properties(package, hkey);
4812 if (rc != ERROR_SUCCESS)
4815 rc = msi_publish_install_properties(package, props);
4816 if (rc != ERROR_SUCCESS)
4819 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4822 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4823 squash_guid(package->ProductCode, squashed_pc);
4824 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4825 RegCloseKey(upgrade);
4826 msi_free(upgrade_code);
4830 uirow = MSI_CreateRecord( 1 );
4831 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4832 ui_actiondata( package, szRegisterProduct, uirow );
4833 msiobj_release( &uirow->hdr );
4836 return ERROR_SUCCESS;
4839 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4841 return execute_script(package,INSTALL_SCRIPT);
4844 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4846 WCHAR *upgrade, **features;
4847 BOOL full_uninstall = TRUE;
4848 MSIFEATURE *feature;
4849 MSIPATCHINFO *patch;
4851 static const WCHAR szUpgradeCode[] =
4852 {'U','p','g','r','a','d','e','C','o','d','e',0};
4854 features = msi_split_string(remove, ',');
4857 ERR("REMOVE feature list is empty!\n");
4858 return ERROR_FUNCTION_FAILED;
4861 if (!strcmpW( features[0], szAll ))
4862 full_uninstall = TRUE;
4865 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4867 if (feature->Action != INSTALLSTATE_ABSENT)
4868 full_uninstall = FALSE;
4873 if (!full_uninstall)
4874 return ERROR_SUCCESS;
4876 MSIREG_DeleteProductKey(package->ProductCode);
4877 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4878 MSIREG_DeleteUninstallKey(package);
4880 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4882 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4883 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4887 MSIREG_DeleteUserProductKey(package->ProductCode);
4888 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4891 upgrade = msi_dup_property(package->db, szUpgradeCode);
4894 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4898 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4900 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4903 return ERROR_SUCCESS;
4906 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4911 /* turn off scheduling */
4912 package->script->CurrentlyScripting= FALSE;
4914 /* first do the same as an InstallExecute */
4915 rc = ACTION_InstallExecute(package);
4916 if (rc != ERROR_SUCCESS)
4919 /* then handle Commit Actions */
4920 rc = execute_script(package,COMMIT_SCRIPT);
4921 if (rc != ERROR_SUCCESS)
4924 remove = msi_dup_property(package->db, szRemove);
4926 rc = msi_unpublish_product(package, remove);
4932 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4934 static const WCHAR RunOnce[] = {
4935 'S','o','f','t','w','a','r','e','\\',
4936 'M','i','c','r','o','s','o','f','t','\\',
4937 'W','i','n','d','o','w','s','\\',
4938 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4939 'R','u','n','O','n','c','e',0};
4940 static const WCHAR InstallRunOnce[] = {
4941 'S','o','f','t','w','a','r','e','\\',
4942 'M','i','c','r','o','s','o','f','t','\\',
4943 'W','i','n','d','o','w','s','\\',
4944 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4945 'I','n','s','t','a','l','l','e','r','\\',
4946 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4948 static const WCHAR msiexec_fmt[] = {
4950 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4951 '\"','%','s','\"',0};
4952 static const WCHAR install_fmt[] = {
4953 '/','I',' ','\"','%','s','\"',' ',
4954 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4955 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4956 WCHAR buffer[256], sysdir[MAX_PATH];
4958 WCHAR squished_pc[100];
4960 squash_guid(package->ProductCode,squished_pc);
4962 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4963 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4964 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4967 msi_reg_set_val_str( hkey, squished_pc, buffer );
4970 TRACE("Reboot command %s\n",debugstr_w(buffer));
4972 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4973 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4975 msi_reg_set_val_str( hkey, squished_pc, buffer );
4978 return ERROR_INSTALL_SUSPEND;
4981 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4987 * We are currently doing what should be done here in the top level Install
4988 * however for Administrative and uninstalls this step will be needed
4990 if (!package->PackagePath)
4991 return ERROR_SUCCESS;
4993 msi_set_sourcedir_props(package, TRUE);
4995 attrib = GetFileAttributesW(package->db->path);
4996 if (attrib == INVALID_FILE_ATTRIBUTES)
5002 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5003 package->Context, MSICODE_PRODUCT,
5004 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5005 if (rc == ERROR_MORE_DATA)
5007 prompt = msi_alloc(size * sizeof(WCHAR));
5008 MsiSourceListGetInfoW(package->ProductCode, NULL,
5009 package->Context, MSICODE_PRODUCT,
5010 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5013 prompt = strdupW(package->db->path);
5015 msg = generate_error_string(package,1302,1,prompt);
5016 while(attrib == INVALID_FILE_ATTRIBUTES)
5018 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5021 rc = ERROR_INSTALL_USEREXIT;
5024 attrib = GetFileAttributesW(package->db->path);
5030 return ERROR_SUCCESS;
5035 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5038 LPWSTR buffer, productid = NULL;
5039 UINT i, rc = ERROR_SUCCESS;
5042 static const WCHAR szPropKeys[][80] =
5044 {'P','r','o','d','u','c','t','I','D',0},
5045 {'U','S','E','R','N','A','M','E',0},
5046 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5050 static const WCHAR szRegKeys[][80] =
5052 {'P','r','o','d','u','c','t','I','D',0},
5053 {'R','e','g','O','w','n','e','r',0},
5054 {'R','e','g','C','o','m','p','a','n','y',0},
5058 if (msi_check_unpublish(package))
5060 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5064 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5068 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5070 if (rc != ERROR_SUCCESS)
5073 for( i = 0; szPropKeys[i][0]; i++ )
5075 buffer = msi_dup_property( package->db, szPropKeys[i] );
5076 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5081 uirow = MSI_CreateRecord( 1 );
5082 MSI_RecordSetStringW( uirow, 1, productid );
5083 ui_actiondata( package, szRegisterUser, uirow );
5084 msiobj_release( &uirow->hdr );
5086 msi_free(productid);
5092 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5096 package->script->InWhatSequence |= SEQUENCE_EXEC;
5097 rc = ACTION_ProcessExecSequence(package,FALSE);
5102 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5104 MSIPACKAGE *package = param;
5105 LPCWSTR compgroupid, component, feature, qualifier, text;
5106 LPWSTR advertise = NULL, output = NULL;
5114 feature = MSI_RecordGetString(rec, 5);
5115 feat = get_loaded_feature(package, feature);
5117 return ERROR_SUCCESS;
5119 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5120 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5121 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5123 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5124 feat->Action = feat->Installed;
5125 return ERROR_SUCCESS;
5128 component = MSI_RecordGetString(rec, 3);
5129 comp = get_loaded_component(package, component);
5131 return ERROR_SUCCESS;
5133 compgroupid = MSI_RecordGetString(rec,1);
5134 qualifier = MSI_RecordGetString(rec,2);
5136 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5137 if (rc != ERROR_SUCCESS)
5140 text = MSI_RecordGetString(rec,4);
5141 advertise = create_component_advertise_string(package, comp, feature);
5143 sz = strlenW(advertise);
5146 sz += lstrlenW(text);
5149 sz *= sizeof(WCHAR);
5151 output = msi_alloc_zero(sz);
5152 strcpyW(output,advertise);
5153 msi_free(advertise);
5156 strcatW(output,text);
5158 msi_reg_set_val_multi_str( hkey, qualifier, output );
5165 uirow = MSI_CreateRecord( 2 );
5166 MSI_RecordSetStringW( uirow, 1, compgroupid );
5167 MSI_RecordSetStringW( uirow, 2, qualifier);
5168 ui_actiondata( package, szPublishComponents, uirow);
5169 msiobj_release( &uirow->hdr );
5170 /* FIXME: call ui_progress? */
5176 * At present I am ignorning the advertised components part of this and only
5177 * focusing on the qualified component sets
5179 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5183 static const WCHAR ExecSeqQuery[] =
5184 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5185 '`','P','u','b','l','i','s','h',
5186 'C','o','m','p','o','n','e','n','t','`',0};
5188 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5189 if (rc != ERROR_SUCCESS)
5190 return ERROR_SUCCESS;
5192 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5193 msiobj_release(&view->hdr);
5198 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5200 static const WCHAR szInstallerComponents[] = {
5201 'S','o','f','t','w','a','r','e','\\',
5202 'M','i','c','r','o','s','o','f','t','\\',
5203 'I','n','s','t','a','l','l','e','r','\\',
5204 'C','o','m','p','o','n','e','n','t','s','\\',0};
5206 MSIPACKAGE *package = param;
5207 LPCWSTR compgroupid, component, feature, qualifier;
5211 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5214 feature = MSI_RecordGetString( rec, 5 );
5215 feat = get_loaded_feature( package, feature );
5217 return ERROR_SUCCESS;
5219 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5221 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5222 feat->Action = feat->Installed;
5223 return ERROR_SUCCESS;
5226 component = MSI_RecordGetString( rec, 3 );
5227 comp = get_loaded_component( package, component );
5229 return ERROR_SUCCESS;
5231 compgroupid = MSI_RecordGetString( rec, 1 );
5232 qualifier = MSI_RecordGetString( rec, 2 );
5234 squash_guid( compgroupid, squashed );
5235 strcpyW( keypath, szInstallerComponents );
5236 strcatW( keypath, squashed );
5238 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5239 if (res != ERROR_SUCCESS)
5241 WARN("Unable to delete component key %d\n", res);
5244 uirow = MSI_CreateRecord( 2 );
5245 MSI_RecordSetStringW( uirow, 1, compgroupid );
5246 MSI_RecordSetStringW( uirow, 2, qualifier );
5247 ui_actiondata( package, szUnpublishComponents, uirow );
5248 msiobj_release( &uirow->hdr );
5250 return ERROR_SUCCESS;
5253 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5257 static const WCHAR query[] =
5258 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5259 '`','P','u','b','l','i','s','h',
5260 'C','o','m','p','o','n','e','n','t','`',0};
5262 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5263 if (rc != ERROR_SUCCESS)
5264 return ERROR_SUCCESS;
5266 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5267 msiobj_release( &view->hdr );
5272 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5274 MSIPACKAGE *package = param;
5277 SC_HANDLE hscm, service = NULL;
5278 LPCWSTR comp, depends, pass;
5279 LPWSTR name = NULL, disp = NULL;
5280 LPCWSTR load_order, serv_name, key;
5281 DWORD serv_type, start_type;
5284 static const WCHAR query[] =
5285 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5286 '`','C','o','m','p','o','n','e','n','t','`',' ',
5287 'W','H','E','R','E',' ',
5288 '`','C','o','m','p','o','n','e','n','t','`',' ',
5289 '=','\'','%','s','\'',0};
5291 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5294 ERR("Failed to open the SC Manager!\n");
5298 start_type = MSI_RecordGetInteger(rec, 5);
5299 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5302 depends = MSI_RecordGetString(rec, 8);
5303 if (depends && *depends)
5304 FIXME("Dependency list unhandled!\n");
5306 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5307 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5308 serv_type = MSI_RecordGetInteger(rec, 4);
5309 err_control = MSI_RecordGetInteger(rec, 6);
5310 load_order = MSI_RecordGetString(rec, 7);
5311 serv_name = MSI_RecordGetString(rec, 9);
5312 pass = MSI_RecordGetString(rec, 10);
5313 comp = MSI_RecordGetString(rec, 12);
5315 /* fetch the service path */
5316 row = MSI_QueryGetRecord(package->db, query, comp);
5319 ERR("Control query failed!\n");
5323 key = MSI_RecordGetString(row, 6);
5325 file = get_loaded_file(package, key);
5326 msiobj_release(&row->hdr);
5329 ERR("Failed to load the service file\n");
5333 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5334 start_type, err_control, file->TargetPath,
5335 load_order, NULL, NULL, serv_name, pass);
5338 if (GetLastError() != ERROR_SERVICE_EXISTS)
5339 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5343 CloseServiceHandle(service);
5344 CloseServiceHandle(hscm);
5348 return ERROR_SUCCESS;
5351 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5355 static const WCHAR ExecSeqQuery[] =
5356 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5357 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5359 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5360 if (rc != ERROR_SUCCESS)
5361 return ERROR_SUCCESS;
5363 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5364 msiobj_release(&view->hdr);
5369 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5370 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5372 LPCWSTR *vector, *temp_vector;
5376 static const WCHAR separator[] = {'[','~',']',0};
5379 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5384 vector = msi_alloc(sizeof(LPWSTR));
5392 vector[*numargs - 1] = p;
5394 if ((q = strstrW(p, separator)))
5398 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5404 vector = temp_vector;
5413 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5415 MSIPACKAGE *package = param;
5418 SC_HANDLE scm = NULL, service = NULL;
5419 LPCWSTR component, *vector = NULL;
5420 LPWSTR name, args, display_name = NULL;
5421 DWORD event, numargs, len;
5422 UINT r = ERROR_FUNCTION_FAILED;
5424 component = MSI_RecordGetString(rec, 6);
5425 comp = get_loaded_component(package, component);
5427 return ERROR_SUCCESS;
5431 TRACE("component is disabled\n");
5432 return ERROR_SUCCESS;
5435 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5437 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5438 comp->Action = comp->Installed;
5439 return ERROR_SUCCESS;
5441 comp->Action = INSTALLSTATE_LOCAL;
5443 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5444 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5445 event = MSI_RecordGetInteger(rec, 3);
5447 if (!(event & msidbServiceControlEventStart))
5453 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5456 ERR("Failed to open the service control manager\n");
5461 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5462 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5464 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5465 GetServiceDisplayNameW( scm, name, display_name, &len );
5468 service = OpenServiceW(scm, name, SERVICE_START);
5471 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5475 vector = msi_service_args_to_vector(args, &numargs);
5477 if (!StartServiceW(service, numargs, vector) &&
5478 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5480 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5487 uirow = MSI_CreateRecord( 2 );
5488 MSI_RecordSetStringW( uirow, 1, display_name );
5489 MSI_RecordSetStringW( uirow, 2, name );
5490 ui_actiondata( package, szStartServices, uirow );
5491 msiobj_release( &uirow->hdr );
5493 CloseServiceHandle(service);
5494 CloseServiceHandle(scm);
5499 msi_free(display_name);
5503 static UINT ACTION_StartServices( MSIPACKAGE *package )
5508 static const WCHAR query[] = {
5509 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5510 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5512 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5513 if (rc != ERROR_SUCCESS)
5514 return ERROR_SUCCESS;
5516 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5517 msiobj_release(&view->hdr);
5522 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5524 DWORD i, needed, count;
5525 ENUM_SERVICE_STATUSW *dependencies;
5529 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5530 0, &needed, &count))
5533 if (GetLastError() != ERROR_MORE_DATA)
5536 dependencies = msi_alloc(needed);
5540 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5541 needed, &needed, &count))
5544 for (i = 0; i < count; i++)
5546 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5547 SERVICE_STOP | SERVICE_QUERY_STATUS);
5551 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5558 msi_free(dependencies);
5562 static UINT stop_service( LPCWSTR name )
5564 SC_HANDLE scm = NULL, service = NULL;
5565 SERVICE_STATUS status;
5566 SERVICE_STATUS_PROCESS ssp;
5569 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5572 WARN("Failed to open the SCM: %d\n", GetLastError());
5576 service = OpenServiceW(scm, name,
5578 SERVICE_QUERY_STATUS |
5579 SERVICE_ENUMERATE_DEPENDENTS);
5582 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5586 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5587 sizeof(SERVICE_STATUS_PROCESS), &needed))
5589 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5593 if (ssp.dwCurrentState == SERVICE_STOPPED)
5596 stop_service_dependents(scm, service);
5598 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5599 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5602 CloseServiceHandle(service);
5603 CloseServiceHandle(scm);
5605 return ERROR_SUCCESS;
5608 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5610 MSIPACKAGE *package = param;
5614 LPWSTR name = NULL, display_name = NULL;
5618 event = MSI_RecordGetInteger( rec, 3 );
5619 if (!(event & msidbServiceControlEventStop))
5620 return ERROR_SUCCESS;
5622 component = MSI_RecordGetString( rec, 6 );
5623 comp = get_loaded_component( package, component );
5625 return ERROR_SUCCESS;
5629 TRACE("component is disabled\n");
5630 return ERROR_SUCCESS;
5633 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5635 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5636 comp->Action = comp->Installed;
5637 return ERROR_SUCCESS;
5639 comp->Action = INSTALLSTATE_ABSENT;
5641 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5644 ERR("Failed to open the service control manager\n");
5649 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5650 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5652 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5653 GetServiceDisplayNameW( scm, name, display_name, &len );
5655 CloseServiceHandle( scm );
5657 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5658 stop_service( name );
5661 uirow = MSI_CreateRecord( 2 );
5662 MSI_RecordSetStringW( uirow, 1, display_name );
5663 MSI_RecordSetStringW( uirow, 2, name );
5664 ui_actiondata( package, szStopServices, uirow );
5665 msiobj_release( &uirow->hdr );
5668 msi_free( display_name );
5669 return ERROR_SUCCESS;
5672 static UINT ACTION_StopServices( MSIPACKAGE *package )
5677 static const WCHAR query[] = {
5678 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5679 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5681 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5682 if (rc != ERROR_SUCCESS)
5683 return ERROR_SUCCESS;
5685 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5686 msiobj_release(&view->hdr);
5691 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5693 MSIPACKAGE *package = param;
5697 LPWSTR name = NULL, display_name = NULL;
5699 SC_HANDLE scm = NULL, service = NULL;
5701 event = MSI_RecordGetInteger( rec, 3 );
5702 if (!(event & msidbServiceControlEventDelete))
5703 return ERROR_SUCCESS;
5705 component = MSI_RecordGetString(rec, 6);
5706 comp = get_loaded_component(package, component);
5708 return ERROR_SUCCESS;
5712 TRACE("component is disabled\n");
5713 return ERROR_SUCCESS;
5716 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5718 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5719 comp->Action = comp->Installed;
5720 return ERROR_SUCCESS;
5722 comp->Action = INSTALLSTATE_ABSENT;
5724 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5725 stop_service( name );
5727 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5730 WARN("Failed to open the SCM: %d\n", GetLastError());
5735 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5736 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5738 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5739 GetServiceDisplayNameW( scm, name, display_name, &len );
5742 service = OpenServiceW( scm, name, DELETE );
5745 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5749 if (!DeleteService( service ))
5750 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5753 uirow = MSI_CreateRecord( 2 );
5754 MSI_RecordSetStringW( uirow, 1, display_name );
5755 MSI_RecordSetStringW( uirow, 2, name );
5756 ui_actiondata( package, szDeleteServices, uirow );
5757 msiobj_release( &uirow->hdr );
5759 CloseServiceHandle( service );
5760 CloseServiceHandle( scm );
5762 msi_free( display_name );
5764 return ERROR_SUCCESS;
5767 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5772 static const WCHAR query[] = {
5773 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5774 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5776 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5777 if (rc != ERROR_SUCCESS)
5778 return ERROR_SUCCESS;
5780 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5781 msiobj_release( &view->hdr );
5786 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5790 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5792 if (!strcmpW( file->File, filename ))
5799 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5801 MSIPACKAGE *package = param;
5802 LPWSTR driver, driver_path, ptr;
5803 WCHAR outpath[MAX_PATH];
5804 MSIFILE *driver_file = NULL, *setup_file = NULL;
5806 LPCWSTR desc, file_key;
5808 UINT r = ERROR_SUCCESS;
5810 static const WCHAR driver_fmt[] = {
5811 'D','r','i','v','e','r','=','%','s',0};
5812 static const WCHAR setup_fmt[] = {
5813 'S','e','t','u','p','=','%','s',0};
5814 static const WCHAR usage_fmt[] = {
5815 'F','i','l','e','U','s','a','g','e','=','1',0};
5817 desc = MSI_RecordGetString(rec, 3);
5819 file_key = MSI_RecordGetString( rec, 4 );
5820 if (file_key) driver_file = msi_find_file( package, file_key );
5822 file_key = MSI_RecordGetString( rec, 5 );
5823 if (file_key) setup_file = msi_find_file( package, file_key );
5827 ERR("ODBC Driver entry not found!\n");
5828 return ERROR_FUNCTION_FAILED;
5831 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5833 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5834 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5836 driver = msi_alloc(len * sizeof(WCHAR));
5838 return ERROR_OUTOFMEMORY;
5841 lstrcpyW(ptr, desc);
5842 ptr += lstrlenW(ptr) + 1;
5844 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5849 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5853 lstrcpyW(ptr, usage_fmt);
5854 ptr += lstrlenW(ptr) + 1;
5857 driver_path = strdupW(driver_file->TargetPath);
5858 ptr = strrchrW(driver_path, '\\');
5859 if (ptr) *ptr = '\0';
5861 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5862 NULL, ODBC_INSTALL_COMPLETE, &usage))
5864 ERR("Failed to install SQL driver!\n");
5865 r = ERROR_FUNCTION_FAILED;
5868 uirow = MSI_CreateRecord( 5 );
5869 MSI_RecordSetStringW( uirow, 1, desc );
5870 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5871 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5872 ui_actiondata( package, szInstallODBC, uirow );
5873 msiobj_release( &uirow->hdr );
5876 msi_free(driver_path);
5881 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5883 MSIPACKAGE *package = param;
5884 LPWSTR translator, translator_path, ptr;
5885 WCHAR outpath[MAX_PATH];
5886 MSIFILE *translator_file = NULL, *setup_file = NULL;
5888 LPCWSTR desc, file_key;
5890 UINT r = ERROR_SUCCESS;
5892 static const WCHAR translator_fmt[] = {
5893 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5894 static const WCHAR setup_fmt[] = {
5895 'S','e','t','u','p','=','%','s',0};
5897 desc = MSI_RecordGetString(rec, 3);
5899 file_key = MSI_RecordGetString( rec, 4 );
5900 if (file_key) translator_file = msi_find_file( package, file_key );
5902 file_key = MSI_RecordGetString( rec, 5 );
5903 if (file_key) setup_file = msi_find_file( package, file_key );
5905 if (!translator_file)
5907 ERR("ODBC Translator entry not found!\n");
5908 return ERROR_FUNCTION_FAILED;
5911 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5913 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5915 translator = msi_alloc(len * sizeof(WCHAR));
5917 return ERROR_OUTOFMEMORY;
5920 lstrcpyW(ptr, desc);
5921 ptr += lstrlenW(ptr) + 1;
5923 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5928 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5933 translator_path = strdupW(translator_file->TargetPath);
5934 ptr = strrchrW(translator_path, '\\');
5935 if (ptr) *ptr = '\0';
5937 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5938 NULL, ODBC_INSTALL_COMPLETE, &usage))
5940 ERR("Failed to install SQL translator!\n");
5941 r = ERROR_FUNCTION_FAILED;
5944 uirow = MSI_CreateRecord( 5 );
5945 MSI_RecordSetStringW( uirow, 1, desc );
5946 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5947 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5948 ui_actiondata( package, szInstallODBC, uirow );
5949 msiobj_release( &uirow->hdr );
5951 msi_free(translator);
5952 msi_free(translator_path);
5957 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5959 MSIPACKAGE *package = param;
5961 LPCWSTR desc, driver;
5962 WORD request = ODBC_ADD_SYS_DSN;
5965 UINT r = ERROR_SUCCESS;
5968 static const WCHAR attrs_fmt[] = {
5969 'D','S','N','=','%','s',0 };
5971 desc = MSI_RecordGetString(rec, 3);
5972 driver = MSI_RecordGetString(rec, 4);
5973 registration = MSI_RecordGetInteger(rec, 5);
5975 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5976 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5978 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5979 attrs = msi_alloc(len * sizeof(WCHAR));
5981 return ERROR_OUTOFMEMORY;
5983 len = sprintfW(attrs, attrs_fmt, desc);
5986 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5988 ERR("Failed to install SQL data source!\n");
5989 r = ERROR_FUNCTION_FAILED;
5992 uirow = MSI_CreateRecord( 5 );
5993 MSI_RecordSetStringW( uirow, 1, desc );
5994 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5995 MSI_RecordSetInteger( uirow, 3, request );
5996 ui_actiondata( package, szInstallODBC, uirow );
5997 msiobj_release( &uirow->hdr );
6004 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6009 static const WCHAR driver_query[] = {
6010 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6011 'O','D','B','C','D','r','i','v','e','r',0 };
6013 static const WCHAR translator_query[] = {
6014 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6015 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6017 static const WCHAR source_query[] = {
6018 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6019 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6021 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6022 if (rc != ERROR_SUCCESS)
6023 return ERROR_SUCCESS;
6025 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6026 msiobj_release(&view->hdr);
6028 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6029 if (rc != ERROR_SUCCESS)
6030 return ERROR_SUCCESS;
6032 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6033 msiobj_release(&view->hdr);
6035 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6036 if (rc != ERROR_SUCCESS)
6037 return ERROR_SUCCESS;
6039 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6040 msiobj_release(&view->hdr);
6045 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6047 MSIPACKAGE *package = param;
6052 desc = MSI_RecordGetString( rec, 3 );
6053 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6055 WARN("Failed to remove ODBC driver\n");
6059 FIXME("Usage count reached 0\n");
6062 uirow = MSI_CreateRecord( 2 );
6063 MSI_RecordSetStringW( uirow, 1, desc );
6064 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6065 ui_actiondata( package, szRemoveODBC, uirow );
6066 msiobj_release( &uirow->hdr );
6068 return ERROR_SUCCESS;
6071 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6073 MSIPACKAGE *package = param;
6078 desc = MSI_RecordGetString( rec, 3 );
6079 if (!SQLRemoveTranslatorW( desc, &usage ))
6081 WARN("Failed to remove ODBC translator\n");
6085 FIXME("Usage count reached 0\n");
6088 uirow = MSI_CreateRecord( 2 );
6089 MSI_RecordSetStringW( uirow, 1, desc );
6090 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6091 ui_actiondata( package, szRemoveODBC, uirow );
6092 msiobj_release( &uirow->hdr );
6094 return ERROR_SUCCESS;
6097 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6099 MSIPACKAGE *package = param;
6102 LPCWSTR desc, driver;
6103 WORD request = ODBC_REMOVE_SYS_DSN;
6107 static const WCHAR attrs_fmt[] = {
6108 'D','S','N','=','%','s',0 };
6110 desc = MSI_RecordGetString( rec, 3 );
6111 driver = MSI_RecordGetString( rec, 4 );
6112 registration = MSI_RecordGetInteger( rec, 5 );
6114 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6115 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6117 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6118 attrs = msi_alloc( len * sizeof(WCHAR) );
6120 return ERROR_OUTOFMEMORY;
6122 FIXME("Use ODBCSourceAttribute table\n");
6124 len = sprintfW( attrs, attrs_fmt, desc );
6127 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6129 WARN("Failed to remove ODBC data source\n");
6133 uirow = MSI_CreateRecord( 3 );
6134 MSI_RecordSetStringW( uirow, 1, desc );
6135 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6136 MSI_RecordSetInteger( uirow, 3, request );
6137 ui_actiondata( package, szRemoveODBC, uirow );
6138 msiobj_release( &uirow->hdr );
6140 return ERROR_SUCCESS;
6143 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6148 static const WCHAR driver_query[] = {
6149 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6150 'O','D','B','C','D','r','i','v','e','r',0 };
6152 static const WCHAR translator_query[] = {
6153 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6154 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6156 static const WCHAR source_query[] = {
6157 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6158 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6160 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6161 if (rc != ERROR_SUCCESS)
6162 return ERROR_SUCCESS;
6164 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6165 msiobj_release( &view->hdr );
6167 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6168 if (rc != ERROR_SUCCESS)
6169 return ERROR_SUCCESS;
6171 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6172 msiobj_release( &view->hdr );
6174 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6175 if (rc != ERROR_SUCCESS)
6176 return ERROR_SUCCESS;
6178 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6179 msiobj_release( &view->hdr );
6184 #define ENV_ACT_SETALWAYS 0x1
6185 #define ENV_ACT_SETABSENT 0x2
6186 #define ENV_ACT_REMOVE 0x4
6187 #define ENV_ACT_REMOVEMATCH 0x8
6189 #define ENV_MOD_MACHINE 0x20000000
6190 #define ENV_MOD_APPEND 0x40000000
6191 #define ENV_MOD_PREFIX 0x80000000
6192 #define ENV_MOD_MASK 0xC0000000
6194 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6196 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6198 LPCWSTR cptr = *name;
6200 static const WCHAR prefix[] = {'[','~',']',0};
6201 static const int prefix_len = 3;
6207 *flags |= ENV_ACT_SETALWAYS;
6208 else if (*cptr == '+')
6209 *flags |= ENV_ACT_SETABSENT;
6210 else if (*cptr == '-')
6211 *flags |= ENV_ACT_REMOVE;
6212 else if (*cptr == '!')
6213 *flags |= ENV_ACT_REMOVEMATCH;
6214 else if (*cptr == '*')
6215 *flags |= ENV_MOD_MACHINE;
6225 ERR("Missing environment variable\n");
6226 return ERROR_FUNCTION_FAILED;
6231 LPCWSTR ptr = *value;
6232 if (!strncmpW(ptr, prefix, prefix_len))
6234 if (ptr[prefix_len] == szSemiColon[0])
6236 *flags |= ENV_MOD_APPEND;
6237 *value += lstrlenW(prefix);
6244 else if (lstrlenW(*value) >= prefix_len)
6246 ptr += lstrlenW(ptr) - prefix_len;
6247 if (!strcmpW( ptr, prefix ))
6249 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6251 *flags |= ENV_MOD_PREFIX;
6252 /* the "[~]" will be removed by deformat_string */;
6262 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6263 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6264 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6265 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6267 ERR("Invalid flags: %08x\n", *flags);
6268 return ERROR_FUNCTION_FAILED;
6272 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6274 return ERROR_SUCCESS;
6277 static UINT open_env_key( DWORD flags, HKEY *key )
6279 static const WCHAR user_env[] =
6280 {'E','n','v','i','r','o','n','m','e','n','t',0};
6281 static const WCHAR machine_env[] =
6282 {'S','y','s','t','e','m','\\',
6283 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6284 'C','o','n','t','r','o','l','\\',
6285 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6286 'E','n','v','i','r','o','n','m','e','n','t',0};
6291 if (flags & ENV_MOD_MACHINE)
6294 root = HKEY_LOCAL_MACHINE;
6299 root = HKEY_CURRENT_USER;
6302 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6303 if (res != ERROR_SUCCESS)
6305 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6306 return ERROR_FUNCTION_FAILED;
6309 return ERROR_SUCCESS;
6312 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6314 MSIPACKAGE *package = param;
6315 LPCWSTR name, value, component;
6316 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6317 DWORD flags, type, size;
6324 component = MSI_RecordGetString(rec, 4);
6325 comp = get_loaded_component(package, component);
6327 return ERROR_SUCCESS;
6331 TRACE("component is disabled\n");
6332 return ERROR_SUCCESS;
6335 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6337 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6338 comp->Action = comp->Installed;
6339 return ERROR_SUCCESS;
6341 comp->Action = INSTALLSTATE_LOCAL;
6343 name = MSI_RecordGetString(rec, 2);
6344 value = MSI_RecordGetString(rec, 3);
6346 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6348 res = env_parse_flags(&name, &value, &flags);
6349 if (res != ERROR_SUCCESS || !value)
6352 if (value && !deformat_string(package, value, &deformatted))
6354 res = ERROR_OUTOFMEMORY;
6358 value = deformatted;
6360 res = open_env_key( flags, &env );
6361 if (res != ERROR_SUCCESS)
6364 if (flags & ENV_MOD_MACHINE)
6365 action |= 0x20000000;
6369 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6370 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6371 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6374 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6378 /* Nothing to do. */
6381 res = ERROR_SUCCESS;
6385 /* If we are appending but the string was empty, strip ; */
6386 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6388 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6389 newval = strdupW(value);
6392 res = ERROR_OUTOFMEMORY;
6400 /* Contrary to MSDN, +-variable to [~];path works */
6401 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6403 res = ERROR_SUCCESS;
6407 data = msi_alloc(size);
6411 return ERROR_OUTOFMEMORY;
6414 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6415 if (res != ERROR_SUCCESS)
6418 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6421 res = RegDeleteValueW(env, name);
6422 if (res != ERROR_SUCCESS)
6423 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6427 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6428 if (flags & ENV_MOD_MASK)
6432 if (flags & ENV_MOD_APPEND) multiplier++;
6433 if (flags & ENV_MOD_PREFIX) multiplier++;
6434 mod_size = lstrlenW(value) * multiplier;
6435 size += mod_size * sizeof(WCHAR);
6438 newval = msi_alloc(size);
6442 res = ERROR_OUTOFMEMORY;
6446 if (flags & ENV_MOD_PREFIX)
6448 lstrcpyW(newval, value);
6449 ptr = newval + lstrlenW(value);
6450 action |= 0x80000000;
6453 lstrcpyW(ptr, data);
6455 if (flags & ENV_MOD_APPEND)
6457 lstrcatW(newval, value);
6458 action |= 0x40000000;
6461 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6462 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6465 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6469 uirow = MSI_CreateRecord( 3 );
6470 MSI_RecordSetStringW( uirow, 1, name );
6471 MSI_RecordSetStringW( uirow, 2, newval );
6472 MSI_RecordSetInteger( uirow, 3, action );
6473 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6474 msiobj_release( &uirow->hdr );
6476 if (env) RegCloseKey(env);
6477 msi_free(deformatted);
6483 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6487 static const WCHAR ExecSeqQuery[] =
6488 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6489 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6490 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6491 if (rc != ERROR_SUCCESS)
6492 return ERROR_SUCCESS;
6494 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6495 msiobj_release(&view->hdr);
6500 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6502 MSIPACKAGE *package = param;
6503 LPCWSTR name, value, component;
6504 LPWSTR deformatted = NULL;
6513 component = MSI_RecordGetString( rec, 4 );
6514 comp = get_loaded_component( package, component );
6516 return ERROR_SUCCESS;
6520 TRACE("component is disabled\n");
6521 return ERROR_SUCCESS;
6524 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6526 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6527 comp->Action = comp->Installed;
6528 return ERROR_SUCCESS;
6530 comp->Action = INSTALLSTATE_ABSENT;
6532 name = MSI_RecordGetString( rec, 2 );
6533 value = MSI_RecordGetString( rec, 3 );
6535 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6537 r = env_parse_flags( &name, &value, &flags );
6538 if (r != ERROR_SUCCESS)
6541 if (!(flags & ENV_ACT_REMOVE))
6543 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6544 return ERROR_SUCCESS;
6547 if (value && !deformat_string( package, value, &deformatted ))
6548 return ERROR_OUTOFMEMORY;
6550 value = deformatted;
6552 r = open_env_key( flags, &env );
6553 if (r != ERROR_SUCCESS)
6559 if (flags & ENV_MOD_MACHINE)
6560 action |= 0x20000000;
6562 TRACE("Removing %s\n", debugstr_w(name));
6564 res = RegDeleteValueW( env, name );
6565 if (res != ERROR_SUCCESS)
6567 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6572 uirow = MSI_CreateRecord( 3 );
6573 MSI_RecordSetStringW( uirow, 1, name );
6574 MSI_RecordSetStringW( uirow, 2, value );
6575 MSI_RecordSetInteger( uirow, 3, action );
6576 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6577 msiobj_release( &uirow->hdr );
6579 if (env) RegCloseKey( env );
6580 msi_free( deformatted );
6584 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6588 static const WCHAR query[] =
6589 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6590 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6592 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6593 if (rc != ERROR_SUCCESS)
6594 return ERROR_SUCCESS;
6596 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6597 msiobj_release( &view->hdr );
6602 typedef struct tagMSIASSEMBLY
6605 MSICOMPONENT *component;
6606 MSIFEATURE *feature;
6610 LPWSTR display_name;
6615 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6617 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6618 LPVOID pvReserved, HMODULE *phModDll);
6620 static BOOL init_functionpointers(void)
6626 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6628 hmscoree = LoadLibraryA("mscoree.dll");
6631 WARN("mscoree.dll not available\n");
6635 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6636 if (!pLoadLibraryShim)
6638 WARN("LoadLibraryShim not available\n");
6639 FreeLibrary(hmscoree);
6643 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6646 WARN("fusion.dll not available\n");
6647 FreeLibrary(hmscoree);
6651 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6653 FreeLibrary(hmscoree);
6657 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6660 IAssemblyCache *cache;
6663 UINT r = ERROR_FUNCTION_FAILED;
6665 TRACE("installing assembly: %s\n", debugstr_w(path));
6667 uirow = MSI_CreateRecord( 2 );
6668 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6669 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6670 msiobj_release( &uirow->hdr );
6672 if (assembly->feature)
6673 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6675 if (assembly->manifest)
6676 FIXME("Manifest unhandled\n");
6678 if (assembly->application)
6680 FIXME("Assembly should be privately installed\n");
6681 return ERROR_SUCCESS;
6684 if (assembly->attributes == msidbAssemblyAttributesWin32)
6686 FIXME("Win32 assemblies not handled\n");
6687 return ERROR_SUCCESS;
6690 hr = pCreateAssemblyCache(&cache, 0);
6694 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6696 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6701 IAssemblyCache_Release(cache);
6705 typedef struct tagASSEMBLY_LIST
6707 MSIPACKAGE *package;
6708 IAssemblyCache *cache;
6709 struct list *assemblies;
6712 typedef struct tagASSEMBLY_NAME
6720 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6722 ASSEMBLY_NAME *asmname = param;
6723 LPCWSTR name = MSI_RecordGetString(rec, 2);
6724 LPWSTR val = msi_dup_record_field(rec, 3);
6726 static const WCHAR Name[] = {'N','a','m','e',0};
6727 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6728 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6729 static const WCHAR PublicKeyToken[] = {
6730 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6732 if (!strcmpiW(name, Name))
6733 asmname->name = val;
6734 else if (!strcmpiW(name, Version))
6735 asmname->version = val;
6736 else if (!strcmpiW(name, Culture))
6737 asmname->culture = val;
6738 else if (!strcmpiW(name, PublicKeyToken))
6739 asmname->pubkeytoken = val;
6743 return ERROR_SUCCESS;
6746 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6750 *size = lstrlenW(append) + 1;
6751 *str = msi_alloc((*size) * sizeof(WCHAR));
6752 lstrcpyW(*str, append);
6756 (*size) += lstrlenW(append);
6757 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6758 lstrcatW(*str, append);
6761 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6763 static const WCHAR separator[] = {',',' ',0};
6764 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6765 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6766 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6767 static const WCHAR query[] = {
6768 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6769 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6770 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6771 '=','\'','%','s','\'',0};
6774 LPWSTR display_name;
6778 display_name = NULL;
6779 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6781 r = MSI_OpenQuery( db, &view, query, comp->Component );
6782 if (r != ERROR_SUCCESS)
6785 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6786 msiobj_release( &view->hdr );
6790 ERR("No assembly name specified!\n");
6794 append_str( &display_name, &size, name.name );
6798 append_str( &display_name, &size, separator );
6799 append_str( &display_name, &size, Version );
6800 append_str( &display_name, &size, name.version );
6804 append_str( &display_name, &size, separator );
6805 append_str( &display_name, &size, Culture );
6806 append_str( &display_name, &size, name.culture );
6808 if (name.pubkeytoken)
6810 append_str( &display_name, &size, separator );
6811 append_str( &display_name, &size, PublicKeyToken );
6812 append_str( &display_name, &size, name.pubkeytoken );
6815 msi_free( name.name );
6816 msi_free( name.version );
6817 msi_free( name.culture );
6818 msi_free( name.pubkeytoken );
6820 return display_name;
6823 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6825 ASSEMBLY_INFO asminfo;
6830 disp = get_assembly_display_name( db, comp );
6834 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6835 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6837 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6839 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6845 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6847 ASSEMBLY_LIST *list = param;
6848 MSIASSEMBLY *assembly;
6851 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6853 return ERROR_OUTOFMEMORY;
6855 component = MSI_RecordGetString(rec, 1);
6856 assembly->component = get_loaded_component(list->package, component);
6857 if (!assembly->component)
6858 return ERROR_SUCCESS;
6860 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6861 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6863 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6864 assembly->component->Action = assembly->component->Installed;
6865 return ERROR_SUCCESS;
6867 assembly->component->Action = assembly->component->ActionRequest;
6869 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6870 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6872 if (!assembly->file)
6874 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6875 return ERROR_FUNCTION_FAILED;
6878 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6879 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6880 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6882 if (assembly->application)
6885 DWORD size = sizeof(version)/sizeof(WCHAR);
6887 /* FIXME: we should probably check the manifest file here */
6889 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6890 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6892 assembly->installed = TRUE;
6896 assembly->installed = check_assembly_installed(list->package->db,
6898 assembly->component);
6900 list_add_head(list->assemblies, &assembly->entry);
6901 return ERROR_SUCCESS;
6904 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6906 IAssemblyCache *cache = NULL;
6912 static const WCHAR query[] =
6913 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6914 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6916 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6917 if (r != ERROR_SUCCESS)
6918 return ERROR_SUCCESS;
6920 hr = pCreateAssemblyCache(&cache, 0);
6922 return ERROR_FUNCTION_FAILED;
6924 list.package = package;
6926 list.assemblies = assemblies;
6928 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6929 msiobj_release(&view->hdr);
6931 IAssemblyCache_Release(cache);
6936 static void free_assemblies(struct list *assemblies)
6938 struct list *item, *cursor;
6940 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6942 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6944 list_remove(&assembly->entry);
6945 msi_free(assembly->application);
6946 msi_free(assembly->manifest);
6947 msi_free(assembly->display_name);
6952 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6954 MSIASSEMBLY *assembly;
6956 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6958 if (!strcmpW( assembly->file->File, file ))
6968 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6969 LPWSTR *path, DWORD *attrs, PVOID user)
6971 MSIASSEMBLY *assembly;
6972 WCHAR temppath[MAX_PATH];
6973 struct list *assemblies = user;
6976 if (!find_assembly(assemblies, file, &assembly))
6979 GetTempPathW(MAX_PATH, temppath);
6980 PathAddBackslashW(temppath);
6981 lstrcatW(temppath, assembly->file->FileName);
6983 if (action == MSICABEXTRACT_BEGINEXTRACT)
6985 if (assembly->installed)
6988 *path = strdupW(temppath);
6989 *attrs = assembly->file->Attributes;
6991 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6993 assembly->installed = TRUE;
6995 r = install_assembly(package, assembly, temppath);
6996 if (r != ERROR_SUCCESS)
6997 ERR("Failed to install assembly\n");
7003 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
7006 struct list assemblies = LIST_INIT(assemblies);
7007 MSIASSEMBLY *assembly;
7010 if (!init_functionpointers() || !pCreateAssemblyCache)
7011 return ERROR_FUNCTION_FAILED;
7013 r = load_assemblies(package, &assemblies);
7014 if (r != ERROR_SUCCESS)
7017 if (list_empty(&assemblies))
7020 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
7023 r = ERROR_OUTOFMEMORY;
7027 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
7029 if (assembly->installed && !mi->is_continuous)
7032 if (assembly->file->IsCompressed)
7034 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
7038 r = ready_media(package, assembly->file, mi);
7039 if (r != ERROR_SUCCESS)
7041 ERR("Failed to ready media\n");
7046 data.package = package;
7047 data.cb = installassembly_cb;
7048 data.user = &assemblies;
7050 if (!msi_cabextract(package, mi, &data))
7052 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7053 r = ERROR_FUNCTION_FAILED;
7060 LPWSTR source = resolve_file_source(package, assembly->file);
7062 r = install_assembly(package, assembly, source);
7063 if (r != ERROR_SUCCESS)
7064 ERR("Failed to install assembly\n");
7069 /* FIXME: write Installer assembly reg values */
7073 free_assemblies(&assemblies);
7077 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7079 LPWSTR key, template, id;
7080 UINT r = ERROR_SUCCESS;
7082 id = msi_dup_property( package->db, szProductID );
7086 return ERROR_SUCCESS;
7088 template = msi_dup_property( package->db, szPIDTemplate );
7089 key = msi_dup_property( package->db, szPIDKEY );
7091 if (key && template)
7093 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7094 r = msi_set_property( package->db, szProductID, key );
7096 msi_free( template );
7101 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7104 package->need_reboot = 1;
7105 return ERROR_SUCCESS;
7108 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7110 static const WCHAR szAvailableFreeReg[] =
7111 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7113 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7115 TRACE("%p %d kilobytes\n", package, space);
7117 uirow = MSI_CreateRecord( 1 );
7118 MSI_RecordSetInteger( uirow, 1, space );
7119 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7120 msiobj_release( &uirow->hdr );
7122 return ERROR_SUCCESS;
7125 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7127 FIXME("%p\n", package);
7128 return ERROR_SUCCESS;
7131 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7133 FIXME("%p\n", package);
7134 return ERROR_SUCCESS;
7137 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7142 static const WCHAR driver_query[] = {
7143 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7144 'O','D','B','C','D','r','i','v','e','r',0 };
7146 static const WCHAR translator_query[] = {
7147 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7148 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7150 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7151 if (r == ERROR_SUCCESS)
7154 r = MSI_IterateRecords( view, &count, NULL, package );
7155 msiobj_release( &view->hdr );
7156 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7159 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7160 if (r == ERROR_SUCCESS)
7163 r = MSI_IterateRecords( view, &count, NULL, package );
7164 msiobj_release( &view->hdr );
7165 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7168 return ERROR_SUCCESS;
7171 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7172 LPCSTR action, LPCWSTR table )
7174 static const WCHAR query[] = {
7175 'S','E','L','E','C','T',' ','*',' ',
7176 'F','R','O','M',' ','`','%','s','`',0 };
7177 MSIQUERY *view = NULL;
7181 r = MSI_OpenQuery( package->db, &view, query, table );
7182 if (r == ERROR_SUCCESS)
7184 r = MSI_IterateRecords(view, &count, NULL, package);
7185 msiobj_release(&view->hdr);
7189 FIXME("%s -> %u ignored %s table values\n",
7190 action, count, debugstr_w(table));
7192 return ERROR_SUCCESS;
7195 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7197 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7198 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7201 static UINT ACTION_BindImage( MSIPACKAGE *package )
7203 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7204 return msi_unimplemented_action_stub( package, "BindImage", table );
7207 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7209 static const WCHAR table[] = {
7210 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7211 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7214 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7216 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7217 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7220 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7222 static const WCHAR table[] = {
7223 'M','s','i','A','s','s','e','m','b','l','y',0 };
7224 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7227 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7229 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7230 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7233 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7235 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7236 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7239 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7241 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7242 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7245 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7247 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7248 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7251 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7253 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7254 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7257 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7261 const WCHAR *action;
7262 UINT (*handler)(MSIPACKAGE *);
7266 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7267 { szAppSearch, ACTION_AppSearch },
7268 { szBindImage, ACTION_BindImage },
7269 { szCCPSearch, ACTION_CCPSearch },
7270 { szCostFinalize, ACTION_CostFinalize },
7271 { szCostInitialize, ACTION_CostInitialize },
7272 { szCreateFolders, ACTION_CreateFolders },
7273 { szCreateShortcuts, ACTION_CreateShortcuts },
7274 { szDeleteServices, ACTION_DeleteServices },
7275 { szDisableRollback, ACTION_DisableRollback },
7276 { szDuplicateFiles, ACTION_DuplicateFiles },
7277 { szExecuteAction, ACTION_ExecuteAction },
7278 { szFileCost, ACTION_FileCost },
7279 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7280 { szForceReboot, ACTION_ForceReboot },
7281 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7282 { szInstallExecute, ACTION_InstallExecute },
7283 { szInstallExecuteAgain, ACTION_InstallExecute },
7284 { szInstallFiles, ACTION_InstallFiles},
7285 { szInstallFinalize, ACTION_InstallFinalize },
7286 { szInstallInitialize, ACTION_InstallInitialize },
7287 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7288 { szInstallValidate, ACTION_InstallValidate },
7289 { szIsolateComponents, ACTION_IsolateComponents },
7290 { szLaunchConditions, ACTION_LaunchConditions },
7291 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7292 { szMoveFiles, ACTION_MoveFiles },
7293 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7294 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7295 { szInstallODBC, ACTION_InstallODBC },
7296 { szInstallServices, ACTION_InstallServices },
7297 { szPatchFiles, ACTION_PatchFiles },
7298 { szProcessComponents, ACTION_ProcessComponents },
7299 { szPublishComponents, ACTION_PublishComponents },
7300 { szPublishFeatures, ACTION_PublishFeatures },
7301 { szPublishProduct, ACTION_PublishProduct },
7302 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7303 { szRegisterComPlus, ACTION_RegisterComPlus},
7304 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7305 { szRegisterFonts, ACTION_RegisterFonts },
7306 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7307 { szRegisterProduct, ACTION_RegisterProduct },
7308 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7309 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7310 { szRegisterUser, ACTION_RegisterUser },
7311 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7312 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7313 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7314 { szRemoveFiles, ACTION_RemoveFiles },
7315 { szRemoveFolders, ACTION_RemoveFolders },
7316 { szRemoveIniValues, ACTION_RemoveIniValues },
7317 { szRemoveODBC, ACTION_RemoveODBC },
7318 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7319 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7320 { szResolveSource, ACTION_ResolveSource },
7321 { szRMCCPSearch, ACTION_RMCCPSearch },
7322 { szScheduleReboot, ACTION_ScheduleReboot },
7323 { szSelfRegModules, ACTION_SelfRegModules },
7324 { szSelfUnregModules, ACTION_SelfUnregModules },
7325 { szSetODBCFolders, ACTION_SetODBCFolders },
7326 { szStartServices, ACTION_StartServices },
7327 { szStopServices, ACTION_StopServices },
7328 { szUnpublishComponents, ACTION_UnpublishComponents },
7329 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7330 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7331 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7332 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7333 { szUnregisterFonts, ACTION_UnregisterFonts },
7334 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7335 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7336 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7337 { szValidateProductID, ACTION_ValidateProductID },
7338 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7339 { szWriteIniValues, ACTION_WriteIniValues },
7340 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7344 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7350 while (StandardActions[i].action != NULL)
7352 if (!strcmpW( StandardActions[i].action, action ))
7354 ui_actionstart( package, action );
7355 if (StandardActions[i].handler)
7357 ui_actioninfo( package, action, TRUE, 0 );
7358 *rc = StandardActions[i].handler( package );
7359 ui_actioninfo( package, action, FALSE, *rc );
7363 FIXME("unhandled standard action %s\n", debugstr_w(action));
7364 *rc = ERROR_SUCCESS;
7374 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7376 UINT rc = ERROR_SUCCESS;
7379 TRACE("Performing action (%s)\n", debugstr_w(action));
7381 handled = ACTION_HandleStandardAction(package, action, &rc);
7384 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7388 WARN("unhandled msi action %s\n", debugstr_w(action));
7389 rc = ERROR_FUNCTION_NOT_CALLED;
7395 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7397 UINT rc = ERROR_SUCCESS;
7398 BOOL handled = FALSE;
7400 TRACE("Performing action (%s)\n", debugstr_w(action));
7402 handled = ACTION_HandleStandardAction(package, action, &rc);
7405 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7407 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7412 WARN("unhandled msi action %s\n", debugstr_w(action));
7413 rc = ERROR_FUNCTION_NOT_CALLED;
7419 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7421 UINT rc = ERROR_SUCCESS;
7424 static const WCHAR ExecSeqQuery[] =
7425 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7426 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7427 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7428 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7429 static const WCHAR UISeqQuery[] =
7430 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7431 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7432 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7433 ' ', '=',' ','%','i',0};
7435 if (needs_ui_sequence(package))
7436 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7438 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7442 LPCWSTR action, cond;
7444 TRACE("Running the actions\n");
7446 /* check conditions */
7447 cond = MSI_RecordGetString(row, 2);
7449 /* this is a hack to skip errors in the condition code */
7450 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7452 msiobj_release(&row->hdr);
7453 return ERROR_SUCCESS;
7456 action = MSI_RecordGetString(row, 1);
7459 ERR("failed to fetch action\n");
7460 msiobj_release(&row->hdr);
7461 return ERROR_FUNCTION_FAILED;
7464 if (needs_ui_sequence(package))
7465 rc = ACTION_PerformUIAction(package, action, -1);
7467 rc = ACTION_PerformAction(package, action, -1);
7469 msiobj_release(&row->hdr);
7475 /****************************************************
7476 * TOP level entry points
7477 *****************************************************/
7479 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7480 LPCWSTR szCommandLine )
7485 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7486 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7488 msi_set_property( package->db, szAction, szInstall );
7490 package->script->InWhatSequence = SEQUENCE_INSTALL;
7497 dir = strdupW(szPackagePath);
7498 p = strrchrW(dir, '\\');
7502 file = szPackagePath + (p - dir);
7507 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7508 GetCurrentDirectoryW(MAX_PATH, dir);
7509 lstrcatW(dir, szBackSlash);
7510 file = szPackagePath;
7513 msi_free( package->PackagePath );
7514 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7515 if (!package->PackagePath)
7518 return ERROR_OUTOFMEMORY;
7521 lstrcpyW(package->PackagePath, dir);
7522 lstrcatW(package->PackagePath, file);
7525 msi_set_sourcedir_props(package, FALSE);
7528 msi_parse_command_line( package, szCommandLine, FALSE );
7530 msi_apply_transforms( package );
7531 msi_apply_patches( package );
7533 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7535 TRACE("setting reinstall property\n");
7536 msi_set_property( package->db, szReinstall, szAll );
7539 /* properties may have been added by a transform */
7540 msi_clone_properties( package );
7542 msi_parse_command_line( package, szCommandLine, FALSE );
7543 msi_adjust_privilege_properties( package );
7544 msi_set_context( package );
7546 if (needs_ui_sequence( package))
7548 package->script->InWhatSequence |= SEQUENCE_UI;
7549 rc = ACTION_ProcessUISequence(package);
7550 ui_exists = ui_sequence_exists(package);
7551 if (rc == ERROR_SUCCESS || !ui_exists)
7553 package->script->InWhatSequence |= SEQUENCE_EXEC;
7554 rc = ACTION_ProcessExecSequence(package, ui_exists);
7558 rc = ACTION_ProcessExecSequence(package, FALSE);
7560 package->script->CurrentlyScripting = FALSE;
7562 /* process the ending type action */
7563 if (rc == ERROR_SUCCESS)
7564 ACTION_PerformActionSequence(package, -1);
7565 else if (rc == ERROR_INSTALL_USEREXIT)
7566 ACTION_PerformActionSequence(package, -2);
7567 else if (rc == ERROR_INSTALL_SUSPEND)
7568 ACTION_PerformActionSequence(package, -4);
7570 ACTION_PerformActionSequence(package, -3);
7572 /* finish up running custom actions */
7573 ACTION_FinishCustomActions(package);
7575 if (rc == ERROR_SUCCESS && package->need_reboot)
7576 return ERROR_SUCCESS_REBOOT_REQUIRED;