2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings[] =
130 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
131 static const WCHAR szRemoveExistingProducts[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterTypeLibraries[] =
162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
163 static const WCHAR szValidateProductID[] =
164 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
165 static const WCHAR szWriteEnvironmentStrings[] =
166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
168 /********************************************************
170 ********************************************************/
172 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
174 static const WCHAR Query_t[] =
175 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
176 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
177 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
178 ' ','\'','%','s','\'',0};
181 row = MSI_QueryGetRecord( package->db, Query_t, action );
184 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
185 msiobj_release(&row->hdr);
188 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
192 static const WCHAR template_s[]=
193 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
195 static const WCHAR template_e[]=
196 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
197 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
199 static const WCHAR format[] =
200 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
204 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
206 sprintfW(message,template_s,timet,action);
208 sprintfW(message,template_e,timet,action,rc);
210 row = MSI_CreateRecord(1);
211 MSI_RecordSetStringW(row,1,message);
213 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
214 msiobj_release(&row->hdr);
217 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
223 LPWSTR prop = NULL, val = NULL;
226 return ERROR_SUCCESS;
238 TRACE("Looking at %s\n",debugstr_w(ptr));
240 ptr2 = strchrW(ptr,'=');
243 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
250 prop = msi_alloc((len+1)*sizeof(WCHAR));
251 memcpy(prop,ptr,len*sizeof(WCHAR));
261 while (*ptr && (quote || (!quote && *ptr!=' ')))
274 val = msi_alloc((len+1)*sizeof(WCHAR));
275 memcpy(val,ptr2,len*sizeof(WCHAR));
278 if (lstrlenW(prop) > 0)
280 UINT r = msi_set_property( package->db, prop, val );
282 TRACE("Found commandline property (%s) = (%s)\n",
283 debugstr_w(prop), debugstr_w(val));
285 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
286 msi_reset_folders( package, TRUE );
292 return ERROR_SUCCESS;
296 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
299 LPWSTR p, *ret = NULL;
305 /* count the number of substrings */
306 for ( pc = str, count = 0; pc; count++ )
308 pc = strchrW( pc, sep );
313 /* allocate space for an array of substring pointers and the substrings */
314 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
315 (lstrlenW(str)+1) * sizeof(WCHAR) );
319 /* copy the string and set the pointers */
320 p = (LPWSTR) &ret[count+1];
322 for( count = 0; (ret[count] = p); count++ )
324 p = strchrW( p, sep );
332 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
334 static const WCHAR szSystemLanguageID[] =
335 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
337 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
338 UINT ret = ERROR_FUNCTION_FAILED;
340 prod_code = msi_dup_property( package->db, szProductCode );
341 patch_product = msi_get_suminfo_product( patch );
343 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
345 if ( strstrW( patch_product, prod_code ) )
350 si = MSI_GetSummaryInformationW( patch, 0 );
353 ERR("no summary information!\n");
357 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
360 ERR("no template property!\n");
361 msiobj_release( &si->hdr );
368 msiobj_release( &si->hdr );
372 langid = msi_dup_property( package->db, szSystemLanguageID );
375 msiobj_release( &si->hdr );
379 p = strchrW( template, ';' );
380 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
382 TRACE("applicable transform\n");
386 /* FIXME: check platform */
388 msiobj_release( &si->hdr );
392 msi_free( patch_product );
393 msi_free( prod_code );
394 msi_free( template );
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
407 TRACE("%p %s\n", package, debugstr_w(name) );
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
418 ret = msi_check_transform_applicable( package, stg );
419 if (ret == ERROR_SUCCESS)
420 msi_table_apply_transform( package->db, stg );
422 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
423 IStorage_Release( stg );
426 ERR("failed to open substorage %s\n", debugstr_w(name));
428 return ERROR_SUCCESS;
431 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
433 LPWSTR guid_list, *guids, product_code;
434 UINT i, ret = ERROR_FUNCTION_FAILED;
436 product_code = msi_dup_property( package->db, szProductCode );
439 /* FIXME: the property ProductCode should be written into the DB somewhere */
440 ERR("no product code to check\n");
441 return ERROR_SUCCESS;
444 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
445 guids = msi_split_string( guid_list, ';' );
446 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
448 if (!lstrcmpW( guids[i], product_code ))
452 msi_free( guid_list );
453 msi_free( product_code );
458 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
461 MSIRECORD *rec = NULL;
466 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
467 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
468 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
469 '`','S','o','u','r','c','e','`',' ','I','S',' ',
470 'N','O','T',' ','N','U','L','L',0};
472 r = MSI_DatabaseOpenViewW(package->db, query, &view);
473 if (r != ERROR_SUCCESS)
476 r = MSI_ViewExecute(view, 0);
477 if (r != ERROR_SUCCESS)
480 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
482 prop = MSI_RecordGetString(rec, 1);
483 patch = msi_dup_property(package->db, szPatch);
484 msi_set_property(package->db, prop, patch);
489 if (rec) msiobj_release(&rec->hdr);
490 msiobj_release(&view->hdr);
495 UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
498 UINT r = ERROR_SUCCESS;
501 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
503 return ERROR_OUTOFMEMORY;
505 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
509 return ERROR_OUTOFMEMORY;
515 msi_free( pi->patchcode );
517 return ERROR_PATCH_PACKAGE_INVALID;
520 p = strchrW( p + 1, '}' );
523 msi_free( pi->patchcode );
525 return ERROR_PATCH_PACKAGE_INVALID;
530 FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
534 TRACE("patch code %s\n", debugstr_w(pi->patchcode));
536 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
539 msi_free( pi->patchcode );
541 return ERROR_OUTOFMEMORY;
548 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
550 UINT i, r = ERROR_SUCCESS;
553 /* apply substorage transforms */
554 substorage = msi_split_string( patch->transforms, ';' );
555 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
556 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
558 msi_free( substorage );
559 if (r != ERROR_SUCCESS)
562 msi_set_media_source_prop( package );
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storages to search for streams.
568 append_storage_to_db( package->db, patch_db->storage );
570 patch->state = MSIPATCHSTATE_APPLIED;
571 list_add_tail( &package->patches, &patch->entry );
572 return ERROR_SUCCESS;
575 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
577 static const WCHAR dotmsp[] = {'.','m','s','p',0};
578 MSIDATABASE *patch_db = NULL;
579 WCHAR localfile[MAX_PATH];
581 MSIPATCHINFO *patch = NULL;
582 UINT r = ERROR_SUCCESS;
584 TRACE("%p %s\n", package, debugstr_w( file ) );
586 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
587 if ( r != ERROR_SUCCESS )
589 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
593 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
596 msiobj_release( &patch_db->hdr );
597 return ERROR_FUNCTION_FAILED;
600 r = msi_check_patch_applicable( package, si );
601 if (r != ERROR_SUCCESS)
603 TRACE("patch not applicable\n");
608 r = msi_parse_patch_summary( si, &patch );
609 if ( r != ERROR_SUCCESS )
612 r = msi_get_local_package_name( localfile, dotmsp );
613 if ( r != ERROR_SUCCESS )
616 TRACE("copying to local package %s\n", debugstr_w(localfile));
618 if (!CopyFileW( file, localfile, FALSE ))
620 ERR("Unable to copy package (%s -> %s) (error %u)\n",
621 debugstr_w(file), debugstr_w(localfile), GetLastError());
625 patch->localfile = strdupW( localfile );
627 r = msi_apply_patch_db( package, patch_db, patch );
628 if ( r != ERROR_SUCCESS )
629 WARN("patch failed to apply %u\n", r);
632 msiobj_release( &si->hdr );
633 msiobj_release( &patch_db->hdr );
634 if (patch && r != ERROR_SUCCESS)
636 if (patch->localfile)
637 DeleteFileW( patch->localfile );
639 msi_free( patch->patchcode );
640 msi_free( patch->transforms );
641 msi_free( patch->localfile );
647 /* get the PATCH property, and apply all the patches it specifies */
648 static UINT msi_apply_patches( MSIPACKAGE *package )
650 LPWSTR patch_list, *patches;
651 UINT i, r = ERROR_SUCCESS;
653 patch_list = msi_dup_property( package->db, szPatch );
655 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
657 patches = msi_split_string( patch_list, ';' );
658 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
659 r = msi_apply_patch_package( package, patches[i] );
662 msi_free( patch_list );
667 static UINT msi_apply_transforms( MSIPACKAGE *package )
669 static const WCHAR szTransforms[] = {
670 'T','R','A','N','S','F','O','R','M','S',0 };
671 LPWSTR xform_list, *xforms;
672 UINT i, r = ERROR_SUCCESS;
674 xform_list = msi_dup_property( package->db, szTransforms );
675 xforms = msi_split_string( xform_list, ';' );
677 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
679 if (xforms[i][0] == ':')
680 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
682 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
686 msi_free( xform_list );
691 static BOOL ui_sequence_exists( MSIPACKAGE *package )
696 static const WCHAR ExecSeqQuery [] =
697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
698 '`','I','n','s','t','a','l','l',
699 'U','I','S','e','q','u','e','n','c','e','`',
700 ' ','W','H','E','R','E',' ',
701 '`','S','e','q','u','e','n','c','e','`',' ',
702 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
703 '`','S','e','q','u','e','n','c','e','`',0};
705 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
706 if (rc == ERROR_SUCCESS)
708 msiobj_release(&view->hdr);
715 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);
967 comp = get_loaded_component(package, component);
969 return ERROR_SUCCESS;
973 TRACE("component is disabled\n");
974 return ERROR_SUCCESS;
977 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
979 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
980 comp->Action = comp->Installed;
981 return ERROR_SUCCESS;
983 comp->Action = INSTALLSTATE_LOCAL;
985 dir = MSI_RecordGetString(row,1);
988 ERR("Unable to get folder id\n");
989 return ERROR_SUCCESS;
992 uirow = MSI_CreateRecord(1);
993 MSI_RecordSetStringW(uirow, 1, dir);
994 ui_actiondata(package, szCreateFolders, uirow);
995 msiobj_release(&uirow->hdr);
997 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1000 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1001 return ERROR_SUCCESS;
1004 TRACE("Folder is %s\n",debugstr_w(full_path));
1006 if (folder->State == 0)
1007 create_full_pathW(full_path);
1011 msi_free(full_path);
1012 return ERROR_SUCCESS;
1015 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1017 static const WCHAR ExecSeqQuery[] =
1018 {'S','E','L','E','C','T',' ',
1019 '`','D','i','r','e','c','t','o','r','y','_','`',
1020 ' ','F','R','O','M',' ',
1021 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1025 /* create all the empty folders specified in the CreateFolder table */
1026 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1027 if (rc != ERROR_SUCCESS)
1028 return ERROR_SUCCESS;
1030 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1031 msiobj_release(&view->hdr);
1036 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1038 MSIPACKAGE *package = param;
1039 LPCWSTR dir, component;
1045 component = MSI_RecordGetString(row, 2);
1046 comp = get_loaded_component(package, component);
1048 return ERROR_SUCCESS;
1052 TRACE("component is disabled\n");
1053 return ERROR_SUCCESS;
1056 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1058 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1059 comp->Action = comp->Installed;
1060 return ERROR_SUCCESS;
1062 comp->Action = INSTALLSTATE_ABSENT;
1064 dir = MSI_RecordGetString( row, 1 );
1067 ERR("Unable to get folder id\n");
1068 return ERROR_SUCCESS;
1071 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1074 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1075 return ERROR_SUCCESS;
1078 TRACE("folder is %s\n", debugstr_w(full_path));
1080 uirow = MSI_CreateRecord( 1 );
1081 MSI_RecordSetStringW( uirow, 1, dir );
1082 ui_actiondata( package, szRemoveFolders, uirow );
1083 msiobj_release( &uirow->hdr );
1085 RemoveDirectoryW( full_path );
1088 msi_free( full_path );
1089 return ERROR_SUCCESS;
1092 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1094 static const WCHAR query[] =
1095 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1096 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1101 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1102 if (rc != ERROR_SUCCESS)
1103 return ERROR_SUCCESS;
1105 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1106 msiobj_release( &view->hdr );
1111 static UINT load_component( MSIRECORD *row, LPVOID param )
1113 MSIPACKAGE *package = param;
1116 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1118 return ERROR_FUNCTION_FAILED;
1120 list_add_tail( &package->components, &comp->entry );
1122 /* fill in the data */
1123 comp->Component = msi_dup_record_field( row, 1 );
1125 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1127 comp->ComponentId = msi_dup_record_field( row, 2 );
1128 comp->Directory = msi_dup_record_field( row, 3 );
1129 comp->Attributes = MSI_RecordGetInteger(row,4);
1130 comp->Condition = msi_dup_record_field( row, 5 );
1131 comp->KeyPath = msi_dup_record_field( row, 6 );
1133 comp->Installed = INSTALLSTATE_UNKNOWN;
1134 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1136 return ERROR_SUCCESS;
1139 static UINT load_all_components( MSIPACKAGE *package )
1141 static const WCHAR query[] = {
1142 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1143 '`','C','o','m','p','o','n','e','n','t','`',0 };
1147 if (!list_empty(&package->components))
1148 return ERROR_SUCCESS;
1150 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1151 if (r != ERROR_SUCCESS)
1154 r = MSI_IterateRecords(view, NULL, load_component, package);
1155 msiobj_release(&view->hdr);
1160 MSIPACKAGE *package;
1161 MSIFEATURE *feature;
1164 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1168 cl = msi_alloc( sizeof (*cl) );
1170 return ERROR_NOT_ENOUGH_MEMORY;
1171 cl->component = comp;
1172 list_add_tail( &feature->Components, &cl->entry );
1174 return ERROR_SUCCESS;
1177 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1181 fl = msi_alloc( sizeof(*fl) );
1183 return ERROR_NOT_ENOUGH_MEMORY;
1184 fl->feature = child;
1185 list_add_tail( &parent->Children, &fl->entry );
1187 return ERROR_SUCCESS;
1190 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1192 _ilfs* ilfs = param;
1196 component = MSI_RecordGetString(row,1);
1198 /* check to see if the component is already loaded */
1199 comp = get_loaded_component( ilfs->package, component );
1202 ERR("unknown component %s\n", debugstr_w(component));
1203 return ERROR_FUNCTION_FAILED;
1206 add_feature_component( ilfs->feature, comp );
1207 comp->Enabled = TRUE;
1209 return ERROR_SUCCESS;
1212 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1214 MSIFEATURE *feature;
1219 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1221 if ( !lstrcmpW( feature->Feature, name ) )
1228 static UINT load_feature(MSIRECORD * row, LPVOID param)
1230 MSIPACKAGE* package = param;
1231 MSIFEATURE* feature;
1232 static const WCHAR Query1[] =
1233 {'S','E','L','E','C','T',' ',
1234 '`','C','o','m','p','o','n','e','n','t','_','`',
1235 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1236 'C','o','m','p','o','n','e','n','t','s','`',' ',
1237 'W','H','E','R','E',' ',
1238 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1243 /* fill in the data */
1245 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1247 return ERROR_NOT_ENOUGH_MEMORY;
1249 list_init( &feature->Children );
1250 list_init( &feature->Components );
1252 feature->Feature = msi_dup_record_field( row, 1 );
1254 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1256 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1257 feature->Title = msi_dup_record_field( row, 3 );
1258 feature->Description = msi_dup_record_field( row, 4 );
1260 if (!MSI_RecordIsNull(row,5))
1261 feature->Display = MSI_RecordGetInteger(row,5);
1263 feature->Level= MSI_RecordGetInteger(row,6);
1264 feature->Directory = msi_dup_record_field( row, 7 );
1265 feature->Attributes = MSI_RecordGetInteger(row,8);
1267 feature->Installed = INSTALLSTATE_UNKNOWN;
1268 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1270 list_add_tail( &package->features, &feature->entry );
1272 /* load feature components */
1274 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1275 if (rc != ERROR_SUCCESS)
1276 return ERROR_SUCCESS;
1278 ilfs.package = package;
1279 ilfs.feature = feature;
1281 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1282 msiobj_release(&view->hdr);
1284 return ERROR_SUCCESS;
1287 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1289 MSIPACKAGE* package = param;
1290 MSIFEATURE *parent, *child;
1292 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1294 return ERROR_FUNCTION_FAILED;
1296 if (!child->Feature_Parent)
1297 return ERROR_SUCCESS;
1299 parent = find_feature_by_name( package, child->Feature_Parent );
1301 return ERROR_FUNCTION_FAILED;
1303 add_feature_child( parent, child );
1304 return ERROR_SUCCESS;
1307 static UINT load_all_features( MSIPACKAGE *package )
1309 static const WCHAR query[] = {
1310 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1311 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1312 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1316 if (!list_empty(&package->features))
1317 return ERROR_SUCCESS;
1319 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1320 if (r != ERROR_SUCCESS)
1323 r = MSI_IterateRecords( view, NULL, load_feature, package );
1324 if (r != ERROR_SUCCESS)
1327 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1328 msiobj_release( &view->hdr );
1333 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1344 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1346 static const WCHAR query[] = {
1347 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1348 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1349 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1350 MSIQUERY *view = NULL;
1351 MSIRECORD *row = NULL;
1354 TRACE("%s\n", debugstr_w(file->File));
1356 r = MSI_OpenQuery(package->db, &view, query, file->File);
1357 if (r != ERROR_SUCCESS)
1360 r = MSI_ViewExecute(view, NULL);
1361 if (r != ERROR_SUCCESS)
1364 r = MSI_ViewFetch(view, &row);
1365 if (r != ERROR_SUCCESS)
1368 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1369 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1370 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1371 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1372 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1375 if (view) msiobj_release(&view->hdr);
1376 if (row) msiobj_release(&row->hdr);
1380 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1383 static const WCHAR query[] = {
1384 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1385 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1386 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1388 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1391 WARN("query failed\n");
1392 return ERROR_FUNCTION_FAILED;
1395 file->disk_id = MSI_RecordGetInteger( row, 1 );
1396 msiobj_release( &row->hdr );
1397 return ERROR_SUCCESS;
1400 static UINT load_file(MSIRECORD *row, LPVOID param)
1402 MSIPACKAGE* package = param;
1406 /* fill in the data */
1408 file = msi_alloc_zero( sizeof (MSIFILE) );
1410 return ERROR_NOT_ENOUGH_MEMORY;
1412 file->File = msi_dup_record_field( row, 1 );
1414 component = MSI_RecordGetString( row, 2 );
1415 file->Component = get_loaded_component( package, component );
1417 if (!file->Component)
1419 WARN("Component not found: %s\n", debugstr_w(component));
1420 msi_free(file->File);
1422 return ERROR_SUCCESS;
1425 file->FileName = msi_dup_record_field( row, 3 );
1426 reduce_to_longfilename( file->FileName );
1428 file->ShortName = msi_dup_record_field( row, 3 );
1429 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1431 file->FileSize = MSI_RecordGetInteger( row, 4 );
1432 file->Version = msi_dup_record_field( row, 5 );
1433 file->Language = msi_dup_record_field( row, 6 );
1434 file->Attributes = MSI_RecordGetInteger( row, 7 );
1435 file->Sequence = MSI_RecordGetInteger( row, 8 );
1437 file->state = msifs_invalid;
1439 /* if the compressed bits are not set in the file attributes,
1440 * then read the information from the package word count property
1442 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1444 file->IsCompressed = FALSE;
1446 else if (file->Attributes &
1447 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1449 file->IsCompressed = TRUE;
1451 else if (file->Attributes & msidbFileAttributesNoncompressed)
1453 file->IsCompressed = FALSE;
1457 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1460 load_file_hash(package, file);
1461 load_file_disk_id(package, file);
1463 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1465 list_add_tail( &package->files, &file->entry );
1467 return ERROR_SUCCESS;
1470 static UINT load_all_files(MSIPACKAGE *package)
1474 static const WCHAR Query[] =
1475 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1476 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1477 '`','S','e','q','u','e','n','c','e','`', 0};
1479 if (!list_empty(&package->files))
1480 return ERROR_SUCCESS;
1482 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1483 if (rc != ERROR_SUCCESS)
1484 return ERROR_SUCCESS;
1486 rc = MSI_IterateRecords(view, NULL, load_file, package);
1487 msiobj_release(&view->hdr);
1489 return ERROR_SUCCESS;
1492 static UINT load_folder( MSIRECORD *row, LPVOID param )
1494 MSIPACKAGE *package = param;
1495 static WCHAR szEmpty[] = { 0 };
1496 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1499 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1501 return ERROR_NOT_ENOUGH_MEMORY;
1503 folder->Directory = msi_dup_record_field( row, 1 );
1505 TRACE("%s\n", debugstr_w(folder->Directory));
1507 p = msi_dup_record_field(row, 3);
1509 /* split src and target dir */
1511 src_short = folder_split_path( p, ':' );
1513 /* split the long and short paths */
1514 tgt_long = folder_split_path( tgt_short, '|' );
1515 src_long = folder_split_path( src_short, '|' );
1517 /* check for no-op dirs */
1518 if (!lstrcmpW(szDot, tgt_short))
1519 tgt_short = szEmpty;
1520 if (!lstrcmpW(szDot, src_short))
1521 src_short = szEmpty;
1524 tgt_long = tgt_short;
1527 src_short = tgt_short;
1528 src_long = tgt_long;
1532 src_long = src_short;
1534 /* FIXME: use the target short path too */
1535 folder->TargetDefault = strdupW(tgt_long);
1536 folder->SourceShortPath = strdupW(src_short);
1537 folder->SourceLongPath = strdupW(src_long);
1540 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1541 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1542 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1544 folder->Parent = msi_dup_record_field( row, 2 );
1546 folder->Property = msi_dup_property( package->db, folder->Directory );
1548 list_add_tail( &package->folders, &folder->entry );
1550 TRACE("returning %p\n", folder);
1552 return ERROR_SUCCESS;
1555 static UINT load_all_folders( MSIPACKAGE *package )
1557 static const WCHAR query[] = {
1558 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1559 '`','D','i','r','e','c','t','o','r','y','`',0 };
1563 if (!list_empty(&package->folders))
1564 return ERROR_SUCCESS;
1566 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1567 if (r != ERROR_SUCCESS)
1570 r = MSI_IterateRecords(view, NULL, load_folder, package);
1571 msiobj_release(&view->hdr);
1576 * I am not doing any of the costing functionality yet.
1577 * Mostly looking at doing the Component and Feature loading
1579 * The native MSI does A LOT of modification to tables here. Mostly adding
1580 * a lot of temporary columns to the Feature and Component tables.
1582 * note: Native msi also tracks the short filename. But I am only going to
1583 * track the long ones. Also looking at this directory table
1584 * it appears that the directory table does not get the parents
1585 * resolved base on property only based on their entries in the
1588 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1590 static const WCHAR szCosting[] =
1591 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1593 msi_set_property( package->db, szCosting, szZero );
1594 msi_set_property( package->db, cszRootDrive, c_colon );
1596 load_all_folders( package );
1597 load_all_components( package );
1598 load_all_features( package );
1599 load_all_files( package );
1601 return ERROR_SUCCESS;
1604 static UINT execute_script(MSIPACKAGE *package, UINT script )
1607 UINT rc = ERROR_SUCCESS;
1609 TRACE("Executing Script %i\n",script);
1611 if (!package->script)
1613 ERR("no script!\n");
1614 return ERROR_FUNCTION_FAILED;
1617 for (i = 0; i < package->script->ActionCount[script]; i++)
1620 action = package->script->Actions[script][i];
1621 ui_actionstart(package, action);
1622 TRACE("Executing Action (%s)\n",debugstr_w(action));
1623 rc = ACTION_PerformAction(package, action, script);
1624 if (rc != ERROR_SUCCESS)
1627 msi_free_action_script(package, script);
1631 static UINT ACTION_FileCost(MSIPACKAGE *package)
1633 return ERROR_SUCCESS;
1636 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1642 state = MsiQueryProductStateW(package->ProductCode);
1644 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1646 if (!comp->ComponentId)
1649 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1650 comp->Installed = INSTALLSTATE_ABSENT;
1653 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1654 package->Context, comp->ComponentId,
1656 if (r != ERROR_SUCCESS)
1657 comp->Installed = INSTALLSTATE_ABSENT;
1662 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1664 MSIFEATURE *feature;
1667 state = MsiQueryProductStateW(package->ProductCode);
1669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1671 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1672 feature->Installed = INSTALLSTATE_ABSENT;
1675 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1681 static BOOL process_state_property(MSIPACKAGE* package, int level,
1682 LPCWSTR property, INSTALLSTATE state)
1685 MSIFEATURE *feature;
1687 override = msi_dup_property( package->db, property );
1691 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1693 if (lstrcmpW(property, szRemove) &&
1694 (feature->Level <= 0 || feature->Level > level))
1697 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1699 if (strcmpiW(override, szAll)==0)
1700 msi_feature_set_state(package, feature, state);
1703 LPWSTR ptr = override;
1704 LPWSTR ptr2 = strchrW(override,',');
1708 int len = ptr2 - ptr;
1710 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1711 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1713 msi_feature_set_state(package, feature, state);
1719 ptr2 = strchrW(ptr,',');
1731 static BOOL process_overrides( MSIPACKAGE *package, int level )
1733 static const WCHAR szAddLocal[] =
1734 {'A','D','D','L','O','C','A','L',0};
1735 static const WCHAR szAddSource[] =
1736 {'A','D','D','S','O','U','R','C','E',0};
1737 static const WCHAR szAdvertise[] =
1738 {'A','D','V','E','R','T','I','S','E',0};
1741 /* all these activation/deactivation things happen in order and things
1742 * later on the list override things earlier on the list.
1744 * 0 INSTALLLEVEL processing
1757 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1758 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1759 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1760 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1761 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1764 msi_set_property( package->db, szPreselected, szOne );
1769 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1772 static const WCHAR szlevel[] =
1773 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1774 MSICOMPONENT* component;
1775 MSIFEATURE *feature;
1777 TRACE("Checking Install Level\n");
1779 level = msi_get_property_int(package->db, szlevel, 1);
1781 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1785 BOOL feature_state = ((feature->Level > 0) &&
1786 (feature->Level <= level));
1788 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1790 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1791 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1792 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1793 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1795 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1799 /* disable child features of unselected parent features */
1800 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1804 if (feature->Level > 0 && feature->Level <= level)
1807 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1808 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1813 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1815 BOOL selected = feature->Level > 0 && feature->Level <= level;
1817 if (selected && feature->Action == INSTALLSTATE_UNKNOWN)
1819 msi_feature_set_state(package, feature, feature->Installed);
1825 * now we want to enable or disable components based on feature
1827 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1831 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
1832 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1833 feature->ActionRequest, feature->Action);
1835 if (!feature->Level)
1838 /* features with components that have compressed files are made local */
1839 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1841 if (cl->component->ForceLocalState &&
1842 feature->Action == INSTALLSTATE_SOURCE)
1844 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1849 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1851 component = cl->component;
1853 switch (feature->Action)
1855 case INSTALLSTATE_ABSENT:
1856 component->anyAbsent = 1;
1858 case INSTALLSTATE_ADVERTISED:
1859 component->hasAdvertiseFeature = 1;
1861 case INSTALLSTATE_SOURCE:
1862 component->hasSourceFeature = 1;
1864 case INSTALLSTATE_LOCAL:
1865 component->hasLocalFeature = 1;
1867 case INSTALLSTATE_DEFAULT:
1868 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1869 component->hasAdvertiseFeature = 1;
1870 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1871 component->hasSourceFeature = 1;
1873 component->hasLocalFeature = 1;
1881 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1883 /* check if it's local or source */
1884 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1885 (component->hasLocalFeature || component->hasSourceFeature))
1887 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1888 !component->ForceLocalState)
1889 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1891 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1895 /* if any feature is local, the component must be local too */
1896 if (component->hasLocalFeature)
1898 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1902 if (component->hasSourceFeature)
1904 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1908 if (component->hasAdvertiseFeature)
1910 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1914 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1915 if (component->anyAbsent)
1916 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1919 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1921 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1923 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1924 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1927 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
1928 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1931 return ERROR_SUCCESS;
1934 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1936 MSIPACKAGE *package = param;
1941 name = MSI_RecordGetString(row,1);
1943 f = get_loaded_folder(package, name);
1944 if (!f) return ERROR_SUCCESS;
1946 /* reset the ResolvedTarget */
1947 msi_free(f->ResolvedTarget);
1948 f->ResolvedTarget = NULL;
1950 /* This helper function now does ALL the work */
1951 TRACE("Dir %s ...\n",debugstr_w(name));
1952 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1953 TRACE("resolves to %s\n",debugstr_w(path));
1956 return ERROR_SUCCESS;
1959 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1961 MSIPACKAGE *package = param;
1963 MSIFEATURE *feature;
1965 name = MSI_RecordGetString( row, 1 );
1967 feature = get_loaded_feature( package, name );
1969 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1973 Condition = MSI_RecordGetString(row,3);
1975 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1977 int level = MSI_RecordGetInteger(row,2);
1978 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1979 feature->Level = level;
1982 return ERROR_SUCCESS;
1985 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
1987 static const WCHAR name[] = {'\\',0};
1988 VS_FIXEDFILEINFO *ret;
1990 DWORD versize, handle;
1993 TRACE("%s\n", debugstr_w(filename));
1995 versize = GetFileVersionInfoSizeW( filename, &handle );
1999 version = msi_alloc( versize );
2003 GetFileVersionInfoW( filename, 0, versize, version );
2005 if (!VerQueryValueW( version, name, (LPVOID *)&ret, &sz ))
2007 msi_free( version );
2011 msi_free( version );
2015 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
2019 msi_parse_version_string( version, &ms, &ls );
2021 if (fi->dwFileVersionMS > ms) return 1;
2022 else if (fi->dwFileVersionMS < ms) return -1;
2023 else if (fi->dwFileVersionLS > ls) return 1;
2024 else if (fi->dwFileVersionLS < ls) return -1;
2028 static DWORD get_disk_file_size( LPCWSTR filename )
2033 TRACE("%s\n", debugstr_w(filename));
2035 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2036 if (file == INVALID_HANDLE_VALUE)
2037 return INVALID_FILE_SIZE;
2039 size = GetFileSize( file, NULL );
2040 CloseHandle( file );
2044 static BOOL hash_matches( MSIFILE *file )
2047 MSIFILEHASHINFO hash;
2049 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2050 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2051 if (r != ERROR_SUCCESS)
2054 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2057 static UINT set_file_install_states( MSIPACKAGE *package )
2059 VS_FIXEDFILEINFO *file_version;
2062 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2064 MSICOMPONENT* comp = file->Component;
2071 if (file->IsCompressed)
2072 comp->ForceLocalState = TRUE;
2074 /* calculate target */
2075 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2076 msi_free(file->TargetPath);
2078 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
2080 file->TargetPath = build_directory_name(2, p, file->FileName);
2083 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2085 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2087 file->state = msifs_missing;
2088 comp->Cost += file->FileSize;
2091 if (file->Version && (file_version = msi_get_disk_file_version( file->TargetPath )))
2093 TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
2094 HIWORD(file_version->dwFileVersionMS),
2095 LOWORD(file_version->dwFileVersionMS),
2096 HIWORD(file_version->dwFileVersionLS),
2097 LOWORD(file_version->dwFileVersionLS));
2099 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2101 file->state = msifs_overwrite;
2102 comp->Cost += file->FileSize;
2106 TRACE("Destination file version equal or greater, not overwriting\n");
2107 file->state = msifs_present;
2109 msi_free( file_version );
2112 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2114 file->state = msifs_overwrite;
2115 comp->Cost += file->FileSize - file_size;
2118 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2120 TRACE("File hashes match, not overwriting\n");
2121 file->state = msifs_present;
2124 file->state = msifs_overwrite;
2125 comp->Cost += file->FileSize - file_size;
2128 return ERROR_SUCCESS;
2132 * A lot is done in this function aside from just the costing.
2133 * The costing needs to be implemented at some point but for now I am going
2134 * to focus on the directory building
2137 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2139 static const WCHAR ExecSeqQuery[] =
2140 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2141 '`','D','i','r','e','c','t','o','r','y','`',0};
2142 static const WCHAR ConditionQuery[] =
2143 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2144 '`','C','o','n','d','i','t','i','o','n','`',0};
2145 static const WCHAR szCosting[] =
2146 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2147 static const WCHAR szlevel[] =
2148 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2149 static const WCHAR szOutOfDiskSpace[] =
2150 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2152 UINT rc = ERROR_SUCCESS;
2156 TRACE("Building Directory properties\n");
2158 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2159 if (rc == ERROR_SUCCESS)
2161 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2163 msiobj_release(&view->hdr);
2166 /* read components states from the registry */
2167 ACTION_GetComponentInstallStates(package);
2168 ACTION_GetFeatureInstallStates(package);
2170 TRACE("Calculating file install states\n");
2171 set_file_install_states( package );
2173 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2175 TRACE("Evaluating feature conditions\n");
2177 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2178 if (rc == ERROR_SUCCESS)
2180 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2181 msiobj_release( &view->hdr );
2184 TRACE("Evaluating component conditions\n");
2186 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2188 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2190 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2191 comp->Enabled = FALSE;
2194 comp->Enabled = TRUE;
2197 msi_set_property( package->db, szCosting, szOne );
2198 /* set default run level if not set */
2199 level = msi_dup_property( package->db, szlevel );
2201 msi_set_property( package->db, szlevel, szOne );
2204 /* FIXME: check volume disk space */
2205 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2207 return MSI_SetFeatureStates(package);
2210 /* OK this value is "interpreted" and then formatted based on the
2211 first few characters */
2212 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2217 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2223 LPWSTR deformated = NULL;
2226 deformat_string(package, &value[2], &deformated);
2228 /* binary value type */
2232 *size = (strlenW(ptr)/2)+1;
2234 *size = strlenW(ptr)/2;
2236 data = msi_alloc(*size);
2242 /* if uneven pad with a zero in front */
2248 data[count] = (BYTE)strtol(byte,NULL,0);
2250 TRACE("Uneven byte count\n");
2258 data[count] = (BYTE)strtol(byte,NULL,0);
2261 msi_free(deformated);
2263 TRACE("Data %i bytes(%i)\n",*size,count);
2270 deformat_string(package, &value[1], &deformated);
2273 *size = sizeof(DWORD);
2274 data = msi_alloc(*size);
2280 if ( (*p < '0') || (*p > '9') )
2286 if (deformated[0] == '-')
2289 TRACE("DWORD %i\n",*(LPDWORD)data);
2291 msi_free(deformated);
2296 static const WCHAR szMulti[] = {'[','~',']',0};
2305 *type=REG_EXPAND_SZ;
2313 if (strstrW(value,szMulti))
2314 *type = REG_MULTI_SZ;
2316 /* remove initial delimiter */
2317 if (!strncmpW(value, szMulti, 3))
2320 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2322 /* add double NULL terminator */
2323 if (*type == REG_MULTI_SZ)
2325 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2326 data = msi_realloc_zero(data, *size);
2332 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2339 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2341 *root_key = HKEY_LOCAL_MACHINE;
2346 *root_key = HKEY_CURRENT_USER;
2351 *root_key = HKEY_CLASSES_ROOT;
2355 *root_key = HKEY_CURRENT_USER;
2359 *root_key = HKEY_LOCAL_MACHINE;
2363 *root_key = HKEY_USERS;
2367 ERR("Unknown root %i\n", root);
2374 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2376 MSIPACKAGE *package = param;
2377 LPSTR value_data = NULL;
2378 HKEY root_key, hkey;
2381 LPCWSTR szRoot, component, name, key, value;
2386 BOOL check_first = FALSE;
2389 ui_progress(package,2,0,0,0);
2391 component = MSI_RecordGetString(row, 6);
2392 comp = get_loaded_component(package,component);
2394 return ERROR_SUCCESS;
2398 TRACE("component is disabled\n");
2399 return ERROR_SUCCESS;
2402 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2404 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2405 comp->Action = comp->Installed;
2406 return ERROR_SUCCESS;
2408 comp->Action = INSTALLSTATE_LOCAL;
2410 name = MSI_RecordGetString(row, 4);
2411 if( MSI_RecordIsNull(row,5) && name )
2413 /* null values can have special meanings */
2414 if (name[0]=='-' && name[1] == 0)
2415 return ERROR_SUCCESS;
2416 else if ((name[0]=='+' && name[1] == 0) ||
2417 (name[0] == '*' && name[1] == 0))
2422 root = MSI_RecordGetInteger(row,2);
2423 key = MSI_RecordGetString(row, 3);
2425 szRoot = get_root_key( package, root, &root_key );
2427 return ERROR_SUCCESS;
2429 deformat_string(package, key , &deformated);
2430 size = strlenW(deformated) + strlenW(szRoot) + 1;
2431 uikey = msi_alloc(size*sizeof(WCHAR));
2432 strcpyW(uikey,szRoot);
2433 strcatW(uikey,deformated);
2435 if (RegCreateKeyW( root_key, deformated, &hkey))
2437 ERR("Could not create key %s\n",debugstr_w(deformated));
2438 msi_free(deformated);
2440 return ERROR_SUCCESS;
2442 msi_free(deformated);
2444 value = MSI_RecordGetString(row,5);
2446 value_data = parse_value(package, value, &type, &size);
2449 value_data = (LPSTR)strdupW(szEmpty);
2450 size = sizeof(szEmpty);
2454 deformat_string(package, name, &deformated);
2458 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2460 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2465 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2466 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2468 TRACE("value %s of %s checked already exists\n",
2469 debugstr_w(deformated), debugstr_w(uikey));
2473 TRACE("Checked and setting value %s of %s\n",
2474 debugstr_w(deformated), debugstr_w(uikey));
2475 if (deformated || size)
2476 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2481 uirow = MSI_CreateRecord(3);
2482 MSI_RecordSetStringW(uirow,2,deformated);
2483 MSI_RecordSetStringW(uirow,1,uikey);
2484 if (type == REG_SZ || type == REG_EXPAND_SZ)
2485 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2486 ui_actiondata(package,szWriteRegistryValues,uirow);
2487 msiobj_release( &uirow->hdr );
2489 msi_free(value_data);
2490 msi_free(deformated);
2493 return ERROR_SUCCESS;
2496 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2500 static const WCHAR ExecSeqQuery[] =
2501 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2502 '`','R','e','g','i','s','t','r','y','`',0 };
2504 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2505 if (rc != ERROR_SUCCESS)
2506 return ERROR_SUCCESS;
2508 /* increment progress bar each time action data is sent */
2509 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2511 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2513 msiobj_release(&view->hdr);
2517 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2521 DWORD num_subkeys, num_values;
2525 if ((res = RegDeleteTreeW( hkey_root, key )))
2527 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2532 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2534 if ((res = RegDeleteValueW( hkey, value )))
2536 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2538 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2539 NULL, NULL, NULL, NULL );
2540 RegCloseKey( hkey );
2542 if (!res && !num_subkeys && !num_values)
2544 TRACE("Removing empty key %s\n", debugstr_w(key));
2545 RegDeleteKeyW( hkey_root, key );
2549 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2553 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2555 MSIPACKAGE *package = param;
2556 LPCWSTR component, name, key_str, root_key_str;
2557 LPWSTR deformated_key, deformated_name, ui_key_str;
2560 BOOL delete_key = FALSE;
2565 ui_progress( package, 2, 0, 0, 0 );
2567 component = MSI_RecordGetString( row, 6 );
2568 comp = get_loaded_component( package, component );
2570 return ERROR_SUCCESS;
2574 TRACE("component is disabled\n");
2575 return ERROR_SUCCESS;
2578 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2580 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2581 comp->Action = comp->Installed;
2582 return ERROR_SUCCESS;
2584 comp->Action = INSTALLSTATE_ABSENT;
2586 name = MSI_RecordGetString( row, 4 );
2587 if (MSI_RecordIsNull( row, 5 ) && name )
2589 if (name[0] == '+' && !name[1])
2590 return ERROR_SUCCESS;
2591 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2598 root = MSI_RecordGetInteger( row, 2 );
2599 key_str = MSI_RecordGetString( row, 3 );
2601 root_key_str = get_root_key( package, root, &hkey_root );
2603 return ERROR_SUCCESS;
2605 deformat_string( package, key_str, &deformated_key );
2606 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2607 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2608 strcpyW( ui_key_str, root_key_str );
2609 strcatW( ui_key_str, deformated_key );
2611 deformat_string( package, name, &deformated_name );
2613 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2614 msi_free( deformated_key );
2616 uirow = MSI_CreateRecord( 2 );
2617 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2618 MSI_RecordSetStringW( uirow, 2, deformated_name );
2620 ui_actiondata( package, szRemoveRegistryValues, uirow );
2621 msiobj_release( &uirow->hdr );
2623 msi_free( ui_key_str );
2624 msi_free( deformated_name );
2625 return ERROR_SUCCESS;
2628 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2630 MSIPACKAGE *package = param;
2631 LPCWSTR component, name, key_str, root_key_str;
2632 LPWSTR deformated_key, deformated_name, ui_key_str;
2635 BOOL delete_key = FALSE;
2640 ui_progress( package, 2, 0, 0, 0 );
2642 component = MSI_RecordGetString( row, 5 );
2643 comp = get_loaded_component( package, component );
2645 return ERROR_SUCCESS;
2649 TRACE("component is disabled\n");
2650 return ERROR_SUCCESS;
2653 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2655 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2656 comp->Action = comp->Installed;
2657 return ERROR_SUCCESS;
2659 comp->Action = INSTALLSTATE_LOCAL;
2661 if ((name = MSI_RecordGetString( row, 4 )))
2663 if (name[0] == '-' && !name[1])
2670 root = MSI_RecordGetInteger( row, 2 );
2671 key_str = MSI_RecordGetString( row, 3 );
2673 root_key_str = get_root_key( package, root, &hkey_root );
2675 return ERROR_SUCCESS;
2677 deformat_string( package, key_str, &deformated_key );
2678 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2679 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2680 strcpyW( ui_key_str, root_key_str );
2681 strcatW( ui_key_str, deformated_key );
2683 deformat_string( package, name, &deformated_name );
2685 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2686 msi_free( deformated_key );
2688 uirow = MSI_CreateRecord( 2 );
2689 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2690 MSI_RecordSetStringW( uirow, 2, deformated_name );
2692 ui_actiondata( package, szRemoveRegistryValues, uirow );
2693 msiobj_release( &uirow->hdr );
2695 msi_free( ui_key_str );
2696 msi_free( deformated_name );
2697 return ERROR_SUCCESS;
2700 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2704 static const WCHAR registry_query[] =
2705 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2706 '`','R','e','g','i','s','t','r','y','`',0 };
2707 static const WCHAR remove_registry_query[] =
2708 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2709 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2711 /* increment progress bar each time action data is sent */
2712 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2714 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2715 if (rc == ERROR_SUCCESS)
2717 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2718 msiobj_release( &view->hdr );
2719 if (rc != ERROR_SUCCESS)
2723 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2724 if (rc == ERROR_SUCCESS)
2726 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2727 msiobj_release( &view->hdr );
2728 if (rc != ERROR_SUCCESS)
2732 return ERROR_SUCCESS;
2735 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2737 package->script->CurrentlyScripting = TRUE;
2739 return ERROR_SUCCESS;
2743 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2748 static const WCHAR q1[]=
2749 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2750 '`','R','e','g','i','s','t','r','y','`',0};
2753 MSIFEATURE *feature;
2756 TRACE("InstallValidate\n");
2758 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2759 if (rc == ERROR_SUCCESS)
2761 MSI_IterateRecords( view, &progress, NULL, package );
2762 msiobj_release( &view->hdr );
2763 total += progress * REG_PROGRESS_VALUE;
2766 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2767 total += COMPONENT_PROGRESS_VALUE;
2769 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2770 total += file->FileSize;
2772 ui_progress(package,0,total,0,0);
2774 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2776 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2777 debugstr_w(feature->Feature), feature->Installed,
2778 feature->ActionRequest, feature->Action);
2781 return ERROR_SUCCESS;
2784 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2786 MSIPACKAGE* package = param;
2787 LPCWSTR cond = NULL;
2788 LPCWSTR message = NULL;
2791 static const WCHAR title[]=
2792 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2794 cond = MSI_RecordGetString(row,1);
2796 r = MSI_EvaluateConditionW(package,cond);
2797 if (r == MSICONDITION_FALSE)
2799 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2802 message = MSI_RecordGetString(row,2);
2803 deformat_string(package,message,&deformated);
2804 MessageBoxW(NULL,deformated,title,MB_OK);
2805 msi_free(deformated);
2808 return ERROR_INSTALL_FAILURE;
2811 return ERROR_SUCCESS;
2814 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2817 MSIQUERY * view = NULL;
2818 static const WCHAR ExecSeqQuery[] =
2819 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2820 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2822 TRACE("Checking launch conditions\n");
2824 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2825 if (rc != ERROR_SUCCESS)
2826 return ERROR_SUCCESS;
2828 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2829 msiobj_release(&view->hdr);
2834 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2838 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2840 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2842 MSIRECORD * row = 0;
2844 LPWSTR deformated,buffer,deformated_name;
2846 static const WCHAR ExecSeqQuery[] =
2847 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2848 '`','R','e','g','i','s','t','r','y','`',' ',
2849 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2850 ' ','=',' ' ,'\'','%','s','\'',0 };
2851 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2852 static const WCHAR fmt2[]=
2853 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2855 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2859 root = MSI_RecordGetInteger(row,2);
2860 key = MSI_RecordGetString(row, 3);
2861 name = MSI_RecordGetString(row, 4);
2862 deformat_string(package, key , &deformated);
2863 deformat_string(package, name, &deformated_name);
2865 len = strlenW(deformated) + 6;
2866 if (deformated_name)
2867 len+=strlenW(deformated_name);
2869 buffer = msi_alloc( len *sizeof(WCHAR));
2871 if (deformated_name)
2872 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2874 sprintfW(buffer,fmt,root,deformated);
2876 msi_free(deformated);
2877 msi_free(deformated_name);
2878 msiobj_release(&row->hdr);
2882 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2884 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2889 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2892 return strdupW( file->TargetPath );
2897 static HKEY openSharedDLLsKey(void)
2900 static const WCHAR path[] =
2901 {'S','o','f','t','w','a','r','e','\\',
2902 'M','i','c','r','o','s','o','f','t','\\',
2903 'W','i','n','d','o','w','s','\\',
2904 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2905 'S','h','a','r','e','d','D','L','L','s',0};
2907 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2911 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2916 DWORD sz = sizeof(count);
2919 hkey = openSharedDLLsKey();
2920 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2921 if (rc != ERROR_SUCCESS)
2927 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2931 hkey = openSharedDLLsKey();
2933 msi_reg_set_val_dword( hkey, path, count );
2935 RegDeleteValueW(hkey,path);
2941 * Return TRUE if the count should be written out and FALSE if not
2943 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2945 MSIFEATURE *feature;
2949 /* only refcount DLLs */
2950 if (comp->KeyPath == NULL ||
2951 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2952 comp->Attributes & msidbComponentAttributesODBCDataSource)
2956 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2957 write = (count > 0);
2959 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2963 /* increment counts */
2964 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2968 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2971 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2973 if ( cl->component == comp )
2978 /* decrement counts */
2979 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2983 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2986 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2988 if ( cl->component == comp )
2993 /* ref count all the files in the component */
2998 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3000 if (file->Component == comp)
3001 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3005 /* add a count for permanent */
3006 if (comp->Attributes & msidbComponentAttributesPermanent)
3009 comp->RefCount = count;
3012 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3015 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3017 WCHAR squished_pc[GUID_SIZE];
3018 WCHAR squished_cc[GUID_SIZE];
3025 squash_guid(package->ProductCode,squished_pc);
3026 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3028 msi_set_sourcedir_props(package, FALSE);
3030 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3034 ui_progress(package,2,0,0,0);
3035 if (!comp->ComponentId)
3038 squash_guid(comp->ComponentId,squished_cc);
3040 msi_free(comp->FullKeypath);
3041 comp->FullKeypath = resolve_keypath( package, comp );
3043 ACTION_RefCountComponent( package, comp );
3045 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3046 debugstr_w(comp->Component),
3047 debugstr_w(squished_cc),
3048 debugstr_w(comp->FullKeypath),
3050 comp->ActionRequest);
3052 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3053 comp->ActionRequest == INSTALLSTATE_SOURCE)
3055 if (!comp->FullKeypath)
3058 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3059 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3062 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3065 if (rc != ERROR_SUCCESS)
3068 if (comp->Attributes & msidbComponentAttributesPermanent)
3070 static const WCHAR szPermKey[] =
3071 { '0','0','0','0','0','0','0','0','0','0','0','0',
3072 '0','0','0','0','0','0','0','0','0','0','0','0',
3073 '0','0','0','0','0','0','0','0',0 };
3075 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3078 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3079 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3085 WCHAR source[MAX_PATH];
3086 WCHAR base[MAX_PATH];
3089 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3090 static const WCHAR query[] = {
3091 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3092 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3093 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3094 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3095 '`','D','i','s','k','I','d','`',0};
3097 file = get_loaded_file(package, comp->KeyPath);
3101 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3102 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3103 ptr2 = strrchrW(source, '\\') + 1;
3104 msiobj_release(&row->hdr);
3106 lstrcpyW(base, package->PackagePath);
3107 ptr = strrchrW(base, '\\');
3110 sourcepath = resolve_file_source(package, file);
3111 ptr = sourcepath + lstrlenW(base);
3112 lstrcpyW(ptr2, ptr);
3113 msi_free(sourcepath);
3115 msi_reg_set_val_str(hkey, squished_pc, source);
3119 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3121 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3122 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3124 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3126 comp->Action = comp->ActionRequest;
3129 uirow = MSI_CreateRecord(3);
3130 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3131 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3132 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3133 ui_actiondata(package,szProcessComponents,uirow);
3134 msiobj_release( &uirow->hdr );
3137 return ERROR_SUCCESS;
3148 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3149 LPWSTR lpszName, LONG_PTR lParam)
3152 typelib_struct *tl_struct = (typelib_struct*) lParam;
3153 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3157 if (!IS_INTRESOURCE(lpszName))
3159 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3163 sz = strlenW(tl_struct->source)+4;
3164 sz *= sizeof(WCHAR);
3166 if ((INT_PTR)lpszName == 1)
3167 tl_struct->path = strdupW(tl_struct->source);
3170 tl_struct->path = msi_alloc(sz);
3171 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3174 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3175 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3178 msi_free(tl_struct->path);
3179 tl_struct->path = NULL;
3184 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3185 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3187 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3191 msi_free(tl_struct->path);
3192 tl_struct->path = NULL;
3194 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3195 ITypeLib_Release(tl_struct->ptLib);
3200 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3202 MSIPACKAGE* package = param;
3206 typelib_struct tl_struct;
3211 component = MSI_RecordGetString(row,3);
3212 comp = get_loaded_component(package,component);
3214 return ERROR_SUCCESS;
3218 TRACE("component is disabled\n");
3219 return ERROR_SUCCESS;
3222 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3224 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3225 comp->Action = comp->Installed;
3226 return ERROR_SUCCESS;
3228 comp->Action = INSTALLSTATE_LOCAL;
3230 file = get_loaded_file( package, comp->KeyPath );
3232 return ERROR_SUCCESS;
3234 ui_actiondata( package, szRegisterTypeLibraries, row );
3236 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3240 guid = MSI_RecordGetString(row,1);
3241 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3242 tl_struct.source = strdupW( file->TargetPath );
3243 tl_struct.path = NULL;
3245 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3246 (LONG_PTR)&tl_struct);
3254 helpid = MSI_RecordGetString(row,6);
3257 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3258 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3262 ERR("Failed to register type library %s\n",
3263 debugstr_w(tl_struct.path));
3265 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3267 ITypeLib_Release(tl_struct.ptLib);
3268 msi_free(tl_struct.path);
3271 ERR("Failed to load type library %s\n",
3272 debugstr_w(tl_struct.source));
3274 FreeLibrary(module);
3275 msi_free(tl_struct.source);
3279 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3282 ERR("Failed to load type library: %08x\n", hr);
3283 return ERROR_INSTALL_FAILURE;
3286 ITypeLib_Release(tlib);
3289 return ERROR_SUCCESS;
3292 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3295 * OK this is a bit confusing.. I am given a _Component key and I believe
3296 * that the file that is being registered as a type library is the "key file
3297 * of that component" which I interpret to mean "The file in the KeyPath of
3302 static const WCHAR Query[] =
3303 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3304 '`','T','y','p','e','L','i','b','`',0};
3306 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3307 if (rc != ERROR_SUCCESS)
3308 return ERROR_SUCCESS;
3310 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3311 msiobj_release(&view->hdr);
3315 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3317 MSIPACKAGE *package = param;
3318 LPCWSTR component, guid;
3326 component = MSI_RecordGetString( row, 3 );
3327 comp = get_loaded_component( package, component );
3329 return ERROR_SUCCESS;
3333 TRACE("component is disabled\n");
3334 return ERROR_SUCCESS;
3337 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3339 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3340 comp->Action = comp->Installed;
3341 return ERROR_SUCCESS;
3343 comp->Action = INSTALLSTATE_ABSENT;
3345 ui_actiondata( package, szUnregisterTypeLibraries, row );
3347 guid = MSI_RecordGetString( row, 1 );
3348 CLSIDFromString( (LPCWSTR)guid, &libid );
3349 version = MSI_RecordGetInteger( row, 4 );
3350 language = MSI_RecordGetInteger( row, 2 );
3353 syskind = SYS_WIN64;
3355 syskind = SYS_WIN32;
3358 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3361 WARN("Failed to unregister typelib: %08x\n", hr);
3364 return ERROR_SUCCESS;
3367 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3371 static const WCHAR query[] =
3372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3373 '`','T','y','p','e','L','i','b','`',0};
3375 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3376 if (rc != ERROR_SUCCESS)
3377 return ERROR_SUCCESS;
3379 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3380 msiobj_release( &view->hdr );
3384 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3386 static const WCHAR szlnk[] = {'.','l','n','k',0};
3387 LPCWSTR directory, extension;
3388 LPWSTR link_folder, link_file, filename;
3390 directory = MSI_RecordGetString( row, 2 );
3391 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3393 /* may be needed because of a bug somewhere else */
3394 create_full_pathW( link_folder );
3396 filename = msi_dup_record_field( row, 3 );
3397 reduce_to_longfilename( filename );
3399 extension = strchrW( filename, '.' );
3400 if (!extension || strcmpiW( extension, szlnk ))
3402 int len = strlenW( filename );
3403 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3404 memcpy( filename + len, szlnk, sizeof(szlnk) );
3406 link_file = build_directory_name( 2, link_folder, filename );
3407 msi_free( link_folder );
3408 msi_free( filename );
3413 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3415 MSIPACKAGE *package = param;
3416 LPWSTR link_file, deformated, path;
3417 LPCWSTR component, target;
3419 IShellLinkW *sl = NULL;
3420 IPersistFile *pf = NULL;
3423 component = MSI_RecordGetString(row, 4);
3424 comp = get_loaded_component(package, component);
3426 return ERROR_SUCCESS;
3430 TRACE("component is disabled\n");
3431 return ERROR_SUCCESS;
3434 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3436 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3437 comp->Action = comp->Installed;
3438 return ERROR_SUCCESS;
3440 comp->Action = INSTALLSTATE_LOCAL;
3442 ui_actiondata(package,szCreateShortcuts,row);
3444 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3445 &IID_IShellLinkW, (LPVOID *) &sl );
3449 ERR("CLSID_ShellLink not available\n");
3453 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3456 ERR("QueryInterface(IID_IPersistFile) failed\n");
3460 target = MSI_RecordGetString(row, 5);
3461 if (strchrW(target, '['))
3463 deformat_string(package, target, &deformated);
3464 IShellLinkW_SetPath(sl,deformated);
3465 msi_free(deformated);
3469 FIXME("poorly handled shortcut format, advertised shortcut\n");
3470 IShellLinkW_SetPath(sl,comp->FullKeypath);
3473 if (!MSI_RecordIsNull(row,6))
3475 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3476 deformat_string(package, arguments, &deformated);
3477 IShellLinkW_SetArguments(sl,deformated);
3478 msi_free(deformated);
3481 if (!MSI_RecordIsNull(row,7))
3483 LPCWSTR description = MSI_RecordGetString(row, 7);
3484 IShellLinkW_SetDescription(sl, description);
3487 if (!MSI_RecordIsNull(row,8))
3488 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3490 if (!MSI_RecordIsNull(row,9))
3493 LPCWSTR icon = MSI_RecordGetString(row, 9);
3495 path = build_icon_path(package, icon);
3496 index = MSI_RecordGetInteger(row,10);
3498 /* no value means 0 */
3499 if (index == MSI_NULL_INTEGER)
3502 IShellLinkW_SetIconLocation(sl, path, index);
3506 if (!MSI_RecordIsNull(row,11))
3507 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3509 if (!MSI_RecordIsNull(row,12))
3511 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3512 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3514 IShellLinkW_SetWorkingDirectory(sl, path);
3518 link_file = get_link_file(package, row);
3520 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3521 IPersistFile_Save(pf, link_file, FALSE);
3523 msi_free(link_file);
3527 IPersistFile_Release( pf );
3529 IShellLinkW_Release( sl );
3531 return ERROR_SUCCESS;
3534 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3539 static const WCHAR Query[] =
3540 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3541 '`','S','h','o','r','t','c','u','t','`',0};
3543 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3544 if (rc != ERROR_SUCCESS)
3545 return ERROR_SUCCESS;
3547 res = CoInitialize( NULL );
3549 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3550 msiobj_release(&view->hdr);
3558 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3560 MSIPACKAGE *package = param;
3565 component = MSI_RecordGetString( row, 4 );
3566 comp = get_loaded_component( package, component );
3568 return ERROR_SUCCESS;
3572 TRACE("component is disabled\n");
3573 return ERROR_SUCCESS;
3576 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3578 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3579 comp->Action = comp->Installed;
3580 return ERROR_SUCCESS;
3582 comp->Action = INSTALLSTATE_ABSENT;
3584 ui_actiondata( package, szRemoveShortcuts, row );
3586 link_file = get_link_file( package, row );
3588 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3589 if (!DeleteFileW( link_file ))
3591 WARN("Failed to remove shortcut file %u\n", GetLastError());
3593 msi_free( link_file );
3595 return ERROR_SUCCESS;
3598 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3602 static const WCHAR query[] =
3603 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3604 '`','S','h','o','r','t','c','u','t','`',0};
3606 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3607 if (rc != ERROR_SUCCESS)
3608 return ERROR_SUCCESS;
3610 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3611 msiobj_release( &view->hdr );
3616 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3618 MSIPACKAGE* package = param;
3626 FileName = MSI_RecordGetString(row,1);
3629 ERR("Unable to get FileName\n");
3630 return ERROR_SUCCESS;
3633 FilePath = build_icon_path(package,FileName);
3635 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3637 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3638 FILE_ATTRIBUTE_NORMAL, NULL);
3640 if (the_file == INVALID_HANDLE_VALUE)
3642 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3644 return ERROR_SUCCESS;
3651 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3652 if (rc != ERROR_SUCCESS)
3654 ERR("Failed to get stream\n");
3655 CloseHandle(the_file);
3656 DeleteFileW(FilePath);
3659 WriteFile(the_file,buffer,sz,&write,NULL);
3660 } while (sz == 1024);
3663 CloseHandle(the_file);
3665 return ERROR_SUCCESS;
3668 static UINT msi_publish_icons(MSIPACKAGE *package)
3673 static const WCHAR query[]= {
3674 'S','E','L','E','C','T',' ','*',' ',
3675 'F','R','O','M',' ','`','I','c','o','n','`',0};
3677 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3678 if (r == ERROR_SUCCESS)
3680 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3681 msiobj_release(&view->hdr);
3684 return ERROR_SUCCESS;
3687 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3693 MSISOURCELISTINFO *info;
3695 r = RegCreateKeyW(hkey, szSourceList, &source);
3696 if (r != ERROR_SUCCESS)
3699 RegCloseKey(source);
3701 buffer = strrchrW(package->PackagePath, '\\') + 1;
3702 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3703 package->Context, MSICODE_PRODUCT,
3704 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3705 if (r != ERROR_SUCCESS)
3708 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3709 package->Context, MSICODE_PRODUCT,
3710 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3711 if (r != ERROR_SUCCESS)
3714 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3715 package->Context, MSICODE_PRODUCT,
3716 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3717 if (r != ERROR_SUCCESS)
3720 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3722 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3723 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3724 info->options, info->value);
3726 MsiSourceListSetInfoW(package->ProductCode, NULL,
3727 info->context, info->options,
3728 info->property, info->value);
3731 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3733 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3734 disk->context, disk->options,
3735 disk->disk_id, disk->volume_label, disk->disk_prompt);
3738 return ERROR_SUCCESS;
3741 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3743 MSIHANDLE hdb, suminfo;
3744 WCHAR guids[MAX_PATH];
3745 WCHAR packcode[SQUISH_GUID_SIZE];
3752 static const WCHAR szProductLanguage[] =
3753 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3754 static const WCHAR szARPProductIcon[] =
3755 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3756 static const WCHAR szProductVersion[] =
3757 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3758 static const WCHAR szAssignment[] =
3759 {'A','s','s','i','g','n','m','e','n','t',0};
3760 static const WCHAR szAdvertiseFlags[] =
3761 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3762 static const WCHAR szClients[] =
3763 {'C','l','i','e','n','t','s',0};
3764 static const WCHAR szColon[] = {':',0};
3766 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3767 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3770 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3771 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3774 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3776 buffer = msi_dup_property(package->db, szARPProductIcon);
3779 LPWSTR path = build_icon_path(package,buffer);
3780 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3785 buffer = msi_dup_property(package->db, szProductVersion);
3788 DWORD verdword = msi_version_str_to_dword(buffer);
3789 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3793 msi_reg_set_val_dword(hkey, szAssignment, 0);
3794 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3795 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3796 msi_reg_set_val_str(hkey, szClients, szColon);
3798 hdb = alloc_msihandle(&package->db->hdr);
3800 return ERROR_NOT_ENOUGH_MEMORY;
3802 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3803 MsiCloseHandle(hdb);
3804 if (r != ERROR_SUCCESS)
3808 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3809 NULL, guids, &size);
3810 if (r != ERROR_SUCCESS)
3813 ptr = strchrW(guids, ';');
3815 squash_guid(guids, packcode);
3816 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3819 MsiCloseHandle(suminfo);
3820 return ERROR_SUCCESS;
3823 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3828 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3830 upgrade = msi_dup_property(package->db, szUpgradeCode);
3832 return ERROR_SUCCESS;
3834 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3836 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3837 if (r != ERROR_SUCCESS)
3842 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3843 if (r != ERROR_SUCCESS)
3847 squash_guid(package->ProductCode, squashed_pc);
3848 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3857 static BOOL msi_check_publish(MSIPACKAGE *package)
3859 MSIFEATURE *feature;
3861 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3863 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3870 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3872 MSIFEATURE *feature;
3874 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3876 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3883 static UINT msi_publish_patches( MSIPACKAGE *package )
3885 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3886 WCHAR patch_squashed[GUID_SIZE];
3887 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
3889 MSIPATCHINFO *patch;
3891 WCHAR *p, *all_patches = NULL;
3894 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
3895 if (r != ERROR_SUCCESS)
3896 return ERROR_FUNCTION_FAILED;
3898 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3899 if (res != ERROR_SUCCESS)
3901 r = ERROR_FUNCTION_FAILED;
3905 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3906 if (r != ERROR_SUCCESS)
3909 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3911 squash_guid( patch->patchcode, patch_squashed );
3912 len += strlenW( patch_squashed ) + 1;
3915 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3919 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3923 squash_guid( patch->patchcode, p );
3924 p += strlenW( p ) + 1;
3926 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3927 (const BYTE *)patch->transforms,
3928 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3929 if (res != ERROR_SUCCESS)
3932 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3933 if (r != ERROR_SUCCESS)
3936 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3937 (const BYTE *)patch->localfile,
3938 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3939 RegCloseKey( patch_key );
3940 if (res != ERROR_SUCCESS)
3943 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3944 if (res != ERROR_SUCCESS)
3947 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
3948 RegCloseKey( patch_key );
3949 if (res != ERROR_SUCCESS)
3953 all_patches[len] = 0;
3954 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3955 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3956 if (res != ERROR_SUCCESS)
3959 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3960 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3961 if (res != ERROR_SUCCESS)
3962 r = ERROR_FUNCTION_FAILED;
3965 RegCloseKey( product_patches_key );
3966 RegCloseKey( patches_key );
3967 RegCloseKey( product_key );
3968 msi_free( all_patches );
3973 * 99% of the work done here is only done for
3974 * advertised installs. However this is where the
3975 * Icon table is processed and written out
3976 * so that is what I am going to do here.
3978 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3981 HKEY hukey = NULL, hudkey = NULL;
3984 if (!list_empty(&package->patches))
3986 rc = msi_publish_patches(package);
3987 if (rc != ERROR_SUCCESS)
3991 /* FIXME: also need to publish if the product is in advertise mode */
3992 if (!msi_check_publish(package))
3993 return ERROR_SUCCESS;
3995 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3997 if (rc != ERROR_SUCCESS)
4000 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4001 NULL, &hudkey, TRUE);
4002 if (rc != ERROR_SUCCESS)
4005 rc = msi_publish_upgrade_code(package);
4006 if (rc != ERROR_SUCCESS)
4009 rc = msi_publish_product_properties(package, hukey);
4010 if (rc != ERROR_SUCCESS)
4013 rc = msi_publish_sourcelist(package, hukey);
4014 if (rc != ERROR_SUCCESS)
4017 rc = msi_publish_icons(package);
4020 uirow = MSI_CreateRecord( 1 );
4021 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4022 ui_actiondata( package, szPublishProduct, uirow );
4023 msiobj_release( &uirow->hdr );
4026 RegCloseKey(hudkey);
4031 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4033 WCHAR *filename, *ptr, *folder, *ret;
4034 const WCHAR *dirprop;
4036 filename = msi_dup_record_field( row, 2 );
4037 if (filename && (ptr = strchrW( filename, '|' )))
4042 dirprop = MSI_RecordGetString( row, 3 );
4045 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4047 folder = msi_dup_property( package->db, dirprop );
4050 folder = msi_dup_property( package->db, szWindowsFolder );
4054 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4055 msi_free( filename );
4059 ret = build_directory_name( 2, folder, ptr );
4061 msi_free( filename );
4066 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4068 MSIPACKAGE *package = param;
4069 LPCWSTR component, section, key, value, identifier;
4070 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4075 component = MSI_RecordGetString(row, 8);
4076 comp = get_loaded_component(package,component);
4078 return ERROR_SUCCESS;
4082 TRACE("component is disabled\n");
4083 return ERROR_SUCCESS;
4086 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4088 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4089 comp->Action = comp->Installed;
4090 return ERROR_SUCCESS;
4092 comp->Action = INSTALLSTATE_LOCAL;
4094 identifier = MSI_RecordGetString(row,1);
4095 section = MSI_RecordGetString(row,4);
4096 key = MSI_RecordGetString(row,5);
4097 value = MSI_RecordGetString(row,6);
4098 action = MSI_RecordGetInteger(row,7);
4100 deformat_string(package,section,&deformated_section);
4101 deformat_string(package,key,&deformated_key);
4102 deformat_string(package,value,&deformated_value);
4104 fullname = get_ini_file_name(package, row);
4108 TRACE("Adding value %s to section %s in %s\n",
4109 debugstr_w(deformated_key), debugstr_w(deformated_section),
4110 debugstr_w(fullname));
4111 WritePrivateProfileStringW(deformated_section, deformated_key,
4112 deformated_value, fullname);
4114 else if (action == 1)
4117 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4118 returned, 10, fullname);
4119 if (returned[0] == 0)
4121 TRACE("Adding value %s to section %s in %s\n",
4122 debugstr_w(deformated_key), debugstr_w(deformated_section),
4123 debugstr_w(fullname));
4125 WritePrivateProfileStringW(deformated_section, deformated_key,
4126 deformated_value, fullname);
4129 else if (action == 3)
4130 FIXME("Append to existing section not yet implemented\n");
4132 uirow = MSI_CreateRecord(4);
4133 MSI_RecordSetStringW(uirow,1,identifier);
4134 MSI_RecordSetStringW(uirow,2,deformated_section);
4135 MSI_RecordSetStringW(uirow,3,deformated_key);
4136 MSI_RecordSetStringW(uirow,4,deformated_value);
4137 ui_actiondata(package,szWriteIniValues,uirow);
4138 msiobj_release( &uirow->hdr );
4141 msi_free(deformated_key);
4142 msi_free(deformated_value);
4143 msi_free(deformated_section);
4144 return ERROR_SUCCESS;
4147 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4151 static const WCHAR ExecSeqQuery[] =
4152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4153 '`','I','n','i','F','i','l','e','`',0};
4155 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4156 if (rc != ERROR_SUCCESS)
4158 TRACE("no IniFile table\n");
4159 return ERROR_SUCCESS;
4162 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4163 msiobj_release(&view->hdr);
4167 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4169 MSIPACKAGE *package = param;
4170 LPCWSTR component, section, key, value, identifier;
4171 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4176 component = MSI_RecordGetString( row, 8 );
4177 comp = get_loaded_component( package, component );
4179 return ERROR_SUCCESS;
4183 TRACE("component is disabled\n");
4184 return ERROR_SUCCESS;
4187 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4189 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4190 comp->Action = comp->Installed;
4191 return ERROR_SUCCESS;
4193 comp->Action = INSTALLSTATE_ABSENT;
4195 identifier = MSI_RecordGetString( row, 1 );
4196 section = MSI_RecordGetString( row, 4 );
4197 key = MSI_RecordGetString( row, 5 );
4198 value = MSI_RecordGetString( row, 6 );
4199 action = MSI_RecordGetInteger( row, 7 );
4201 deformat_string( package, section, &deformated_section );
4202 deformat_string( package, key, &deformated_key );
4203 deformat_string( package, value, &deformated_value );
4205 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4207 filename = get_ini_file_name( package, row );
4209 TRACE("Removing key %s from section %s in %s\n",
4210 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4212 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4214 WARN("Unable to remove key %u\n", GetLastError());
4216 msi_free( filename );
4219 FIXME("Unsupported action %d\n", action);
4222 uirow = MSI_CreateRecord( 4 );
4223 MSI_RecordSetStringW( uirow, 1, identifier );
4224 MSI_RecordSetStringW( uirow, 2, deformated_section );
4225 MSI_RecordSetStringW( uirow, 3, deformated_key );
4226 MSI_RecordSetStringW( uirow, 4, deformated_value );
4227 ui_actiondata( package, szRemoveIniValues, uirow );
4228 msiobj_release( &uirow->hdr );
4230 msi_free( deformated_key );
4231 msi_free( deformated_value );
4232 msi_free( deformated_section );
4233 return ERROR_SUCCESS;
4236 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4238 MSIPACKAGE *package = param;
4239 LPCWSTR component, section, key, value, identifier;
4240 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4245 component = MSI_RecordGetString( row, 8 );
4246 comp = get_loaded_component( package, component );
4248 return ERROR_SUCCESS;
4252 TRACE("component is disabled\n");
4253 return ERROR_SUCCESS;
4256 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4258 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4259 comp->Action = comp->Installed;
4260 return ERROR_SUCCESS;
4262 comp->Action = INSTALLSTATE_LOCAL;
4264 identifier = MSI_RecordGetString( row, 1 );
4265 section = MSI_RecordGetString( row, 4 );
4266 key = MSI_RecordGetString( row, 5 );
4267 value = MSI_RecordGetString( row, 6 );
4268 action = MSI_RecordGetInteger( row, 7 );
4270 deformat_string( package, section, &deformated_section );
4271 deformat_string( package, key, &deformated_key );
4272 deformat_string( package, value, &deformated_value );
4274 if (action == msidbIniFileActionRemoveLine)
4276 filename = get_ini_file_name( package, row );
4278 TRACE("Removing key %s from section %s in %s\n",
4279 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4281 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4283 WARN("Unable to remove key %u\n", GetLastError());
4285 msi_free( filename );
4288 FIXME("Unsupported action %d\n", action);
4290 uirow = MSI_CreateRecord( 4 );
4291 MSI_RecordSetStringW( uirow, 1, identifier );
4292 MSI_RecordSetStringW( uirow, 2, deformated_section );
4293 MSI_RecordSetStringW( uirow, 3, deformated_key );
4294 MSI_RecordSetStringW( uirow, 4, deformated_value );
4295 ui_actiondata( package, szRemoveIniValues, uirow );
4296 msiobj_release( &uirow->hdr );
4298 msi_free( deformated_key );
4299 msi_free( deformated_value );
4300 msi_free( deformated_section );
4301 return ERROR_SUCCESS;
4304 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4308 static const WCHAR query[] =
4309 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4310 '`','I','n','i','F','i','l','e','`',0};
4311 static const WCHAR remove_query[] =
4312 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4313 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4315 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4316 if (rc == ERROR_SUCCESS)
4318 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4319 msiobj_release( &view->hdr );
4320 if (rc != ERROR_SUCCESS)
4324 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4325 if (rc == ERROR_SUCCESS)
4327 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4328 msiobj_release( &view->hdr );
4329 if (rc != ERROR_SUCCESS)
4333 return ERROR_SUCCESS;
4336 static void register_dll( const WCHAR *dll, BOOL unregister )
4340 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4343 HRESULT (WINAPI *func_ptr)( void );
4344 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4346 func_ptr = (void *)GetProcAddress( hmod, func );
4349 HRESULT hr = func_ptr();
4351 WARN("failed to register dll 0x%08x\n", hr);
4354 WARN("entry point %s not found\n", func);
4355 FreeLibrary( hmod );
4358 WARN("failed to load library %u\n", GetLastError());
4361 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4363 MSIPACKAGE *package = param;
4368 filename = MSI_RecordGetString(row,1);
4369 file = get_loaded_file( package, filename );
4373 ERR("Unable to find file id %s\n",debugstr_w(filename));
4374 return ERROR_SUCCESS;
4377 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4379 register_dll( file->TargetPath, FALSE );
4381 uirow = MSI_CreateRecord( 2 );
4382 MSI_RecordSetStringW( uirow, 1, filename );
4383 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4384 ui_actiondata( package, szSelfRegModules, uirow );
4385 msiobj_release( &uirow->hdr );
4387 return ERROR_SUCCESS;
4390 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4394 static const WCHAR ExecSeqQuery[] =
4395 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4396 '`','S','e','l','f','R','e','g','`',0};
4398 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4399 if (rc != ERROR_SUCCESS)
4401 TRACE("no SelfReg table\n");
4402 return ERROR_SUCCESS;
4405 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4406 msiobj_release(&view->hdr);
4408 return ERROR_SUCCESS;
4411 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4413 MSIPACKAGE *package = param;
4418 filename = MSI_RecordGetString( row, 1 );
4419 file = get_loaded_file( package, filename );
4423 ERR("Unable to find file id %s\n", debugstr_w(filename));
4424 return ERROR_SUCCESS;
4427 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4429 register_dll( file->TargetPath, TRUE );
4431 uirow = MSI_CreateRecord( 2 );
4432 MSI_RecordSetStringW( uirow, 1, filename );
4433 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4434 ui_actiondata( package, szSelfUnregModules, uirow );
4435 msiobj_release( &uirow->hdr );
4437 return ERROR_SUCCESS;
4440 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4444 static const WCHAR query[] =
4445 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4446 '`','S','e','l','f','R','e','g','`',0};
4448 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4449 if (rc != ERROR_SUCCESS)
4451 TRACE("no SelfReg table\n");
4452 return ERROR_SUCCESS;
4455 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4456 msiobj_release( &view->hdr );
4458 return ERROR_SUCCESS;
4461 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4463 MSIFEATURE *feature;
4465 HKEY hkey = NULL, userdata = NULL;
4467 if (!msi_check_publish(package))
4468 return ERROR_SUCCESS;
4470 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4472 if (rc != ERROR_SUCCESS)
4475 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4477 if (rc != ERROR_SUCCESS)
4480 /* here the guids are base 85 encoded */
4481 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4487 BOOL absent = FALSE;
4490 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4491 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4492 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4495 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4499 if (feature->Feature_Parent)
4500 size += strlenW( feature->Feature_Parent )+2;
4502 data = msi_alloc(size * sizeof(WCHAR));
4505 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4507 MSICOMPONENT* component = cl->component;
4511 if (component->ComponentId)
4513 TRACE("From %s\n",debugstr_w(component->ComponentId));
4514 CLSIDFromString(component->ComponentId, &clsid);
4515 encode_base85_guid(&clsid,buf);
4516 TRACE("to %s\n",debugstr_w(buf));
4521 if (feature->Feature_Parent)
4523 static const WCHAR sep[] = {'\2',0};
4525 strcatW(data,feature->Feature_Parent);
4528 msi_reg_set_val_str( userdata, feature->Feature, data );
4532 if (feature->Feature_Parent)
4533 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4536 size += sizeof(WCHAR);
4537 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4538 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4542 size += 2*sizeof(WCHAR);
4543 data = msi_alloc(size);
4546 if (feature->Feature_Parent)
4547 strcpyW( &data[1], feature->Feature_Parent );
4548 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4554 uirow = MSI_CreateRecord( 1 );
4555 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4556 ui_actiondata( package, szPublishFeatures, uirow);
4557 msiobj_release( &uirow->hdr );
4558 /* FIXME: call ui_progress? */
4563 RegCloseKey(userdata);
4567 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4573 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4575 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4577 if (r == ERROR_SUCCESS)
4579 RegDeleteValueW(hkey, feature->Feature);
4583 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4585 if (r == ERROR_SUCCESS)
4587 RegDeleteValueW(hkey, feature->Feature);
4591 uirow = MSI_CreateRecord( 1 );
4592 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4593 ui_actiondata( package, szUnpublishFeatures, uirow );
4594 msiobj_release( &uirow->hdr );
4596 return ERROR_SUCCESS;
4599 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4601 MSIFEATURE *feature;
4603 if (!msi_check_unpublish(package))
4604 return ERROR_SUCCESS;
4606 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4608 msi_unpublish_feature(package, feature);
4611 return ERROR_SUCCESS;
4614 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4618 WCHAR date[9], *val, *buffer;
4619 const WCHAR *prop, *key;
4621 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4622 static const WCHAR szWindowsInstaller[] =
4623 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4624 static const WCHAR modpath_fmt[] =
4625 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4626 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4627 static const WCHAR szModifyPath[] =
4628 {'M','o','d','i','f','y','P','a','t','h',0};
4629 static const WCHAR szUninstallString[] =
4630 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4631 static const WCHAR szEstimatedSize[] =
4632 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4633 static const WCHAR szProductLanguage[] =
4634 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4635 static const WCHAR szProductVersion[] =
4636 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4637 static const WCHAR szDisplayVersion[] =
4638 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4639 static const WCHAR szInstallSource[] =
4640 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4641 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4642 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4643 static const WCHAR szAuthorizedCDFPrefix[] =
4644 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4645 static const WCHAR szARPCONTACT[] =
4646 {'A','R','P','C','O','N','T','A','C','T',0};
4647 static const WCHAR szContact[] =
4648 {'C','o','n','t','a','c','t',0};
4649 static const WCHAR szARPCOMMENTS[] =
4650 {'A','R','P','C','O','M','M','E','N','T','S',0};
4651 static const WCHAR szComments[] =
4652 {'C','o','m','m','e','n','t','s',0};
4653 static const WCHAR szProductName[] =
4654 {'P','r','o','d','u','c','t','N','a','m','e',0};
4655 static const WCHAR szDisplayName[] =
4656 {'D','i','s','p','l','a','y','N','a','m','e',0};
4657 static const WCHAR szARPHELPLINK[] =
4658 {'A','R','P','H','E','L','P','L','I','N','K',0};
4659 static const WCHAR szHelpLink[] =
4660 {'H','e','l','p','L','i','n','k',0};
4661 static const WCHAR szARPHELPTELEPHONE[] =
4662 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4663 static const WCHAR szHelpTelephone[] =
4664 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4665 static const WCHAR szARPINSTALLLOCATION[] =
4666 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4667 static const WCHAR szInstallLocation[] =
4668 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4669 static const WCHAR szManufacturer[] =
4670 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4671 static const WCHAR szPublisher[] =
4672 {'P','u','b','l','i','s','h','e','r',0};
4673 static const WCHAR szARPREADME[] =
4674 {'A','R','P','R','E','A','D','M','E',0};
4675 static const WCHAR szReadme[] =
4676 {'R','e','a','d','M','e',0};
4677 static const WCHAR szARPSIZE[] =
4678 {'A','R','P','S','I','Z','E',0};
4679 static const WCHAR szSize[] =
4680 {'S','i','z','e',0};
4681 static const WCHAR szARPURLINFOABOUT[] =
4682 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4683 static const WCHAR szURLInfoAbout[] =
4684 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4685 static const WCHAR szARPURLUPDATEINFO[] =
4686 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4687 static const WCHAR szURLUpdateInfo[] =
4688 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4690 static const WCHAR *propval[] = {
4691 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4692 szARPCONTACT, szContact,
4693 szARPCOMMENTS, szComments,
4694 szProductName, szDisplayName,
4695 szARPHELPLINK, szHelpLink,
4696 szARPHELPTELEPHONE, szHelpTelephone,
4697 szARPINSTALLLOCATION, szInstallLocation,
4698 cszSourceDir, szInstallSource,
4699 szManufacturer, szPublisher,
4700 szARPREADME, szReadme,
4702 szARPURLINFOABOUT, szURLInfoAbout,
4703 szARPURLUPDATEINFO, szURLUpdateInfo,
4706 const WCHAR **p = propval;
4712 val = msi_dup_property(package->db, prop);
4713 msi_reg_set_val_str(hkey, key, val);
4717 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4719 size = deformat_string(package, modpath_fmt, &buffer);
4720 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4721 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4724 /* FIXME: Write real Estimated Size when we have it */
4725 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4727 GetLocalTime(&systime);
4728 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4729 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4731 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4732 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4734 buffer = msi_dup_property(package->db, szProductVersion);
4735 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4738 DWORD verdword = msi_version_str_to_dword(buffer);
4740 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4741 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4742 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4746 return ERROR_SUCCESS;
4749 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4751 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4753 LPWSTR upgrade_code;
4758 /* FIXME: also need to publish if the product is in advertise mode */
4759 if (!msi_check_publish(package))
4760 return ERROR_SUCCESS;
4762 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4763 if (rc != ERROR_SUCCESS)
4766 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4767 NULL, &props, TRUE);
4768 if (rc != ERROR_SUCCESS)
4771 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4772 msi_free( package->db->localfile );
4773 package->db->localfile = NULL;
4775 rc = msi_publish_install_properties(package, hkey);
4776 if (rc != ERROR_SUCCESS)
4779 rc = msi_publish_install_properties(package, props);
4780 if (rc != ERROR_SUCCESS)
4783 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4786 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4787 squash_guid(package->ProductCode, squashed_pc);
4788 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4789 RegCloseKey(upgrade);
4790 msi_free(upgrade_code);
4794 uirow = MSI_CreateRecord( 1 );
4795 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4796 ui_actiondata( package, szRegisterProduct, uirow );
4797 msiobj_release( &uirow->hdr );
4800 return ERROR_SUCCESS;
4803 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4805 return execute_script(package,INSTALL_SCRIPT);
4808 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4810 WCHAR *upgrade, **features;
4811 BOOL full_uninstall = TRUE;
4812 MSIFEATURE *feature;
4813 MSIPATCHINFO *patch;
4815 static const WCHAR szUpgradeCode[] =
4816 {'U','p','g','r','a','d','e','C','o','d','e',0};
4818 features = msi_split_string(remove, ',');
4821 ERR("REMOVE feature list is empty!\n");
4822 return ERROR_FUNCTION_FAILED;
4825 if (!lstrcmpW(features[0], szAll))
4826 full_uninstall = TRUE;
4829 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4831 if (feature->Action != INSTALLSTATE_ABSENT)
4832 full_uninstall = FALSE;
4837 if (!full_uninstall)
4838 return ERROR_SUCCESS;
4840 MSIREG_DeleteProductKey(package->ProductCode);
4841 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4842 MSIREG_DeleteUninstallKey(package->ProductCode);
4844 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4846 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4847 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4851 MSIREG_DeleteUserProductKey(package->ProductCode);
4852 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4855 upgrade = msi_dup_property(package->db, szUpgradeCode);
4858 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4862 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4864 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4867 return ERROR_SUCCESS;
4870 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4875 /* turn off scheduling */
4876 package->script->CurrentlyScripting= FALSE;
4878 /* first do the same as an InstallExecute */
4879 rc = ACTION_InstallExecute(package);
4880 if (rc != ERROR_SUCCESS)
4883 /* then handle Commit Actions */
4884 rc = execute_script(package,COMMIT_SCRIPT);
4885 if (rc != ERROR_SUCCESS)
4888 remove = msi_dup_property(package->db, szRemove);
4890 rc = msi_unpublish_product(package, remove);
4896 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4898 static const WCHAR RunOnce[] = {
4899 'S','o','f','t','w','a','r','e','\\',
4900 'M','i','c','r','o','s','o','f','t','\\',
4901 'W','i','n','d','o','w','s','\\',
4902 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4903 'R','u','n','O','n','c','e',0};
4904 static const WCHAR InstallRunOnce[] = {
4905 'S','o','f','t','w','a','r','e','\\',
4906 'M','i','c','r','o','s','o','f','t','\\',
4907 'W','i','n','d','o','w','s','\\',
4908 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4909 'I','n','s','t','a','l','l','e','r','\\',
4910 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4912 static const WCHAR msiexec_fmt[] = {
4914 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4915 '\"','%','s','\"',0};
4916 static const WCHAR install_fmt[] = {
4917 '/','I',' ','\"','%','s','\"',' ',
4918 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4919 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4920 WCHAR buffer[256], sysdir[MAX_PATH];
4922 WCHAR squished_pc[100];
4924 squash_guid(package->ProductCode,squished_pc);
4926 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4927 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4928 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4931 msi_reg_set_val_str( hkey, squished_pc, buffer );
4934 TRACE("Reboot command %s\n",debugstr_w(buffer));
4936 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4937 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4939 msi_reg_set_val_str( hkey, squished_pc, buffer );
4942 return ERROR_INSTALL_SUSPEND;
4945 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4951 * We are currently doing what should be done here in the top level Install
4952 * however for Administrative and uninstalls this step will be needed
4954 if (!package->PackagePath)
4955 return ERROR_SUCCESS;
4957 msi_set_sourcedir_props(package, TRUE);
4959 attrib = GetFileAttributesW(package->db->path);
4960 if (attrib == INVALID_FILE_ATTRIBUTES)
4966 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4967 package->Context, MSICODE_PRODUCT,
4968 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4969 if (rc == ERROR_MORE_DATA)
4971 prompt = msi_alloc(size * sizeof(WCHAR));
4972 MsiSourceListGetInfoW(package->ProductCode, NULL,
4973 package->Context, MSICODE_PRODUCT,
4974 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4977 prompt = strdupW(package->db->path);
4979 msg = generate_error_string(package,1302,1,prompt);
4980 while(attrib == INVALID_FILE_ATTRIBUTES)
4982 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4985 rc = ERROR_INSTALL_USEREXIT;
4988 attrib = GetFileAttributesW(package->db->path);
4994 return ERROR_SUCCESS;
4999 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5002 LPWSTR buffer, productid = NULL;
5003 UINT i, rc = ERROR_SUCCESS;
5006 static const WCHAR szPropKeys[][80] =
5008 {'P','r','o','d','u','c','t','I','D',0},
5009 {'U','S','E','R','N','A','M','E',0},
5010 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5014 static const WCHAR szRegKeys[][80] =
5016 {'P','r','o','d','u','c','t','I','D',0},
5017 {'R','e','g','O','w','n','e','r',0},
5018 {'R','e','g','C','o','m','p','a','n','y',0},
5022 if (msi_check_unpublish(package))
5024 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5028 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5032 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5034 if (rc != ERROR_SUCCESS)
5037 for( i = 0; szPropKeys[i][0]; i++ )
5039 buffer = msi_dup_property( package->db, szPropKeys[i] );
5040 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5045 uirow = MSI_CreateRecord( 1 );
5046 MSI_RecordSetStringW( uirow, 1, productid );
5047 ui_actiondata( package, szRegisterUser, uirow );
5048 msiobj_release( &uirow->hdr );
5050 msi_free(productid);
5056 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5060 package->script->InWhatSequence |= SEQUENCE_EXEC;
5061 rc = ACTION_ProcessExecSequence(package,FALSE);
5066 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5068 MSIPACKAGE *package = param;
5069 LPCWSTR compgroupid, component, feature, qualifier, text;
5070 LPWSTR advertise = NULL, output = NULL;
5078 feature = MSI_RecordGetString(rec, 5);
5079 feat = get_loaded_feature(package, feature);
5081 return ERROR_SUCCESS;
5083 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5084 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5085 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5087 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5088 feat->Action = feat->Installed;
5089 return ERROR_SUCCESS;
5092 component = MSI_RecordGetString(rec, 3);
5093 comp = get_loaded_component(package, component);
5095 return ERROR_SUCCESS;
5097 compgroupid = MSI_RecordGetString(rec,1);
5098 qualifier = MSI_RecordGetString(rec,2);
5100 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5101 if (rc != ERROR_SUCCESS)
5104 text = MSI_RecordGetString(rec,4);
5105 advertise = create_component_advertise_string(package, comp, feature);
5107 sz = strlenW(advertise);
5110 sz += lstrlenW(text);
5113 sz *= sizeof(WCHAR);
5115 output = msi_alloc_zero(sz);
5116 strcpyW(output,advertise);
5117 msi_free(advertise);
5120 strcatW(output,text);
5122 msi_reg_set_val_multi_str( hkey, qualifier, output );
5129 uirow = MSI_CreateRecord( 2 );
5130 MSI_RecordSetStringW( uirow, 1, compgroupid );
5131 MSI_RecordSetStringW( uirow, 2, qualifier);
5132 ui_actiondata( package, szPublishComponents, uirow);
5133 msiobj_release( &uirow->hdr );
5134 /* FIXME: call ui_progress? */
5140 * At present I am ignorning the advertised components part of this and only
5141 * focusing on the qualified component sets
5143 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5147 static const WCHAR ExecSeqQuery[] =
5148 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5149 '`','P','u','b','l','i','s','h',
5150 'C','o','m','p','o','n','e','n','t','`',0};
5152 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5153 if (rc != ERROR_SUCCESS)
5154 return ERROR_SUCCESS;
5156 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5157 msiobj_release(&view->hdr);
5162 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5164 static const WCHAR szInstallerComponents[] = {
5165 'S','o','f','t','w','a','r','e','\\',
5166 'M','i','c','r','o','s','o','f','t','\\',
5167 'I','n','s','t','a','l','l','e','r','\\',
5168 'C','o','m','p','o','n','e','n','t','s','\\',0};
5170 MSIPACKAGE *package = param;
5171 LPCWSTR compgroupid, component, feature, qualifier;
5175 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5178 feature = MSI_RecordGetString( rec, 5 );
5179 feat = get_loaded_feature( package, feature );
5181 return ERROR_SUCCESS;
5183 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5185 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5186 feat->Action = feat->Installed;
5187 return ERROR_SUCCESS;
5190 component = MSI_RecordGetString( rec, 3 );
5191 comp = get_loaded_component( package, component );
5193 return ERROR_SUCCESS;
5195 compgroupid = MSI_RecordGetString( rec, 1 );
5196 qualifier = MSI_RecordGetString( rec, 2 );
5198 squash_guid( compgroupid, squashed );
5199 strcpyW( keypath, szInstallerComponents );
5200 strcatW( keypath, squashed );
5202 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5203 if (res != ERROR_SUCCESS)
5205 WARN("Unable to delete component key %d\n", res);
5208 uirow = MSI_CreateRecord( 2 );
5209 MSI_RecordSetStringW( uirow, 1, compgroupid );
5210 MSI_RecordSetStringW( uirow, 2, qualifier );
5211 ui_actiondata( package, szUnpublishComponents, uirow );
5212 msiobj_release( &uirow->hdr );
5214 return ERROR_SUCCESS;
5217 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5221 static const WCHAR query[] =
5222 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5223 '`','P','u','b','l','i','s','h',
5224 'C','o','m','p','o','n','e','n','t','`',0};
5226 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5227 if (rc != ERROR_SUCCESS)
5228 return ERROR_SUCCESS;
5230 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5231 msiobj_release( &view->hdr );
5236 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5238 MSIPACKAGE *package = param;
5241 SC_HANDLE hscm, service = NULL;
5242 LPCWSTR comp, depends, pass;
5243 LPWSTR name = NULL, disp = NULL;
5244 LPCWSTR load_order, serv_name, key;
5245 DWORD serv_type, start_type;
5248 static const WCHAR query[] =
5249 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5250 '`','C','o','m','p','o','n','e','n','t','`',' ',
5251 'W','H','E','R','E',' ',
5252 '`','C','o','m','p','o','n','e','n','t','`',' ',
5253 '=','\'','%','s','\'',0};
5255 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5258 ERR("Failed to open the SC Manager!\n");
5262 start_type = MSI_RecordGetInteger(rec, 5);
5263 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5266 depends = MSI_RecordGetString(rec, 8);
5267 if (depends && *depends)
5268 FIXME("Dependency list unhandled!\n");
5270 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5271 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5272 serv_type = MSI_RecordGetInteger(rec, 4);
5273 err_control = MSI_RecordGetInteger(rec, 6);
5274 load_order = MSI_RecordGetString(rec, 7);
5275 serv_name = MSI_RecordGetString(rec, 9);
5276 pass = MSI_RecordGetString(rec, 10);
5277 comp = MSI_RecordGetString(rec, 12);
5279 /* fetch the service path */
5280 row = MSI_QueryGetRecord(package->db, query, comp);
5283 ERR("Control query failed!\n");
5287 key = MSI_RecordGetString(row, 6);
5289 file = get_loaded_file(package, key);
5290 msiobj_release(&row->hdr);
5293 ERR("Failed to load the service file\n");
5297 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5298 start_type, err_control, file->TargetPath,
5299 load_order, NULL, NULL, serv_name, pass);
5302 if (GetLastError() != ERROR_SERVICE_EXISTS)
5303 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5307 CloseServiceHandle(service);
5308 CloseServiceHandle(hscm);
5312 return ERROR_SUCCESS;
5315 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5319 static const WCHAR ExecSeqQuery[] =
5320 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5321 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5323 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5324 if (rc != ERROR_SUCCESS)
5325 return ERROR_SUCCESS;
5327 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5328 msiobj_release(&view->hdr);
5333 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5334 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5336 LPCWSTR *vector, *temp_vector;
5340 static const WCHAR separator[] = {'[','~',']',0};
5343 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5348 vector = msi_alloc(sizeof(LPWSTR));
5356 vector[*numargs - 1] = p;
5358 if ((q = strstrW(p, separator)))
5362 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5368 vector = temp_vector;
5377 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5379 MSIPACKAGE *package = param;
5382 SC_HANDLE scm = NULL, service = NULL;
5383 LPCWSTR component, *vector = NULL;
5384 LPWSTR name, args, display_name = NULL;
5385 DWORD event, numargs, len;
5386 UINT r = ERROR_FUNCTION_FAILED;
5388 component = MSI_RecordGetString(rec, 6);
5389 comp = get_loaded_component(package, component);
5391 return ERROR_SUCCESS;
5395 TRACE("component is disabled\n");
5396 return ERROR_SUCCESS;
5399 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5401 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5402 comp->Action = comp->Installed;
5403 return ERROR_SUCCESS;
5405 comp->Action = INSTALLSTATE_LOCAL;
5407 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5408 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5409 event = MSI_RecordGetInteger(rec, 3);
5411 if (!(event & msidbServiceControlEventStart))
5417 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5420 ERR("Failed to open the service control manager\n");
5425 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5426 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5428 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5429 GetServiceDisplayNameW( scm, name, display_name, &len );
5432 service = OpenServiceW(scm, name, SERVICE_START);
5435 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5439 vector = msi_service_args_to_vector(args, &numargs);
5441 if (!StartServiceW(service, numargs, vector) &&
5442 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5444 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5451 uirow = MSI_CreateRecord( 2 );
5452 MSI_RecordSetStringW( uirow, 1, display_name );
5453 MSI_RecordSetStringW( uirow, 2, name );
5454 ui_actiondata( package, szStartServices, uirow );
5455 msiobj_release( &uirow->hdr );
5457 CloseServiceHandle(service);
5458 CloseServiceHandle(scm);
5463 msi_free(display_name);
5467 static UINT ACTION_StartServices( MSIPACKAGE *package )
5472 static const WCHAR query[] = {
5473 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5474 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5476 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5477 if (rc != ERROR_SUCCESS)
5478 return ERROR_SUCCESS;
5480 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5481 msiobj_release(&view->hdr);
5486 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5488 DWORD i, needed, count;
5489 ENUM_SERVICE_STATUSW *dependencies;
5493 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5494 0, &needed, &count))
5497 if (GetLastError() != ERROR_MORE_DATA)
5500 dependencies = msi_alloc(needed);
5504 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5505 needed, &needed, &count))
5508 for (i = 0; i < count; i++)
5510 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5511 SERVICE_STOP | SERVICE_QUERY_STATUS);
5515 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5522 msi_free(dependencies);
5526 static UINT stop_service( LPCWSTR name )
5528 SC_HANDLE scm = NULL, service = NULL;
5529 SERVICE_STATUS status;
5530 SERVICE_STATUS_PROCESS ssp;
5533 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5536 WARN("Failed to open the SCM: %d\n", GetLastError());
5540 service = OpenServiceW(scm, name,
5542 SERVICE_QUERY_STATUS |
5543 SERVICE_ENUMERATE_DEPENDENTS);
5546 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5550 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5551 sizeof(SERVICE_STATUS_PROCESS), &needed))
5553 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5557 if (ssp.dwCurrentState == SERVICE_STOPPED)
5560 stop_service_dependents(scm, service);
5562 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5563 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5566 CloseServiceHandle(service);
5567 CloseServiceHandle(scm);
5569 return ERROR_SUCCESS;
5572 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5574 MSIPACKAGE *package = param;
5578 LPWSTR name = NULL, display_name = NULL;
5582 event = MSI_RecordGetInteger( rec, 3 );
5583 if (!(event & msidbServiceControlEventStop))
5584 return ERROR_SUCCESS;
5586 component = MSI_RecordGetString( rec, 6 );
5587 comp = get_loaded_component( package, component );
5589 return ERROR_SUCCESS;
5593 TRACE("component is disabled\n");
5594 return ERROR_SUCCESS;
5597 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5599 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5600 comp->Action = comp->Installed;
5601 return ERROR_SUCCESS;
5603 comp->Action = INSTALLSTATE_ABSENT;
5605 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5608 ERR("Failed to open the service control manager\n");
5613 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5614 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5616 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5617 GetServiceDisplayNameW( scm, name, display_name, &len );
5619 CloseServiceHandle( scm );
5621 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5622 stop_service( name );
5625 uirow = MSI_CreateRecord( 2 );
5626 MSI_RecordSetStringW( uirow, 1, display_name );
5627 MSI_RecordSetStringW( uirow, 2, name );
5628 ui_actiondata( package, szStopServices, uirow );
5629 msiobj_release( &uirow->hdr );
5632 msi_free( display_name );
5633 return ERROR_SUCCESS;
5636 static UINT ACTION_StopServices( MSIPACKAGE *package )
5641 static const WCHAR query[] = {
5642 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5643 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5645 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5646 if (rc != ERROR_SUCCESS)
5647 return ERROR_SUCCESS;
5649 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5650 msiobj_release(&view->hdr);
5655 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5657 MSIPACKAGE *package = param;
5661 LPWSTR name = NULL, display_name = NULL;
5663 SC_HANDLE scm = NULL, service = NULL;
5665 event = MSI_RecordGetInteger( rec, 3 );
5666 if (!(event & msidbServiceControlEventDelete))
5667 return ERROR_SUCCESS;
5669 component = MSI_RecordGetString(rec, 6);
5670 comp = get_loaded_component(package, component);
5672 return ERROR_SUCCESS;
5676 TRACE("component is disabled\n");
5677 return ERROR_SUCCESS;
5680 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5682 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5683 comp->Action = comp->Installed;
5684 return ERROR_SUCCESS;
5686 comp->Action = INSTALLSTATE_ABSENT;
5688 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5689 stop_service( name );
5691 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5694 WARN("Failed to open the SCM: %d\n", GetLastError());
5699 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5700 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5702 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5703 GetServiceDisplayNameW( scm, name, display_name, &len );
5706 service = OpenServiceW( scm, name, DELETE );
5709 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5713 if (!DeleteService( service ))
5714 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5717 uirow = MSI_CreateRecord( 2 );
5718 MSI_RecordSetStringW( uirow, 1, display_name );
5719 MSI_RecordSetStringW( uirow, 2, name );
5720 ui_actiondata( package, szDeleteServices, uirow );
5721 msiobj_release( &uirow->hdr );
5723 CloseServiceHandle( service );
5724 CloseServiceHandle( scm );
5726 msi_free( display_name );
5728 return ERROR_SUCCESS;
5731 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5736 static const WCHAR query[] = {
5737 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5738 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5740 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5741 if (rc != ERROR_SUCCESS)
5742 return ERROR_SUCCESS;
5744 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5745 msiobj_release( &view->hdr );
5750 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5754 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5756 if (!lstrcmpW(file->File, filename))
5763 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5765 MSIPACKAGE *package = param;
5766 LPWSTR driver, driver_path, ptr;
5767 WCHAR outpath[MAX_PATH];
5768 MSIFILE *driver_file, *setup_file;
5772 UINT r = ERROR_SUCCESS;
5774 static const WCHAR driver_fmt[] = {
5775 'D','r','i','v','e','r','=','%','s',0};
5776 static const WCHAR setup_fmt[] = {
5777 'S','e','t','u','p','=','%','s',0};
5778 static const WCHAR usage_fmt[] = {
5779 'F','i','l','e','U','s','a','g','e','=','1',0};
5781 desc = MSI_RecordGetString(rec, 3);
5783 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5784 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5788 ERR("ODBC Driver entry not found!\n");
5789 return ERROR_FUNCTION_FAILED;
5792 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5794 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5795 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5797 driver = msi_alloc(len * sizeof(WCHAR));
5799 return ERROR_OUTOFMEMORY;
5802 lstrcpyW(ptr, desc);
5803 ptr += lstrlenW(ptr) + 1;
5805 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5810 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5814 lstrcpyW(ptr, usage_fmt);
5815 ptr += lstrlenW(ptr) + 1;
5818 driver_path = strdupW(driver_file->TargetPath);
5819 ptr = strrchrW(driver_path, '\\');
5820 if (ptr) *ptr = '\0';
5822 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5823 NULL, ODBC_INSTALL_COMPLETE, &usage))
5825 ERR("Failed to install SQL driver!\n");
5826 r = ERROR_FUNCTION_FAILED;
5829 uirow = MSI_CreateRecord( 5 );
5830 MSI_RecordSetStringW( uirow, 1, desc );
5831 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5832 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5833 ui_actiondata( package, szInstallODBC, uirow );
5834 msiobj_release( &uirow->hdr );
5837 msi_free(driver_path);
5842 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5844 MSIPACKAGE *package = param;
5845 LPWSTR translator, translator_path, ptr;
5846 WCHAR outpath[MAX_PATH];
5847 MSIFILE *translator_file, *setup_file;
5851 UINT r = ERROR_SUCCESS;
5853 static const WCHAR translator_fmt[] = {
5854 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5855 static const WCHAR setup_fmt[] = {
5856 'S','e','t','u','p','=','%','s',0};
5858 desc = MSI_RecordGetString(rec, 3);
5860 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5861 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5863 if (!translator_file)
5865 ERR("ODBC Translator entry not found!\n");
5866 return ERROR_FUNCTION_FAILED;
5869 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5871 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5873 translator = msi_alloc(len * sizeof(WCHAR));
5875 return ERROR_OUTOFMEMORY;
5878 lstrcpyW(ptr, desc);
5879 ptr += lstrlenW(ptr) + 1;
5881 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5886 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5891 translator_path = strdupW(translator_file->TargetPath);
5892 ptr = strrchrW(translator_path, '\\');
5893 if (ptr) *ptr = '\0';
5895 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5896 NULL, ODBC_INSTALL_COMPLETE, &usage))
5898 ERR("Failed to install SQL translator!\n");
5899 r = ERROR_FUNCTION_FAILED;
5902 uirow = MSI_CreateRecord( 5 );
5903 MSI_RecordSetStringW( uirow, 1, desc );
5904 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5905 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5906 ui_actiondata( package, szInstallODBC, uirow );
5907 msiobj_release( &uirow->hdr );
5909 msi_free(translator);
5910 msi_free(translator_path);
5915 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5917 MSIPACKAGE *package = param;
5919 LPCWSTR desc, driver;
5920 WORD request = ODBC_ADD_SYS_DSN;
5923 UINT r = ERROR_SUCCESS;
5926 static const WCHAR attrs_fmt[] = {
5927 'D','S','N','=','%','s',0 };
5929 desc = MSI_RecordGetString(rec, 3);
5930 driver = MSI_RecordGetString(rec, 4);
5931 registration = MSI_RecordGetInteger(rec, 5);
5933 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5934 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5936 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5937 attrs = msi_alloc(len * sizeof(WCHAR));
5939 return ERROR_OUTOFMEMORY;
5941 len = sprintfW(attrs, attrs_fmt, desc);
5944 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5946 ERR("Failed to install SQL data source!\n");
5947 r = ERROR_FUNCTION_FAILED;
5950 uirow = MSI_CreateRecord( 5 );
5951 MSI_RecordSetStringW( uirow, 1, desc );
5952 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5953 MSI_RecordSetInteger( uirow, 3, request );
5954 ui_actiondata( package, szInstallODBC, uirow );
5955 msiobj_release( &uirow->hdr );
5962 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5967 static const WCHAR driver_query[] = {
5968 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5969 'O','D','B','C','D','r','i','v','e','r',0 };
5971 static const WCHAR translator_query[] = {
5972 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5973 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5975 static const WCHAR source_query[] = {
5976 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5977 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5979 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5980 if (rc != ERROR_SUCCESS)
5981 return ERROR_SUCCESS;
5983 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5984 msiobj_release(&view->hdr);
5986 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5987 if (rc != ERROR_SUCCESS)
5988 return ERROR_SUCCESS;
5990 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5991 msiobj_release(&view->hdr);
5993 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5994 if (rc != ERROR_SUCCESS)
5995 return ERROR_SUCCESS;
5997 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5998 msiobj_release(&view->hdr);
6003 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6005 MSIPACKAGE *package = param;
6010 desc = MSI_RecordGetString( rec, 3 );
6011 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6013 WARN("Failed to remove ODBC driver\n");
6017 FIXME("Usage count reached 0\n");
6020 uirow = MSI_CreateRecord( 2 );
6021 MSI_RecordSetStringW( uirow, 1, desc );
6022 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6023 ui_actiondata( package, szRemoveODBC, uirow );
6024 msiobj_release( &uirow->hdr );
6026 return ERROR_SUCCESS;
6029 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6031 MSIPACKAGE *package = param;
6036 desc = MSI_RecordGetString( rec, 3 );
6037 if (!SQLRemoveTranslatorW( desc, &usage ))
6039 WARN("Failed to remove ODBC translator\n");
6043 FIXME("Usage count reached 0\n");
6046 uirow = MSI_CreateRecord( 2 );
6047 MSI_RecordSetStringW( uirow, 1, desc );
6048 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6049 ui_actiondata( package, szRemoveODBC, uirow );
6050 msiobj_release( &uirow->hdr );
6052 return ERROR_SUCCESS;
6055 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6057 MSIPACKAGE *package = param;
6060 LPCWSTR desc, driver;
6061 WORD request = ODBC_REMOVE_SYS_DSN;
6065 static const WCHAR attrs_fmt[] = {
6066 'D','S','N','=','%','s',0 };
6068 desc = MSI_RecordGetString( rec, 3 );
6069 driver = MSI_RecordGetString( rec, 4 );
6070 registration = MSI_RecordGetInteger( rec, 5 );
6072 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6073 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6075 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6076 attrs = msi_alloc( len * sizeof(WCHAR) );
6078 return ERROR_OUTOFMEMORY;
6080 FIXME("Use ODBCSourceAttribute table\n");
6082 len = sprintfW( attrs, attrs_fmt, desc );
6085 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6087 WARN("Failed to remove ODBC data source\n");
6091 uirow = MSI_CreateRecord( 3 );
6092 MSI_RecordSetStringW( uirow, 1, desc );
6093 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6094 MSI_RecordSetInteger( uirow, 3, request );
6095 ui_actiondata( package, szRemoveODBC, uirow );
6096 msiobj_release( &uirow->hdr );
6098 return ERROR_SUCCESS;
6101 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6106 static const WCHAR driver_query[] = {
6107 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6108 'O','D','B','C','D','r','i','v','e','r',0 };
6110 static const WCHAR translator_query[] = {
6111 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6112 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6114 static const WCHAR source_query[] = {
6115 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6116 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6118 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6119 if (rc != ERROR_SUCCESS)
6120 return ERROR_SUCCESS;
6122 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6123 msiobj_release( &view->hdr );
6125 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6126 if (rc != ERROR_SUCCESS)
6127 return ERROR_SUCCESS;
6129 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6130 msiobj_release( &view->hdr );
6132 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6133 if (rc != ERROR_SUCCESS)
6134 return ERROR_SUCCESS;
6136 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6137 msiobj_release( &view->hdr );
6142 #define ENV_ACT_SETALWAYS 0x1
6143 #define ENV_ACT_SETABSENT 0x2
6144 #define ENV_ACT_REMOVE 0x4
6145 #define ENV_ACT_REMOVEMATCH 0x8
6147 #define ENV_MOD_MACHINE 0x20000000
6148 #define ENV_MOD_APPEND 0x40000000
6149 #define ENV_MOD_PREFIX 0x80000000
6150 #define ENV_MOD_MASK 0xC0000000
6152 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6154 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6156 LPCWSTR cptr = *name;
6158 static const WCHAR prefix[] = {'[','~',']',0};
6159 static const int prefix_len = 3;
6165 *flags |= ENV_ACT_SETALWAYS;
6166 else if (*cptr == '+')
6167 *flags |= ENV_ACT_SETABSENT;
6168 else if (*cptr == '-')
6169 *flags |= ENV_ACT_REMOVE;
6170 else if (*cptr == '!')
6171 *flags |= ENV_ACT_REMOVEMATCH;
6172 else if (*cptr == '*')
6173 *flags |= ENV_MOD_MACHINE;
6183 ERR("Missing environment variable\n");
6184 return ERROR_FUNCTION_FAILED;
6189 LPCWSTR ptr = *value;
6190 if (!strncmpW(ptr, prefix, prefix_len))
6192 if (ptr[prefix_len] == szSemiColon[0])
6194 *flags |= ENV_MOD_APPEND;
6195 *value += lstrlenW(prefix);
6202 else if (lstrlenW(*value) >= prefix_len)
6204 ptr += lstrlenW(ptr) - prefix_len;
6205 if (!lstrcmpW(ptr, prefix))
6207 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6209 *flags |= ENV_MOD_PREFIX;
6210 /* the "[~]" will be removed by deformat_string */;
6220 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6221 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6222 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6223 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6225 ERR("Invalid flags: %08x\n", *flags);
6226 return ERROR_FUNCTION_FAILED;
6230 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6232 return ERROR_SUCCESS;
6235 static UINT open_env_key( DWORD flags, HKEY *key )
6237 static const WCHAR user_env[] =
6238 {'E','n','v','i','r','o','n','m','e','n','t',0};
6239 static const WCHAR machine_env[] =
6240 {'S','y','s','t','e','m','\\',
6241 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6242 'C','o','n','t','r','o','l','\\',
6243 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6244 'E','n','v','i','r','o','n','m','e','n','t',0};
6249 if (flags & ENV_MOD_MACHINE)
6252 root = HKEY_LOCAL_MACHINE;
6257 root = HKEY_CURRENT_USER;
6260 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6261 if (res != ERROR_SUCCESS)
6263 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6264 return ERROR_FUNCTION_FAILED;
6267 return ERROR_SUCCESS;
6270 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6272 MSIPACKAGE *package = param;
6273 LPCWSTR name, value, component;
6274 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6275 DWORD flags, type, size;
6282 component = MSI_RecordGetString(rec, 4);
6283 comp = get_loaded_component(package, component);
6285 return ERROR_SUCCESS;
6289 TRACE("component is disabled\n");
6290 return ERROR_SUCCESS;
6293 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6295 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6296 comp->Action = comp->Installed;
6297 return ERROR_SUCCESS;
6299 comp->Action = INSTALLSTATE_LOCAL;
6301 name = MSI_RecordGetString(rec, 2);
6302 value = MSI_RecordGetString(rec, 3);
6304 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6306 res = env_parse_flags(&name, &value, &flags);
6307 if (res != ERROR_SUCCESS || !value)
6310 if (value && !deformat_string(package, value, &deformatted))
6312 res = ERROR_OUTOFMEMORY;
6316 value = deformatted;
6318 res = open_env_key( flags, &env );
6319 if (res != ERROR_SUCCESS)
6322 if (flags & ENV_MOD_MACHINE)
6323 action |= 0x20000000;
6327 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6328 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6329 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6332 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6336 /* Nothing to do. */
6339 res = ERROR_SUCCESS;
6343 /* If we are appending but the string was empty, strip ; */
6344 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6346 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6347 newval = strdupW(value);
6350 res = ERROR_OUTOFMEMORY;
6358 /* Contrary to MSDN, +-variable to [~];path works */
6359 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6361 res = ERROR_SUCCESS;
6365 data = msi_alloc(size);
6369 return ERROR_OUTOFMEMORY;
6372 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6373 if (res != ERROR_SUCCESS)
6376 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6379 res = RegDeleteValueW(env, name);
6380 if (res != ERROR_SUCCESS)
6381 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6385 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6386 if (flags & ENV_MOD_MASK)
6390 if (flags & ENV_MOD_APPEND) multiplier++;
6391 if (flags & ENV_MOD_PREFIX) multiplier++;
6392 mod_size = lstrlenW(value) * multiplier;
6393 size += mod_size * sizeof(WCHAR);
6396 newval = msi_alloc(size);
6400 res = ERROR_OUTOFMEMORY;
6404 if (flags & ENV_MOD_PREFIX)
6406 lstrcpyW(newval, value);
6407 ptr = newval + lstrlenW(value);
6408 action |= 0x80000000;
6411 lstrcpyW(ptr, data);
6413 if (flags & ENV_MOD_APPEND)
6415 lstrcatW(newval, value);
6416 action |= 0x40000000;
6419 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6420 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6423 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6427 uirow = MSI_CreateRecord( 3 );
6428 MSI_RecordSetStringW( uirow, 1, name );
6429 MSI_RecordSetStringW( uirow, 2, newval );
6430 MSI_RecordSetInteger( uirow, 3, action );
6431 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6432 msiobj_release( &uirow->hdr );
6434 if (env) RegCloseKey(env);
6435 msi_free(deformatted);
6441 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6445 static const WCHAR ExecSeqQuery[] =
6446 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6447 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6448 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6449 if (rc != ERROR_SUCCESS)
6450 return ERROR_SUCCESS;
6452 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6453 msiobj_release(&view->hdr);
6458 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6460 MSIPACKAGE *package = param;
6461 LPCWSTR name, value, component;
6462 LPWSTR deformatted = NULL;
6471 component = MSI_RecordGetString( rec, 4 );
6472 comp = get_loaded_component( package, component );
6474 return ERROR_SUCCESS;
6478 TRACE("component is disabled\n");
6479 return ERROR_SUCCESS;
6482 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6484 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6485 comp->Action = comp->Installed;
6486 return ERROR_SUCCESS;
6488 comp->Action = INSTALLSTATE_ABSENT;
6490 name = MSI_RecordGetString( rec, 2 );
6491 value = MSI_RecordGetString( rec, 3 );
6493 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6495 r = env_parse_flags( &name, &value, &flags );
6496 if (r != ERROR_SUCCESS)
6499 if (!(flags & ENV_ACT_REMOVE))
6501 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6502 return ERROR_SUCCESS;
6505 if (value && !deformat_string( package, value, &deformatted ))
6506 return ERROR_OUTOFMEMORY;
6508 value = deformatted;
6510 r = open_env_key( flags, &env );
6511 if (r != ERROR_SUCCESS)
6517 if (flags & ENV_MOD_MACHINE)
6518 action |= 0x20000000;
6520 TRACE("Removing %s\n", debugstr_w(name));
6522 res = RegDeleteValueW( env, name );
6523 if (res != ERROR_SUCCESS)
6525 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6530 uirow = MSI_CreateRecord( 3 );
6531 MSI_RecordSetStringW( uirow, 1, name );
6532 MSI_RecordSetStringW( uirow, 2, value );
6533 MSI_RecordSetInteger( uirow, 3, action );
6534 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6535 msiobj_release( &uirow->hdr );
6537 if (env) RegCloseKey( env );
6538 msi_free( deformatted );
6542 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6546 static const WCHAR query[] =
6547 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6548 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6550 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6551 if (rc != ERROR_SUCCESS)
6552 return ERROR_SUCCESS;
6554 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6555 msiobj_release( &view->hdr );
6560 typedef struct tagMSIASSEMBLY
6563 MSICOMPONENT *component;
6564 MSIFEATURE *feature;
6568 LPWSTR display_name;
6573 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6575 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6576 LPVOID pvReserved, HMODULE *phModDll);
6578 static BOOL init_functionpointers(void)
6584 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6586 hmscoree = LoadLibraryA("mscoree.dll");
6589 WARN("mscoree.dll not available\n");
6593 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6594 if (!pLoadLibraryShim)
6596 WARN("LoadLibraryShim not available\n");
6597 FreeLibrary(hmscoree);
6601 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6604 WARN("fusion.dll not available\n");
6605 FreeLibrary(hmscoree);
6609 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6611 FreeLibrary(hmscoree);
6615 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6618 IAssemblyCache *cache;
6621 UINT r = ERROR_FUNCTION_FAILED;
6623 TRACE("installing assembly: %s\n", debugstr_w(path));
6625 uirow = MSI_CreateRecord( 2 );
6626 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6627 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6628 msiobj_release( &uirow->hdr );
6630 if (assembly->feature)
6631 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6633 if (assembly->manifest)
6634 FIXME("Manifest unhandled\n");
6636 if (assembly->application)
6638 FIXME("Assembly should be privately installed\n");
6639 return ERROR_SUCCESS;
6642 if (assembly->attributes == msidbAssemblyAttributesWin32)
6644 FIXME("Win32 assemblies not handled\n");
6645 return ERROR_SUCCESS;
6648 hr = pCreateAssemblyCache(&cache, 0);
6652 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6654 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6659 IAssemblyCache_Release(cache);
6663 typedef struct tagASSEMBLY_LIST
6665 MSIPACKAGE *package;
6666 IAssemblyCache *cache;
6667 struct list *assemblies;
6670 typedef struct tagASSEMBLY_NAME
6678 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6680 ASSEMBLY_NAME *asmname = param;
6681 LPCWSTR name = MSI_RecordGetString(rec, 2);
6682 LPWSTR val = msi_dup_record_field(rec, 3);
6684 static const WCHAR Name[] = {'N','a','m','e',0};
6685 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6686 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6687 static const WCHAR PublicKeyToken[] = {
6688 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6690 if (!strcmpiW(name, Name))
6691 asmname->name = val;
6692 else if (!strcmpiW(name, Version))
6693 asmname->version = val;
6694 else if (!strcmpiW(name, Culture))
6695 asmname->culture = val;
6696 else if (!strcmpiW(name, PublicKeyToken))
6697 asmname->pubkeytoken = val;
6701 return ERROR_SUCCESS;
6704 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6708 *size = lstrlenW(append) + 1;
6709 *str = msi_alloc((*size) * sizeof(WCHAR));
6710 lstrcpyW(*str, append);
6714 (*size) += lstrlenW(append);
6715 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6716 lstrcatW(*str, append);
6719 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6721 static const WCHAR separator[] = {',',' ',0};
6722 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6723 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6724 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6725 static const WCHAR query[] = {
6726 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6727 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6728 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6729 '=','\'','%','s','\'',0};
6732 LPWSTR display_name;
6736 display_name = NULL;
6737 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6739 r = MSI_OpenQuery( db, &view, query, comp->Component );
6740 if (r != ERROR_SUCCESS)
6743 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6744 msiobj_release( &view->hdr );
6748 ERR("No assembly name specified!\n");
6752 append_str( &display_name, &size, name.name );
6756 append_str( &display_name, &size, separator );
6757 append_str( &display_name, &size, Version );
6758 append_str( &display_name, &size, name.version );
6762 append_str( &display_name, &size, separator );
6763 append_str( &display_name, &size, Culture );
6764 append_str( &display_name, &size, name.culture );
6766 if (name.pubkeytoken)
6768 append_str( &display_name, &size, separator );
6769 append_str( &display_name, &size, PublicKeyToken );
6770 append_str( &display_name, &size, name.pubkeytoken );
6773 msi_free( name.name );
6774 msi_free( name.version );
6775 msi_free( name.culture );
6776 msi_free( name.pubkeytoken );
6778 return display_name;
6781 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6783 ASSEMBLY_INFO asminfo;
6788 disp = get_assembly_display_name( db, comp );
6792 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6793 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6795 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6797 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6803 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6805 ASSEMBLY_LIST *list = param;
6806 MSIASSEMBLY *assembly;
6809 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6811 return ERROR_OUTOFMEMORY;
6813 component = MSI_RecordGetString(rec, 1);
6814 assembly->component = get_loaded_component(list->package, component);
6815 if (!assembly->component)
6816 return ERROR_SUCCESS;
6818 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6819 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6821 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6822 assembly->component->Action = assembly->component->Installed;
6823 return ERROR_SUCCESS;
6825 assembly->component->Action = assembly->component->ActionRequest;
6827 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6828 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6830 if (!assembly->file)
6832 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6833 return ERROR_FUNCTION_FAILED;
6836 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6837 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6838 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6840 if (assembly->application)
6843 DWORD size = sizeof(version)/sizeof(WCHAR);
6845 /* FIXME: we should probably check the manifest file here */
6847 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6848 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6850 assembly->installed = TRUE;
6854 assembly->installed = check_assembly_installed(list->package->db,
6856 assembly->component);
6858 list_add_head(list->assemblies, &assembly->entry);
6859 return ERROR_SUCCESS;
6862 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6864 IAssemblyCache *cache = NULL;
6870 static const WCHAR query[] =
6871 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6872 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6874 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6875 if (r != ERROR_SUCCESS)
6876 return ERROR_SUCCESS;
6878 hr = pCreateAssemblyCache(&cache, 0);
6880 return ERROR_FUNCTION_FAILED;
6882 list.package = package;
6884 list.assemblies = assemblies;
6886 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6887 msiobj_release(&view->hdr);
6889 IAssemblyCache_Release(cache);
6894 static void free_assemblies(struct list *assemblies)
6896 struct list *item, *cursor;
6898 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6900 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6902 list_remove(&assembly->entry);
6903 msi_free(assembly->application);
6904 msi_free(assembly->manifest);
6905 msi_free(assembly->display_name);
6910 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6912 MSIASSEMBLY *assembly;
6914 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6916 if (!lstrcmpW(assembly->file->File, file))
6926 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6927 LPWSTR *path, DWORD *attrs, PVOID user)
6929 MSIASSEMBLY *assembly;
6930 WCHAR temppath[MAX_PATH];
6931 struct list *assemblies = user;
6934 if (!find_assembly(assemblies, file, &assembly))
6937 GetTempPathW(MAX_PATH, temppath);
6938 PathAddBackslashW(temppath);
6939 lstrcatW(temppath, assembly->file->FileName);
6941 if (action == MSICABEXTRACT_BEGINEXTRACT)
6943 if (assembly->installed)
6946 *path = strdupW(temppath);
6947 *attrs = assembly->file->Attributes;
6949 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6951 assembly->installed = TRUE;
6953 r = install_assembly(package, assembly, temppath);
6954 if (r != ERROR_SUCCESS)
6955 ERR("Failed to install assembly\n");
6961 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6964 struct list assemblies = LIST_INIT(assemblies);
6965 MSIASSEMBLY *assembly;
6968 if (!init_functionpointers() || !pCreateAssemblyCache)
6969 return ERROR_FUNCTION_FAILED;
6971 r = load_assemblies(package, &assemblies);
6972 if (r != ERROR_SUCCESS)
6975 if (list_empty(&assemblies))
6978 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6981 r = ERROR_OUTOFMEMORY;
6985 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6987 if (assembly->installed && !mi->is_continuous)
6990 if (assembly->file->IsCompressed)
6992 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
6996 r = ready_media(package, assembly->file, mi);
6997 if (r != ERROR_SUCCESS)
6999 ERR("Failed to ready media\n");
7004 data.package = package;
7005 data.cb = installassembly_cb;
7006 data.user = &assemblies;
7008 if (!msi_cabextract(package, mi, &data))
7010 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7011 r = ERROR_FUNCTION_FAILED;
7018 LPWSTR source = resolve_file_source(package, assembly->file);
7020 r = install_assembly(package, assembly, source);
7021 if (r != ERROR_SUCCESS)
7022 ERR("Failed to install assembly\n");
7027 /* FIXME: write Installer assembly reg values */
7031 free_assemblies(&assemblies);
7035 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7037 LPWSTR key, template, id;
7038 UINT r = ERROR_SUCCESS;
7040 id = msi_dup_property( package->db, szProductID );
7044 return ERROR_SUCCESS;
7046 template = msi_dup_property( package->db, szPIDTemplate );
7047 key = msi_dup_property( package->db, szPIDKEY );
7049 if (key && template)
7051 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7052 r = msi_set_property( package->db, szProductID, key );
7054 msi_free( template );
7059 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7062 package->need_reboot = 1;
7063 return ERROR_SUCCESS;
7066 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7068 static const WCHAR szAvailableFreeReg[] =
7069 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7071 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7073 TRACE("%p %d kilobytes\n", package, space);
7075 uirow = MSI_CreateRecord( 1 );
7076 MSI_RecordSetInteger( uirow, 1, space );
7077 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7078 msiobj_release( &uirow->hdr );
7080 return ERROR_SUCCESS;
7083 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7085 FIXME("%p\n", package);
7086 return ERROR_SUCCESS;
7089 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7091 FIXME("%p\n", package);
7092 return ERROR_SUCCESS;
7095 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7100 static const WCHAR driver_query[] = {
7101 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7102 'O','D','B','C','D','r','i','v','e','r',0 };
7104 static const WCHAR translator_query[] = {
7105 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7106 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7108 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7109 if (r == ERROR_SUCCESS)
7112 r = MSI_IterateRecords( view, &count, NULL, package );
7113 msiobj_release( &view->hdr );
7114 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7117 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7118 if (r == ERROR_SUCCESS)
7121 r = MSI_IterateRecords( view, &count, NULL, package );
7122 msiobj_release( &view->hdr );
7123 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7126 return ERROR_SUCCESS;
7129 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7130 LPCSTR action, LPCWSTR table )
7132 static const WCHAR query[] = {
7133 'S','E','L','E','C','T',' ','*',' ',
7134 'F','R','O','M',' ','`','%','s','`',0 };
7135 MSIQUERY *view = NULL;
7139 r = MSI_OpenQuery( package->db, &view, query, table );
7140 if (r == ERROR_SUCCESS)
7142 r = MSI_IterateRecords(view, &count, NULL, package);
7143 msiobj_release(&view->hdr);
7147 FIXME("%s -> %u ignored %s table values\n",
7148 action, count, debugstr_w(table));
7150 return ERROR_SUCCESS;
7153 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7155 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7156 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7159 static UINT ACTION_BindImage( MSIPACKAGE *package )
7161 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7162 return msi_unimplemented_action_stub( package, "BindImage", table );
7165 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7167 static const WCHAR table[] = {
7168 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7169 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7172 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7174 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7175 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7178 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7180 static const WCHAR table[] = {
7181 'M','s','i','A','s','s','e','m','b','l','y',0 };
7182 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7185 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7187 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7188 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7191 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7193 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7194 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7197 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7199 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7200 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7203 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7205 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7206 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7209 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7211 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7212 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7215 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7219 const WCHAR *action;
7220 UINT (*handler)(MSIPACKAGE *);
7224 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7225 { szAppSearch, ACTION_AppSearch },
7226 { szBindImage, ACTION_BindImage },
7227 { szCCPSearch, ACTION_CCPSearch },
7228 { szCostFinalize, ACTION_CostFinalize },
7229 { szCostInitialize, ACTION_CostInitialize },
7230 { szCreateFolders, ACTION_CreateFolders },
7231 { szCreateShortcuts, ACTION_CreateShortcuts },
7232 { szDeleteServices, ACTION_DeleteServices },
7233 { szDisableRollback, ACTION_DisableRollback },
7234 { szDuplicateFiles, ACTION_DuplicateFiles },
7235 { szExecuteAction, ACTION_ExecuteAction },
7236 { szFileCost, ACTION_FileCost },
7237 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7238 { szForceReboot, ACTION_ForceReboot },
7239 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7240 { szInstallExecute, ACTION_InstallExecute },
7241 { szInstallExecuteAgain, ACTION_InstallExecute },
7242 { szInstallFiles, ACTION_InstallFiles},
7243 { szInstallFinalize, ACTION_InstallFinalize },
7244 { szInstallInitialize, ACTION_InstallInitialize },
7245 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7246 { szInstallValidate, ACTION_InstallValidate },
7247 { szIsolateComponents, ACTION_IsolateComponents },
7248 { szLaunchConditions, ACTION_LaunchConditions },
7249 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7250 { szMoveFiles, ACTION_MoveFiles },
7251 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7252 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7253 { szInstallODBC, ACTION_InstallODBC },
7254 { szInstallServices, ACTION_InstallServices },
7255 { szPatchFiles, ACTION_PatchFiles },
7256 { szProcessComponents, ACTION_ProcessComponents },
7257 { szPublishComponents, ACTION_PublishComponents },
7258 { szPublishFeatures, ACTION_PublishFeatures },
7259 { szPublishProduct, ACTION_PublishProduct },
7260 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7261 { szRegisterComPlus, ACTION_RegisterComPlus},
7262 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7263 { szRegisterFonts, ACTION_RegisterFonts },
7264 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7265 { szRegisterProduct, ACTION_RegisterProduct },
7266 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7267 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7268 { szRegisterUser, ACTION_RegisterUser },
7269 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7270 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7271 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7272 { szRemoveFiles, ACTION_RemoveFiles },
7273 { szRemoveFolders, ACTION_RemoveFolders },
7274 { szRemoveIniValues, ACTION_RemoveIniValues },
7275 { szRemoveODBC, ACTION_RemoveODBC },
7276 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7277 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7278 { szResolveSource, ACTION_ResolveSource },
7279 { szRMCCPSearch, ACTION_RMCCPSearch },
7280 { szScheduleReboot, ACTION_ScheduleReboot },
7281 { szSelfRegModules, ACTION_SelfRegModules },
7282 { szSelfUnregModules, ACTION_SelfUnregModules },
7283 { szSetODBCFolders, ACTION_SetODBCFolders },
7284 { szStartServices, ACTION_StartServices },
7285 { szStopServices, ACTION_StopServices },
7286 { szUnpublishComponents, ACTION_UnpublishComponents },
7287 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7288 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7289 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7290 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7291 { szUnregisterFonts, ACTION_UnregisterFonts },
7292 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7293 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7294 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7295 { szValidateProductID, ACTION_ValidateProductID },
7296 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7297 { szWriteIniValues, ACTION_WriteIniValues },
7298 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7302 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7308 while (StandardActions[i].action != NULL)
7310 if (!strcmpW( StandardActions[i].action, action ))
7312 ui_actionstart( package, action );
7313 if (StandardActions[i].handler)
7315 ui_actioninfo( package, action, TRUE, 0 );
7316 *rc = StandardActions[i].handler( package );
7317 ui_actioninfo( package, action, FALSE, *rc );
7321 FIXME("unhandled standard action %s\n", debugstr_w(action));
7322 *rc = ERROR_SUCCESS;
7332 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7334 UINT rc = ERROR_SUCCESS;
7337 TRACE("Performing action (%s)\n", debugstr_w(action));
7339 handled = ACTION_HandleStandardAction(package, action, &rc);
7342 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7346 WARN("unhandled msi action %s\n", debugstr_w(action));
7347 rc = ERROR_FUNCTION_NOT_CALLED;
7353 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7355 UINT rc = ERROR_SUCCESS;
7356 BOOL handled = FALSE;
7358 TRACE("Performing action (%s)\n", debugstr_w(action));
7360 handled = ACTION_HandleStandardAction(package, action, &rc);
7363 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7365 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7370 WARN("unhandled msi action %s\n", debugstr_w(action));
7371 rc = ERROR_FUNCTION_NOT_CALLED;
7377 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7379 UINT rc = ERROR_SUCCESS;
7382 static const WCHAR ExecSeqQuery[] =
7383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7384 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7385 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7386 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7387 static const WCHAR UISeqQuery[] =
7388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7389 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7390 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7391 ' ', '=',' ','%','i',0};
7393 if (needs_ui_sequence(package))
7394 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7396 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7400 LPCWSTR action, cond;
7402 TRACE("Running the actions\n");
7404 /* check conditions */
7405 cond = MSI_RecordGetString(row, 2);
7407 /* this is a hack to skip errors in the condition code */
7408 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7410 msiobj_release(&row->hdr);
7411 return ERROR_SUCCESS;
7414 action = MSI_RecordGetString(row, 1);
7417 ERR("failed to fetch action\n");
7418 msiobj_release(&row->hdr);
7419 return ERROR_FUNCTION_FAILED;
7422 if (needs_ui_sequence(package))
7423 rc = ACTION_PerformUIAction(package, action, -1);
7425 rc = ACTION_PerformAction(package, action, -1);
7427 msiobj_release(&row->hdr);
7433 /****************************************************
7434 * TOP level entry points
7435 *****************************************************/
7437 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7438 LPCWSTR szCommandLine )
7443 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7444 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7446 msi_set_property( package->db, szAction, szInstall );
7448 package->script->InWhatSequence = SEQUENCE_INSTALL;
7455 dir = strdupW(szPackagePath);
7456 p = strrchrW(dir, '\\');
7460 file = szPackagePath + (p - dir);
7465 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7466 GetCurrentDirectoryW(MAX_PATH, dir);
7467 lstrcatW(dir, szBackSlash);
7468 file = szPackagePath;
7471 msi_free( package->PackagePath );
7472 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7473 if (!package->PackagePath)
7476 return ERROR_OUTOFMEMORY;
7479 lstrcpyW(package->PackagePath, dir);
7480 lstrcatW(package->PackagePath, file);
7483 msi_set_sourcedir_props(package, FALSE);
7486 msi_parse_command_line( package, szCommandLine, FALSE );
7488 msi_apply_transforms( package );
7489 msi_apply_patches( package );
7491 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7493 TRACE("setting reinstall property\n");
7494 msi_set_property( package->db, szReinstall, szAll );
7497 /* properties may have been added by a transform */
7498 msi_clone_properties( package );
7500 msi_parse_command_line( package, szCommandLine, FALSE );
7501 msi_adjust_allusers_property( package );
7502 msi_set_context( package );
7504 if (needs_ui_sequence( package))
7506 package->script->InWhatSequence |= SEQUENCE_UI;
7507 rc = ACTION_ProcessUISequence(package);
7508 ui_exists = ui_sequence_exists(package);
7509 if (rc == ERROR_SUCCESS || !ui_exists)
7511 package->script->InWhatSequence |= SEQUENCE_EXEC;
7512 rc = ACTION_ProcessExecSequence(package, ui_exists);
7516 rc = ACTION_ProcessExecSequence(package, FALSE);
7518 package->script->CurrentlyScripting = FALSE;
7520 /* process the ending type action */
7521 if (rc == ERROR_SUCCESS)
7522 ACTION_PerformActionSequence(package, -1);
7523 else if (rc == ERROR_INSTALL_USEREXIT)
7524 ACTION_PerformActionSequence(package, -2);
7525 else if (rc == ERROR_INSTALL_SUSPEND)
7526 ACTION_PerformActionSequence(package, -4);
7528 ACTION_PerformActionSequence(package, -3);
7530 /* finish up running custom actions */
7531 ACTION_FinishCustomActions(package);
7533 if (rc == ERROR_SUCCESS && package->need_reboot)
7534 return ERROR_SUCCESS_REBOOT_REQUIRED;