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->ActionRequest == 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->ActionRequest == 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->ActionRequest == 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->ActionRequest)
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 WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path )
2376 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'};
2377 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]);
2379 if (is_64bit && package->platform == PLATFORM_INTEL &&
2380 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len ))
2385 size = (strlenW( path ) + strlenW( szWow6432Node ) + 1) * sizeof(WCHAR);
2386 path_32node = msi_alloc( size );
2390 memcpy( path_32node, path, len * sizeof(WCHAR) );
2391 path_32node[len] = 0;
2392 strcatW( path_32node, szWow6432Node );
2393 strcatW( path_32node, szBackSlash );
2394 strcatW( path_32node, path + len );
2398 return strdupW( path );
2401 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2403 MSIPACKAGE *package = param;
2404 LPSTR value_data = NULL;
2405 HKEY root_key, hkey;
2407 LPWSTR deformated, uikey, keypath;
2408 LPCWSTR szRoot, component, name, key, value;
2412 BOOL check_first = FALSE;
2415 ui_progress(package,2,0,0,0);
2417 component = MSI_RecordGetString(row, 6);
2418 comp = get_loaded_component(package,component);
2420 return ERROR_SUCCESS;
2424 TRACE("component is disabled\n");
2425 return ERROR_SUCCESS;
2428 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2430 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2431 comp->Action = comp->Installed;
2432 return ERROR_SUCCESS;
2434 comp->Action = INSTALLSTATE_LOCAL;
2436 name = MSI_RecordGetString(row, 4);
2437 if( MSI_RecordIsNull(row,5) && name )
2439 /* null values can have special meanings */
2440 if (name[0]=='-' && name[1] == 0)
2441 return ERROR_SUCCESS;
2442 else if ((name[0]=='+' && name[1] == 0) ||
2443 (name[0] == '*' && name[1] == 0))
2448 root = MSI_RecordGetInteger(row,2);
2449 key = MSI_RecordGetString(row, 3);
2451 szRoot = get_root_key( package, root, &root_key );
2453 return ERROR_SUCCESS;
2455 deformat_string(package, key , &deformated);
2456 size = strlenW(deformated) + strlenW(szRoot) + 1;
2457 uikey = msi_alloc(size*sizeof(WCHAR));
2458 strcpyW(uikey,szRoot);
2459 strcatW(uikey,deformated);
2461 keypath = get_keypath( package, root_key, deformated );
2462 msi_free( deformated );
2463 if (RegCreateKeyW( root_key, keypath, &hkey ))
2465 ERR("Could not create key %s\n", debugstr_w(keypath));
2467 return ERROR_SUCCESS;
2470 value = MSI_RecordGetString(row,5);
2472 value_data = parse_value(package, value, &type, &size);
2475 value_data = (LPSTR)strdupW(szEmpty);
2476 size = sizeof(szEmpty);
2480 deformat_string(package, name, &deformated);
2484 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2486 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2491 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2492 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2494 TRACE("value %s of %s checked already exists\n",
2495 debugstr_w(deformated), debugstr_w(uikey));
2499 TRACE("Checked and setting value %s of %s\n",
2500 debugstr_w(deformated), debugstr_w(uikey));
2501 if (deformated || size)
2502 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2507 uirow = MSI_CreateRecord(3);
2508 MSI_RecordSetStringW(uirow,2,deformated);
2509 MSI_RecordSetStringW(uirow,1,uikey);
2510 if (type == REG_SZ || type == REG_EXPAND_SZ)
2511 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2512 ui_actiondata(package,szWriteRegistryValues,uirow);
2513 msiobj_release( &uirow->hdr );
2515 msi_free(value_data);
2516 msi_free(deformated);
2519 return ERROR_SUCCESS;
2522 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2526 static const WCHAR ExecSeqQuery[] =
2527 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2528 '`','R','e','g','i','s','t','r','y','`',0 };
2530 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2531 if (rc != ERROR_SUCCESS)
2532 return ERROR_SUCCESS;
2534 /* increment progress bar each time action data is sent */
2535 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2537 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2539 msiobj_release(&view->hdr);
2543 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2547 DWORD num_subkeys, num_values;
2551 if ((res = RegDeleteTreeW( hkey_root, key )))
2553 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2558 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2560 if ((res = RegDeleteValueW( hkey, value )))
2562 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2564 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2565 NULL, NULL, NULL, NULL );
2566 RegCloseKey( hkey );
2568 if (!res && !num_subkeys && !num_values)
2570 TRACE("Removing empty key %s\n", debugstr_w(key));
2571 RegDeleteKeyW( hkey_root, key );
2575 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2579 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2581 MSIPACKAGE *package = param;
2582 LPCWSTR component, name, key_str, root_key_str;
2583 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2586 BOOL delete_key = FALSE;
2591 ui_progress( package, 2, 0, 0, 0 );
2593 component = MSI_RecordGetString( row, 6 );
2594 comp = get_loaded_component( package, component );
2596 return ERROR_SUCCESS;
2600 TRACE("component is disabled\n");
2601 return ERROR_SUCCESS;
2604 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2606 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2607 comp->Action = comp->Installed;
2608 return ERROR_SUCCESS;
2610 comp->Action = INSTALLSTATE_ABSENT;
2612 name = MSI_RecordGetString( row, 4 );
2613 if (MSI_RecordIsNull( row, 5 ) && name )
2615 if (name[0] == '+' && !name[1])
2616 return ERROR_SUCCESS;
2617 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2624 root = MSI_RecordGetInteger( row, 2 );
2625 key_str = MSI_RecordGetString( row, 3 );
2627 root_key_str = get_root_key( package, root, &hkey_root );
2629 return ERROR_SUCCESS;
2631 deformat_string( package, key_str, &deformated_key );
2632 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2633 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2634 strcpyW( ui_key_str, root_key_str );
2635 strcatW( ui_key_str, deformated_key );
2637 deformat_string( package, name, &deformated_name );
2639 keypath = get_keypath( package, hkey_root, deformated_key );
2640 msi_free( deformated_key );
2641 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2642 msi_free( keypath );
2644 uirow = MSI_CreateRecord( 2 );
2645 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2646 MSI_RecordSetStringW( uirow, 2, deformated_name );
2648 ui_actiondata( package, szRemoveRegistryValues, uirow );
2649 msiobj_release( &uirow->hdr );
2651 msi_free( ui_key_str );
2652 msi_free( deformated_name );
2653 return ERROR_SUCCESS;
2656 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2658 MSIPACKAGE *package = param;
2659 LPCWSTR component, name, key_str, root_key_str;
2660 LPWSTR deformated_key, deformated_name, ui_key_str, keypath;
2663 BOOL delete_key = FALSE;
2668 ui_progress( package, 2, 0, 0, 0 );
2670 component = MSI_RecordGetString( row, 5 );
2671 comp = get_loaded_component( package, component );
2673 return ERROR_SUCCESS;
2677 TRACE("component is disabled\n");
2678 return ERROR_SUCCESS;
2681 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2683 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2684 comp->Action = comp->Installed;
2685 return ERROR_SUCCESS;
2687 comp->Action = INSTALLSTATE_LOCAL;
2689 if ((name = MSI_RecordGetString( row, 4 )))
2691 if (name[0] == '-' && !name[1])
2698 root = MSI_RecordGetInteger( row, 2 );
2699 key_str = MSI_RecordGetString( row, 3 );
2701 root_key_str = get_root_key( package, root, &hkey_root );
2703 return ERROR_SUCCESS;
2705 deformat_string( package, key_str, &deformated_key );
2706 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2707 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2708 strcpyW( ui_key_str, root_key_str );
2709 strcatW( ui_key_str, deformated_key );
2711 deformat_string( package, name, &deformated_name );
2713 keypath = get_keypath( package, hkey_root, deformated_key );
2714 msi_free( deformated_key );
2715 delete_reg_key_or_value( hkey_root, keypath, deformated_name, delete_key );
2716 msi_free( keypath );
2718 uirow = MSI_CreateRecord( 2 );
2719 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2720 MSI_RecordSetStringW( uirow, 2, deformated_name );
2722 ui_actiondata( package, szRemoveRegistryValues, uirow );
2723 msiobj_release( &uirow->hdr );
2725 msi_free( ui_key_str );
2726 msi_free( deformated_name );
2727 return ERROR_SUCCESS;
2730 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2734 static const WCHAR registry_query[] =
2735 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2736 '`','R','e','g','i','s','t','r','y','`',0 };
2737 static const WCHAR remove_registry_query[] =
2738 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2739 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2741 /* increment progress bar each time action data is sent */
2742 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2744 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2745 if (rc == ERROR_SUCCESS)
2747 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2748 msiobj_release( &view->hdr );
2749 if (rc != ERROR_SUCCESS)
2753 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2754 if (rc == ERROR_SUCCESS)
2756 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2757 msiobj_release( &view->hdr );
2758 if (rc != ERROR_SUCCESS)
2762 return ERROR_SUCCESS;
2765 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2767 package->script->CurrentlyScripting = TRUE;
2769 return ERROR_SUCCESS;
2773 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2778 static const WCHAR q1[]=
2779 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2780 '`','R','e','g','i','s','t','r','y','`',0};
2783 MSIFEATURE *feature;
2786 TRACE("InstallValidate\n");
2788 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2789 if (rc == ERROR_SUCCESS)
2791 MSI_IterateRecords( view, &progress, NULL, package );
2792 msiobj_release( &view->hdr );
2793 total += progress * REG_PROGRESS_VALUE;
2796 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2797 total += COMPONENT_PROGRESS_VALUE;
2799 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2800 total += file->FileSize;
2802 ui_progress(package,0,total,0,0);
2804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2806 TRACE("Feature: %s Installed %d Request %d Action %d\n",
2807 debugstr_w(feature->Feature), feature->Installed,
2808 feature->ActionRequest, feature->Action);
2811 return ERROR_SUCCESS;
2814 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2816 MSIPACKAGE* package = param;
2817 LPCWSTR cond = NULL;
2818 LPCWSTR message = NULL;
2821 static const WCHAR title[]=
2822 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2824 cond = MSI_RecordGetString(row,1);
2826 r = MSI_EvaluateConditionW(package,cond);
2827 if (r == MSICONDITION_FALSE)
2829 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2832 message = MSI_RecordGetString(row,2);
2833 deformat_string(package,message,&deformated);
2834 MessageBoxW(NULL,deformated,title,MB_OK);
2835 msi_free(deformated);
2838 return ERROR_INSTALL_FAILURE;
2841 return ERROR_SUCCESS;
2844 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2847 MSIQUERY * view = NULL;
2848 static const WCHAR ExecSeqQuery[] =
2849 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2850 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2852 TRACE("Checking launch conditions\n");
2854 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2855 if (rc != ERROR_SUCCESS)
2856 return ERROR_SUCCESS;
2858 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2859 msiobj_release(&view->hdr);
2864 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2868 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2870 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2872 MSIRECORD * row = 0;
2874 LPWSTR deformated,buffer,deformated_name;
2876 static const WCHAR ExecSeqQuery[] =
2877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2878 '`','R','e','g','i','s','t','r','y','`',' ',
2879 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2880 ' ','=',' ' ,'\'','%','s','\'',0 };
2881 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2882 static const WCHAR fmt2[]=
2883 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2885 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2889 root = MSI_RecordGetInteger(row,2);
2890 key = MSI_RecordGetString(row, 3);
2891 name = MSI_RecordGetString(row, 4);
2892 deformat_string(package, key , &deformated);
2893 deformat_string(package, name, &deformated_name);
2895 len = strlenW(deformated) + 6;
2896 if (deformated_name)
2897 len+=strlenW(deformated_name);
2899 buffer = msi_alloc( len *sizeof(WCHAR));
2901 if (deformated_name)
2902 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2904 sprintfW(buffer,fmt,root,deformated);
2906 msi_free(deformated);
2907 msi_free(deformated_name);
2908 msiobj_release(&row->hdr);
2912 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2914 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2919 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2922 return strdupW( file->TargetPath );
2927 static HKEY openSharedDLLsKey(void)
2930 static const WCHAR path[] =
2931 {'S','o','f','t','w','a','r','e','\\',
2932 'M','i','c','r','o','s','o','f','t','\\',
2933 'W','i','n','d','o','w','s','\\',
2934 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2935 'S','h','a','r','e','d','D','L','L','s',0};
2937 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2941 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2946 DWORD sz = sizeof(count);
2949 hkey = openSharedDLLsKey();
2950 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2951 if (rc != ERROR_SUCCESS)
2957 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2961 hkey = openSharedDLLsKey();
2963 msi_reg_set_val_dword( hkey, path, count );
2965 RegDeleteValueW(hkey,path);
2971 * Return TRUE if the count should be written out and FALSE if not
2973 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2975 MSIFEATURE *feature;
2979 /* only refcount DLLs */
2980 if (comp->KeyPath == NULL ||
2981 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2982 comp->Attributes & msidbComponentAttributesODBCDataSource)
2986 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2987 write = (count > 0);
2989 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2993 /* increment counts */
2994 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2998 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
3001 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3003 if ( cl->component == comp )
3008 /* decrement counts */
3009 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3013 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3016 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3018 if ( cl->component == comp )
3023 /* ref count all the files in the component */
3028 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3030 if (file->Component == comp)
3031 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
3035 /* add a count for permanent */
3036 if (comp->Attributes & msidbComponentAttributesPermanent)
3039 comp->RefCount = count;
3042 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
3045 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3047 WCHAR squished_pc[GUID_SIZE];
3048 WCHAR squished_cc[GUID_SIZE];
3055 squash_guid(package->ProductCode,squished_pc);
3056 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3058 msi_set_sourcedir_props(package, FALSE);
3060 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3064 ui_progress(package,2,0,0,0);
3065 if (!comp->ComponentId)
3068 squash_guid(comp->ComponentId,squished_cc);
3070 msi_free(comp->FullKeypath);
3071 comp->FullKeypath = resolve_keypath( package, comp );
3073 ACTION_RefCountComponent( package, comp );
3075 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3076 debugstr_w(comp->Component),
3077 debugstr_w(squished_cc),
3078 debugstr_w(comp->FullKeypath),
3080 comp->ActionRequest);
3082 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3083 comp->ActionRequest == INSTALLSTATE_SOURCE)
3085 if (!comp->FullKeypath)
3088 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3089 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3092 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3095 if (rc != ERROR_SUCCESS)
3098 if (comp->Attributes & msidbComponentAttributesPermanent)
3100 static const WCHAR szPermKey[] =
3101 { '0','0','0','0','0','0','0','0','0','0','0','0',
3102 '0','0','0','0','0','0','0','0','0','0','0','0',
3103 '0','0','0','0','0','0','0','0',0 };
3105 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3108 if (comp->ActionRequest == INSTALLSTATE_LOCAL)
3109 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3115 WCHAR source[MAX_PATH];
3116 WCHAR base[MAX_PATH];
3119 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3120 static const WCHAR query[] = {
3121 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3122 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3123 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3124 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3125 '`','D','i','s','k','I','d','`',0};
3127 file = get_loaded_file(package, comp->KeyPath);
3131 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3132 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3133 ptr2 = strrchrW(source, '\\') + 1;
3134 msiobj_release(&row->hdr);
3136 lstrcpyW(base, package->PackagePath);
3137 ptr = strrchrW(base, '\\');
3140 sourcepath = resolve_file_source(package, file);
3141 ptr = sourcepath + lstrlenW(base);
3142 lstrcpyW(ptr2, ptr);
3143 msi_free(sourcepath);
3145 msi_reg_set_val_str(hkey, squished_pc, source);
3149 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3151 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3152 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3154 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3156 comp->Action = comp->ActionRequest;
3159 uirow = MSI_CreateRecord(3);
3160 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3161 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3162 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3163 ui_actiondata(package,szProcessComponents,uirow);
3164 msiobj_release( &uirow->hdr );
3167 return ERROR_SUCCESS;
3178 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3179 LPWSTR lpszName, LONG_PTR lParam)
3182 typelib_struct *tl_struct = (typelib_struct*) lParam;
3183 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3187 if (!IS_INTRESOURCE(lpszName))
3189 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3193 sz = strlenW(tl_struct->source)+4;
3194 sz *= sizeof(WCHAR);
3196 if ((INT_PTR)lpszName == 1)
3197 tl_struct->path = strdupW(tl_struct->source);
3200 tl_struct->path = msi_alloc(sz);
3201 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3204 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3205 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3208 msi_free(tl_struct->path);
3209 tl_struct->path = NULL;
3214 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3215 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3217 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3221 msi_free(tl_struct->path);
3222 tl_struct->path = NULL;
3224 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3225 ITypeLib_Release(tl_struct->ptLib);
3230 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3232 MSIPACKAGE* package = param;
3236 typelib_struct tl_struct;
3241 component = MSI_RecordGetString(row,3);
3242 comp = get_loaded_component(package,component);
3244 return ERROR_SUCCESS;
3248 TRACE("component is disabled\n");
3249 return ERROR_SUCCESS;
3252 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3254 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3255 comp->Action = comp->Installed;
3256 return ERROR_SUCCESS;
3258 comp->Action = INSTALLSTATE_LOCAL;
3260 file = get_loaded_file( package, comp->KeyPath );
3262 return ERROR_SUCCESS;
3264 ui_actiondata( package, szRegisterTypeLibraries, row );
3266 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3270 guid = MSI_RecordGetString(row,1);
3271 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3272 tl_struct.source = strdupW( file->TargetPath );
3273 tl_struct.path = NULL;
3275 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3276 (LONG_PTR)&tl_struct);
3284 helpid = MSI_RecordGetString(row,6);
3287 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3288 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3292 ERR("Failed to register type library %s\n",
3293 debugstr_w(tl_struct.path));
3295 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3297 ITypeLib_Release(tl_struct.ptLib);
3298 msi_free(tl_struct.path);
3301 ERR("Failed to load type library %s\n",
3302 debugstr_w(tl_struct.source));
3304 FreeLibrary(module);
3305 msi_free(tl_struct.source);
3309 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3312 ERR("Failed to load type library: %08x\n", hr);
3313 return ERROR_INSTALL_FAILURE;
3316 ITypeLib_Release(tlib);
3319 return ERROR_SUCCESS;
3322 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3325 * OK this is a bit confusing.. I am given a _Component key and I believe
3326 * that the file that is being registered as a type library is the "key file
3327 * of that component" which I interpret to mean "The file in the KeyPath of
3332 static const WCHAR Query[] =
3333 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3334 '`','T','y','p','e','L','i','b','`',0};
3336 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3337 if (rc != ERROR_SUCCESS)
3338 return ERROR_SUCCESS;
3340 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3341 msiobj_release(&view->hdr);
3345 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3347 MSIPACKAGE *package = param;
3348 LPCWSTR component, guid;
3356 component = MSI_RecordGetString( row, 3 );
3357 comp = get_loaded_component( package, component );
3359 return ERROR_SUCCESS;
3363 TRACE("component is disabled\n");
3364 return ERROR_SUCCESS;
3367 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3369 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3370 comp->Action = comp->Installed;
3371 return ERROR_SUCCESS;
3373 comp->Action = INSTALLSTATE_ABSENT;
3375 ui_actiondata( package, szUnregisterTypeLibraries, row );
3377 guid = MSI_RecordGetString( row, 1 );
3378 CLSIDFromString( (LPCWSTR)guid, &libid );
3379 version = MSI_RecordGetInteger( row, 4 );
3380 language = MSI_RecordGetInteger( row, 2 );
3383 syskind = SYS_WIN64;
3385 syskind = SYS_WIN32;
3388 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3391 WARN("Failed to unregister typelib: %08x\n", hr);
3394 return ERROR_SUCCESS;
3397 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3401 static const WCHAR query[] =
3402 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3403 '`','T','y','p','e','L','i','b','`',0};
3405 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3406 if (rc != ERROR_SUCCESS)
3407 return ERROR_SUCCESS;
3409 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3410 msiobj_release( &view->hdr );
3414 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3416 static const WCHAR szlnk[] = {'.','l','n','k',0};
3417 LPCWSTR directory, extension;
3418 LPWSTR link_folder, link_file, filename;
3420 directory = MSI_RecordGetString( row, 2 );
3421 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3423 /* may be needed because of a bug somewhere else */
3424 create_full_pathW( link_folder );
3426 filename = msi_dup_record_field( row, 3 );
3427 reduce_to_longfilename( filename );
3429 extension = strchrW( filename, '.' );
3430 if (!extension || strcmpiW( extension, szlnk ))
3432 int len = strlenW( filename );
3433 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3434 memcpy( filename + len, szlnk, sizeof(szlnk) );
3436 link_file = build_directory_name( 2, link_folder, filename );
3437 msi_free( link_folder );
3438 msi_free( filename );
3443 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3445 MSIPACKAGE *package = param;
3446 LPWSTR link_file, deformated, path;
3447 LPCWSTR component, target;
3449 IShellLinkW *sl = NULL;
3450 IPersistFile *pf = NULL;
3453 component = MSI_RecordGetString(row, 4);
3454 comp = get_loaded_component(package, component);
3456 return ERROR_SUCCESS;
3460 TRACE("component is disabled\n");
3461 return ERROR_SUCCESS;
3464 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3466 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3467 comp->Action = comp->Installed;
3468 return ERROR_SUCCESS;
3470 comp->Action = INSTALLSTATE_LOCAL;
3472 ui_actiondata(package,szCreateShortcuts,row);
3474 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3475 &IID_IShellLinkW, (LPVOID *) &sl );
3479 ERR("CLSID_ShellLink not available\n");
3483 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3486 ERR("QueryInterface(IID_IPersistFile) failed\n");
3490 target = MSI_RecordGetString(row, 5);
3491 if (strchrW(target, '['))
3493 deformat_string(package, target, &deformated);
3494 IShellLinkW_SetPath(sl,deformated);
3495 msi_free(deformated);
3499 FIXME("poorly handled shortcut format, advertised shortcut\n");
3500 IShellLinkW_SetPath(sl,comp->FullKeypath);
3503 if (!MSI_RecordIsNull(row,6))
3505 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3506 deformat_string(package, arguments, &deformated);
3507 IShellLinkW_SetArguments(sl,deformated);
3508 msi_free(deformated);
3511 if (!MSI_RecordIsNull(row,7))
3513 LPCWSTR description = MSI_RecordGetString(row, 7);
3514 IShellLinkW_SetDescription(sl, description);
3517 if (!MSI_RecordIsNull(row,8))
3518 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3520 if (!MSI_RecordIsNull(row,9))
3523 LPCWSTR icon = MSI_RecordGetString(row, 9);
3525 path = build_icon_path(package, icon);
3526 index = MSI_RecordGetInteger(row,10);
3528 /* no value means 0 */
3529 if (index == MSI_NULL_INTEGER)
3532 IShellLinkW_SetIconLocation(sl, path, index);
3536 if (!MSI_RecordIsNull(row,11))
3537 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3539 if (!MSI_RecordIsNull(row,12))
3541 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3542 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3544 IShellLinkW_SetWorkingDirectory(sl, path);
3548 link_file = get_link_file(package, row);
3550 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3551 IPersistFile_Save(pf, link_file, FALSE);
3553 msi_free(link_file);
3557 IPersistFile_Release( pf );
3559 IShellLinkW_Release( sl );
3561 return ERROR_SUCCESS;
3564 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3569 static const WCHAR Query[] =
3570 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3571 '`','S','h','o','r','t','c','u','t','`',0};
3573 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3574 if (rc != ERROR_SUCCESS)
3575 return ERROR_SUCCESS;
3577 res = CoInitialize( NULL );
3579 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3580 msiobj_release(&view->hdr);
3588 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3590 MSIPACKAGE *package = param;
3595 component = MSI_RecordGetString( row, 4 );
3596 comp = get_loaded_component( package, component );
3598 return ERROR_SUCCESS;
3602 TRACE("component is disabled\n");
3603 return ERROR_SUCCESS;
3606 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3608 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3609 comp->Action = comp->Installed;
3610 return ERROR_SUCCESS;
3612 comp->Action = INSTALLSTATE_ABSENT;
3614 ui_actiondata( package, szRemoveShortcuts, row );
3616 link_file = get_link_file( package, row );
3618 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3619 if (!DeleteFileW( link_file ))
3621 WARN("Failed to remove shortcut file %u\n", GetLastError());
3623 msi_free( link_file );
3625 return ERROR_SUCCESS;
3628 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3632 static const WCHAR query[] =
3633 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3634 '`','S','h','o','r','t','c','u','t','`',0};
3636 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3637 if (rc != ERROR_SUCCESS)
3638 return ERROR_SUCCESS;
3640 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3641 msiobj_release( &view->hdr );
3646 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3648 MSIPACKAGE* package = param;
3656 FileName = MSI_RecordGetString(row,1);
3659 ERR("Unable to get FileName\n");
3660 return ERROR_SUCCESS;
3663 FilePath = build_icon_path(package,FileName);
3665 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3667 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3668 FILE_ATTRIBUTE_NORMAL, NULL);
3670 if (the_file == INVALID_HANDLE_VALUE)
3672 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3674 return ERROR_SUCCESS;
3681 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3682 if (rc != ERROR_SUCCESS)
3684 ERR("Failed to get stream\n");
3685 CloseHandle(the_file);
3686 DeleteFileW(FilePath);
3689 WriteFile(the_file,buffer,sz,&write,NULL);
3690 } while (sz == 1024);
3693 CloseHandle(the_file);
3695 return ERROR_SUCCESS;
3698 static UINT msi_publish_icons(MSIPACKAGE *package)
3703 static const WCHAR query[]= {
3704 'S','E','L','E','C','T',' ','*',' ',
3705 'F','R','O','M',' ','`','I','c','o','n','`',0};
3707 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3708 if (r == ERROR_SUCCESS)
3710 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3711 msiobj_release(&view->hdr);
3714 return ERROR_SUCCESS;
3717 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3723 MSISOURCELISTINFO *info;
3725 r = RegCreateKeyW(hkey, szSourceList, &source);
3726 if (r != ERROR_SUCCESS)
3729 RegCloseKey(source);
3731 buffer = strrchrW(package->PackagePath, '\\') + 1;
3732 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3733 package->Context, MSICODE_PRODUCT,
3734 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3735 if (r != ERROR_SUCCESS)
3738 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3739 package->Context, MSICODE_PRODUCT,
3740 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3741 if (r != ERROR_SUCCESS)
3744 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3745 package->Context, MSICODE_PRODUCT,
3746 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3747 if (r != ERROR_SUCCESS)
3750 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3752 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3753 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3754 info->options, info->value);
3756 MsiSourceListSetInfoW(package->ProductCode, NULL,
3757 info->context, info->options,
3758 info->property, info->value);
3761 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3763 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3764 disk->context, disk->options,
3765 disk->disk_id, disk->volume_label, disk->disk_prompt);
3768 return ERROR_SUCCESS;
3771 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3773 MSIHANDLE hdb, suminfo;
3774 WCHAR guids[MAX_PATH];
3775 WCHAR packcode[SQUISH_GUID_SIZE];
3782 static const WCHAR szProductLanguage[] =
3783 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3784 static const WCHAR szARPProductIcon[] =
3785 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3786 static const WCHAR szProductVersion[] =
3787 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3788 static const WCHAR szAssignment[] =
3789 {'A','s','s','i','g','n','m','e','n','t',0};
3790 static const WCHAR szAdvertiseFlags[] =
3791 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3792 static const WCHAR szClients[] =
3793 {'C','l','i','e','n','t','s',0};
3794 static const WCHAR szColon[] = {':',0};
3796 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3797 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3800 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3801 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3804 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3806 buffer = msi_dup_property(package->db, szARPProductIcon);
3809 LPWSTR path = build_icon_path(package,buffer);
3810 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3815 buffer = msi_dup_property(package->db, szProductVersion);
3818 DWORD verdword = msi_version_str_to_dword(buffer);
3819 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3823 msi_reg_set_val_dword(hkey, szAssignment, 0);
3824 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3825 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3826 msi_reg_set_val_str(hkey, szClients, szColon);
3828 hdb = alloc_msihandle(&package->db->hdr);
3830 return ERROR_NOT_ENOUGH_MEMORY;
3832 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3833 MsiCloseHandle(hdb);
3834 if (r != ERROR_SUCCESS)
3838 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3839 NULL, guids, &size);
3840 if (r != ERROR_SUCCESS)
3843 ptr = strchrW(guids, ';');
3845 squash_guid(guids, packcode);
3846 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3849 MsiCloseHandle(suminfo);
3850 return ERROR_SUCCESS;
3853 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3858 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3860 upgrade = msi_dup_property(package->db, szUpgradeCode);
3862 return ERROR_SUCCESS;
3864 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3866 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3867 if (r != ERROR_SUCCESS)
3872 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3873 if (r != ERROR_SUCCESS)
3877 squash_guid(package->ProductCode, squashed_pc);
3878 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3887 static BOOL msi_check_publish(MSIPACKAGE *package)
3889 MSIFEATURE *feature;
3891 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3893 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3900 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3902 MSIFEATURE *feature;
3904 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3906 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3913 static UINT msi_publish_patches( MSIPACKAGE *package )
3915 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3916 WCHAR patch_squashed[GUID_SIZE];
3917 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
3919 MSIPATCHINFO *patch;
3921 WCHAR *p, *all_patches = NULL;
3924 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
3925 if (r != ERROR_SUCCESS)
3926 return ERROR_FUNCTION_FAILED;
3928 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3929 if (res != ERROR_SUCCESS)
3931 r = ERROR_FUNCTION_FAILED;
3935 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3936 if (r != ERROR_SUCCESS)
3939 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3941 squash_guid( patch->patchcode, patch_squashed );
3942 len += strlenW( patch_squashed ) + 1;
3945 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3949 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3953 squash_guid( patch->patchcode, p );
3954 p += strlenW( p ) + 1;
3956 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3957 (const BYTE *)patch->transforms,
3958 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3959 if (res != ERROR_SUCCESS)
3962 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3963 if (r != ERROR_SUCCESS)
3966 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3967 (const BYTE *)patch->localfile,
3968 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3969 RegCloseKey( patch_key );
3970 if (res != ERROR_SUCCESS)
3973 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3974 if (res != ERROR_SUCCESS)
3977 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
3978 RegCloseKey( patch_key );
3979 if (res != ERROR_SUCCESS)
3983 all_patches[len] = 0;
3984 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3985 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3986 if (res != ERROR_SUCCESS)
3989 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3990 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3991 if (res != ERROR_SUCCESS)
3992 r = ERROR_FUNCTION_FAILED;
3995 RegCloseKey( product_patches_key );
3996 RegCloseKey( patches_key );
3997 RegCloseKey( product_key );
3998 msi_free( all_patches );
4003 * 99% of the work done here is only done for
4004 * advertised installs. However this is where the
4005 * Icon table is processed and written out
4006 * so that is what I am going to do here.
4008 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4011 HKEY hukey = NULL, hudkey = NULL;
4014 if (!list_empty(&package->patches))
4016 rc = msi_publish_patches(package);
4017 if (rc != ERROR_SUCCESS)
4021 /* FIXME: also need to publish if the product is in advertise mode */
4022 if (!msi_check_publish(package))
4023 return ERROR_SUCCESS;
4025 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4027 if (rc != ERROR_SUCCESS)
4030 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4031 NULL, &hudkey, TRUE);
4032 if (rc != ERROR_SUCCESS)
4035 rc = msi_publish_upgrade_code(package);
4036 if (rc != ERROR_SUCCESS)
4039 rc = msi_publish_product_properties(package, hukey);
4040 if (rc != ERROR_SUCCESS)
4043 rc = msi_publish_sourcelist(package, hukey);
4044 if (rc != ERROR_SUCCESS)
4047 rc = msi_publish_icons(package);
4050 uirow = MSI_CreateRecord( 1 );
4051 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4052 ui_actiondata( package, szPublishProduct, uirow );
4053 msiobj_release( &uirow->hdr );
4056 RegCloseKey(hudkey);
4061 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4063 WCHAR *filename, *ptr, *folder, *ret;
4064 const WCHAR *dirprop;
4066 filename = msi_dup_record_field( row, 2 );
4067 if (filename && (ptr = strchrW( filename, '|' )))
4072 dirprop = MSI_RecordGetString( row, 3 );
4075 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4077 folder = msi_dup_property( package->db, dirprop );
4080 folder = msi_dup_property( package->db, szWindowsFolder );
4084 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4085 msi_free( filename );
4089 ret = build_directory_name( 2, folder, ptr );
4091 msi_free( filename );
4096 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4098 MSIPACKAGE *package = param;
4099 LPCWSTR component, section, key, value, identifier;
4100 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4105 component = MSI_RecordGetString(row, 8);
4106 comp = get_loaded_component(package,component);
4108 return ERROR_SUCCESS;
4112 TRACE("component is disabled\n");
4113 return ERROR_SUCCESS;
4116 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4118 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4119 comp->Action = comp->Installed;
4120 return ERROR_SUCCESS;
4122 comp->Action = INSTALLSTATE_LOCAL;
4124 identifier = MSI_RecordGetString(row,1);
4125 section = MSI_RecordGetString(row,4);
4126 key = MSI_RecordGetString(row,5);
4127 value = MSI_RecordGetString(row,6);
4128 action = MSI_RecordGetInteger(row,7);
4130 deformat_string(package,section,&deformated_section);
4131 deformat_string(package,key,&deformated_key);
4132 deformat_string(package,value,&deformated_value);
4134 fullname = get_ini_file_name(package, row);
4138 TRACE("Adding value %s to section %s in %s\n",
4139 debugstr_w(deformated_key), debugstr_w(deformated_section),
4140 debugstr_w(fullname));
4141 WritePrivateProfileStringW(deformated_section, deformated_key,
4142 deformated_value, fullname);
4144 else if (action == 1)
4147 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4148 returned, 10, fullname);
4149 if (returned[0] == 0)
4151 TRACE("Adding value %s to section %s in %s\n",
4152 debugstr_w(deformated_key), debugstr_w(deformated_section),
4153 debugstr_w(fullname));
4155 WritePrivateProfileStringW(deformated_section, deformated_key,
4156 deformated_value, fullname);
4159 else if (action == 3)
4160 FIXME("Append to existing section not yet implemented\n");
4162 uirow = MSI_CreateRecord(4);
4163 MSI_RecordSetStringW(uirow,1,identifier);
4164 MSI_RecordSetStringW(uirow,2,deformated_section);
4165 MSI_RecordSetStringW(uirow,3,deformated_key);
4166 MSI_RecordSetStringW(uirow,4,deformated_value);
4167 ui_actiondata(package,szWriteIniValues,uirow);
4168 msiobj_release( &uirow->hdr );
4171 msi_free(deformated_key);
4172 msi_free(deformated_value);
4173 msi_free(deformated_section);
4174 return ERROR_SUCCESS;
4177 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4181 static const WCHAR ExecSeqQuery[] =
4182 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4183 '`','I','n','i','F','i','l','e','`',0};
4185 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4186 if (rc != ERROR_SUCCESS)
4188 TRACE("no IniFile table\n");
4189 return ERROR_SUCCESS;
4192 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4193 msiobj_release(&view->hdr);
4197 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4199 MSIPACKAGE *package = param;
4200 LPCWSTR component, section, key, value, identifier;
4201 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4206 component = MSI_RecordGetString( row, 8 );
4207 comp = get_loaded_component( package, component );
4209 return ERROR_SUCCESS;
4213 TRACE("component is disabled\n");
4214 return ERROR_SUCCESS;
4217 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4219 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4220 comp->Action = comp->Installed;
4221 return ERROR_SUCCESS;
4223 comp->Action = INSTALLSTATE_ABSENT;
4225 identifier = MSI_RecordGetString( row, 1 );
4226 section = MSI_RecordGetString( row, 4 );
4227 key = MSI_RecordGetString( row, 5 );
4228 value = MSI_RecordGetString( row, 6 );
4229 action = MSI_RecordGetInteger( row, 7 );
4231 deformat_string( package, section, &deformated_section );
4232 deformat_string( package, key, &deformated_key );
4233 deformat_string( package, value, &deformated_value );
4235 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4237 filename = get_ini_file_name( package, row );
4239 TRACE("Removing key %s from section %s in %s\n",
4240 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4242 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4244 WARN("Unable to remove key %u\n", GetLastError());
4246 msi_free( filename );
4249 FIXME("Unsupported action %d\n", action);
4252 uirow = MSI_CreateRecord( 4 );
4253 MSI_RecordSetStringW( uirow, 1, identifier );
4254 MSI_RecordSetStringW( uirow, 2, deformated_section );
4255 MSI_RecordSetStringW( uirow, 3, deformated_key );
4256 MSI_RecordSetStringW( uirow, 4, deformated_value );
4257 ui_actiondata( package, szRemoveIniValues, uirow );
4258 msiobj_release( &uirow->hdr );
4260 msi_free( deformated_key );
4261 msi_free( deformated_value );
4262 msi_free( deformated_section );
4263 return ERROR_SUCCESS;
4266 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4268 MSIPACKAGE *package = param;
4269 LPCWSTR component, section, key, value, identifier;
4270 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4275 component = MSI_RecordGetString( row, 8 );
4276 comp = get_loaded_component( package, component );
4278 return ERROR_SUCCESS;
4282 TRACE("component is disabled\n");
4283 return ERROR_SUCCESS;
4286 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4288 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4289 comp->Action = comp->Installed;
4290 return ERROR_SUCCESS;
4292 comp->Action = INSTALLSTATE_LOCAL;
4294 identifier = MSI_RecordGetString( row, 1 );
4295 section = MSI_RecordGetString( row, 4 );
4296 key = MSI_RecordGetString( row, 5 );
4297 value = MSI_RecordGetString( row, 6 );
4298 action = MSI_RecordGetInteger( row, 7 );
4300 deformat_string( package, section, &deformated_section );
4301 deformat_string( package, key, &deformated_key );
4302 deformat_string( package, value, &deformated_value );
4304 if (action == msidbIniFileActionRemoveLine)
4306 filename = get_ini_file_name( package, row );
4308 TRACE("Removing key %s from section %s in %s\n",
4309 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4311 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4313 WARN("Unable to remove key %u\n", GetLastError());
4315 msi_free( filename );
4318 FIXME("Unsupported action %d\n", action);
4320 uirow = MSI_CreateRecord( 4 );
4321 MSI_RecordSetStringW( uirow, 1, identifier );
4322 MSI_RecordSetStringW( uirow, 2, deformated_section );
4323 MSI_RecordSetStringW( uirow, 3, deformated_key );
4324 MSI_RecordSetStringW( uirow, 4, deformated_value );
4325 ui_actiondata( package, szRemoveIniValues, uirow );
4326 msiobj_release( &uirow->hdr );
4328 msi_free( deformated_key );
4329 msi_free( deformated_value );
4330 msi_free( deformated_section );
4331 return ERROR_SUCCESS;
4334 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4338 static const WCHAR query[] =
4339 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4340 '`','I','n','i','F','i','l','e','`',0};
4341 static const WCHAR remove_query[] =
4342 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4343 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4345 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4346 if (rc == ERROR_SUCCESS)
4348 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4349 msiobj_release( &view->hdr );
4350 if (rc != ERROR_SUCCESS)
4354 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4355 if (rc == ERROR_SUCCESS)
4357 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4358 msiobj_release( &view->hdr );
4359 if (rc != ERROR_SUCCESS)
4363 return ERROR_SUCCESS;
4366 static void register_dll( const WCHAR *dll, BOOL unregister )
4370 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4373 HRESULT (WINAPI *func_ptr)( void );
4374 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4376 func_ptr = (void *)GetProcAddress( hmod, func );
4379 HRESULT hr = func_ptr();
4381 WARN("failed to register dll 0x%08x\n", hr);
4384 WARN("entry point %s not found\n", func);
4385 FreeLibrary( hmod );
4388 WARN("failed to load library %u\n", GetLastError());
4391 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4393 MSIPACKAGE *package = param;
4398 filename = MSI_RecordGetString(row,1);
4399 file = get_loaded_file( package, filename );
4403 ERR("Unable to find file id %s\n",debugstr_w(filename));
4404 return ERROR_SUCCESS;
4407 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4409 register_dll( file->TargetPath, FALSE );
4411 uirow = MSI_CreateRecord( 2 );
4412 MSI_RecordSetStringW( uirow, 1, filename );
4413 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4414 ui_actiondata( package, szSelfRegModules, uirow );
4415 msiobj_release( &uirow->hdr );
4417 return ERROR_SUCCESS;
4420 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4424 static const WCHAR ExecSeqQuery[] =
4425 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4426 '`','S','e','l','f','R','e','g','`',0};
4428 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4429 if (rc != ERROR_SUCCESS)
4431 TRACE("no SelfReg table\n");
4432 return ERROR_SUCCESS;
4435 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4436 msiobj_release(&view->hdr);
4438 return ERROR_SUCCESS;
4441 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4443 MSIPACKAGE *package = param;
4448 filename = MSI_RecordGetString( row, 1 );
4449 file = get_loaded_file( package, filename );
4453 ERR("Unable to find file id %s\n", debugstr_w(filename));
4454 return ERROR_SUCCESS;
4457 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4459 register_dll( file->TargetPath, TRUE );
4461 uirow = MSI_CreateRecord( 2 );
4462 MSI_RecordSetStringW( uirow, 1, filename );
4463 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4464 ui_actiondata( package, szSelfUnregModules, uirow );
4465 msiobj_release( &uirow->hdr );
4467 return ERROR_SUCCESS;
4470 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4474 static const WCHAR query[] =
4475 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4476 '`','S','e','l','f','R','e','g','`',0};
4478 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4479 if (rc != ERROR_SUCCESS)
4481 TRACE("no SelfReg table\n");
4482 return ERROR_SUCCESS;
4485 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4486 msiobj_release( &view->hdr );
4488 return ERROR_SUCCESS;
4491 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4493 MSIFEATURE *feature;
4495 HKEY hkey = NULL, userdata = NULL;
4497 if (!msi_check_publish(package))
4498 return ERROR_SUCCESS;
4500 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4502 if (rc != ERROR_SUCCESS)
4505 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4507 if (rc != ERROR_SUCCESS)
4510 /* here the guids are base 85 encoded */
4511 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4517 BOOL absent = FALSE;
4520 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4521 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4522 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4525 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4529 if (feature->Feature_Parent)
4530 size += strlenW( feature->Feature_Parent )+2;
4532 data = msi_alloc(size * sizeof(WCHAR));
4535 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4537 MSICOMPONENT* component = cl->component;
4541 if (component->ComponentId)
4543 TRACE("From %s\n",debugstr_w(component->ComponentId));
4544 CLSIDFromString(component->ComponentId, &clsid);
4545 encode_base85_guid(&clsid,buf);
4546 TRACE("to %s\n",debugstr_w(buf));
4551 if (feature->Feature_Parent)
4553 static const WCHAR sep[] = {'\2',0};
4555 strcatW(data,feature->Feature_Parent);
4558 msi_reg_set_val_str( userdata, feature->Feature, data );
4562 if (feature->Feature_Parent)
4563 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4566 size += sizeof(WCHAR);
4567 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4568 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4572 size += 2*sizeof(WCHAR);
4573 data = msi_alloc(size);
4576 if (feature->Feature_Parent)
4577 strcpyW( &data[1], feature->Feature_Parent );
4578 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4584 uirow = MSI_CreateRecord( 1 );
4585 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4586 ui_actiondata( package, szPublishFeatures, uirow);
4587 msiobj_release( &uirow->hdr );
4588 /* FIXME: call ui_progress? */
4593 RegCloseKey(userdata);
4597 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4603 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4605 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4607 if (r == ERROR_SUCCESS)
4609 RegDeleteValueW(hkey, feature->Feature);
4613 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4615 if (r == ERROR_SUCCESS)
4617 RegDeleteValueW(hkey, feature->Feature);
4621 uirow = MSI_CreateRecord( 1 );
4622 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4623 ui_actiondata( package, szUnpublishFeatures, uirow );
4624 msiobj_release( &uirow->hdr );
4626 return ERROR_SUCCESS;
4629 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4631 MSIFEATURE *feature;
4633 if (!msi_check_unpublish(package))
4634 return ERROR_SUCCESS;
4636 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4638 msi_unpublish_feature(package, feature);
4641 return ERROR_SUCCESS;
4644 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4648 WCHAR date[9], *val, *buffer;
4649 const WCHAR *prop, *key;
4651 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4652 static const WCHAR szWindowsInstaller[] =
4653 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4654 static const WCHAR modpath_fmt[] =
4655 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4656 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4657 static const WCHAR szModifyPath[] =
4658 {'M','o','d','i','f','y','P','a','t','h',0};
4659 static const WCHAR szUninstallString[] =
4660 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4661 static const WCHAR szEstimatedSize[] =
4662 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4663 static const WCHAR szProductLanguage[] =
4664 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4665 static const WCHAR szProductVersion[] =
4666 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4667 static const WCHAR szDisplayVersion[] =
4668 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4669 static const WCHAR szInstallSource[] =
4670 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4671 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4672 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4673 static const WCHAR szAuthorizedCDFPrefix[] =
4674 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4675 static const WCHAR szARPCONTACT[] =
4676 {'A','R','P','C','O','N','T','A','C','T',0};
4677 static const WCHAR szContact[] =
4678 {'C','o','n','t','a','c','t',0};
4679 static const WCHAR szARPCOMMENTS[] =
4680 {'A','R','P','C','O','M','M','E','N','T','S',0};
4681 static const WCHAR szComments[] =
4682 {'C','o','m','m','e','n','t','s',0};
4683 static const WCHAR szProductName[] =
4684 {'P','r','o','d','u','c','t','N','a','m','e',0};
4685 static const WCHAR szDisplayName[] =
4686 {'D','i','s','p','l','a','y','N','a','m','e',0};
4687 static const WCHAR szARPHELPLINK[] =
4688 {'A','R','P','H','E','L','P','L','I','N','K',0};
4689 static const WCHAR szHelpLink[] =
4690 {'H','e','l','p','L','i','n','k',0};
4691 static const WCHAR szARPHELPTELEPHONE[] =
4692 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4693 static const WCHAR szHelpTelephone[] =
4694 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4695 static const WCHAR szARPINSTALLLOCATION[] =
4696 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4697 static const WCHAR szInstallLocation[] =
4698 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4699 static const WCHAR szManufacturer[] =
4700 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4701 static const WCHAR szPublisher[] =
4702 {'P','u','b','l','i','s','h','e','r',0};
4703 static const WCHAR szARPREADME[] =
4704 {'A','R','P','R','E','A','D','M','E',0};
4705 static const WCHAR szReadme[] =
4706 {'R','e','a','d','M','e',0};
4707 static const WCHAR szARPSIZE[] =
4708 {'A','R','P','S','I','Z','E',0};
4709 static const WCHAR szSize[] =
4710 {'S','i','z','e',0};
4711 static const WCHAR szARPURLINFOABOUT[] =
4712 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4713 static const WCHAR szURLInfoAbout[] =
4714 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4715 static const WCHAR szARPURLUPDATEINFO[] =
4716 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4717 static const WCHAR szURLUpdateInfo[] =
4718 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4720 static const WCHAR *propval[] = {
4721 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4722 szARPCONTACT, szContact,
4723 szARPCOMMENTS, szComments,
4724 szProductName, szDisplayName,
4725 szARPHELPLINK, szHelpLink,
4726 szARPHELPTELEPHONE, szHelpTelephone,
4727 szARPINSTALLLOCATION, szInstallLocation,
4728 cszSourceDir, szInstallSource,
4729 szManufacturer, szPublisher,
4730 szARPREADME, szReadme,
4732 szARPURLINFOABOUT, szURLInfoAbout,
4733 szARPURLUPDATEINFO, szURLUpdateInfo,
4736 const WCHAR **p = propval;
4742 val = msi_dup_property(package->db, prop);
4743 msi_reg_set_val_str(hkey, key, val);
4747 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4749 size = deformat_string(package, modpath_fmt, &buffer);
4750 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4751 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4754 /* FIXME: Write real Estimated Size when we have it */
4755 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4757 GetLocalTime(&systime);
4758 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4759 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4761 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4762 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4764 buffer = msi_dup_property(package->db, szProductVersion);
4765 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4768 DWORD verdword = msi_version_str_to_dword(buffer);
4770 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4771 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4772 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4776 return ERROR_SUCCESS;
4779 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4781 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4783 LPWSTR upgrade_code;
4788 /* FIXME: also need to publish if the product is in advertise mode */
4789 if (!msi_check_publish(package))
4790 return ERROR_SUCCESS;
4792 rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4793 if (rc != ERROR_SUCCESS)
4796 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4797 NULL, &props, TRUE);
4798 if (rc != ERROR_SUCCESS)
4801 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4802 msi_free( package->db->localfile );
4803 package->db->localfile = NULL;
4805 rc = msi_publish_install_properties(package, hkey);
4806 if (rc != ERROR_SUCCESS)
4809 rc = msi_publish_install_properties(package, props);
4810 if (rc != ERROR_SUCCESS)
4813 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4816 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4817 squash_guid(package->ProductCode, squashed_pc);
4818 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4819 RegCloseKey(upgrade);
4820 msi_free(upgrade_code);
4824 uirow = MSI_CreateRecord( 1 );
4825 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4826 ui_actiondata( package, szRegisterProduct, uirow );
4827 msiobj_release( &uirow->hdr );
4830 return ERROR_SUCCESS;
4833 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4835 return execute_script(package,INSTALL_SCRIPT);
4838 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4840 WCHAR *upgrade, **features;
4841 BOOL full_uninstall = TRUE;
4842 MSIFEATURE *feature;
4843 MSIPATCHINFO *patch;
4845 static const WCHAR szUpgradeCode[] =
4846 {'U','p','g','r','a','d','e','C','o','d','e',0};
4848 features = msi_split_string(remove, ',');
4851 ERR("REMOVE feature list is empty!\n");
4852 return ERROR_FUNCTION_FAILED;
4855 if (!lstrcmpW(features[0], szAll))
4856 full_uninstall = TRUE;
4859 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4861 if (feature->Action != INSTALLSTATE_ABSENT)
4862 full_uninstall = FALSE;
4867 if (!full_uninstall)
4868 return ERROR_SUCCESS;
4870 MSIREG_DeleteProductKey(package->ProductCode);
4871 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4872 MSIREG_DeleteUninstallKey(package);
4874 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4876 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4877 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4881 MSIREG_DeleteUserProductKey(package->ProductCode);
4882 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4885 upgrade = msi_dup_property(package->db, szUpgradeCode);
4888 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4892 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4894 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4897 return ERROR_SUCCESS;
4900 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4905 /* turn off scheduling */
4906 package->script->CurrentlyScripting= FALSE;
4908 /* first do the same as an InstallExecute */
4909 rc = ACTION_InstallExecute(package);
4910 if (rc != ERROR_SUCCESS)
4913 /* then handle Commit Actions */
4914 rc = execute_script(package,COMMIT_SCRIPT);
4915 if (rc != ERROR_SUCCESS)
4918 remove = msi_dup_property(package->db, szRemove);
4920 rc = msi_unpublish_product(package, remove);
4926 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4928 static const WCHAR RunOnce[] = {
4929 'S','o','f','t','w','a','r','e','\\',
4930 'M','i','c','r','o','s','o','f','t','\\',
4931 'W','i','n','d','o','w','s','\\',
4932 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4933 'R','u','n','O','n','c','e',0};
4934 static const WCHAR InstallRunOnce[] = {
4935 'S','o','f','t','w','a','r','e','\\',
4936 'M','i','c','r','o','s','o','f','t','\\',
4937 'W','i','n','d','o','w','s','\\',
4938 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4939 'I','n','s','t','a','l','l','e','r','\\',
4940 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4942 static const WCHAR msiexec_fmt[] = {
4944 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4945 '\"','%','s','\"',0};
4946 static const WCHAR install_fmt[] = {
4947 '/','I',' ','\"','%','s','\"',' ',
4948 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4949 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4950 WCHAR buffer[256], sysdir[MAX_PATH];
4952 WCHAR squished_pc[100];
4954 squash_guid(package->ProductCode,squished_pc);
4956 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4957 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4958 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4961 msi_reg_set_val_str( hkey, squished_pc, buffer );
4964 TRACE("Reboot command %s\n",debugstr_w(buffer));
4966 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4967 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4969 msi_reg_set_val_str( hkey, squished_pc, buffer );
4972 return ERROR_INSTALL_SUSPEND;
4975 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4981 * We are currently doing what should be done here in the top level Install
4982 * however for Administrative and uninstalls this step will be needed
4984 if (!package->PackagePath)
4985 return ERROR_SUCCESS;
4987 msi_set_sourcedir_props(package, TRUE);
4989 attrib = GetFileAttributesW(package->db->path);
4990 if (attrib == INVALID_FILE_ATTRIBUTES)
4996 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4997 package->Context, MSICODE_PRODUCT,
4998 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4999 if (rc == ERROR_MORE_DATA)
5001 prompt = msi_alloc(size * sizeof(WCHAR));
5002 MsiSourceListGetInfoW(package->ProductCode, NULL,
5003 package->Context, MSICODE_PRODUCT,
5004 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5007 prompt = strdupW(package->db->path);
5009 msg = generate_error_string(package,1302,1,prompt);
5010 while(attrib == INVALID_FILE_ATTRIBUTES)
5012 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5015 rc = ERROR_INSTALL_USEREXIT;
5018 attrib = GetFileAttributesW(package->db->path);
5024 return ERROR_SUCCESS;
5029 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5032 LPWSTR buffer, productid = NULL;
5033 UINT i, rc = ERROR_SUCCESS;
5036 static const WCHAR szPropKeys[][80] =
5038 {'P','r','o','d','u','c','t','I','D',0},
5039 {'U','S','E','R','N','A','M','E',0},
5040 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5044 static const WCHAR szRegKeys[][80] =
5046 {'P','r','o','d','u','c','t','I','D',0},
5047 {'R','e','g','O','w','n','e','r',0},
5048 {'R','e','g','C','o','m','p','a','n','y',0},
5052 if (msi_check_unpublish(package))
5054 MSIREG_DeleteUserDataProductKey(package->ProductCode);
5058 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5062 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5064 if (rc != ERROR_SUCCESS)
5067 for( i = 0; szPropKeys[i][0]; i++ )
5069 buffer = msi_dup_property( package->db, szPropKeys[i] );
5070 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5075 uirow = MSI_CreateRecord( 1 );
5076 MSI_RecordSetStringW( uirow, 1, productid );
5077 ui_actiondata( package, szRegisterUser, uirow );
5078 msiobj_release( &uirow->hdr );
5080 msi_free(productid);
5086 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5090 package->script->InWhatSequence |= SEQUENCE_EXEC;
5091 rc = ACTION_ProcessExecSequence(package,FALSE);
5096 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5098 MSIPACKAGE *package = param;
5099 LPCWSTR compgroupid, component, feature, qualifier, text;
5100 LPWSTR advertise = NULL, output = NULL;
5108 feature = MSI_RecordGetString(rec, 5);
5109 feat = get_loaded_feature(package, feature);
5111 return ERROR_SUCCESS;
5113 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5114 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5115 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5117 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5118 feat->Action = feat->Installed;
5119 return ERROR_SUCCESS;
5122 component = MSI_RecordGetString(rec, 3);
5123 comp = get_loaded_component(package, component);
5125 return ERROR_SUCCESS;
5127 compgroupid = MSI_RecordGetString(rec,1);
5128 qualifier = MSI_RecordGetString(rec,2);
5130 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5131 if (rc != ERROR_SUCCESS)
5134 text = MSI_RecordGetString(rec,4);
5135 advertise = create_component_advertise_string(package, comp, feature);
5137 sz = strlenW(advertise);
5140 sz += lstrlenW(text);
5143 sz *= sizeof(WCHAR);
5145 output = msi_alloc_zero(sz);
5146 strcpyW(output,advertise);
5147 msi_free(advertise);
5150 strcatW(output,text);
5152 msi_reg_set_val_multi_str( hkey, qualifier, output );
5159 uirow = MSI_CreateRecord( 2 );
5160 MSI_RecordSetStringW( uirow, 1, compgroupid );
5161 MSI_RecordSetStringW( uirow, 2, qualifier);
5162 ui_actiondata( package, szPublishComponents, uirow);
5163 msiobj_release( &uirow->hdr );
5164 /* FIXME: call ui_progress? */
5170 * At present I am ignorning the advertised components part of this and only
5171 * focusing on the qualified component sets
5173 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5177 static const WCHAR ExecSeqQuery[] =
5178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5179 '`','P','u','b','l','i','s','h',
5180 'C','o','m','p','o','n','e','n','t','`',0};
5182 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5183 if (rc != ERROR_SUCCESS)
5184 return ERROR_SUCCESS;
5186 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5187 msiobj_release(&view->hdr);
5192 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5194 static const WCHAR szInstallerComponents[] = {
5195 'S','o','f','t','w','a','r','e','\\',
5196 'M','i','c','r','o','s','o','f','t','\\',
5197 'I','n','s','t','a','l','l','e','r','\\',
5198 'C','o','m','p','o','n','e','n','t','s','\\',0};
5200 MSIPACKAGE *package = param;
5201 LPCWSTR compgroupid, component, feature, qualifier;
5205 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5208 feature = MSI_RecordGetString( rec, 5 );
5209 feat = get_loaded_feature( package, feature );
5211 return ERROR_SUCCESS;
5213 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5215 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5216 feat->Action = feat->Installed;
5217 return ERROR_SUCCESS;
5220 component = MSI_RecordGetString( rec, 3 );
5221 comp = get_loaded_component( package, component );
5223 return ERROR_SUCCESS;
5225 compgroupid = MSI_RecordGetString( rec, 1 );
5226 qualifier = MSI_RecordGetString( rec, 2 );
5228 squash_guid( compgroupid, squashed );
5229 strcpyW( keypath, szInstallerComponents );
5230 strcatW( keypath, squashed );
5232 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5233 if (res != ERROR_SUCCESS)
5235 WARN("Unable to delete component key %d\n", res);
5238 uirow = MSI_CreateRecord( 2 );
5239 MSI_RecordSetStringW( uirow, 1, compgroupid );
5240 MSI_RecordSetStringW( uirow, 2, qualifier );
5241 ui_actiondata( package, szUnpublishComponents, uirow );
5242 msiobj_release( &uirow->hdr );
5244 return ERROR_SUCCESS;
5247 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5251 static const WCHAR query[] =
5252 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5253 '`','P','u','b','l','i','s','h',
5254 'C','o','m','p','o','n','e','n','t','`',0};
5256 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5257 if (rc != ERROR_SUCCESS)
5258 return ERROR_SUCCESS;
5260 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5261 msiobj_release( &view->hdr );
5266 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5268 MSIPACKAGE *package = param;
5271 SC_HANDLE hscm, service = NULL;
5272 LPCWSTR comp, depends, pass;
5273 LPWSTR name = NULL, disp = NULL;
5274 LPCWSTR load_order, serv_name, key;
5275 DWORD serv_type, start_type;
5278 static const WCHAR query[] =
5279 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5280 '`','C','o','m','p','o','n','e','n','t','`',' ',
5281 'W','H','E','R','E',' ',
5282 '`','C','o','m','p','o','n','e','n','t','`',' ',
5283 '=','\'','%','s','\'',0};
5285 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5288 ERR("Failed to open the SC Manager!\n");
5292 start_type = MSI_RecordGetInteger(rec, 5);
5293 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5296 depends = MSI_RecordGetString(rec, 8);
5297 if (depends && *depends)
5298 FIXME("Dependency list unhandled!\n");
5300 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5301 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5302 serv_type = MSI_RecordGetInteger(rec, 4);
5303 err_control = MSI_RecordGetInteger(rec, 6);
5304 load_order = MSI_RecordGetString(rec, 7);
5305 serv_name = MSI_RecordGetString(rec, 9);
5306 pass = MSI_RecordGetString(rec, 10);
5307 comp = MSI_RecordGetString(rec, 12);
5309 /* fetch the service path */
5310 row = MSI_QueryGetRecord(package->db, query, comp);
5313 ERR("Control query failed!\n");
5317 key = MSI_RecordGetString(row, 6);
5319 file = get_loaded_file(package, key);
5320 msiobj_release(&row->hdr);
5323 ERR("Failed to load the service file\n");
5327 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5328 start_type, err_control, file->TargetPath,
5329 load_order, NULL, NULL, serv_name, pass);
5332 if (GetLastError() != ERROR_SERVICE_EXISTS)
5333 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5337 CloseServiceHandle(service);
5338 CloseServiceHandle(hscm);
5342 return ERROR_SUCCESS;
5345 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5349 static const WCHAR ExecSeqQuery[] =
5350 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5351 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5353 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5354 if (rc != ERROR_SUCCESS)
5355 return ERROR_SUCCESS;
5357 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5358 msiobj_release(&view->hdr);
5363 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5364 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5366 LPCWSTR *vector, *temp_vector;
5370 static const WCHAR separator[] = {'[','~',']',0};
5373 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5378 vector = msi_alloc(sizeof(LPWSTR));
5386 vector[*numargs - 1] = p;
5388 if ((q = strstrW(p, separator)))
5392 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5398 vector = temp_vector;
5407 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5409 MSIPACKAGE *package = param;
5412 SC_HANDLE scm = NULL, service = NULL;
5413 LPCWSTR component, *vector = NULL;
5414 LPWSTR name, args, display_name = NULL;
5415 DWORD event, numargs, len;
5416 UINT r = ERROR_FUNCTION_FAILED;
5418 component = MSI_RecordGetString(rec, 6);
5419 comp = get_loaded_component(package, component);
5421 return ERROR_SUCCESS;
5425 TRACE("component is disabled\n");
5426 return ERROR_SUCCESS;
5429 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5431 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5432 comp->Action = comp->Installed;
5433 return ERROR_SUCCESS;
5435 comp->Action = INSTALLSTATE_LOCAL;
5437 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5438 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5439 event = MSI_RecordGetInteger(rec, 3);
5441 if (!(event & msidbServiceControlEventStart))
5447 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5450 ERR("Failed to open the service control manager\n");
5455 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5456 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5458 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5459 GetServiceDisplayNameW( scm, name, display_name, &len );
5462 service = OpenServiceW(scm, name, SERVICE_START);
5465 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5469 vector = msi_service_args_to_vector(args, &numargs);
5471 if (!StartServiceW(service, numargs, vector) &&
5472 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5474 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5481 uirow = MSI_CreateRecord( 2 );
5482 MSI_RecordSetStringW( uirow, 1, display_name );
5483 MSI_RecordSetStringW( uirow, 2, name );
5484 ui_actiondata( package, szStartServices, uirow );
5485 msiobj_release( &uirow->hdr );
5487 CloseServiceHandle(service);
5488 CloseServiceHandle(scm);
5493 msi_free(display_name);
5497 static UINT ACTION_StartServices( MSIPACKAGE *package )
5502 static const WCHAR query[] = {
5503 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5504 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5506 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5507 if (rc != ERROR_SUCCESS)
5508 return ERROR_SUCCESS;
5510 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5511 msiobj_release(&view->hdr);
5516 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5518 DWORD i, needed, count;
5519 ENUM_SERVICE_STATUSW *dependencies;
5523 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5524 0, &needed, &count))
5527 if (GetLastError() != ERROR_MORE_DATA)
5530 dependencies = msi_alloc(needed);
5534 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5535 needed, &needed, &count))
5538 for (i = 0; i < count; i++)
5540 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5541 SERVICE_STOP | SERVICE_QUERY_STATUS);
5545 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5552 msi_free(dependencies);
5556 static UINT stop_service( LPCWSTR name )
5558 SC_HANDLE scm = NULL, service = NULL;
5559 SERVICE_STATUS status;
5560 SERVICE_STATUS_PROCESS ssp;
5563 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5566 WARN("Failed to open the SCM: %d\n", GetLastError());
5570 service = OpenServiceW(scm, name,
5572 SERVICE_QUERY_STATUS |
5573 SERVICE_ENUMERATE_DEPENDENTS);
5576 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5580 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5581 sizeof(SERVICE_STATUS_PROCESS), &needed))
5583 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5587 if (ssp.dwCurrentState == SERVICE_STOPPED)
5590 stop_service_dependents(scm, service);
5592 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5593 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5596 CloseServiceHandle(service);
5597 CloseServiceHandle(scm);
5599 return ERROR_SUCCESS;
5602 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5604 MSIPACKAGE *package = param;
5608 LPWSTR name = NULL, display_name = NULL;
5612 event = MSI_RecordGetInteger( rec, 3 );
5613 if (!(event & msidbServiceControlEventStop))
5614 return ERROR_SUCCESS;
5616 component = MSI_RecordGetString( rec, 6 );
5617 comp = get_loaded_component( package, component );
5619 return ERROR_SUCCESS;
5623 TRACE("component is disabled\n");
5624 return ERROR_SUCCESS;
5627 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5629 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5630 comp->Action = comp->Installed;
5631 return ERROR_SUCCESS;
5633 comp->Action = INSTALLSTATE_ABSENT;
5635 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5638 ERR("Failed to open the service control manager\n");
5643 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5644 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5646 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5647 GetServiceDisplayNameW( scm, name, display_name, &len );
5649 CloseServiceHandle( scm );
5651 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5652 stop_service( name );
5655 uirow = MSI_CreateRecord( 2 );
5656 MSI_RecordSetStringW( uirow, 1, display_name );
5657 MSI_RecordSetStringW( uirow, 2, name );
5658 ui_actiondata( package, szStopServices, uirow );
5659 msiobj_release( &uirow->hdr );
5662 msi_free( display_name );
5663 return ERROR_SUCCESS;
5666 static UINT ACTION_StopServices( MSIPACKAGE *package )
5671 static const WCHAR query[] = {
5672 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5673 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5675 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5676 if (rc != ERROR_SUCCESS)
5677 return ERROR_SUCCESS;
5679 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5680 msiobj_release(&view->hdr);
5685 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5687 MSIPACKAGE *package = param;
5691 LPWSTR name = NULL, display_name = NULL;
5693 SC_HANDLE scm = NULL, service = NULL;
5695 event = MSI_RecordGetInteger( rec, 3 );
5696 if (!(event & msidbServiceControlEventDelete))
5697 return ERROR_SUCCESS;
5699 component = MSI_RecordGetString(rec, 6);
5700 comp = get_loaded_component(package, component);
5702 return ERROR_SUCCESS;
5706 TRACE("component is disabled\n");
5707 return ERROR_SUCCESS;
5710 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5712 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5713 comp->Action = comp->Installed;
5714 return ERROR_SUCCESS;
5716 comp->Action = INSTALLSTATE_ABSENT;
5718 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5719 stop_service( name );
5721 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5724 WARN("Failed to open the SCM: %d\n", GetLastError());
5729 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5730 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5732 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5733 GetServiceDisplayNameW( scm, name, display_name, &len );
5736 service = OpenServiceW( scm, name, DELETE );
5739 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5743 if (!DeleteService( service ))
5744 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5747 uirow = MSI_CreateRecord( 2 );
5748 MSI_RecordSetStringW( uirow, 1, display_name );
5749 MSI_RecordSetStringW( uirow, 2, name );
5750 ui_actiondata( package, szDeleteServices, uirow );
5751 msiobj_release( &uirow->hdr );
5753 CloseServiceHandle( service );
5754 CloseServiceHandle( scm );
5756 msi_free( display_name );
5758 return ERROR_SUCCESS;
5761 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5766 static const WCHAR query[] = {
5767 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5768 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5770 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5771 if (rc != ERROR_SUCCESS)
5772 return ERROR_SUCCESS;
5774 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5775 msiobj_release( &view->hdr );
5780 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5784 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5786 if (!lstrcmpW(file->File, filename))
5793 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5795 MSIPACKAGE *package = param;
5796 LPWSTR driver, driver_path, ptr;
5797 WCHAR outpath[MAX_PATH];
5798 MSIFILE *driver_file, *setup_file;
5802 UINT r = ERROR_SUCCESS;
5804 static const WCHAR driver_fmt[] = {
5805 'D','r','i','v','e','r','=','%','s',0};
5806 static const WCHAR setup_fmt[] = {
5807 'S','e','t','u','p','=','%','s',0};
5808 static const WCHAR usage_fmt[] = {
5809 'F','i','l','e','U','s','a','g','e','=','1',0};
5811 desc = MSI_RecordGetString(rec, 3);
5813 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5814 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5818 ERR("ODBC Driver entry not found!\n");
5819 return ERROR_FUNCTION_FAILED;
5822 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5824 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5825 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5827 driver = msi_alloc(len * sizeof(WCHAR));
5829 return ERROR_OUTOFMEMORY;
5832 lstrcpyW(ptr, desc);
5833 ptr += lstrlenW(ptr) + 1;
5835 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5840 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5844 lstrcpyW(ptr, usage_fmt);
5845 ptr += lstrlenW(ptr) + 1;
5848 driver_path = strdupW(driver_file->TargetPath);
5849 ptr = strrchrW(driver_path, '\\');
5850 if (ptr) *ptr = '\0';
5852 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5853 NULL, ODBC_INSTALL_COMPLETE, &usage))
5855 ERR("Failed to install SQL driver!\n");
5856 r = ERROR_FUNCTION_FAILED;
5859 uirow = MSI_CreateRecord( 5 );
5860 MSI_RecordSetStringW( uirow, 1, desc );
5861 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5862 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5863 ui_actiondata( package, szInstallODBC, uirow );
5864 msiobj_release( &uirow->hdr );
5867 msi_free(driver_path);
5872 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5874 MSIPACKAGE *package = param;
5875 LPWSTR translator, translator_path, ptr;
5876 WCHAR outpath[MAX_PATH];
5877 MSIFILE *translator_file, *setup_file;
5881 UINT r = ERROR_SUCCESS;
5883 static const WCHAR translator_fmt[] = {
5884 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5885 static const WCHAR setup_fmt[] = {
5886 'S','e','t','u','p','=','%','s',0};
5888 desc = MSI_RecordGetString(rec, 3);
5890 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5891 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5893 if (!translator_file)
5895 ERR("ODBC Translator entry not found!\n");
5896 return ERROR_FUNCTION_FAILED;
5899 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5901 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5903 translator = msi_alloc(len * sizeof(WCHAR));
5905 return ERROR_OUTOFMEMORY;
5908 lstrcpyW(ptr, desc);
5909 ptr += lstrlenW(ptr) + 1;
5911 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5916 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5921 translator_path = strdupW(translator_file->TargetPath);
5922 ptr = strrchrW(translator_path, '\\');
5923 if (ptr) *ptr = '\0';
5925 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5926 NULL, ODBC_INSTALL_COMPLETE, &usage))
5928 ERR("Failed to install SQL translator!\n");
5929 r = ERROR_FUNCTION_FAILED;
5932 uirow = MSI_CreateRecord( 5 );
5933 MSI_RecordSetStringW( uirow, 1, desc );
5934 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5935 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
5936 ui_actiondata( package, szInstallODBC, uirow );
5937 msiobj_release( &uirow->hdr );
5939 msi_free(translator);
5940 msi_free(translator_path);
5945 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5947 MSIPACKAGE *package = param;
5949 LPCWSTR desc, driver;
5950 WORD request = ODBC_ADD_SYS_DSN;
5953 UINT r = ERROR_SUCCESS;
5956 static const WCHAR attrs_fmt[] = {
5957 'D','S','N','=','%','s',0 };
5959 desc = MSI_RecordGetString(rec, 3);
5960 driver = MSI_RecordGetString(rec, 4);
5961 registration = MSI_RecordGetInteger(rec, 5);
5963 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5964 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5966 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5967 attrs = msi_alloc(len * sizeof(WCHAR));
5969 return ERROR_OUTOFMEMORY;
5971 len = sprintfW(attrs, attrs_fmt, desc);
5974 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5976 ERR("Failed to install SQL data source!\n");
5977 r = ERROR_FUNCTION_FAILED;
5980 uirow = MSI_CreateRecord( 5 );
5981 MSI_RecordSetStringW( uirow, 1, desc );
5982 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5983 MSI_RecordSetInteger( uirow, 3, request );
5984 ui_actiondata( package, szInstallODBC, uirow );
5985 msiobj_release( &uirow->hdr );
5992 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5997 static const WCHAR driver_query[] = {
5998 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5999 'O','D','B','C','D','r','i','v','e','r',0 };
6001 static const WCHAR translator_query[] = {
6002 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6003 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6005 static const WCHAR source_query[] = {
6006 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6007 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6009 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6010 if (rc != ERROR_SUCCESS)
6011 return ERROR_SUCCESS;
6013 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6014 msiobj_release(&view->hdr);
6016 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6017 if (rc != ERROR_SUCCESS)
6018 return ERROR_SUCCESS;
6020 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6021 msiobj_release(&view->hdr);
6023 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6024 if (rc != ERROR_SUCCESS)
6025 return ERROR_SUCCESS;
6027 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6028 msiobj_release(&view->hdr);
6033 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6035 MSIPACKAGE *package = param;
6040 desc = MSI_RecordGetString( rec, 3 );
6041 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6043 WARN("Failed to remove ODBC driver\n");
6047 FIXME("Usage count reached 0\n");
6050 uirow = MSI_CreateRecord( 2 );
6051 MSI_RecordSetStringW( uirow, 1, desc );
6052 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6053 ui_actiondata( package, szRemoveODBC, uirow );
6054 msiobj_release( &uirow->hdr );
6056 return ERROR_SUCCESS;
6059 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6061 MSIPACKAGE *package = param;
6066 desc = MSI_RecordGetString( rec, 3 );
6067 if (!SQLRemoveTranslatorW( desc, &usage ))
6069 WARN("Failed to remove ODBC translator\n");
6073 FIXME("Usage count reached 0\n");
6076 uirow = MSI_CreateRecord( 2 );
6077 MSI_RecordSetStringW( uirow, 1, desc );
6078 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6079 ui_actiondata( package, szRemoveODBC, uirow );
6080 msiobj_release( &uirow->hdr );
6082 return ERROR_SUCCESS;
6085 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6087 MSIPACKAGE *package = param;
6090 LPCWSTR desc, driver;
6091 WORD request = ODBC_REMOVE_SYS_DSN;
6095 static const WCHAR attrs_fmt[] = {
6096 'D','S','N','=','%','s',0 };
6098 desc = MSI_RecordGetString( rec, 3 );
6099 driver = MSI_RecordGetString( rec, 4 );
6100 registration = MSI_RecordGetInteger( rec, 5 );
6102 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6103 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6105 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6106 attrs = msi_alloc( len * sizeof(WCHAR) );
6108 return ERROR_OUTOFMEMORY;
6110 FIXME("Use ODBCSourceAttribute table\n");
6112 len = sprintfW( attrs, attrs_fmt, desc );
6115 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6117 WARN("Failed to remove ODBC data source\n");
6121 uirow = MSI_CreateRecord( 3 );
6122 MSI_RecordSetStringW( uirow, 1, desc );
6123 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6124 MSI_RecordSetInteger( uirow, 3, request );
6125 ui_actiondata( package, szRemoveODBC, uirow );
6126 msiobj_release( &uirow->hdr );
6128 return ERROR_SUCCESS;
6131 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6136 static const WCHAR driver_query[] = {
6137 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6138 'O','D','B','C','D','r','i','v','e','r',0 };
6140 static const WCHAR translator_query[] = {
6141 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6142 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6144 static const WCHAR source_query[] = {
6145 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6146 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6148 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6149 if (rc != ERROR_SUCCESS)
6150 return ERROR_SUCCESS;
6152 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6153 msiobj_release( &view->hdr );
6155 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6156 if (rc != ERROR_SUCCESS)
6157 return ERROR_SUCCESS;
6159 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6160 msiobj_release( &view->hdr );
6162 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6163 if (rc != ERROR_SUCCESS)
6164 return ERROR_SUCCESS;
6166 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6167 msiobj_release( &view->hdr );
6172 #define ENV_ACT_SETALWAYS 0x1
6173 #define ENV_ACT_SETABSENT 0x2
6174 #define ENV_ACT_REMOVE 0x4
6175 #define ENV_ACT_REMOVEMATCH 0x8
6177 #define ENV_MOD_MACHINE 0x20000000
6178 #define ENV_MOD_APPEND 0x40000000
6179 #define ENV_MOD_PREFIX 0x80000000
6180 #define ENV_MOD_MASK 0xC0000000
6182 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6184 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6186 LPCWSTR cptr = *name;
6188 static const WCHAR prefix[] = {'[','~',']',0};
6189 static const int prefix_len = 3;
6195 *flags |= ENV_ACT_SETALWAYS;
6196 else if (*cptr == '+')
6197 *flags |= ENV_ACT_SETABSENT;
6198 else if (*cptr == '-')
6199 *flags |= ENV_ACT_REMOVE;
6200 else if (*cptr == '!')
6201 *flags |= ENV_ACT_REMOVEMATCH;
6202 else if (*cptr == '*')
6203 *flags |= ENV_MOD_MACHINE;
6213 ERR("Missing environment variable\n");
6214 return ERROR_FUNCTION_FAILED;
6219 LPCWSTR ptr = *value;
6220 if (!strncmpW(ptr, prefix, prefix_len))
6222 if (ptr[prefix_len] == szSemiColon[0])
6224 *flags |= ENV_MOD_APPEND;
6225 *value += lstrlenW(prefix);
6232 else if (lstrlenW(*value) >= prefix_len)
6234 ptr += lstrlenW(ptr) - prefix_len;
6235 if (!lstrcmpW(ptr, prefix))
6237 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6239 *flags |= ENV_MOD_PREFIX;
6240 /* the "[~]" will be removed by deformat_string */;
6250 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6251 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6252 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6253 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6255 ERR("Invalid flags: %08x\n", *flags);
6256 return ERROR_FUNCTION_FAILED;
6260 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6262 return ERROR_SUCCESS;
6265 static UINT open_env_key( DWORD flags, HKEY *key )
6267 static const WCHAR user_env[] =
6268 {'E','n','v','i','r','o','n','m','e','n','t',0};
6269 static const WCHAR machine_env[] =
6270 {'S','y','s','t','e','m','\\',
6271 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6272 'C','o','n','t','r','o','l','\\',
6273 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6274 'E','n','v','i','r','o','n','m','e','n','t',0};
6279 if (flags & ENV_MOD_MACHINE)
6282 root = HKEY_LOCAL_MACHINE;
6287 root = HKEY_CURRENT_USER;
6290 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6291 if (res != ERROR_SUCCESS)
6293 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6294 return ERROR_FUNCTION_FAILED;
6297 return ERROR_SUCCESS;
6300 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6302 MSIPACKAGE *package = param;
6303 LPCWSTR name, value, component;
6304 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6305 DWORD flags, type, size;
6312 component = MSI_RecordGetString(rec, 4);
6313 comp = get_loaded_component(package, component);
6315 return ERROR_SUCCESS;
6319 TRACE("component is disabled\n");
6320 return ERROR_SUCCESS;
6323 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6325 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6326 comp->Action = comp->Installed;
6327 return ERROR_SUCCESS;
6329 comp->Action = INSTALLSTATE_LOCAL;
6331 name = MSI_RecordGetString(rec, 2);
6332 value = MSI_RecordGetString(rec, 3);
6334 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6336 res = env_parse_flags(&name, &value, &flags);
6337 if (res != ERROR_SUCCESS || !value)
6340 if (value && !deformat_string(package, value, &deformatted))
6342 res = ERROR_OUTOFMEMORY;
6346 value = deformatted;
6348 res = open_env_key( flags, &env );
6349 if (res != ERROR_SUCCESS)
6352 if (flags & ENV_MOD_MACHINE)
6353 action |= 0x20000000;
6357 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6358 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6359 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6362 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6366 /* Nothing to do. */
6369 res = ERROR_SUCCESS;
6373 /* If we are appending but the string was empty, strip ; */
6374 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6376 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6377 newval = strdupW(value);
6380 res = ERROR_OUTOFMEMORY;
6388 /* Contrary to MSDN, +-variable to [~];path works */
6389 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6391 res = ERROR_SUCCESS;
6395 data = msi_alloc(size);
6399 return ERROR_OUTOFMEMORY;
6402 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6403 if (res != ERROR_SUCCESS)
6406 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6409 res = RegDeleteValueW(env, name);
6410 if (res != ERROR_SUCCESS)
6411 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6415 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6416 if (flags & ENV_MOD_MASK)
6420 if (flags & ENV_MOD_APPEND) multiplier++;
6421 if (flags & ENV_MOD_PREFIX) multiplier++;
6422 mod_size = lstrlenW(value) * multiplier;
6423 size += mod_size * sizeof(WCHAR);
6426 newval = msi_alloc(size);
6430 res = ERROR_OUTOFMEMORY;
6434 if (flags & ENV_MOD_PREFIX)
6436 lstrcpyW(newval, value);
6437 ptr = newval + lstrlenW(value);
6438 action |= 0x80000000;
6441 lstrcpyW(ptr, data);
6443 if (flags & ENV_MOD_APPEND)
6445 lstrcatW(newval, value);
6446 action |= 0x40000000;
6449 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6450 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6453 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6457 uirow = MSI_CreateRecord( 3 );
6458 MSI_RecordSetStringW( uirow, 1, name );
6459 MSI_RecordSetStringW( uirow, 2, newval );
6460 MSI_RecordSetInteger( uirow, 3, action );
6461 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6462 msiobj_release( &uirow->hdr );
6464 if (env) RegCloseKey(env);
6465 msi_free(deformatted);
6471 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6475 static const WCHAR ExecSeqQuery[] =
6476 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6477 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6478 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6479 if (rc != ERROR_SUCCESS)
6480 return ERROR_SUCCESS;
6482 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6483 msiobj_release(&view->hdr);
6488 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6490 MSIPACKAGE *package = param;
6491 LPCWSTR name, value, component;
6492 LPWSTR deformatted = NULL;
6501 component = MSI_RecordGetString( rec, 4 );
6502 comp = get_loaded_component( package, component );
6504 return ERROR_SUCCESS;
6508 TRACE("component is disabled\n");
6509 return ERROR_SUCCESS;
6512 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6514 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6515 comp->Action = comp->Installed;
6516 return ERROR_SUCCESS;
6518 comp->Action = INSTALLSTATE_ABSENT;
6520 name = MSI_RecordGetString( rec, 2 );
6521 value = MSI_RecordGetString( rec, 3 );
6523 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6525 r = env_parse_flags( &name, &value, &flags );
6526 if (r != ERROR_SUCCESS)
6529 if (!(flags & ENV_ACT_REMOVE))
6531 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6532 return ERROR_SUCCESS;
6535 if (value && !deformat_string( package, value, &deformatted ))
6536 return ERROR_OUTOFMEMORY;
6538 value = deformatted;
6540 r = open_env_key( flags, &env );
6541 if (r != ERROR_SUCCESS)
6547 if (flags & ENV_MOD_MACHINE)
6548 action |= 0x20000000;
6550 TRACE("Removing %s\n", debugstr_w(name));
6552 res = RegDeleteValueW( env, name );
6553 if (res != ERROR_SUCCESS)
6555 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6560 uirow = MSI_CreateRecord( 3 );
6561 MSI_RecordSetStringW( uirow, 1, name );
6562 MSI_RecordSetStringW( uirow, 2, value );
6563 MSI_RecordSetInteger( uirow, 3, action );
6564 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6565 msiobj_release( &uirow->hdr );
6567 if (env) RegCloseKey( env );
6568 msi_free( deformatted );
6572 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6576 static const WCHAR query[] =
6577 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6578 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6580 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6581 if (rc != ERROR_SUCCESS)
6582 return ERROR_SUCCESS;
6584 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6585 msiobj_release( &view->hdr );
6590 typedef struct tagMSIASSEMBLY
6593 MSICOMPONENT *component;
6594 MSIFEATURE *feature;
6598 LPWSTR display_name;
6603 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6605 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6606 LPVOID pvReserved, HMODULE *phModDll);
6608 static BOOL init_functionpointers(void)
6614 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6616 hmscoree = LoadLibraryA("mscoree.dll");
6619 WARN("mscoree.dll not available\n");
6623 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6624 if (!pLoadLibraryShim)
6626 WARN("LoadLibraryShim not available\n");
6627 FreeLibrary(hmscoree);
6631 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6634 WARN("fusion.dll not available\n");
6635 FreeLibrary(hmscoree);
6639 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6641 FreeLibrary(hmscoree);
6645 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6648 IAssemblyCache *cache;
6651 UINT r = ERROR_FUNCTION_FAILED;
6653 TRACE("installing assembly: %s\n", debugstr_w(path));
6655 uirow = MSI_CreateRecord( 2 );
6656 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6657 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6658 msiobj_release( &uirow->hdr );
6660 if (assembly->feature)
6661 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6663 if (assembly->manifest)
6664 FIXME("Manifest unhandled\n");
6666 if (assembly->application)
6668 FIXME("Assembly should be privately installed\n");
6669 return ERROR_SUCCESS;
6672 if (assembly->attributes == msidbAssemblyAttributesWin32)
6674 FIXME("Win32 assemblies not handled\n");
6675 return ERROR_SUCCESS;
6678 hr = pCreateAssemblyCache(&cache, 0);
6682 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6684 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6689 IAssemblyCache_Release(cache);
6693 typedef struct tagASSEMBLY_LIST
6695 MSIPACKAGE *package;
6696 IAssemblyCache *cache;
6697 struct list *assemblies;
6700 typedef struct tagASSEMBLY_NAME
6708 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6710 ASSEMBLY_NAME *asmname = param;
6711 LPCWSTR name = MSI_RecordGetString(rec, 2);
6712 LPWSTR val = msi_dup_record_field(rec, 3);
6714 static const WCHAR Name[] = {'N','a','m','e',0};
6715 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6716 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6717 static const WCHAR PublicKeyToken[] = {
6718 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6720 if (!strcmpiW(name, Name))
6721 asmname->name = val;
6722 else if (!strcmpiW(name, Version))
6723 asmname->version = val;
6724 else if (!strcmpiW(name, Culture))
6725 asmname->culture = val;
6726 else if (!strcmpiW(name, PublicKeyToken))
6727 asmname->pubkeytoken = val;
6731 return ERROR_SUCCESS;
6734 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6738 *size = lstrlenW(append) + 1;
6739 *str = msi_alloc((*size) * sizeof(WCHAR));
6740 lstrcpyW(*str, append);
6744 (*size) += lstrlenW(append);
6745 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6746 lstrcatW(*str, append);
6749 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6751 static const WCHAR separator[] = {',',' ',0};
6752 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6753 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6754 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6755 static const WCHAR query[] = {
6756 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6757 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6758 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6759 '=','\'','%','s','\'',0};
6762 LPWSTR display_name;
6766 display_name = NULL;
6767 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6769 r = MSI_OpenQuery( db, &view, query, comp->Component );
6770 if (r != ERROR_SUCCESS)
6773 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6774 msiobj_release( &view->hdr );
6778 ERR("No assembly name specified!\n");
6782 append_str( &display_name, &size, name.name );
6786 append_str( &display_name, &size, separator );
6787 append_str( &display_name, &size, Version );
6788 append_str( &display_name, &size, name.version );
6792 append_str( &display_name, &size, separator );
6793 append_str( &display_name, &size, Culture );
6794 append_str( &display_name, &size, name.culture );
6796 if (name.pubkeytoken)
6798 append_str( &display_name, &size, separator );
6799 append_str( &display_name, &size, PublicKeyToken );
6800 append_str( &display_name, &size, name.pubkeytoken );
6803 msi_free( name.name );
6804 msi_free( name.version );
6805 msi_free( name.culture );
6806 msi_free( name.pubkeytoken );
6808 return display_name;
6811 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6813 ASSEMBLY_INFO asminfo;
6818 disp = get_assembly_display_name( db, comp );
6822 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6823 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6825 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6827 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6833 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6835 ASSEMBLY_LIST *list = param;
6836 MSIASSEMBLY *assembly;
6839 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6841 return ERROR_OUTOFMEMORY;
6843 component = MSI_RecordGetString(rec, 1);
6844 assembly->component = get_loaded_component(list->package, component);
6845 if (!assembly->component)
6846 return ERROR_SUCCESS;
6848 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6849 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6851 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6852 assembly->component->Action = assembly->component->Installed;
6853 return ERROR_SUCCESS;
6855 assembly->component->Action = assembly->component->ActionRequest;
6857 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6858 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6860 if (!assembly->file)
6862 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6863 return ERROR_FUNCTION_FAILED;
6866 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6867 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6868 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6870 if (assembly->application)
6873 DWORD size = sizeof(version)/sizeof(WCHAR);
6875 /* FIXME: we should probably check the manifest file here */
6877 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6878 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6880 assembly->installed = TRUE;
6884 assembly->installed = check_assembly_installed(list->package->db,
6886 assembly->component);
6888 list_add_head(list->assemblies, &assembly->entry);
6889 return ERROR_SUCCESS;
6892 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6894 IAssemblyCache *cache = NULL;
6900 static const WCHAR query[] =
6901 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6902 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6904 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6905 if (r != ERROR_SUCCESS)
6906 return ERROR_SUCCESS;
6908 hr = pCreateAssemblyCache(&cache, 0);
6910 return ERROR_FUNCTION_FAILED;
6912 list.package = package;
6914 list.assemblies = assemblies;
6916 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6917 msiobj_release(&view->hdr);
6919 IAssemblyCache_Release(cache);
6924 static void free_assemblies(struct list *assemblies)
6926 struct list *item, *cursor;
6928 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6930 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6932 list_remove(&assembly->entry);
6933 msi_free(assembly->application);
6934 msi_free(assembly->manifest);
6935 msi_free(assembly->display_name);
6940 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6942 MSIASSEMBLY *assembly;
6944 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6946 if (!lstrcmpW(assembly->file->File, file))
6956 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6957 LPWSTR *path, DWORD *attrs, PVOID user)
6959 MSIASSEMBLY *assembly;
6960 WCHAR temppath[MAX_PATH];
6961 struct list *assemblies = user;
6964 if (!find_assembly(assemblies, file, &assembly))
6967 GetTempPathW(MAX_PATH, temppath);
6968 PathAddBackslashW(temppath);
6969 lstrcatW(temppath, assembly->file->FileName);
6971 if (action == MSICABEXTRACT_BEGINEXTRACT)
6973 if (assembly->installed)
6976 *path = strdupW(temppath);
6977 *attrs = assembly->file->Attributes;
6979 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6981 assembly->installed = TRUE;
6983 r = install_assembly(package, assembly, temppath);
6984 if (r != ERROR_SUCCESS)
6985 ERR("Failed to install assembly\n");
6991 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6994 struct list assemblies = LIST_INIT(assemblies);
6995 MSIASSEMBLY *assembly;
6998 if (!init_functionpointers() || !pCreateAssemblyCache)
6999 return ERROR_FUNCTION_FAILED;
7001 r = load_assemblies(package, &assemblies);
7002 if (r != ERROR_SUCCESS)
7005 if (list_empty(&assemblies))
7008 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
7011 r = ERROR_OUTOFMEMORY;
7015 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
7017 if (assembly->installed && !mi->is_continuous)
7020 if (assembly->file->IsCompressed)
7022 if (assembly->file->disk_id != mi->disk_id || mi->is_continuous)
7026 r = ready_media(package, assembly->file, mi);
7027 if (r != ERROR_SUCCESS)
7029 ERR("Failed to ready media\n");
7034 data.package = package;
7035 data.cb = installassembly_cb;
7036 data.user = &assemblies;
7038 if (!msi_cabextract(package, mi, &data))
7040 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
7041 r = ERROR_FUNCTION_FAILED;
7048 LPWSTR source = resolve_file_source(package, assembly->file);
7050 r = install_assembly(package, assembly, source);
7051 if (r != ERROR_SUCCESS)
7052 ERR("Failed to install assembly\n");
7057 /* FIXME: write Installer assembly reg values */
7061 free_assemblies(&assemblies);
7065 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7067 LPWSTR key, template, id;
7068 UINT r = ERROR_SUCCESS;
7070 id = msi_dup_property( package->db, szProductID );
7074 return ERROR_SUCCESS;
7076 template = msi_dup_property( package->db, szPIDTemplate );
7077 key = msi_dup_property( package->db, szPIDKEY );
7079 if (key && template)
7081 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7082 r = msi_set_property( package->db, szProductID, key );
7084 msi_free( template );
7089 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7092 package->need_reboot = 1;
7093 return ERROR_SUCCESS;
7096 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7098 static const WCHAR szAvailableFreeReg[] =
7099 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7101 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
7103 TRACE("%p %d kilobytes\n", package, space);
7105 uirow = MSI_CreateRecord( 1 );
7106 MSI_RecordSetInteger( uirow, 1, space );
7107 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7108 msiobj_release( &uirow->hdr );
7110 return ERROR_SUCCESS;
7113 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7115 FIXME("%p\n", package);
7116 return ERROR_SUCCESS;
7119 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7121 FIXME("%p\n", package);
7122 return ERROR_SUCCESS;
7125 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7130 static const WCHAR driver_query[] = {
7131 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7132 'O','D','B','C','D','r','i','v','e','r',0 };
7134 static const WCHAR translator_query[] = {
7135 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7136 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7138 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7139 if (r == ERROR_SUCCESS)
7142 r = MSI_IterateRecords( view, &count, NULL, package );
7143 msiobj_release( &view->hdr );
7144 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7147 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7148 if (r == ERROR_SUCCESS)
7151 r = MSI_IterateRecords( view, &count, NULL, package );
7152 msiobj_release( &view->hdr );
7153 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7156 return ERROR_SUCCESS;
7159 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7160 LPCSTR action, LPCWSTR table )
7162 static const WCHAR query[] = {
7163 'S','E','L','E','C','T',' ','*',' ',
7164 'F','R','O','M',' ','`','%','s','`',0 };
7165 MSIQUERY *view = NULL;
7169 r = MSI_OpenQuery( package->db, &view, query, table );
7170 if (r == ERROR_SUCCESS)
7172 r = MSI_IterateRecords(view, &count, NULL, package);
7173 msiobj_release(&view->hdr);
7177 FIXME("%s -> %u ignored %s table values\n",
7178 action, count, debugstr_w(table));
7180 return ERROR_SUCCESS;
7183 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7185 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7186 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7189 static UINT ACTION_BindImage( MSIPACKAGE *package )
7191 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7192 return msi_unimplemented_action_stub( package, "BindImage", table );
7195 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7197 static const WCHAR table[] = {
7198 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7199 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7202 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7204 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7205 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7208 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7210 static const WCHAR table[] = {
7211 'M','s','i','A','s','s','e','m','b','l','y',0 };
7212 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7215 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7217 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7218 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7221 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7223 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7224 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7227 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7229 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7230 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7233 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7235 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7236 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7239 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7241 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7242 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7245 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7249 const WCHAR *action;
7250 UINT (*handler)(MSIPACKAGE *);
7254 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7255 { szAppSearch, ACTION_AppSearch },
7256 { szBindImage, ACTION_BindImage },
7257 { szCCPSearch, ACTION_CCPSearch },
7258 { szCostFinalize, ACTION_CostFinalize },
7259 { szCostInitialize, ACTION_CostInitialize },
7260 { szCreateFolders, ACTION_CreateFolders },
7261 { szCreateShortcuts, ACTION_CreateShortcuts },
7262 { szDeleteServices, ACTION_DeleteServices },
7263 { szDisableRollback, ACTION_DisableRollback },
7264 { szDuplicateFiles, ACTION_DuplicateFiles },
7265 { szExecuteAction, ACTION_ExecuteAction },
7266 { szFileCost, ACTION_FileCost },
7267 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7268 { szForceReboot, ACTION_ForceReboot },
7269 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7270 { szInstallExecute, ACTION_InstallExecute },
7271 { szInstallExecuteAgain, ACTION_InstallExecute },
7272 { szInstallFiles, ACTION_InstallFiles},
7273 { szInstallFinalize, ACTION_InstallFinalize },
7274 { szInstallInitialize, ACTION_InstallInitialize },
7275 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7276 { szInstallValidate, ACTION_InstallValidate },
7277 { szIsolateComponents, ACTION_IsolateComponents },
7278 { szLaunchConditions, ACTION_LaunchConditions },
7279 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7280 { szMoveFiles, ACTION_MoveFiles },
7281 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7282 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7283 { szInstallODBC, ACTION_InstallODBC },
7284 { szInstallServices, ACTION_InstallServices },
7285 { szPatchFiles, ACTION_PatchFiles },
7286 { szProcessComponents, ACTION_ProcessComponents },
7287 { szPublishComponents, ACTION_PublishComponents },
7288 { szPublishFeatures, ACTION_PublishFeatures },
7289 { szPublishProduct, ACTION_PublishProduct },
7290 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7291 { szRegisterComPlus, ACTION_RegisterComPlus},
7292 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7293 { szRegisterFonts, ACTION_RegisterFonts },
7294 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7295 { szRegisterProduct, ACTION_RegisterProduct },
7296 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7297 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7298 { szRegisterUser, ACTION_RegisterUser },
7299 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7300 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7301 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7302 { szRemoveFiles, ACTION_RemoveFiles },
7303 { szRemoveFolders, ACTION_RemoveFolders },
7304 { szRemoveIniValues, ACTION_RemoveIniValues },
7305 { szRemoveODBC, ACTION_RemoveODBC },
7306 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7307 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7308 { szResolveSource, ACTION_ResolveSource },
7309 { szRMCCPSearch, ACTION_RMCCPSearch },
7310 { szScheduleReboot, ACTION_ScheduleReboot },
7311 { szSelfRegModules, ACTION_SelfRegModules },
7312 { szSelfUnregModules, ACTION_SelfUnregModules },
7313 { szSetODBCFolders, ACTION_SetODBCFolders },
7314 { szStartServices, ACTION_StartServices },
7315 { szStopServices, ACTION_StopServices },
7316 { szUnpublishComponents, ACTION_UnpublishComponents },
7317 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7318 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7319 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7320 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7321 { szUnregisterFonts, ACTION_UnregisterFonts },
7322 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7323 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7324 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7325 { szValidateProductID, ACTION_ValidateProductID },
7326 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7327 { szWriteIniValues, ACTION_WriteIniValues },
7328 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7332 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7338 while (StandardActions[i].action != NULL)
7340 if (!strcmpW( StandardActions[i].action, action ))
7342 ui_actionstart( package, action );
7343 if (StandardActions[i].handler)
7345 ui_actioninfo( package, action, TRUE, 0 );
7346 *rc = StandardActions[i].handler( package );
7347 ui_actioninfo( package, action, FALSE, *rc );
7351 FIXME("unhandled standard action %s\n", debugstr_w(action));
7352 *rc = ERROR_SUCCESS;
7362 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7364 UINT rc = ERROR_SUCCESS;
7367 TRACE("Performing action (%s)\n", debugstr_w(action));
7369 handled = ACTION_HandleStandardAction(package, action, &rc);
7372 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7376 WARN("unhandled msi action %s\n", debugstr_w(action));
7377 rc = ERROR_FUNCTION_NOT_CALLED;
7383 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7385 UINT rc = ERROR_SUCCESS;
7386 BOOL handled = FALSE;
7388 TRACE("Performing action (%s)\n", debugstr_w(action));
7390 handled = ACTION_HandleStandardAction(package, action, &rc);
7393 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7395 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7400 WARN("unhandled msi action %s\n", debugstr_w(action));
7401 rc = ERROR_FUNCTION_NOT_CALLED;
7407 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7409 UINT rc = ERROR_SUCCESS;
7412 static const WCHAR ExecSeqQuery[] =
7413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7414 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7415 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7416 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7417 static const WCHAR UISeqQuery[] =
7418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7419 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7420 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7421 ' ', '=',' ','%','i',0};
7423 if (needs_ui_sequence(package))
7424 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7426 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7430 LPCWSTR action, cond;
7432 TRACE("Running the actions\n");
7434 /* check conditions */
7435 cond = MSI_RecordGetString(row, 2);
7437 /* this is a hack to skip errors in the condition code */
7438 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7440 msiobj_release(&row->hdr);
7441 return ERROR_SUCCESS;
7444 action = MSI_RecordGetString(row, 1);
7447 ERR("failed to fetch action\n");
7448 msiobj_release(&row->hdr);
7449 return ERROR_FUNCTION_FAILED;
7452 if (needs_ui_sequence(package))
7453 rc = ACTION_PerformUIAction(package, action, -1);
7455 rc = ACTION_PerformAction(package, action, -1);
7457 msiobj_release(&row->hdr);
7463 /****************************************************
7464 * TOP level entry points
7465 *****************************************************/
7467 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7468 LPCWSTR szCommandLine )
7473 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7474 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7476 msi_set_property( package->db, szAction, szInstall );
7478 package->script->InWhatSequence = SEQUENCE_INSTALL;
7485 dir = strdupW(szPackagePath);
7486 p = strrchrW(dir, '\\');
7490 file = szPackagePath + (p - dir);
7495 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7496 GetCurrentDirectoryW(MAX_PATH, dir);
7497 lstrcatW(dir, szBackSlash);
7498 file = szPackagePath;
7501 msi_free( package->PackagePath );
7502 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7503 if (!package->PackagePath)
7506 return ERROR_OUTOFMEMORY;
7509 lstrcpyW(package->PackagePath, dir);
7510 lstrcatW(package->PackagePath, file);
7513 msi_set_sourcedir_props(package, FALSE);
7516 msi_parse_command_line( package, szCommandLine, FALSE );
7518 msi_apply_transforms( package );
7519 msi_apply_patches( package );
7521 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7523 TRACE("setting reinstall property\n");
7524 msi_set_property( package->db, szReinstall, szAll );
7527 /* properties may have been added by a transform */
7528 msi_clone_properties( package );
7530 msi_parse_command_line( package, szCommandLine, FALSE );
7531 msi_adjust_privilege_properties( package );
7532 msi_set_context( package );
7534 if (needs_ui_sequence( package))
7536 package->script->InWhatSequence |= SEQUENCE_UI;
7537 rc = ACTION_ProcessUISequence(package);
7538 ui_exists = ui_sequence_exists(package);
7539 if (rc == ERROR_SUCCESS || !ui_exists)
7541 package->script->InWhatSequence |= SEQUENCE_EXEC;
7542 rc = ACTION_ProcessExecSequence(package, ui_exists);
7546 rc = ACTION_ProcessExecSequence(package, FALSE);
7548 package->script->CurrentlyScripting = FALSE;
7550 /* process the ending type action */
7551 if (rc == ERROR_SUCCESS)
7552 ACTION_PerformActionSequence(package, -1);
7553 else if (rc == ERROR_INSTALL_USEREXIT)
7554 ACTION_PerformActionSequence(package, -2);
7555 else if (rc == ERROR_INSTALL_SUSPEND)
7556 ACTION_PerformActionSequence(package, -4);
7558 ACTION_PerformActionSequence(package, -3);
7560 /* finish up running custom actions */
7561 ACTION_FinishCustomActions(package);
7563 if (rc == ERROR_SUCCESS && package->need_reboot)
7564 return ERROR_SUCCESS_REBOOT_REQUIRED;