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;
500 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
502 return ERROR_OUTOFMEMORY;
504 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
508 return ERROR_OUTOFMEMORY;
511 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
514 msi_free( pi->patchcode );
516 return ERROR_OUTOFMEMORY;
523 UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
525 UINT i, r = ERROR_SUCCESS;
528 /* apply substorage transforms */
529 substorage = msi_split_string( patch->transforms, ';' );
530 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
531 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
533 msi_free( substorage );
534 if (r != ERROR_SUCCESS)
537 msi_set_media_source_prop( package );
540 * There might be a CAB file in the patch package,
541 * so append it to the list of storages to search for streams.
543 append_storage_to_db( package->db, patch_db->storage );
545 list_add_tail( &package->patches, &patch->entry );
546 return ERROR_SUCCESS;
549 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
551 static const WCHAR dotmsp[] = {'.','m','s','p',0};
552 MSIDATABASE *patch_db = NULL;
553 WCHAR localfile[MAX_PATH];
555 MSIPATCHINFO *patch = NULL;
556 UINT r = ERROR_SUCCESS;
558 TRACE("%p %s\n", package, debugstr_w( file ) );
560 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
561 if ( r != ERROR_SUCCESS )
563 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
567 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
570 msiobj_release( &patch_db->hdr );
571 return ERROR_FUNCTION_FAILED;
574 r = msi_check_patch_applicable( package, si );
575 if (r != ERROR_SUCCESS)
577 TRACE("patch not applicable\n");
582 r = msi_parse_patch_summary( si, &patch );
583 if ( r != ERROR_SUCCESS )
586 r = msi_get_local_package_name( localfile, dotmsp );
587 if ( r != ERROR_SUCCESS )
590 TRACE("copying to local package %s\n", debugstr_w(localfile));
592 if (!CopyFileW( file, localfile, FALSE ))
594 ERR("Unable to copy package (%s -> %s) (error %u)\n",
595 debugstr_w(file), debugstr_w(localfile), GetLastError());
599 patch->localfile = strdupW( localfile );
601 r = msi_apply_patch_db( package, patch_db, patch );
602 if ( r != ERROR_SUCCESS )
603 WARN("patch failed to apply %u\n", r);
606 msiobj_release( &si->hdr );
607 msiobj_release( &patch_db->hdr );
608 if (patch && r != ERROR_SUCCESS)
610 if (patch->localfile)
611 DeleteFileW( patch->localfile );
613 msi_free( patch->patchcode );
614 msi_free( patch->transforms );
615 msi_free( patch->localfile );
621 /* get the PATCH property, and apply all the patches it specifies */
622 static UINT msi_apply_patches( MSIPACKAGE *package )
624 LPWSTR patch_list, *patches;
625 UINT i, r = ERROR_SUCCESS;
627 patch_list = msi_dup_property( package->db, szPatch );
629 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
631 patches = msi_split_string( patch_list, ';' );
632 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
633 r = msi_apply_patch_package( package, patches[i] );
636 msi_free( patch_list );
641 static UINT msi_apply_transforms( MSIPACKAGE *package )
643 static const WCHAR szTransforms[] = {
644 'T','R','A','N','S','F','O','R','M','S',0 };
645 LPWSTR xform_list, *xforms;
646 UINT i, r = ERROR_SUCCESS;
648 xform_list = msi_dup_property( package->db, szTransforms );
649 xforms = msi_split_string( xform_list, ';' );
651 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
653 if (xforms[i][0] == ':')
654 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
656 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
660 msi_free( xform_list );
665 static BOOL ui_sequence_exists( MSIPACKAGE *package )
670 static const WCHAR ExecSeqQuery [] =
671 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
672 '`','I','n','s','t','a','l','l',
673 'U','I','S','e','q','u','e','n','c','e','`',
674 ' ','W','H','E','R','E',' ',
675 '`','S','e','q','u','e','n','c','e','`',' ',
676 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
677 '`','S','e','q','u','e','n','c','e','`',0};
679 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
680 if (rc == ERROR_SUCCESS)
682 msiobj_release(&view->hdr);
689 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
692 LPWSTR source, check;
695 static const WCHAR szOriginalDatabase[] =
696 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
698 db = msi_dup_property( package->db, szOriginalDatabase );
700 return ERROR_OUTOFMEMORY;
702 p = strrchrW( db, '\\' );
705 p = strrchrW( db, '/' );
709 return ERROR_SUCCESS;
714 source = msi_alloc( len * sizeof(WCHAR) );
715 lstrcpynW( source, db, len );
717 check = msi_dup_property( package->db, cszSourceDir );
718 if (!check || replace)
720 UINT r = msi_set_property( package->db, cszSourceDir, source );
721 if (r == ERROR_SUCCESS)
722 msi_reset_folders( package, TRUE );
726 check = msi_dup_property( package->db, cszSOURCEDIR );
727 if (!check || replace)
728 msi_set_property( package->db, cszSOURCEDIR, source );
734 return ERROR_SUCCESS;
737 static BOOL needs_ui_sequence(MSIPACKAGE *package)
739 INT level = msi_get_property_int(package->db, szUILevel, 0);
740 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
743 UINT msi_set_context(MSIPACKAGE *package)
747 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
749 num = msi_get_property_int(package->db, szAllUsers, 0);
750 if (num == 1 || num == 2)
751 package->Context = MSIINSTALLCONTEXT_MACHINE;
753 return ERROR_SUCCESS;
756 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
759 LPCWSTR cond, action;
760 MSIPACKAGE *package = param;
762 action = MSI_RecordGetString(row,1);
765 ERR("Error is retrieving action name\n");
766 return ERROR_FUNCTION_FAILED;
769 /* check conditions */
770 cond = MSI_RecordGetString(row,2);
772 /* this is a hack to skip errors in the condition code */
773 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
775 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
776 return ERROR_SUCCESS;
779 if (needs_ui_sequence(package))
780 rc = ACTION_PerformUIAction(package, action, -1);
782 rc = ACTION_PerformAction(package, action, -1, FALSE);
784 msi_dialog_check_messages( NULL );
786 if (package->CurrentInstallState != ERROR_SUCCESS)
787 rc = package->CurrentInstallState;
789 if (rc == ERROR_FUNCTION_NOT_CALLED)
792 if (rc != ERROR_SUCCESS)
793 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
798 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
802 static const WCHAR query[] =
803 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
805 ' ','W','H','E','R','E',' ',
806 '`','S','e','q','u','e','n','c','e','`',' ',
807 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
808 '`','S','e','q','u','e','n','c','e','`',0};
810 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
812 r = MSI_OpenQuery( package->db, &view, query, szTable );
813 if (r == ERROR_SUCCESS)
815 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
816 msiobj_release(&view->hdr);
822 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
826 static const WCHAR ExecSeqQuery[] =
827 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
828 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
829 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
830 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
831 'O','R','D','E','R',' ', 'B','Y',' ',
832 '`','S','e','q','u','e','n','c','e','`',0 };
833 static const WCHAR IVQuery[] =
834 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
835 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
836 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
837 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
838 ' ','\'', 'I','n','s','t','a','l','l',
839 'V','a','l','i','d','a','t','e','\'', 0};
842 if (package->script->ExecuteSequenceRun)
844 TRACE("Execute Sequence already Run\n");
845 return ERROR_SUCCESS;
848 package->script->ExecuteSequenceRun = TRUE;
850 /* get the sequence number */
853 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
855 return ERROR_FUNCTION_FAILED;
856 seq = MSI_RecordGetInteger(row,1);
857 msiobj_release(&row->hdr);
860 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
861 if (rc == ERROR_SUCCESS)
863 TRACE("Running the actions\n");
865 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
866 msiobj_release(&view->hdr);
872 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
876 static const WCHAR ExecSeqQuery [] =
877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
878 '`','I','n','s','t','a','l','l',
879 'U','I','S','e','q','u','e','n','c','e','`',
880 ' ','W','H','E','R','E',' ',
881 '`','S','e','q','u','e','n','c','e','`',' ',
882 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
883 '`','S','e','q','u','e','n','c','e','`',0};
885 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
886 if (rc == ERROR_SUCCESS)
888 TRACE("Running the actions\n");
890 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
891 msiobj_release(&view->hdr);
897 /********************************************************
898 * ACTION helper functions and functions that perform the actions
899 *******************************************************/
900 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
901 UINT* rc, UINT script, BOOL force )
906 arc = ACTION_CustomAction(package, action, script, force);
908 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
917 * Actual Action Handlers
920 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
922 MSIPACKAGE *package = param;
923 LPCWSTR dir, component;
929 component = MSI_RecordGetString(row, 2);
930 comp = get_loaded_component(package, component);
932 return ERROR_SUCCESS;
934 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
936 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
937 comp->Action = comp->Installed;
938 return ERROR_SUCCESS;
940 comp->Action = INSTALLSTATE_LOCAL;
942 dir = MSI_RecordGetString(row,1);
945 ERR("Unable to get folder id\n");
946 return ERROR_SUCCESS;
949 uirow = MSI_CreateRecord(1);
950 MSI_RecordSetStringW(uirow, 1, dir);
951 ui_actiondata(package, szCreateFolders, uirow);
952 msiobj_release(&uirow->hdr);
954 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
957 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
958 return ERROR_SUCCESS;
961 TRACE("Folder is %s\n",debugstr_w(full_path));
963 if (folder->State == 0)
964 create_full_pathW(full_path);
969 return ERROR_SUCCESS;
972 /* FIXME: probably should merge this with the above function */
973 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
975 UINT rc = ERROR_SUCCESS;
979 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
981 return ERROR_FUNCTION_FAILED;
983 /* create the path */
984 if (folder->State == 0)
986 create_full_pathW(install_path);
989 msi_free(install_path);
994 UINT msi_create_component_directories( MSIPACKAGE *package )
998 /* create all the folders required by the components are going to install */
999 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1001 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
1003 msi_create_directory( package, comp->Directory );
1006 return ERROR_SUCCESS;
1009 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1011 static const WCHAR ExecSeqQuery[] =
1012 {'S','E','L','E','C','T',' ',
1013 '`','D','i','r','e','c','t','o','r','y','_','`',
1014 ' ','F','R','O','M',' ',
1015 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1019 /* create all the empty folders specified in the CreateFolder table */
1020 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1021 if (rc != ERROR_SUCCESS)
1022 return ERROR_SUCCESS;
1024 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1025 msiobj_release(&view->hdr);
1030 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1032 MSIPACKAGE *package = param;
1033 LPCWSTR dir, component;
1039 component = MSI_RecordGetString(row, 2);
1040 comp = get_loaded_component(package, component);
1042 return ERROR_SUCCESS;
1044 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1046 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1047 comp->Action = comp->Installed;
1048 return ERROR_SUCCESS;
1050 comp->Action = INSTALLSTATE_ABSENT;
1052 dir = MSI_RecordGetString( row, 1 );
1055 ERR("Unable to get folder id\n");
1056 return ERROR_SUCCESS;
1059 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1062 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1063 return ERROR_SUCCESS;
1066 TRACE("folder is %s\n", debugstr_w(full_path));
1068 uirow = MSI_CreateRecord( 1 );
1069 MSI_RecordSetStringW( uirow, 1, full_path );
1070 ui_actiondata( package, szRemoveFolders, uirow );
1071 msiobj_release( &uirow->hdr );
1073 RemoveDirectoryW( full_path );
1076 msi_free( full_path );
1077 return ERROR_SUCCESS;
1080 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1082 static const WCHAR query[] =
1083 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1084 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1089 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1090 if (rc != ERROR_SUCCESS)
1091 return ERROR_SUCCESS;
1093 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1094 msiobj_release( &view->hdr );
1099 static UINT load_component( MSIRECORD *row, LPVOID param )
1101 MSIPACKAGE *package = param;
1104 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1106 return ERROR_FUNCTION_FAILED;
1108 list_add_tail( &package->components, &comp->entry );
1110 /* fill in the data */
1111 comp->Component = msi_dup_record_field( row, 1 );
1113 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1115 comp->ComponentId = msi_dup_record_field( row, 2 );
1116 comp->Directory = msi_dup_record_field( row, 3 );
1117 comp->Attributes = MSI_RecordGetInteger(row,4);
1118 comp->Condition = msi_dup_record_field( row, 5 );
1119 comp->KeyPath = msi_dup_record_field( row, 6 );
1121 comp->Installed = INSTALLSTATE_UNKNOWN;
1122 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1124 return ERROR_SUCCESS;
1127 static UINT load_all_components( MSIPACKAGE *package )
1129 static const WCHAR query[] = {
1130 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1131 '`','C','o','m','p','o','n','e','n','t','`',0 };
1135 if (!list_empty(&package->components))
1136 return ERROR_SUCCESS;
1138 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1139 if (r != ERROR_SUCCESS)
1142 r = MSI_IterateRecords(view, NULL, load_component, package);
1143 msiobj_release(&view->hdr);
1148 MSIPACKAGE *package;
1149 MSIFEATURE *feature;
1152 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1156 cl = msi_alloc( sizeof (*cl) );
1158 return ERROR_NOT_ENOUGH_MEMORY;
1159 cl->component = comp;
1160 list_add_tail( &feature->Components, &cl->entry );
1162 return ERROR_SUCCESS;
1165 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1169 fl = msi_alloc( sizeof(*fl) );
1171 return ERROR_NOT_ENOUGH_MEMORY;
1172 fl->feature = child;
1173 list_add_tail( &parent->Children, &fl->entry );
1175 return ERROR_SUCCESS;
1178 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1180 _ilfs* ilfs = param;
1184 component = MSI_RecordGetString(row,1);
1186 /* check to see if the component is already loaded */
1187 comp = get_loaded_component( ilfs->package, component );
1190 ERR("unknown component %s\n", debugstr_w(component));
1191 return ERROR_FUNCTION_FAILED;
1194 add_feature_component( ilfs->feature, comp );
1195 comp->Enabled = TRUE;
1197 return ERROR_SUCCESS;
1200 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1202 MSIFEATURE *feature;
1207 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1209 if ( !lstrcmpW( feature->Feature, name ) )
1216 static UINT load_feature(MSIRECORD * row, LPVOID param)
1218 MSIPACKAGE* package = param;
1219 MSIFEATURE* feature;
1220 static const WCHAR Query1[] =
1221 {'S','E','L','E','C','T',' ',
1222 '`','C','o','m','p','o','n','e','n','t','_','`',
1223 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1224 'C','o','m','p','o','n','e','n','t','s','`',' ',
1225 'W','H','E','R','E',' ',
1226 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1231 /* fill in the data */
1233 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1235 return ERROR_NOT_ENOUGH_MEMORY;
1237 list_init( &feature->Children );
1238 list_init( &feature->Components );
1240 feature->Feature = msi_dup_record_field( row, 1 );
1242 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1244 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1245 feature->Title = msi_dup_record_field( row, 3 );
1246 feature->Description = msi_dup_record_field( row, 4 );
1248 if (!MSI_RecordIsNull(row,5))
1249 feature->Display = MSI_RecordGetInteger(row,5);
1251 feature->Level= MSI_RecordGetInteger(row,6);
1252 feature->Directory = msi_dup_record_field( row, 7 );
1253 feature->Attributes = MSI_RecordGetInteger(row,8);
1255 feature->Installed = INSTALLSTATE_UNKNOWN;
1256 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1258 list_add_tail( &package->features, &feature->entry );
1260 /* load feature components */
1262 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1263 if (rc != ERROR_SUCCESS)
1264 return ERROR_SUCCESS;
1266 ilfs.package = package;
1267 ilfs.feature = feature;
1269 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1270 msiobj_release(&view->hdr);
1272 return ERROR_SUCCESS;
1275 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1277 MSIPACKAGE* package = param;
1278 MSIFEATURE *parent, *child;
1280 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1282 return ERROR_FUNCTION_FAILED;
1284 if (!child->Feature_Parent)
1285 return ERROR_SUCCESS;
1287 parent = find_feature_by_name( package, child->Feature_Parent );
1289 return ERROR_FUNCTION_FAILED;
1291 add_feature_child( parent, child );
1292 return ERROR_SUCCESS;
1295 static UINT load_all_features( MSIPACKAGE *package )
1297 static const WCHAR query[] = {
1298 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1299 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1300 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1304 if (!list_empty(&package->features))
1305 return ERROR_SUCCESS;
1307 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1308 if (r != ERROR_SUCCESS)
1311 r = MSI_IterateRecords( view, NULL, load_feature, package );
1312 if (r != ERROR_SUCCESS)
1315 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1316 msiobj_release( &view->hdr );
1321 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1332 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1334 static const WCHAR query[] = {
1335 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1336 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1337 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1338 MSIQUERY *view = NULL;
1339 MSIRECORD *row = NULL;
1342 TRACE("%s\n", debugstr_w(file->File));
1344 r = MSI_OpenQuery(package->db, &view, query, file->File);
1345 if (r != ERROR_SUCCESS)
1348 r = MSI_ViewExecute(view, NULL);
1349 if (r != ERROR_SUCCESS)
1352 r = MSI_ViewFetch(view, &row);
1353 if (r != ERROR_SUCCESS)
1356 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1357 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1358 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1359 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1360 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1363 if (view) msiobj_release(&view->hdr);
1364 if (row) msiobj_release(&row->hdr);
1368 static UINT load_file(MSIRECORD *row, LPVOID param)
1370 MSIPACKAGE* package = param;
1374 /* fill in the data */
1376 file = msi_alloc_zero( sizeof (MSIFILE) );
1378 return ERROR_NOT_ENOUGH_MEMORY;
1380 file->File = msi_dup_record_field( row, 1 );
1382 component = MSI_RecordGetString( row, 2 );
1383 file->Component = get_loaded_component( package, component );
1385 if (!file->Component)
1387 WARN("Component not found: %s\n", debugstr_w(component));
1388 msi_free(file->File);
1390 return ERROR_SUCCESS;
1393 file->FileName = msi_dup_record_field( row, 3 );
1394 reduce_to_longfilename( file->FileName );
1396 file->ShortName = msi_dup_record_field( row, 3 );
1397 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1399 file->FileSize = MSI_RecordGetInteger( row, 4 );
1400 file->Version = msi_dup_record_field( row, 5 );
1401 file->Language = msi_dup_record_field( row, 6 );
1402 file->Attributes = MSI_RecordGetInteger( row, 7 );
1403 file->Sequence = MSI_RecordGetInteger( row, 8 );
1405 file->state = msifs_invalid;
1407 /* if the compressed bits are not set in the file attributes,
1408 * then read the information from the package word count property
1410 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1412 file->IsCompressed = FALSE;
1414 else if (file->Attributes &
1415 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1417 file->IsCompressed = TRUE;
1419 else if (file->Attributes & msidbFileAttributesNoncompressed)
1421 file->IsCompressed = FALSE;
1425 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1428 load_file_hash(package, file);
1430 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1432 list_add_tail( &package->files, &file->entry );
1434 return ERROR_SUCCESS;
1437 static UINT load_all_files(MSIPACKAGE *package)
1441 static const WCHAR Query[] =
1442 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1443 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1444 '`','S','e','q','u','e','n','c','e','`', 0};
1446 if (!list_empty(&package->files))
1447 return ERROR_SUCCESS;
1449 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1450 if (rc != ERROR_SUCCESS)
1451 return ERROR_SUCCESS;
1453 rc = MSI_IterateRecords(view, NULL, load_file, package);
1454 msiobj_release(&view->hdr);
1456 return ERROR_SUCCESS;
1459 static UINT load_folder( MSIRECORD *row, LPVOID param )
1461 MSIPACKAGE *package = param;
1462 static WCHAR szEmpty[] = { 0 };
1463 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1466 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1468 return ERROR_NOT_ENOUGH_MEMORY;
1470 folder->Directory = msi_dup_record_field( row, 1 );
1472 TRACE("%s\n", debugstr_w(folder->Directory));
1474 p = msi_dup_record_field(row, 3);
1476 /* split src and target dir */
1478 src_short = folder_split_path( p, ':' );
1480 /* split the long and short paths */
1481 tgt_long = folder_split_path( tgt_short, '|' );
1482 src_long = folder_split_path( src_short, '|' );
1484 /* check for no-op dirs */
1485 if (!lstrcmpW(szDot, tgt_short))
1486 tgt_short = szEmpty;
1487 if (!lstrcmpW(szDot, src_short))
1488 src_short = szEmpty;
1491 tgt_long = tgt_short;
1494 src_short = tgt_short;
1495 src_long = tgt_long;
1499 src_long = src_short;
1501 /* FIXME: use the target short path too */
1502 folder->TargetDefault = strdupW(tgt_long);
1503 folder->SourceShortPath = strdupW(src_short);
1504 folder->SourceLongPath = strdupW(src_long);
1507 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1508 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1509 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1511 folder->Parent = msi_dup_record_field( row, 2 );
1513 folder->Property = msi_dup_property( package->db, folder->Directory );
1515 list_add_tail( &package->folders, &folder->entry );
1517 TRACE("returning %p\n", folder);
1519 return ERROR_SUCCESS;
1522 static UINT load_all_folders( MSIPACKAGE *package )
1524 static const WCHAR query[] = {
1525 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1526 '`','D','i','r','e','c','t','o','r','y','`',0 };
1530 if (!list_empty(&package->folders))
1531 return ERROR_SUCCESS;
1533 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1534 if (r != ERROR_SUCCESS)
1537 r = MSI_IterateRecords(view, NULL, load_folder, package);
1538 msiobj_release(&view->hdr);
1543 * I am not doing any of the costing functionality yet.
1544 * Mostly looking at doing the Component and Feature loading
1546 * The native MSI does A LOT of modification to tables here. Mostly adding
1547 * a lot of temporary columns to the Feature and Component tables.
1549 * note: Native msi also tracks the short filename. But I am only going to
1550 * track the long ones. Also looking at this directory table
1551 * it appears that the directory table does not get the parents
1552 * resolved base on property only based on their entries in the
1555 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1557 static const WCHAR szCosting[] =
1558 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1560 msi_set_property( package->db, szCosting, szZero );
1561 msi_set_property( package->db, cszRootDrive, c_colon );
1563 load_all_folders( package );
1564 load_all_components( package );
1565 load_all_features( package );
1566 load_all_files( package );
1568 return ERROR_SUCCESS;
1571 static UINT execute_script(MSIPACKAGE *package, UINT script )
1574 UINT rc = ERROR_SUCCESS;
1576 TRACE("Executing Script %i\n",script);
1578 if (!package->script)
1580 ERR("no script!\n");
1581 return ERROR_FUNCTION_FAILED;
1584 for (i = 0; i < package->script->ActionCount[script]; i++)
1587 action = package->script->Actions[script][i];
1588 ui_actionstart(package, action);
1589 TRACE("Executing Action (%s)\n",debugstr_w(action));
1590 rc = ACTION_PerformAction(package, action, script, TRUE);
1591 if (rc != ERROR_SUCCESS)
1594 msi_free_action_script(package, script);
1598 static UINT ACTION_FileCost(MSIPACKAGE *package)
1600 return ERROR_SUCCESS;
1603 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1609 state = MsiQueryProductStateW(package->ProductCode);
1611 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1613 if (!comp->ComponentId)
1616 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1617 comp->Installed = INSTALLSTATE_ABSENT;
1620 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1621 package->Context, comp->ComponentId,
1623 if (r != ERROR_SUCCESS)
1624 comp->Installed = INSTALLSTATE_ABSENT;
1629 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1631 MSIFEATURE *feature;
1634 state = MsiQueryProductStateW(package->ProductCode);
1636 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1638 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1639 feature->Installed = INSTALLSTATE_ABSENT;
1642 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1648 static BOOL process_state_property(MSIPACKAGE* package, int level,
1649 LPCWSTR property, INSTALLSTATE state)
1652 MSIFEATURE *feature;
1654 override = msi_dup_property( package->db, property );
1658 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1660 if (lstrcmpW(property, szRemove) &&
1661 (feature->Level <= 0 || feature->Level > level))
1664 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1666 if (strcmpiW(override, szAll)==0)
1667 msi_feature_set_state(package, feature, state);
1670 LPWSTR ptr = override;
1671 LPWSTR ptr2 = strchrW(override,',');
1675 int len = ptr2 - ptr;
1677 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1678 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1680 msi_feature_set_state(package, feature, state);
1686 ptr2 = strchrW(ptr,',');
1698 static BOOL process_overrides( MSIPACKAGE *package, int level )
1700 static const WCHAR szAddLocal[] =
1701 {'A','D','D','L','O','C','A','L',0};
1702 static const WCHAR szAddSource[] =
1703 {'A','D','D','S','O','U','R','C','E',0};
1704 static const WCHAR szAdvertise[] =
1705 {'A','D','V','E','R','T','I','S','E',0};
1708 /* all these activation/deactivation things happen in order and things
1709 * later on the list override things earlier on the list.
1711 * 0 INSTALLLEVEL processing
1724 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1725 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1726 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1727 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1728 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1731 msi_set_property( package->db, szPreselected, szOne );
1736 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1739 static const WCHAR szlevel[] =
1740 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1741 MSICOMPONENT* component;
1742 MSIFEATURE *feature;
1744 TRACE("Checking Install Level\n");
1746 level = msi_get_property_int(package->db, szlevel, 1);
1748 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1750 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1752 BOOL feature_state = ((feature->Level > 0) &&
1753 (feature->Level <= level));
1755 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1757 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1758 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1759 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1760 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1762 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1766 /* disable child features of unselected parent features */
1767 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1771 if (feature->Level > 0 && feature->Level <= level)
1774 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1775 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1780 * now we want to enable or disable components base on feature
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1787 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1788 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1790 if (!feature->Level)
1793 /* features with components that have compressed files are made local */
1794 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1796 if (cl->component->Enabled &&
1797 cl->component->ForceLocalState &&
1798 feature->Action == INSTALLSTATE_SOURCE)
1800 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1805 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1807 component = cl->component;
1809 if (!component->Enabled)
1812 switch (feature->Action)
1814 case INSTALLSTATE_ABSENT:
1815 component->anyAbsent = 1;
1817 case INSTALLSTATE_ADVERTISED:
1818 component->hasAdvertiseFeature = 1;
1820 case INSTALLSTATE_SOURCE:
1821 component->hasSourceFeature = 1;
1823 case INSTALLSTATE_LOCAL:
1824 component->hasLocalFeature = 1;
1826 case INSTALLSTATE_DEFAULT:
1827 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1828 component->hasAdvertiseFeature = 1;
1829 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1830 component->hasSourceFeature = 1;
1832 component->hasLocalFeature = 1;
1840 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1842 /* if the component isn't enabled, leave it alone */
1843 if (!component->Enabled)
1846 /* check if it's local or source */
1847 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1848 (component->hasLocalFeature || component->hasSourceFeature))
1850 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1851 !component->ForceLocalState)
1852 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1854 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1858 /* if any feature is local, the component must be local too */
1859 if (component->hasLocalFeature)
1861 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1865 if (component->hasSourceFeature)
1867 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1871 if (component->hasAdvertiseFeature)
1873 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1877 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1878 if (component->anyAbsent)
1879 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1882 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1884 if (component->Action == INSTALLSTATE_DEFAULT)
1886 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1887 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1890 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1891 debugstr_w(component->Component), component->Installed, component->Action);
1895 return ERROR_SUCCESS;
1898 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1900 MSIPACKAGE *package = param;
1905 name = MSI_RecordGetString(row,1);
1907 f = get_loaded_folder(package, name);
1908 if (!f) return ERROR_SUCCESS;
1910 /* reset the ResolvedTarget */
1911 msi_free(f->ResolvedTarget);
1912 f->ResolvedTarget = NULL;
1914 /* This helper function now does ALL the work */
1915 TRACE("Dir %s ...\n",debugstr_w(name));
1916 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1917 TRACE("resolves to %s\n",debugstr_w(path));
1920 return ERROR_SUCCESS;
1923 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1925 MSIPACKAGE *package = param;
1927 MSIFEATURE *feature;
1929 name = MSI_RecordGetString( row, 1 );
1931 feature = get_loaded_feature( package, name );
1933 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1937 Condition = MSI_RecordGetString(row,3);
1939 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1941 int level = MSI_RecordGetInteger(row,2);
1942 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1943 feature->Level = level;
1946 return ERROR_SUCCESS;
1949 static LPWSTR get_disk_file_version( LPCWSTR filename )
1951 static const WCHAR name_fmt[] =
1952 {'%','u','.','%','u','.','%','u','.','%','u',0};
1953 static const WCHAR name[] = {'\\',0};
1954 VS_FIXEDFILEINFO *lpVer;
1955 WCHAR filever[0x100];
1961 TRACE("%s\n", debugstr_w(filename));
1963 versize = GetFileVersionInfoSizeW( filename, &handle );
1967 version = msi_alloc( versize );
1968 GetFileVersionInfoW( filename, 0, versize, version );
1970 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1972 msi_free( version );
1976 sprintfW( filever, name_fmt,
1977 HIWORD(lpVer->dwFileVersionMS),
1978 LOWORD(lpVer->dwFileVersionMS),
1979 HIWORD(lpVer->dwFileVersionLS),
1980 LOWORD(lpVer->dwFileVersionLS));
1982 msi_free( version );
1984 return strdupW( filever );
1987 static DWORD get_disk_file_size( LPCWSTR filename )
1992 TRACE("%s\n", debugstr_w(filename));
1994 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
1995 if (file == INVALID_HANDLE_VALUE)
1996 return INVALID_FILE_SIZE;
1998 size = GetFileSize( file, NULL );
1999 CloseHandle( file );
2003 static BOOL hash_matches( MSIFILE *file )
2006 MSIFILEHASHINFO hash;
2008 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2009 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2010 if (r != ERROR_SUCCESS)
2013 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2016 static UINT set_file_install_states( MSIPACKAGE *package )
2018 LPWSTR file_version;
2021 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2023 MSICOMPONENT* comp = file->Component;
2030 if (file->IsCompressed)
2031 comp->ForceLocalState = TRUE;
2033 /* calculate target */
2034 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2036 msi_free(file->TargetPath);
2038 TRACE("file %s is named %s\n",
2039 debugstr_w(file->File), debugstr_w(file->FileName));
2041 file->TargetPath = build_directory_name(2, p, file->FileName);
2045 TRACE("file %s resolves to %s\n",
2046 debugstr_w(file->File), debugstr_w(file->TargetPath));
2048 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2050 file->state = msifs_missing;
2051 comp->Cost += file->FileSize;
2054 if (file->Version && (file_version = get_disk_file_version( file->TargetPath )))
2056 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(file_version));
2058 if (strcmpiW(file_version, file->Version) < 0)
2060 file->state = msifs_overwrite;
2061 comp->Cost += file->FileSize;
2065 TRACE("Destination file version equal or greater, not overwriting\n");
2066 file->state = msifs_present;
2068 msi_free( file_version );
2071 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
2073 file->state = msifs_overwrite;
2074 comp->Cost += file->FileSize - file_size;
2077 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2079 TRACE("File hashes match, not overwriting\n");
2080 file->state = msifs_present;
2083 file->state = msifs_overwrite;
2084 comp->Cost += file->FileSize - file_size;
2087 return ERROR_SUCCESS;
2091 * A lot is done in this function aside from just the costing.
2092 * The costing needs to be implemented at some point but for now I am going
2093 * to focus on the directory building
2096 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2098 static const WCHAR ExecSeqQuery[] =
2099 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2100 '`','D','i','r','e','c','t','o','r','y','`',0};
2101 static const WCHAR ConditionQuery[] =
2102 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2103 '`','C','o','n','d','i','t','i','o','n','`',0};
2104 static const WCHAR szCosting[] =
2105 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2106 static const WCHAR szlevel[] =
2107 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2108 static const WCHAR szOutOfDiskSpace[] =
2109 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2111 UINT rc = ERROR_SUCCESS;
2115 TRACE("Building Directory properties\n");
2117 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2118 if (rc == ERROR_SUCCESS)
2120 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2122 msiobj_release(&view->hdr);
2125 /* read components states from the registry */
2126 ACTION_GetComponentInstallStates(package);
2127 ACTION_GetFeatureInstallStates(package);
2129 TRACE("Calculating file install states\n");
2130 set_file_install_states( package );
2132 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2134 TRACE("Evaluating feature conditions\n");
2136 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2137 if (rc == ERROR_SUCCESS)
2139 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2140 msiobj_release( &view->hdr );
2143 TRACE("Evaluating component conditions\n");
2145 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2147 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2149 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2150 comp->Enabled = FALSE;
2153 comp->Enabled = TRUE;
2156 msi_set_property( package->db, szCosting, szOne );
2157 /* set default run level if not set */
2158 level = msi_dup_property( package->db, szlevel );
2160 msi_set_property( package->db, szlevel, szOne );
2163 /* FIXME: check volume disk space */
2164 msi_set_property( package->db, szOutOfDiskSpace, szZero );
2166 return MSI_SetFeatureStates(package);
2169 /* OK this value is "interpreted" and then formatted based on the
2170 first few characters */
2171 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2176 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2182 LPWSTR deformated = NULL;
2185 deformat_string(package, &value[2], &deformated);
2187 /* binary value type */
2191 *size = (strlenW(ptr)/2)+1;
2193 *size = strlenW(ptr)/2;
2195 data = msi_alloc(*size);
2201 /* if uneven pad with a zero in front */
2207 data[count] = (BYTE)strtol(byte,NULL,0);
2209 TRACE("Uneven byte count\n");
2217 data[count] = (BYTE)strtol(byte,NULL,0);
2220 msi_free(deformated);
2222 TRACE("Data %i bytes(%i)\n",*size,count);
2229 deformat_string(package, &value[1], &deformated);
2232 *size = sizeof(DWORD);
2233 data = msi_alloc(*size);
2239 if ( (*p < '0') || (*p > '9') )
2245 if (deformated[0] == '-')
2248 TRACE("DWORD %i\n",*(LPDWORD)data);
2250 msi_free(deformated);
2255 static const WCHAR szMulti[] = {'[','~',']',0};
2264 *type=REG_EXPAND_SZ;
2272 if (strstrW(value,szMulti))
2273 *type = REG_MULTI_SZ;
2275 /* remove initial delimiter */
2276 if (!strncmpW(value, szMulti, 3))
2279 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2281 /* add double NULL terminator */
2282 if (*type == REG_MULTI_SZ)
2284 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2285 data = msi_realloc_zero(data, *size);
2291 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2298 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2300 *root_key = HKEY_LOCAL_MACHINE;
2305 *root_key = HKEY_CURRENT_USER;
2310 *root_key = HKEY_CLASSES_ROOT;
2314 *root_key = HKEY_CURRENT_USER;
2318 *root_key = HKEY_LOCAL_MACHINE;
2322 *root_key = HKEY_USERS;
2326 ERR("Unknown root %i\n", root);
2333 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2335 MSIPACKAGE *package = param;
2336 LPSTR value_data = NULL;
2337 HKEY root_key, hkey;
2340 LPCWSTR szRoot, component, name, key, value;
2345 BOOL check_first = FALSE;
2348 ui_progress(package,2,0,0,0);
2355 component = MSI_RecordGetString(row, 6);
2356 comp = get_loaded_component(package,component);
2358 return ERROR_SUCCESS;
2360 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2362 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2363 comp->Action = comp->Installed;
2364 return ERROR_SUCCESS;
2366 comp->Action = INSTALLSTATE_LOCAL;
2368 name = MSI_RecordGetString(row, 4);
2369 if( MSI_RecordIsNull(row,5) && name )
2371 /* null values can have special meanings */
2372 if (name[0]=='-' && name[1] == 0)
2373 return ERROR_SUCCESS;
2374 else if ((name[0]=='+' && name[1] == 0) ||
2375 (name[0] == '*' && name[1] == 0))
2380 root = MSI_RecordGetInteger(row,2);
2381 key = MSI_RecordGetString(row, 3);
2383 szRoot = get_root_key( package, root, &root_key );
2385 return ERROR_SUCCESS;
2387 deformat_string(package, key , &deformated);
2388 size = strlenW(deformated) + strlenW(szRoot) + 1;
2389 uikey = msi_alloc(size*sizeof(WCHAR));
2390 strcpyW(uikey,szRoot);
2391 strcatW(uikey,deformated);
2393 if (RegCreateKeyW( root_key, deformated, &hkey))
2395 ERR("Could not create key %s\n",debugstr_w(deformated));
2396 msi_free(deformated);
2398 return ERROR_SUCCESS;
2400 msi_free(deformated);
2402 value = MSI_RecordGetString(row,5);
2404 value_data = parse_value(package, value, &type, &size);
2407 value_data = (LPSTR)strdupW(szEmpty);
2408 size = sizeof(szEmpty);
2412 deformat_string(package, name, &deformated);
2416 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2418 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2423 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2424 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2426 TRACE("value %s of %s checked already exists\n",
2427 debugstr_w(deformated), debugstr_w(uikey));
2431 TRACE("Checked and setting value %s of %s\n",
2432 debugstr_w(deformated), debugstr_w(uikey));
2433 if (deformated || size)
2434 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2439 uirow = MSI_CreateRecord(3);
2440 MSI_RecordSetStringW(uirow,2,deformated);
2441 MSI_RecordSetStringW(uirow,1,uikey);
2442 if (type == REG_SZ || type == REG_EXPAND_SZ)
2443 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2444 ui_actiondata(package,szWriteRegistryValues,uirow);
2445 msiobj_release( &uirow->hdr );
2447 msi_free(value_data);
2448 msi_free(deformated);
2451 return ERROR_SUCCESS;
2454 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2458 static const WCHAR ExecSeqQuery[] =
2459 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2460 '`','R','e','g','i','s','t','r','y','`',0 };
2462 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2463 if (rc != ERROR_SUCCESS)
2464 return ERROR_SUCCESS;
2466 /* increment progress bar each time action data is sent */
2467 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2469 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2471 msiobj_release(&view->hdr);
2475 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2479 DWORD num_subkeys, num_values;
2483 if ((res = RegDeleteTreeW( hkey_root, key )))
2485 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2490 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2492 if ((res = RegDeleteValueW( hkey, value )))
2494 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2496 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2497 NULL, NULL, NULL, NULL );
2498 RegCloseKey( hkey );
2500 if (!res && !num_subkeys && !num_values)
2502 TRACE("Removing empty key %s\n", debugstr_w(key));
2503 RegDeleteKeyW( hkey_root, key );
2507 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2511 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2513 MSIPACKAGE *package = param;
2514 LPCWSTR component, name, key_str, root_key_str;
2515 LPWSTR deformated_key, deformated_name, ui_key_str;
2518 BOOL delete_key = FALSE;
2523 ui_progress( package, 2, 0, 0, 0 );
2525 component = MSI_RecordGetString( row, 6 );
2526 comp = get_loaded_component( package, component );
2528 return ERROR_SUCCESS;
2530 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2532 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2533 comp->Action = comp->Installed;
2534 return ERROR_SUCCESS;
2536 comp->Action = INSTALLSTATE_ABSENT;
2538 name = MSI_RecordGetString( row, 4 );
2539 if (MSI_RecordIsNull( row, 5 ) && name )
2541 if (name[0] == '+' && !name[1])
2542 return ERROR_SUCCESS;
2543 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2550 root = MSI_RecordGetInteger( row, 2 );
2551 key_str = MSI_RecordGetString( row, 3 );
2553 root_key_str = get_root_key( package, root, &hkey_root );
2555 return ERROR_SUCCESS;
2557 deformat_string( package, key_str, &deformated_key );
2558 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2559 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2560 strcpyW( ui_key_str, root_key_str );
2561 strcatW( ui_key_str, deformated_key );
2563 deformat_string( package, name, &deformated_name );
2565 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2566 msi_free( deformated_key );
2568 uirow = MSI_CreateRecord( 2 );
2569 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2570 MSI_RecordSetStringW( uirow, 2, deformated_name );
2572 ui_actiondata( package, szRemoveRegistryValues, uirow );
2573 msiobj_release( &uirow->hdr );
2575 msi_free( ui_key_str );
2576 msi_free( deformated_name );
2577 return ERROR_SUCCESS;
2580 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2582 MSIPACKAGE *package = param;
2583 LPCWSTR component, name, key_str, root_key_str;
2584 LPWSTR deformated_key, deformated_name, ui_key_str;
2587 BOOL delete_key = FALSE;
2592 ui_progress( package, 2, 0, 0, 0 );
2594 component = MSI_RecordGetString( row, 5 );
2595 comp = get_loaded_component( package, component );
2597 return ERROR_SUCCESS;
2599 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2601 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2602 comp->Action = comp->Installed;
2603 return ERROR_SUCCESS;
2605 comp->Action = INSTALLSTATE_LOCAL;
2607 if ((name = MSI_RecordGetString( row, 4 )))
2609 if (name[0] == '-' && !name[1])
2616 root = MSI_RecordGetInteger( row, 2 );
2617 key_str = MSI_RecordGetString( row, 3 );
2619 root_key_str = get_root_key( package, root, &hkey_root );
2621 return ERROR_SUCCESS;
2623 deformat_string( package, key_str, &deformated_key );
2624 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2625 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2626 strcpyW( ui_key_str, root_key_str );
2627 strcatW( ui_key_str, deformated_key );
2629 deformat_string( package, name, &deformated_name );
2631 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2632 msi_free( deformated_key );
2634 uirow = MSI_CreateRecord( 2 );
2635 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2636 MSI_RecordSetStringW( uirow, 2, deformated_name );
2638 ui_actiondata( package, szRemoveRegistryValues, uirow );
2639 msiobj_release( &uirow->hdr );
2641 msi_free( ui_key_str );
2642 msi_free( deformated_name );
2643 return ERROR_SUCCESS;
2646 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2650 static const WCHAR registry_query[] =
2651 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2652 '`','R','e','g','i','s','t','r','y','`',0 };
2653 static const WCHAR remove_registry_query[] =
2654 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2655 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2657 /* increment progress bar each time action data is sent */
2658 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2660 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2661 if (rc == ERROR_SUCCESS)
2663 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2664 msiobj_release( &view->hdr );
2665 if (rc != ERROR_SUCCESS)
2669 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2670 if (rc == ERROR_SUCCESS)
2672 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2673 msiobj_release( &view->hdr );
2674 if (rc != ERROR_SUCCESS)
2678 return ERROR_SUCCESS;
2681 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2683 package->script->CurrentlyScripting = TRUE;
2685 return ERROR_SUCCESS;
2689 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2694 static const WCHAR q1[]=
2695 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2696 '`','R','e','g','i','s','t','r','y','`',0};
2699 MSIFEATURE *feature;
2702 TRACE("InstallValidate\n");
2704 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2705 if (rc == ERROR_SUCCESS)
2707 MSI_IterateRecords( view, &progress, NULL, package );
2708 msiobj_release( &view->hdr );
2709 total += progress * REG_PROGRESS_VALUE;
2712 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2713 total += COMPONENT_PROGRESS_VALUE;
2715 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2716 total += file->FileSize;
2718 ui_progress(package,0,total,0,0);
2720 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2722 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2723 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2724 feature->ActionRequest);
2727 return ERROR_SUCCESS;
2730 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2732 MSIPACKAGE* package = param;
2733 LPCWSTR cond = NULL;
2734 LPCWSTR message = NULL;
2737 static const WCHAR title[]=
2738 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2740 cond = MSI_RecordGetString(row,1);
2742 r = MSI_EvaluateConditionW(package,cond);
2743 if (r == MSICONDITION_FALSE)
2745 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2748 message = MSI_RecordGetString(row,2);
2749 deformat_string(package,message,&deformated);
2750 MessageBoxW(NULL,deformated,title,MB_OK);
2751 msi_free(deformated);
2754 return ERROR_INSTALL_FAILURE;
2757 return ERROR_SUCCESS;
2760 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2763 MSIQUERY * view = NULL;
2764 static const WCHAR ExecSeqQuery[] =
2765 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2766 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2768 TRACE("Checking launch conditions\n");
2770 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2771 if (rc != ERROR_SUCCESS)
2772 return ERROR_SUCCESS;
2774 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2775 msiobj_release(&view->hdr);
2780 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2784 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2786 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2788 MSIRECORD * row = 0;
2790 LPWSTR deformated,buffer,deformated_name;
2792 static const WCHAR ExecSeqQuery[] =
2793 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2794 '`','R','e','g','i','s','t','r','y','`',' ',
2795 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2796 ' ','=',' ' ,'\'','%','s','\'',0 };
2797 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2798 static const WCHAR fmt2[]=
2799 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2801 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2805 root = MSI_RecordGetInteger(row,2);
2806 key = MSI_RecordGetString(row, 3);
2807 name = MSI_RecordGetString(row, 4);
2808 deformat_string(package, key , &deformated);
2809 deformat_string(package, name, &deformated_name);
2811 len = strlenW(deformated) + 6;
2812 if (deformated_name)
2813 len+=strlenW(deformated_name);
2815 buffer = msi_alloc( len *sizeof(WCHAR));
2817 if (deformated_name)
2818 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2820 sprintfW(buffer,fmt,root,deformated);
2822 msi_free(deformated);
2823 msi_free(deformated_name);
2824 msiobj_release(&row->hdr);
2828 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2830 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2835 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2838 return strdupW( file->TargetPath );
2843 static HKEY openSharedDLLsKey(void)
2846 static const WCHAR path[] =
2847 {'S','o','f','t','w','a','r','e','\\',
2848 'M','i','c','r','o','s','o','f','t','\\',
2849 'W','i','n','d','o','w','s','\\',
2850 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2851 'S','h','a','r','e','d','D','L','L','s',0};
2853 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2857 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2862 DWORD sz = sizeof(count);
2865 hkey = openSharedDLLsKey();
2866 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2867 if (rc != ERROR_SUCCESS)
2873 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2877 hkey = openSharedDLLsKey();
2879 msi_reg_set_val_dword( hkey, path, count );
2881 RegDeleteValueW(hkey,path);
2887 * Return TRUE if the count should be written out and FALSE if not
2889 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2891 MSIFEATURE *feature;
2895 /* only refcount DLLs */
2896 if (comp->KeyPath == NULL ||
2897 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2898 comp->Attributes & msidbComponentAttributesODBCDataSource)
2902 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2903 write = (count > 0);
2905 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2909 /* increment counts */
2910 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2914 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2917 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2919 if ( cl->component == comp )
2924 /* decrement counts */
2925 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2929 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2932 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2934 if ( cl->component == comp )
2939 /* ref count all the files in the component */
2944 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2946 if (file->Component == comp)
2947 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2951 /* add a count for permanent */
2952 if (comp->Attributes & msidbComponentAttributesPermanent)
2955 comp->RefCount = count;
2958 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2961 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2963 WCHAR squished_pc[GUID_SIZE];
2964 WCHAR squished_cc[GUID_SIZE];
2971 squash_guid(package->ProductCode,squished_pc);
2972 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2974 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2978 ui_progress(package,2,0,0,0);
2979 if (!comp->ComponentId)
2982 squash_guid(comp->ComponentId,squished_cc);
2984 msi_free(comp->FullKeypath);
2985 comp->FullKeypath = resolve_keypath( package, comp );
2987 ACTION_RefCountComponent( package, comp );
2989 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2990 debugstr_w(comp->Component),
2991 debugstr_w(squished_cc),
2992 debugstr_w(comp->FullKeypath),
2995 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2996 comp->ActionRequest == INSTALLSTATE_SOURCE)
2998 if (!comp->FullKeypath)
3001 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3002 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3005 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3008 if (rc != ERROR_SUCCESS)
3011 if (comp->Attributes & msidbComponentAttributesPermanent)
3013 static const WCHAR szPermKey[] =
3014 { '0','0','0','0','0','0','0','0','0','0','0','0',
3015 '0','0','0','0','0','0','0','0','0','0','0','0',
3016 '0','0','0','0','0','0','0','0',0 };
3018 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
3021 if (comp->Action == INSTALLSTATE_LOCAL)
3022 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3028 WCHAR source[MAX_PATH];
3029 WCHAR base[MAX_PATH];
3032 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3033 static const WCHAR query[] = {
3034 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3035 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3036 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3037 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3038 '`','D','i','s','k','I','d','`',0};
3040 file = get_loaded_file(package, comp->KeyPath);
3044 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3045 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3046 ptr2 = strrchrW(source, '\\') + 1;
3047 msiobj_release(&row->hdr);
3049 lstrcpyW(base, package->PackagePath);
3050 ptr = strrchrW(base, '\\');
3053 sourcepath = resolve_file_source(package, file);
3054 ptr = sourcepath + lstrlenW(base);
3055 lstrcpyW(ptr2, ptr);
3056 msi_free(sourcepath);
3058 msi_reg_set_val_str(hkey, squished_pc, source);
3062 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3064 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3065 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3067 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3069 comp->Action = comp->ActionRequest;
3072 uirow = MSI_CreateRecord(3);
3073 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3074 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3075 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3076 ui_actiondata(package,szProcessComponents,uirow);
3077 msiobj_release( &uirow->hdr );
3080 return ERROR_SUCCESS;
3091 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3092 LPWSTR lpszName, LONG_PTR lParam)
3095 typelib_struct *tl_struct = (typelib_struct*) lParam;
3096 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3100 if (!IS_INTRESOURCE(lpszName))
3102 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3106 sz = strlenW(tl_struct->source)+4;
3107 sz *= sizeof(WCHAR);
3109 if ((INT_PTR)lpszName == 1)
3110 tl_struct->path = strdupW(tl_struct->source);
3113 tl_struct->path = msi_alloc(sz);
3114 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3117 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3118 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3121 msi_free(tl_struct->path);
3122 tl_struct->path = NULL;
3127 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3128 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3130 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3134 msi_free(tl_struct->path);
3135 tl_struct->path = NULL;
3137 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3138 ITypeLib_Release(tl_struct->ptLib);
3143 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3145 MSIPACKAGE* package = param;
3149 typelib_struct tl_struct;
3154 component = MSI_RecordGetString(row,3);
3155 comp = get_loaded_component(package,component);
3157 return ERROR_SUCCESS;
3159 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3161 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3162 comp->Action = comp->Installed;
3163 return ERROR_SUCCESS;
3165 comp->Action = INSTALLSTATE_LOCAL;
3167 file = get_loaded_file( package, comp->KeyPath );
3169 return ERROR_SUCCESS;
3171 ui_actiondata( package, szRegisterTypeLibraries, row );
3173 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3177 guid = MSI_RecordGetString(row,1);
3178 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3179 tl_struct.source = strdupW( file->TargetPath );
3180 tl_struct.path = NULL;
3182 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3183 (LONG_PTR)&tl_struct);
3191 helpid = MSI_RecordGetString(row,6);
3194 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3195 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3199 ERR("Failed to register type library %s\n",
3200 debugstr_w(tl_struct.path));
3202 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3204 ITypeLib_Release(tl_struct.ptLib);
3205 msi_free(tl_struct.path);
3208 ERR("Failed to load type library %s\n",
3209 debugstr_w(tl_struct.source));
3211 FreeLibrary(module);
3212 msi_free(tl_struct.source);
3216 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3219 ERR("Failed to load type library: %08x\n", hr);
3220 return ERROR_INSTALL_FAILURE;
3223 ITypeLib_Release(tlib);
3226 return ERROR_SUCCESS;
3229 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3232 * OK this is a bit confusing.. I am given a _Component key and I believe
3233 * that the file that is being registered as a type library is the "key file
3234 * of that component" which I interpret to mean "The file in the KeyPath of
3239 static const WCHAR Query[] =
3240 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3241 '`','T','y','p','e','L','i','b','`',0};
3243 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3244 if (rc != ERROR_SUCCESS)
3245 return ERROR_SUCCESS;
3247 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3248 msiobj_release(&view->hdr);
3252 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3254 MSIPACKAGE *package = param;
3255 LPCWSTR component, guid;
3263 component = MSI_RecordGetString( row, 3 );
3264 comp = get_loaded_component( package, component );
3266 return ERROR_SUCCESS;
3268 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3270 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3271 comp->Action = comp->Installed;
3272 return ERROR_SUCCESS;
3274 comp->Action = INSTALLSTATE_ABSENT;
3276 ui_actiondata( package, szUnregisterTypeLibraries, row );
3278 guid = MSI_RecordGetString( row, 1 );
3279 CLSIDFromString( (LPCWSTR)guid, &libid );
3280 version = MSI_RecordGetInteger( row, 4 );
3281 language = MSI_RecordGetInteger( row, 2 );
3284 syskind = SYS_WIN64;
3286 syskind = SYS_WIN32;
3289 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3292 WARN("Failed to unregister typelib: %08x\n", hr);
3295 return ERROR_SUCCESS;
3298 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3302 static const WCHAR query[] =
3303 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3304 '`','T','y','p','e','L','i','b','`',0};
3306 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3307 if (rc != ERROR_SUCCESS)
3308 return ERROR_SUCCESS;
3310 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3311 msiobj_release( &view->hdr );
3315 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3317 static const WCHAR szlnk[] = {'.','l','n','k',0};
3318 LPCWSTR directory, extension;
3319 LPWSTR link_folder, link_file, filename;
3321 directory = MSI_RecordGetString( row, 2 );
3322 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3324 /* may be needed because of a bug somewhere else */
3325 create_full_pathW( link_folder );
3327 filename = msi_dup_record_field( row, 3 );
3328 reduce_to_longfilename( filename );
3330 extension = strchrW( filename, '.' );
3331 if (!extension || strcmpiW( extension, szlnk ))
3333 int len = strlenW( filename );
3334 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3335 memcpy( filename + len, szlnk, sizeof(szlnk) );
3337 link_file = build_directory_name( 2, link_folder, filename );
3338 msi_free( link_folder );
3339 msi_free( filename );
3344 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3346 MSIPACKAGE *package = param;
3347 LPWSTR link_file, deformated, path;
3348 LPCWSTR component, target;
3350 IShellLinkW *sl = NULL;
3351 IPersistFile *pf = NULL;
3354 component = MSI_RecordGetString(row, 4);
3355 comp = get_loaded_component(package, component);
3357 return ERROR_SUCCESS;
3359 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3361 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3362 comp->Action = comp->Installed;
3363 return ERROR_SUCCESS;
3365 comp->Action = INSTALLSTATE_LOCAL;
3367 ui_actiondata(package,szCreateShortcuts,row);
3369 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3370 &IID_IShellLinkW, (LPVOID *) &sl );
3374 ERR("CLSID_ShellLink not available\n");
3378 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3381 ERR("QueryInterface(IID_IPersistFile) failed\n");
3385 target = MSI_RecordGetString(row, 5);
3386 if (strchrW(target, '['))
3388 deformat_string(package, target, &deformated);
3389 IShellLinkW_SetPath(sl,deformated);
3390 msi_free(deformated);
3394 FIXME("poorly handled shortcut format, advertised shortcut\n");
3395 IShellLinkW_SetPath(sl,comp->FullKeypath);
3398 if (!MSI_RecordIsNull(row,6))
3400 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3401 deformat_string(package, arguments, &deformated);
3402 IShellLinkW_SetArguments(sl,deformated);
3403 msi_free(deformated);
3406 if (!MSI_RecordIsNull(row,7))
3408 LPCWSTR description = MSI_RecordGetString(row, 7);
3409 IShellLinkW_SetDescription(sl, description);
3412 if (!MSI_RecordIsNull(row,8))
3413 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3415 if (!MSI_RecordIsNull(row,9))
3418 LPCWSTR icon = MSI_RecordGetString(row, 9);
3420 path = build_icon_path(package, icon);
3421 index = MSI_RecordGetInteger(row,10);
3423 /* no value means 0 */
3424 if (index == MSI_NULL_INTEGER)
3427 IShellLinkW_SetIconLocation(sl, path, index);
3431 if (!MSI_RecordIsNull(row,11))
3432 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3434 if (!MSI_RecordIsNull(row,12))
3436 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3437 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3439 IShellLinkW_SetWorkingDirectory(sl, path);
3443 link_file = get_link_file(package, row);
3445 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3446 IPersistFile_Save(pf, link_file, FALSE);
3448 msi_free(link_file);
3452 IPersistFile_Release( pf );
3454 IShellLinkW_Release( sl );
3456 return ERROR_SUCCESS;
3459 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3464 static const WCHAR Query[] =
3465 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3466 '`','S','h','o','r','t','c','u','t','`',0};
3468 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3469 if (rc != ERROR_SUCCESS)
3470 return ERROR_SUCCESS;
3472 res = CoInitialize( NULL );
3474 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3475 msiobj_release(&view->hdr);
3483 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3485 MSIPACKAGE *package = param;
3490 component = MSI_RecordGetString( row, 4 );
3491 comp = get_loaded_component( package, component );
3493 return ERROR_SUCCESS;
3495 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3497 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3498 comp->Action = comp->Installed;
3499 return ERROR_SUCCESS;
3501 comp->Action = INSTALLSTATE_ABSENT;
3503 ui_actiondata( package, szRemoveShortcuts, row );
3505 link_file = get_link_file( package, row );
3507 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3508 if (!DeleteFileW( link_file ))
3510 WARN("Failed to remove shortcut file %u\n", GetLastError());
3512 msi_free( link_file );
3514 return ERROR_SUCCESS;
3517 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3521 static const WCHAR query[] =
3522 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3523 '`','S','h','o','r','t','c','u','t','`',0};
3525 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3526 if (rc != ERROR_SUCCESS)
3527 return ERROR_SUCCESS;
3529 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3530 msiobj_release( &view->hdr );
3535 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3537 MSIPACKAGE* package = param;
3545 FileName = MSI_RecordGetString(row,1);
3548 ERR("Unable to get FileName\n");
3549 return ERROR_SUCCESS;
3552 FilePath = build_icon_path(package,FileName);
3554 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3556 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3557 FILE_ATTRIBUTE_NORMAL, NULL);
3559 if (the_file == INVALID_HANDLE_VALUE)
3561 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3563 return ERROR_SUCCESS;
3570 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3571 if (rc != ERROR_SUCCESS)
3573 ERR("Failed to get stream\n");
3574 CloseHandle(the_file);
3575 DeleteFileW(FilePath);
3578 WriteFile(the_file,buffer,sz,&write,NULL);
3579 } while (sz == 1024);
3582 CloseHandle(the_file);
3584 return ERROR_SUCCESS;
3587 static UINT msi_publish_icons(MSIPACKAGE *package)
3592 static const WCHAR query[]= {
3593 'S','E','L','E','C','T',' ','*',' ',
3594 'F','R','O','M',' ','`','I','c','o','n','`',0};
3596 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3597 if (r == ERROR_SUCCESS)
3599 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3600 msiobj_release(&view->hdr);
3603 return ERROR_SUCCESS;
3606 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3612 MSISOURCELISTINFO *info;
3614 r = RegCreateKeyW(hkey, szSourceList, &source);
3615 if (r != ERROR_SUCCESS)
3618 RegCloseKey(source);
3620 buffer = strrchrW(package->PackagePath, '\\') + 1;
3621 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3622 package->Context, MSICODE_PRODUCT,
3623 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3624 if (r != ERROR_SUCCESS)
3627 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3628 package->Context, MSICODE_PRODUCT,
3629 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3630 if (r != ERROR_SUCCESS)
3633 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3634 package->Context, MSICODE_PRODUCT,
3635 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3636 if (r != ERROR_SUCCESS)
3639 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3641 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3642 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3643 info->options, info->value);
3645 MsiSourceListSetInfoW(package->ProductCode, NULL,
3646 info->context, info->options,
3647 info->property, info->value);
3650 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3652 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3653 disk->context, disk->options,
3654 disk->disk_id, disk->volume_label, disk->disk_prompt);
3657 return ERROR_SUCCESS;
3660 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3662 MSIHANDLE hdb, suminfo;
3663 WCHAR guids[MAX_PATH];
3664 WCHAR packcode[SQUISH_GUID_SIZE];
3671 static const WCHAR szProductLanguage[] =
3672 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3673 static const WCHAR szARPProductIcon[] =
3674 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3675 static const WCHAR szProductVersion[] =
3676 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3677 static const WCHAR szAssignment[] =
3678 {'A','s','s','i','g','n','m','e','n','t',0};
3679 static const WCHAR szAdvertiseFlags[] =
3680 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3681 static const WCHAR szClients[] =
3682 {'C','l','i','e','n','t','s',0};
3683 static const WCHAR szColon[] = {':',0};
3685 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3686 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3689 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3690 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3693 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3695 buffer = msi_dup_property(package->db, szARPProductIcon);
3698 LPWSTR path = build_icon_path(package,buffer);
3699 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3704 buffer = msi_dup_property(package->db, szProductVersion);
3707 DWORD verdword = msi_version_str_to_dword(buffer);
3708 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3712 msi_reg_set_val_dword(hkey, szAssignment, 0);
3713 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3714 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3715 msi_reg_set_val_str(hkey, szClients, szColon);
3717 hdb = alloc_msihandle(&package->db->hdr);
3719 return ERROR_NOT_ENOUGH_MEMORY;
3721 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3722 MsiCloseHandle(hdb);
3723 if (r != ERROR_SUCCESS)
3727 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3728 NULL, guids, &size);
3729 if (r != ERROR_SUCCESS)
3732 ptr = strchrW(guids, ';');
3734 squash_guid(guids, packcode);
3735 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3738 MsiCloseHandle(suminfo);
3739 return ERROR_SUCCESS;
3742 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3747 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3749 static const WCHAR szUpgradeCode[] =
3750 {'U','p','g','r','a','d','e','C','o','d','e',0};
3752 upgrade = msi_dup_property(package->db, szUpgradeCode);
3754 return ERROR_SUCCESS;
3756 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3758 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3759 if (r != ERROR_SUCCESS)
3764 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3765 if (r != ERROR_SUCCESS)
3769 squash_guid(package->ProductCode, squashed_pc);
3770 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3779 static BOOL msi_check_publish(MSIPACKAGE *package)
3781 MSIFEATURE *feature;
3783 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3785 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3792 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3794 MSIFEATURE *feature;
3796 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3798 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3805 static UINT msi_publish_patches( MSIPACKAGE *package, HKEY prodkey )
3807 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
3808 WCHAR patch_squashed[GUID_SIZE];
3809 HKEY patches_key = NULL, product_patches_key;
3811 MSIPATCHINFO *patch;
3813 WCHAR *p, *all_patches = NULL;
3816 res = RegCreateKeyExW( prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
3817 if (res != ERROR_SUCCESS)
3818 return ERROR_FUNCTION_FAILED;
3820 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3821 if (r != ERROR_SUCCESS)
3824 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3826 squash_guid( patch->patchcode, patch_squashed );
3827 len += strlenW( patch_squashed ) + 1;
3830 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3834 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3838 squash_guid( patch->patchcode, p );
3839 p += strlenW( p ) + 1;
3841 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
3842 (const BYTE *)patch->transforms,
3843 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3844 if (res != ERROR_SUCCESS)
3847 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3848 if (r != ERROR_SUCCESS)
3851 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3852 (const BYTE *)patch->localfile,
3853 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3854 RegCloseKey( patch_key );
3855 if (res != ERROR_SUCCESS)
3858 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3859 RegCloseKey( patch_key );
3860 if (res != ERROR_SUCCESS)
3864 all_patches[len] = 0;
3865 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
3866 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3867 if (res != ERROR_SUCCESS)
3870 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3871 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3872 if (res != ERROR_SUCCESS)
3873 r = ERROR_FUNCTION_FAILED;
3876 RegCloseKey( product_patches_key );
3877 RegCloseKey( patches_key );
3878 msi_free( all_patches );
3883 * 99% of the work done here is only done for
3884 * advertised installs. However this is where the
3885 * Icon table is processed and written out
3886 * so that is what I am going to do here.
3888 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3891 HKEY hukey = NULL, hudkey = NULL;
3894 /* FIXME: also need to publish if the product is in advertise mode */
3895 if (!msi_check_publish(package))
3896 return ERROR_SUCCESS;
3898 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3900 if (rc != ERROR_SUCCESS)
3903 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3904 NULL, &hudkey, TRUE);
3905 if (rc != ERROR_SUCCESS)
3908 rc = msi_publish_upgrade_code(package);
3909 if (rc != ERROR_SUCCESS)
3912 if (!list_empty(&package->patches))
3914 rc = msi_publish_patches(package, hukey);
3915 if (rc != ERROR_SUCCESS)
3919 rc = msi_publish_product_properties(package, hukey);
3920 if (rc != ERROR_SUCCESS)
3923 rc = msi_publish_sourcelist(package, hukey);
3924 if (rc != ERROR_SUCCESS)
3927 rc = msi_publish_icons(package);
3930 uirow = MSI_CreateRecord( 1 );
3931 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3932 ui_actiondata( package, szPublishProduct, uirow );
3933 msiobj_release( &uirow->hdr );
3936 RegCloseKey(hudkey);
3941 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3943 WCHAR *filename, *ptr, *folder, *ret;
3944 const WCHAR *dirprop;
3946 filename = msi_dup_record_field( row, 2 );
3947 if (filename && (ptr = strchrW( filename, '|' )))
3952 dirprop = MSI_RecordGetString( row, 3 );
3955 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3957 folder = msi_dup_property( package->db, dirprop );
3960 folder = msi_dup_property( package->db, szWindowsFolder );
3964 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3965 msi_free( filename );
3969 ret = build_directory_name( 2, folder, ptr );
3971 msi_free( filename );
3976 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3978 MSIPACKAGE *package = param;
3979 LPCWSTR component, section, key, value, identifier;
3980 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3985 component = MSI_RecordGetString(row, 8);
3986 comp = get_loaded_component(package,component);
3988 return ERROR_SUCCESS;
3990 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3992 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3993 comp->Action = comp->Installed;
3994 return ERROR_SUCCESS;
3996 comp->Action = INSTALLSTATE_LOCAL;
3998 identifier = MSI_RecordGetString(row,1);
3999 section = MSI_RecordGetString(row,4);
4000 key = MSI_RecordGetString(row,5);
4001 value = MSI_RecordGetString(row,6);
4002 action = MSI_RecordGetInteger(row,7);
4004 deformat_string(package,section,&deformated_section);
4005 deformat_string(package,key,&deformated_key);
4006 deformat_string(package,value,&deformated_value);
4008 fullname = get_ini_file_name(package, row);
4012 TRACE("Adding value %s to section %s in %s\n",
4013 debugstr_w(deformated_key), debugstr_w(deformated_section),
4014 debugstr_w(fullname));
4015 WritePrivateProfileStringW(deformated_section, deformated_key,
4016 deformated_value, fullname);
4018 else if (action == 1)
4021 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4022 returned, 10, fullname);
4023 if (returned[0] == 0)
4025 TRACE("Adding value %s to section %s in %s\n",
4026 debugstr_w(deformated_key), debugstr_w(deformated_section),
4027 debugstr_w(fullname));
4029 WritePrivateProfileStringW(deformated_section, deformated_key,
4030 deformated_value, fullname);
4033 else if (action == 3)
4034 FIXME("Append to existing section not yet implemented\n");
4036 uirow = MSI_CreateRecord(4);
4037 MSI_RecordSetStringW(uirow,1,identifier);
4038 MSI_RecordSetStringW(uirow,2,deformated_section);
4039 MSI_RecordSetStringW(uirow,3,deformated_key);
4040 MSI_RecordSetStringW(uirow,4,deformated_value);
4041 ui_actiondata(package,szWriteIniValues,uirow);
4042 msiobj_release( &uirow->hdr );
4045 msi_free(deformated_key);
4046 msi_free(deformated_value);
4047 msi_free(deformated_section);
4048 return ERROR_SUCCESS;
4051 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4055 static const WCHAR ExecSeqQuery[] =
4056 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4057 '`','I','n','i','F','i','l','e','`',0};
4059 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4060 if (rc != ERROR_SUCCESS)
4062 TRACE("no IniFile table\n");
4063 return ERROR_SUCCESS;
4066 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4067 msiobj_release(&view->hdr);
4071 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4073 MSIPACKAGE *package = param;
4074 LPCWSTR component, section, key, value, identifier;
4075 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4080 component = MSI_RecordGetString( row, 8 );
4081 comp = get_loaded_component( package, component );
4083 return ERROR_SUCCESS;
4085 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4087 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4088 comp->Action = comp->Installed;
4089 return ERROR_SUCCESS;
4091 comp->Action = INSTALLSTATE_ABSENT;
4093 identifier = MSI_RecordGetString( row, 1 );
4094 section = MSI_RecordGetString( row, 4 );
4095 key = MSI_RecordGetString( row, 5 );
4096 value = MSI_RecordGetString( row, 6 );
4097 action = MSI_RecordGetInteger( row, 7 );
4099 deformat_string( package, section, &deformated_section );
4100 deformat_string( package, key, &deformated_key );
4101 deformat_string( package, value, &deformated_value );
4103 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4105 filename = get_ini_file_name( package, row );
4107 TRACE("Removing key %s from section %s in %s\n",
4108 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4110 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4112 WARN("Unable to remove key %u\n", GetLastError());
4114 msi_free( filename );
4117 FIXME("Unsupported action %d\n", action);
4120 uirow = MSI_CreateRecord( 4 );
4121 MSI_RecordSetStringW( uirow, 1, identifier );
4122 MSI_RecordSetStringW( uirow, 2, deformated_section );
4123 MSI_RecordSetStringW( uirow, 3, deformated_key );
4124 MSI_RecordSetStringW( uirow, 4, deformated_value );
4125 ui_actiondata( package, szRemoveIniValues, uirow );
4126 msiobj_release( &uirow->hdr );
4128 msi_free( deformated_key );
4129 msi_free( deformated_value );
4130 msi_free( deformated_section );
4131 return ERROR_SUCCESS;
4134 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4136 MSIPACKAGE *package = param;
4137 LPCWSTR component, section, key, value, identifier;
4138 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4143 component = MSI_RecordGetString( row, 8 );
4144 comp = get_loaded_component( package, component );
4146 return ERROR_SUCCESS;
4148 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4150 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4151 comp->Action = comp->Installed;
4152 return ERROR_SUCCESS;
4154 comp->Action = INSTALLSTATE_LOCAL;
4156 identifier = MSI_RecordGetString( row, 1 );
4157 section = MSI_RecordGetString( row, 4 );
4158 key = MSI_RecordGetString( row, 5 );
4159 value = MSI_RecordGetString( row, 6 );
4160 action = MSI_RecordGetInteger( row, 7 );
4162 deformat_string( package, section, &deformated_section );
4163 deformat_string( package, key, &deformated_key );
4164 deformat_string( package, value, &deformated_value );
4166 if (action == msidbIniFileActionRemoveLine)
4168 filename = get_ini_file_name( package, row );
4170 TRACE("Removing key %s from section %s in %s\n",
4171 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4173 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4175 WARN("Unable to remove key %u\n", GetLastError());
4177 msi_free( filename );
4180 FIXME("Unsupported action %d\n", action);
4182 uirow = MSI_CreateRecord( 4 );
4183 MSI_RecordSetStringW( uirow, 1, identifier );
4184 MSI_RecordSetStringW( uirow, 2, deformated_section );
4185 MSI_RecordSetStringW( uirow, 3, deformated_key );
4186 MSI_RecordSetStringW( uirow, 4, deformated_value );
4187 ui_actiondata( package, szRemoveIniValues, uirow );
4188 msiobj_release( &uirow->hdr );
4190 msi_free( deformated_key );
4191 msi_free( deformated_value );
4192 msi_free( deformated_section );
4193 return ERROR_SUCCESS;
4196 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4200 static const WCHAR query[] =
4201 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4202 '`','I','n','i','F','i','l','e','`',0};
4203 static const WCHAR remove_query[] =
4204 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4205 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4207 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4208 if (rc == ERROR_SUCCESS)
4210 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4211 msiobj_release( &view->hdr );
4212 if (rc != ERROR_SUCCESS)
4216 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4217 if (rc == ERROR_SUCCESS)
4219 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4220 msiobj_release( &view->hdr );
4221 if (rc != ERROR_SUCCESS)
4225 return ERROR_SUCCESS;
4228 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4230 MSIPACKAGE *package = param;
4235 static const WCHAR ExeStr[] =
4236 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4237 static const WCHAR close[] = {'\"',0};
4239 PROCESS_INFORMATION info;
4244 memset(&si,0,sizeof(STARTUPINFOW));
4246 filename = MSI_RecordGetString(row,1);
4247 file = get_loaded_file( package, filename );
4251 ERR("Unable to find file id %s\n",debugstr_w(filename));
4252 return ERROR_SUCCESS;
4255 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4257 FullName = msi_alloc(len*sizeof(WCHAR));
4258 strcpyW(FullName,ExeStr);
4259 strcatW( FullName, file->TargetPath );
4260 strcatW(FullName,close);
4262 TRACE("Registering %s\n",debugstr_w(FullName));
4263 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4268 CloseHandle(info.hThread);
4269 msi_dialog_check_messages(info.hProcess);
4270 CloseHandle(info.hProcess);
4273 uirow = MSI_CreateRecord( 2 );
4274 MSI_RecordSetStringW( uirow, 1, filename );
4275 uipath = strdupW( file->TargetPath );
4276 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4277 MSI_RecordSetStringW( uirow, 2, uipath );
4278 ui_actiondata( package, szSelfRegModules, uirow );
4279 msiobj_release( &uirow->hdr );
4281 msi_free( FullName );
4283 return ERROR_SUCCESS;
4286 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4290 static const WCHAR ExecSeqQuery[] =
4291 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4292 '`','S','e','l','f','R','e','g','`',0};
4294 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4295 if (rc != ERROR_SUCCESS)
4297 TRACE("no SelfReg table\n");
4298 return ERROR_SUCCESS;
4301 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4302 msiobj_release(&view->hdr);
4304 return ERROR_SUCCESS;
4307 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4309 static const WCHAR regsvr32[] =
4310 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4311 static const WCHAR close[] = {'\"',0};
4312 MSIPACKAGE *package = param;
4318 PROCESS_INFORMATION pi;
4323 memset( &si, 0, sizeof(STARTUPINFOW) );
4325 filename = MSI_RecordGetString( row, 1 );
4326 file = get_loaded_file( package, filename );
4330 ERR("Unable to find file id %s\n", debugstr_w(filename));
4331 return ERROR_SUCCESS;
4334 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4336 cmdline = msi_alloc( len * sizeof(WCHAR) );
4337 strcpyW( cmdline, regsvr32 );
4338 strcatW( cmdline, file->TargetPath );
4339 strcatW( cmdline, close );
4341 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4343 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4346 CloseHandle( pi.hThread );
4347 msi_dialog_check_messages( pi.hProcess );
4348 CloseHandle( pi.hProcess );
4351 uirow = MSI_CreateRecord( 2 );
4352 MSI_RecordSetStringW( uirow, 1, filename );
4353 uipath = strdupW( file->TargetPath );
4354 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4355 MSI_RecordSetStringW( uirow, 2, uipath );
4356 ui_actiondata( package, szSelfUnregModules, uirow );
4357 msiobj_release( &uirow->hdr );
4359 msi_free( cmdline );
4361 return ERROR_SUCCESS;
4364 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4368 static const WCHAR query[] =
4369 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4370 '`','S','e','l','f','R','e','g','`',0};
4372 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4373 if (rc != ERROR_SUCCESS)
4375 TRACE("no SelfReg table\n");
4376 return ERROR_SUCCESS;
4379 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4380 msiobj_release( &view->hdr );
4382 return ERROR_SUCCESS;
4385 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4387 MSIFEATURE *feature;
4389 HKEY hkey = NULL, userdata = NULL;
4391 if (!msi_check_publish(package))
4392 return ERROR_SUCCESS;
4394 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4396 if (rc != ERROR_SUCCESS)
4399 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4401 if (rc != ERROR_SUCCESS)
4404 /* here the guids are base 85 encoded */
4405 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4411 BOOL absent = FALSE;
4414 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4415 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4416 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4419 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4423 if (feature->Feature_Parent)
4424 size += strlenW( feature->Feature_Parent )+2;
4426 data = msi_alloc(size * sizeof(WCHAR));
4429 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4431 MSICOMPONENT* component = cl->component;
4435 if (component->ComponentId)
4437 TRACE("From %s\n",debugstr_w(component->ComponentId));
4438 CLSIDFromString(component->ComponentId, &clsid);
4439 encode_base85_guid(&clsid,buf);
4440 TRACE("to %s\n",debugstr_w(buf));
4445 if (feature->Feature_Parent)
4447 static const WCHAR sep[] = {'\2',0};
4449 strcatW(data,feature->Feature_Parent);
4452 msi_reg_set_val_str( userdata, feature->Feature, data );
4456 if (feature->Feature_Parent)
4457 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4460 size += sizeof(WCHAR);
4461 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4462 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4466 size += 2*sizeof(WCHAR);
4467 data = msi_alloc(size);
4470 if (feature->Feature_Parent)
4471 strcpyW( &data[1], feature->Feature_Parent );
4472 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4478 uirow = MSI_CreateRecord( 1 );
4479 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4480 ui_actiondata( package, szPublishFeatures, uirow);
4481 msiobj_release( &uirow->hdr );
4482 /* FIXME: call ui_progress? */
4487 RegCloseKey(userdata);
4491 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4497 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4499 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4501 if (r == ERROR_SUCCESS)
4503 RegDeleteValueW(hkey, feature->Feature);
4507 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4509 if (r == ERROR_SUCCESS)
4511 RegDeleteValueW(hkey, feature->Feature);
4515 uirow = MSI_CreateRecord( 1 );
4516 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4517 ui_actiondata( package, szUnpublishFeatures, uirow );
4518 msiobj_release( &uirow->hdr );
4520 return ERROR_SUCCESS;
4523 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4525 MSIFEATURE *feature;
4527 if (!msi_check_unpublish(package))
4528 return ERROR_SUCCESS;
4530 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4532 msi_unpublish_feature(package, feature);
4535 return ERROR_SUCCESS;
4538 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4542 WCHAR date[9], *val, *buffer;
4543 const WCHAR *prop, *key;
4545 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4546 static const WCHAR szWindowsInstaller[] =
4547 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4548 static const WCHAR modpath_fmt[] =
4549 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4550 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4551 static const WCHAR szModifyPath[] =
4552 {'M','o','d','i','f','y','P','a','t','h',0};
4553 static const WCHAR szUninstallString[] =
4554 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4555 static const WCHAR szEstimatedSize[] =
4556 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4557 static const WCHAR szProductLanguage[] =
4558 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4559 static const WCHAR szProductVersion[] =
4560 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4561 static const WCHAR szDisplayVersion[] =
4562 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4563 static const WCHAR szInstallSource[] =
4564 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4565 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4566 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4567 static const WCHAR szAuthorizedCDFPrefix[] =
4568 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4569 static const WCHAR szARPCONTACT[] =
4570 {'A','R','P','C','O','N','T','A','C','T',0};
4571 static const WCHAR szContact[] =
4572 {'C','o','n','t','a','c','t',0};
4573 static const WCHAR szARPCOMMENTS[] =
4574 {'A','R','P','C','O','M','M','E','N','T','S',0};
4575 static const WCHAR szComments[] =
4576 {'C','o','m','m','e','n','t','s',0};
4577 static const WCHAR szProductName[] =
4578 {'P','r','o','d','u','c','t','N','a','m','e',0};
4579 static const WCHAR szDisplayName[] =
4580 {'D','i','s','p','l','a','y','N','a','m','e',0};
4581 static const WCHAR szARPHELPLINK[] =
4582 {'A','R','P','H','E','L','P','L','I','N','K',0};
4583 static const WCHAR szHelpLink[] =
4584 {'H','e','l','p','L','i','n','k',0};
4585 static const WCHAR szARPHELPTELEPHONE[] =
4586 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4587 static const WCHAR szHelpTelephone[] =
4588 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4589 static const WCHAR szARPINSTALLLOCATION[] =
4590 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4591 static const WCHAR szInstallLocation[] =
4592 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4593 static const WCHAR szManufacturer[] =
4594 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4595 static const WCHAR szPublisher[] =
4596 {'P','u','b','l','i','s','h','e','r',0};
4597 static const WCHAR szARPREADME[] =
4598 {'A','R','P','R','E','A','D','M','E',0};
4599 static const WCHAR szReadme[] =
4600 {'R','e','a','d','M','e',0};
4601 static const WCHAR szARPSIZE[] =
4602 {'A','R','P','S','I','Z','E',0};
4603 static const WCHAR szSize[] =
4604 {'S','i','z','e',0};
4605 static const WCHAR szARPURLINFOABOUT[] =
4606 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4607 static const WCHAR szURLInfoAbout[] =
4608 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4609 static const WCHAR szARPURLUPDATEINFO[] =
4610 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4611 static const WCHAR szURLUpdateInfo[] =
4612 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4614 static const WCHAR *propval[] = {
4615 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4616 szARPCONTACT, szContact,
4617 szARPCOMMENTS, szComments,
4618 szProductName, szDisplayName,
4619 szARPHELPLINK, szHelpLink,
4620 szARPHELPTELEPHONE, szHelpTelephone,
4621 szARPINSTALLLOCATION, szInstallLocation,
4622 cszSourceDir, szInstallSource,
4623 szManufacturer, szPublisher,
4624 szARPREADME, szReadme,
4626 szARPURLINFOABOUT, szURLInfoAbout,
4627 szARPURLUPDATEINFO, szURLUpdateInfo,
4630 const WCHAR **p = propval;
4636 val = msi_dup_property(package->db, prop);
4637 msi_reg_set_val_str(hkey, key, val);
4641 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4643 size = deformat_string(package, modpath_fmt, &buffer);
4644 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4645 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4648 /* FIXME: Write real Estimated Size when we have it */
4649 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4651 GetLocalTime(&systime);
4652 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4653 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4655 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4656 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4658 buffer = msi_dup_property(package->db, szProductVersion);
4659 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4662 DWORD verdword = msi_version_str_to_dword(buffer);
4664 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4665 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4666 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4670 return ERROR_SUCCESS;
4673 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4675 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4677 LPWSTR upgrade_code;
4682 static const WCHAR szUpgradeCode[] = {
4683 'U','p','g','r','a','d','e','C','o','d','e',0};
4685 /* FIXME: also need to publish if the product is in advertise mode */
4686 if (!msi_check_publish(package))
4687 return ERROR_SUCCESS;
4689 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4690 if (rc != ERROR_SUCCESS)
4693 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4694 NULL, &props, TRUE);
4695 if (rc != ERROR_SUCCESS)
4698 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4699 msi_free( package->db->localfile );
4700 package->db->localfile = NULL;
4702 rc = msi_publish_install_properties(package, hkey);
4703 if (rc != ERROR_SUCCESS)
4706 rc = msi_publish_install_properties(package, props);
4707 if (rc != ERROR_SUCCESS)
4710 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4713 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4714 squash_guid(package->ProductCode, squashed_pc);
4715 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4716 RegCloseKey(upgrade);
4717 msi_free(upgrade_code);
4721 uirow = MSI_CreateRecord( 1 );
4722 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4723 ui_actiondata( package, szRegisterProduct, uirow );
4724 msiobj_release( &uirow->hdr );
4727 return ERROR_SUCCESS;
4730 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4732 return execute_script(package,INSTALL_SCRIPT);
4735 static UINT msi_unpublish_product(MSIPACKAGE *package)
4738 LPWSTR remove = NULL;
4739 LPWSTR *features = NULL;
4740 BOOL full_uninstall = TRUE;
4741 MSIFEATURE *feature;
4742 MSIPATCHINFO *patch;
4744 static const WCHAR szUpgradeCode[] =
4745 {'U','p','g','r','a','d','e','C','o','d','e',0};
4747 remove = msi_dup_property(package->db, szRemove);
4749 return ERROR_SUCCESS;
4751 features = msi_split_string(remove, ',');
4755 ERR("REMOVE feature list is empty!\n");
4756 return ERROR_FUNCTION_FAILED;
4759 if (!lstrcmpW(features[0], szAll))
4760 full_uninstall = TRUE;
4763 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4765 if (feature->Action != INSTALLSTATE_ABSENT)
4766 full_uninstall = FALSE;
4770 if (!full_uninstall)
4773 MSIREG_DeleteProductKey(package->ProductCode);
4774 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4775 MSIREG_DeleteUninstallKey(package->ProductCode);
4777 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4779 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4780 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4784 MSIREG_DeleteUserProductKey(package->ProductCode);
4785 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4788 upgrade = msi_dup_property(package->db, szUpgradeCode);
4791 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4795 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4797 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4803 return ERROR_SUCCESS;
4806 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4810 rc = msi_unpublish_product(package);
4811 if (rc != ERROR_SUCCESS)
4814 /* turn off scheduling */
4815 package->script->CurrentlyScripting= FALSE;
4817 /* first do the same as an InstallExecute */
4818 rc = ACTION_InstallExecute(package);
4819 if (rc != ERROR_SUCCESS)
4822 /* then handle Commit Actions */
4823 rc = execute_script(package,COMMIT_SCRIPT);
4828 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4830 static const WCHAR RunOnce[] = {
4831 'S','o','f','t','w','a','r','e','\\',
4832 'M','i','c','r','o','s','o','f','t','\\',
4833 'W','i','n','d','o','w','s','\\',
4834 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4835 'R','u','n','O','n','c','e',0};
4836 static const WCHAR InstallRunOnce[] = {
4837 'S','o','f','t','w','a','r','e','\\',
4838 'M','i','c','r','o','s','o','f','t','\\',
4839 'W','i','n','d','o','w','s','\\',
4840 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4841 'I','n','s','t','a','l','l','e','r','\\',
4842 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4844 static const WCHAR msiexec_fmt[] = {
4846 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4847 '\"','%','s','\"',0};
4848 static const WCHAR install_fmt[] = {
4849 '/','I',' ','\"','%','s','\"',' ',
4850 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4851 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4852 WCHAR buffer[256], sysdir[MAX_PATH];
4854 WCHAR squished_pc[100];
4856 squash_guid(package->ProductCode,squished_pc);
4858 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4859 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4860 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4863 msi_reg_set_val_str( hkey, squished_pc, buffer );
4866 TRACE("Reboot command %s\n",debugstr_w(buffer));
4868 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4869 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4871 msi_reg_set_val_str( hkey, squished_pc, buffer );
4874 return ERROR_INSTALL_SUSPEND;
4877 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4883 * We are currently doing what should be done here in the top level Install
4884 * however for Administrative and uninstalls this step will be needed
4886 if (!package->PackagePath)
4887 return ERROR_SUCCESS;
4889 msi_set_sourcedir_props(package, TRUE);
4891 attrib = GetFileAttributesW(package->db->path);
4892 if (attrib == INVALID_FILE_ATTRIBUTES)
4898 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4899 package->Context, MSICODE_PRODUCT,
4900 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4901 if (rc == ERROR_MORE_DATA)
4903 prompt = msi_alloc(size * sizeof(WCHAR));
4904 MsiSourceListGetInfoW(package->ProductCode, NULL,
4905 package->Context, MSICODE_PRODUCT,
4906 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4909 prompt = strdupW(package->db->path);
4911 msg = generate_error_string(package,1302,1,prompt);
4912 while(attrib == INVALID_FILE_ATTRIBUTES)
4914 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4917 rc = ERROR_INSTALL_USEREXIT;
4920 attrib = GetFileAttributesW(package->db->path);
4926 return ERROR_SUCCESS;
4931 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4934 LPWSTR buffer, productid = NULL;
4935 UINT i, rc = ERROR_SUCCESS;
4938 static const WCHAR szPropKeys[][80] =
4940 {'P','r','o','d','u','c','t','I','D',0},
4941 {'U','S','E','R','N','A','M','E',0},
4942 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4946 static const WCHAR szRegKeys[][80] =
4948 {'P','r','o','d','u','c','t','I','D',0},
4949 {'R','e','g','O','w','n','e','r',0},
4950 {'R','e','g','C','o','m','p','a','n','y',0},
4954 if (msi_check_unpublish(package))
4956 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4960 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
4964 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4966 if (rc != ERROR_SUCCESS)
4969 for( i = 0; szPropKeys[i][0]; i++ )
4971 buffer = msi_dup_property( package->db, szPropKeys[i] );
4972 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4977 uirow = MSI_CreateRecord( 1 );
4978 MSI_RecordSetStringW( uirow, 1, productid );
4979 ui_actiondata( package, szRegisterUser, uirow );
4980 msiobj_release( &uirow->hdr );
4982 msi_free(productid);
4988 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4992 package->script->InWhatSequence |= SEQUENCE_EXEC;
4993 rc = ACTION_ProcessExecSequence(package,FALSE);
4998 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5000 MSIPACKAGE *package = param;
5001 LPCWSTR compgroupid, component, feature, qualifier, text;
5002 LPWSTR advertise = NULL, output = NULL;
5010 feature = MSI_RecordGetString(rec, 5);
5011 feat = get_loaded_feature(package, feature);
5013 return ERROR_SUCCESS;
5015 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5016 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5017 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5019 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5020 feat->Action = feat->Installed;
5021 return ERROR_SUCCESS;
5024 component = MSI_RecordGetString(rec, 3);
5025 comp = get_loaded_component(package, component);
5027 return ERROR_SUCCESS;
5029 compgroupid = MSI_RecordGetString(rec,1);
5030 qualifier = MSI_RecordGetString(rec,2);
5032 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5033 if (rc != ERROR_SUCCESS)
5036 text = MSI_RecordGetString(rec,4);
5037 advertise = create_component_advertise_string(package, comp, feature);
5039 sz = strlenW(advertise);
5042 sz += lstrlenW(text);
5045 sz *= sizeof(WCHAR);
5047 output = msi_alloc_zero(sz);
5048 strcpyW(output,advertise);
5049 msi_free(advertise);
5052 strcatW(output,text);
5054 msi_reg_set_val_multi_str( hkey, qualifier, output );
5061 uirow = MSI_CreateRecord( 2 );
5062 MSI_RecordSetStringW( uirow, 1, compgroupid );
5063 MSI_RecordSetStringW( uirow, 2, qualifier);
5064 ui_actiondata( package, szPublishComponents, uirow);
5065 msiobj_release( &uirow->hdr );
5066 /* FIXME: call ui_progress? */
5072 * At present I am ignorning the advertised components part of this and only
5073 * focusing on the qualified component sets
5075 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5079 static const WCHAR ExecSeqQuery[] =
5080 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5081 '`','P','u','b','l','i','s','h',
5082 'C','o','m','p','o','n','e','n','t','`',0};
5084 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5085 if (rc != ERROR_SUCCESS)
5086 return ERROR_SUCCESS;
5088 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5089 msiobj_release(&view->hdr);
5094 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5096 static const WCHAR szInstallerComponents[] = {
5097 'S','o','f','t','w','a','r','e','\\',
5098 'M','i','c','r','o','s','o','f','t','\\',
5099 'I','n','s','t','a','l','l','e','r','\\',
5100 'C','o','m','p','o','n','e','n','t','s','\\',0};
5102 MSIPACKAGE *package = param;
5103 LPCWSTR compgroupid, component, feature, qualifier;
5107 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5110 feature = MSI_RecordGetString( rec, 5 );
5111 feat = get_loaded_feature( package, feature );
5113 return ERROR_SUCCESS;
5115 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5117 TRACE("Feature %s not scheduled for removal\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 squash_guid( compgroupid, squashed );
5131 strcpyW( keypath, szInstallerComponents );
5132 strcatW( keypath, squashed );
5134 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5135 if (res != ERROR_SUCCESS)
5137 WARN("Unable to delete component key %d\n", res);
5140 uirow = MSI_CreateRecord( 2 );
5141 MSI_RecordSetStringW( uirow, 1, compgroupid );
5142 MSI_RecordSetStringW( uirow, 2, qualifier );
5143 ui_actiondata( package, szUnpublishComponents, uirow );
5144 msiobj_release( &uirow->hdr );
5146 return ERROR_SUCCESS;
5149 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5153 static const WCHAR query[] =
5154 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5155 '`','P','u','b','l','i','s','h',
5156 'C','o','m','p','o','n','e','n','t','`',0};
5158 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5159 if (rc != ERROR_SUCCESS)
5160 return ERROR_SUCCESS;
5162 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5163 msiobj_release( &view->hdr );
5168 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5170 MSIPACKAGE *package = param;
5173 SC_HANDLE hscm, service = NULL;
5174 LPCWSTR comp, depends, pass;
5175 LPWSTR name = NULL, disp = NULL;
5176 LPCWSTR load_order, serv_name, key;
5177 DWORD serv_type, start_type;
5180 static const WCHAR query[] =
5181 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5182 '`','C','o','m','p','o','n','e','n','t','`',' ',
5183 'W','H','E','R','E',' ',
5184 '`','C','o','m','p','o','n','e','n','t','`',' ',
5185 '=','\'','%','s','\'',0};
5187 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5190 ERR("Failed to open the SC Manager!\n");
5194 start_type = MSI_RecordGetInteger(rec, 5);
5195 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5198 depends = MSI_RecordGetString(rec, 8);
5199 if (depends && *depends)
5200 FIXME("Dependency list unhandled!\n");
5202 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5203 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5204 serv_type = MSI_RecordGetInteger(rec, 4);
5205 err_control = MSI_RecordGetInteger(rec, 6);
5206 load_order = MSI_RecordGetString(rec, 7);
5207 serv_name = MSI_RecordGetString(rec, 9);
5208 pass = MSI_RecordGetString(rec, 10);
5209 comp = MSI_RecordGetString(rec, 12);
5211 /* fetch the service path */
5212 row = MSI_QueryGetRecord(package->db, query, comp);
5215 ERR("Control query failed!\n");
5219 key = MSI_RecordGetString(row, 6);
5221 file = get_loaded_file(package, key);
5222 msiobj_release(&row->hdr);
5225 ERR("Failed to load the service file\n");
5229 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5230 start_type, err_control, file->TargetPath,
5231 load_order, NULL, NULL, serv_name, pass);
5234 if (GetLastError() != ERROR_SERVICE_EXISTS)
5235 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5239 CloseServiceHandle(service);
5240 CloseServiceHandle(hscm);
5244 return ERROR_SUCCESS;
5247 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5251 static const WCHAR ExecSeqQuery[] =
5252 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5253 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5255 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5256 if (rc != ERROR_SUCCESS)
5257 return ERROR_SUCCESS;
5259 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5260 msiobj_release(&view->hdr);
5265 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5266 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5268 LPCWSTR *vector, *temp_vector;
5272 static const WCHAR separator[] = {'[','~',']',0};
5275 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5280 vector = msi_alloc(sizeof(LPWSTR));
5288 vector[*numargs - 1] = p;
5290 if ((q = strstrW(p, separator)))
5294 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5300 vector = temp_vector;
5309 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5311 MSIPACKAGE *package = param;
5314 SC_HANDLE scm = NULL, service = NULL;
5315 LPCWSTR component, *vector = NULL;
5316 LPWSTR name, args, display_name = NULL;
5317 DWORD event, numargs, len;
5318 UINT r = ERROR_FUNCTION_FAILED;
5320 component = MSI_RecordGetString(rec, 6);
5321 comp = get_loaded_component(package, component);
5323 return ERROR_SUCCESS;
5325 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5327 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5328 comp->Action = comp->Installed;
5329 return ERROR_SUCCESS;
5331 comp->Action = INSTALLSTATE_LOCAL;
5333 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5334 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5335 event = MSI_RecordGetInteger(rec, 3);
5337 if (!(event & msidbServiceControlEventStart))
5343 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5346 ERR("Failed to open the service control manager\n");
5351 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5352 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5354 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5355 GetServiceDisplayNameW( scm, name, display_name, &len );
5358 service = OpenServiceW(scm, name, SERVICE_START);
5361 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5365 vector = msi_service_args_to_vector(args, &numargs);
5367 if (!StartServiceW(service, numargs, vector) &&
5368 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5370 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5377 uirow = MSI_CreateRecord( 2 );
5378 MSI_RecordSetStringW( uirow, 1, display_name );
5379 MSI_RecordSetStringW( uirow, 2, name );
5380 ui_actiondata( package, szStartServices, uirow );
5381 msiobj_release( &uirow->hdr );
5383 CloseServiceHandle(service);
5384 CloseServiceHandle(scm);
5389 msi_free(display_name);
5393 static UINT ACTION_StartServices( MSIPACKAGE *package )
5398 static const WCHAR query[] = {
5399 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5400 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5402 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5403 if (rc != ERROR_SUCCESS)
5404 return ERROR_SUCCESS;
5406 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5407 msiobj_release(&view->hdr);
5412 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5414 DWORD i, needed, count;
5415 ENUM_SERVICE_STATUSW *dependencies;
5419 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5420 0, &needed, &count))
5423 if (GetLastError() != ERROR_MORE_DATA)
5426 dependencies = msi_alloc(needed);
5430 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5431 needed, &needed, &count))
5434 for (i = 0; i < count; i++)
5436 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5437 SERVICE_STOP | SERVICE_QUERY_STATUS);
5441 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5448 msi_free(dependencies);
5452 static UINT stop_service( LPCWSTR name )
5454 SC_HANDLE scm = NULL, service = NULL;
5455 SERVICE_STATUS status;
5456 SERVICE_STATUS_PROCESS ssp;
5459 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5462 WARN("Failed to open the SCM: %d\n", GetLastError());
5466 service = OpenServiceW(scm, name,
5468 SERVICE_QUERY_STATUS |
5469 SERVICE_ENUMERATE_DEPENDENTS);
5472 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5476 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5477 sizeof(SERVICE_STATUS_PROCESS), &needed))
5479 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5483 if (ssp.dwCurrentState == SERVICE_STOPPED)
5486 stop_service_dependents(scm, service);
5488 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5489 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5492 CloseServiceHandle(service);
5493 CloseServiceHandle(scm);
5495 return ERROR_SUCCESS;
5498 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5500 MSIPACKAGE *package = param;
5504 LPWSTR name = NULL, display_name = NULL;
5508 event = MSI_RecordGetInteger( rec, 3 );
5509 if (!(event & msidbServiceControlEventStop))
5510 return ERROR_SUCCESS;
5512 component = MSI_RecordGetString( rec, 6 );
5513 comp = get_loaded_component( package, component );
5515 return ERROR_SUCCESS;
5517 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5519 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5520 comp->Action = comp->Installed;
5521 return ERROR_SUCCESS;
5523 comp->Action = INSTALLSTATE_ABSENT;
5525 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5528 ERR("Failed to open the service control manager\n");
5533 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5534 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5536 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5537 GetServiceDisplayNameW( scm, name, display_name, &len );
5539 CloseServiceHandle( scm );
5541 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5542 stop_service( name );
5545 uirow = MSI_CreateRecord( 2 );
5546 MSI_RecordSetStringW( uirow, 1, display_name );
5547 MSI_RecordSetStringW( uirow, 2, name );
5548 ui_actiondata( package, szStopServices, uirow );
5549 msiobj_release( &uirow->hdr );
5552 msi_free( display_name );
5553 return ERROR_SUCCESS;
5556 static UINT ACTION_StopServices( MSIPACKAGE *package )
5561 static const WCHAR query[] = {
5562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5563 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5565 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5566 if (rc != ERROR_SUCCESS)
5567 return ERROR_SUCCESS;
5569 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5570 msiobj_release(&view->hdr);
5575 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5577 MSIPACKAGE *package = param;
5581 LPWSTR name = NULL, display_name = NULL;
5583 SC_HANDLE scm = NULL, service = NULL;
5585 event = MSI_RecordGetInteger( rec, 3 );
5586 if (!(event & msidbServiceControlEventDelete))
5587 return ERROR_SUCCESS;
5589 component = MSI_RecordGetString(rec, 6);
5590 comp = get_loaded_component(package, component);
5592 return ERROR_SUCCESS;
5594 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5596 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5597 comp->Action = comp->Installed;
5598 return ERROR_SUCCESS;
5600 comp->Action = INSTALLSTATE_ABSENT;
5602 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5603 stop_service( name );
5605 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5608 WARN("Failed to open the SCM: %d\n", GetLastError());
5613 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5614 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5616 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5617 GetServiceDisplayNameW( scm, name, display_name, &len );
5620 service = OpenServiceW( scm, name, DELETE );
5623 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5627 if (!DeleteService( service ))
5628 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5631 uirow = MSI_CreateRecord( 2 );
5632 MSI_RecordSetStringW( uirow, 1, display_name );
5633 MSI_RecordSetStringW( uirow, 2, name );
5634 ui_actiondata( package, szDeleteServices, uirow );
5635 msiobj_release( &uirow->hdr );
5637 CloseServiceHandle( service );
5638 CloseServiceHandle( scm );
5640 msi_free( display_name );
5642 return ERROR_SUCCESS;
5645 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5650 static const WCHAR query[] = {
5651 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5652 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5654 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5655 if (rc != ERROR_SUCCESS)
5656 return ERROR_SUCCESS;
5658 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5659 msiobj_release( &view->hdr );
5664 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5668 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5670 if (!lstrcmpW(file->File, filename))
5677 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5679 MSIPACKAGE *package = param;
5680 LPWSTR driver, driver_path, ptr;
5681 WCHAR outpath[MAX_PATH];
5682 MSIFILE *driver_file, *setup_file;
5686 UINT r = ERROR_SUCCESS;
5688 static const WCHAR driver_fmt[] = {
5689 'D','r','i','v','e','r','=','%','s',0};
5690 static const WCHAR setup_fmt[] = {
5691 'S','e','t','u','p','=','%','s',0};
5692 static const WCHAR usage_fmt[] = {
5693 'F','i','l','e','U','s','a','g','e','=','1',0};
5695 desc = MSI_RecordGetString(rec, 3);
5697 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5698 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5702 ERR("ODBC Driver entry not found!\n");
5703 return ERROR_FUNCTION_FAILED;
5706 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5708 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5709 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5711 driver = msi_alloc(len * sizeof(WCHAR));
5713 return ERROR_OUTOFMEMORY;
5716 lstrcpyW(ptr, desc);
5717 ptr += lstrlenW(ptr) + 1;
5719 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5724 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5728 lstrcpyW(ptr, usage_fmt);
5729 ptr += lstrlenW(ptr) + 1;
5732 driver_path = strdupW(driver_file->TargetPath);
5733 ptr = strrchrW(driver_path, '\\');
5734 if (ptr) *ptr = '\0';
5736 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5737 NULL, ODBC_INSTALL_COMPLETE, &usage))
5739 ERR("Failed to install SQL driver!\n");
5740 r = ERROR_FUNCTION_FAILED;
5743 uirow = MSI_CreateRecord( 5 );
5744 MSI_RecordSetStringW( uirow, 1, desc );
5745 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5746 MSI_RecordSetStringW( uirow, 3, driver_path );
5747 ui_actiondata( package, szInstallODBC, uirow );
5748 msiobj_release( &uirow->hdr );
5751 msi_free(driver_path);
5756 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5758 MSIPACKAGE *package = param;
5759 LPWSTR translator, translator_path, ptr;
5760 WCHAR outpath[MAX_PATH];
5761 MSIFILE *translator_file, *setup_file;
5765 UINT r = ERROR_SUCCESS;
5767 static const WCHAR translator_fmt[] = {
5768 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5769 static const WCHAR setup_fmt[] = {
5770 'S','e','t','u','p','=','%','s',0};
5772 desc = MSI_RecordGetString(rec, 3);
5774 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5775 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5777 if (!translator_file)
5779 ERR("ODBC Translator entry not found!\n");
5780 return ERROR_FUNCTION_FAILED;
5783 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5785 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5787 translator = msi_alloc(len * sizeof(WCHAR));
5789 return ERROR_OUTOFMEMORY;
5792 lstrcpyW(ptr, desc);
5793 ptr += lstrlenW(ptr) + 1;
5795 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5800 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5805 translator_path = strdupW(translator_file->TargetPath);
5806 ptr = strrchrW(translator_path, '\\');
5807 if (ptr) *ptr = '\0';
5809 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5810 NULL, ODBC_INSTALL_COMPLETE, &usage))
5812 ERR("Failed to install SQL translator!\n");
5813 r = ERROR_FUNCTION_FAILED;
5816 uirow = MSI_CreateRecord( 5 );
5817 MSI_RecordSetStringW( uirow, 1, desc );
5818 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5819 MSI_RecordSetStringW( uirow, 3, translator_path );
5820 ui_actiondata( package, szInstallODBC, uirow );
5821 msiobj_release( &uirow->hdr );
5823 msi_free(translator);
5824 msi_free(translator_path);
5829 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5831 MSIPACKAGE *package = param;
5833 LPCWSTR desc, driver;
5834 WORD request = ODBC_ADD_SYS_DSN;
5837 UINT r = ERROR_SUCCESS;
5840 static const WCHAR attrs_fmt[] = {
5841 'D','S','N','=','%','s',0 };
5843 desc = MSI_RecordGetString(rec, 3);
5844 driver = MSI_RecordGetString(rec, 4);
5845 registration = MSI_RecordGetInteger(rec, 5);
5847 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5848 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5850 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5851 attrs = msi_alloc(len * sizeof(WCHAR));
5853 return ERROR_OUTOFMEMORY;
5855 len = sprintfW(attrs, attrs_fmt, desc);
5858 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5860 ERR("Failed to install SQL data source!\n");
5861 r = ERROR_FUNCTION_FAILED;
5864 uirow = MSI_CreateRecord( 5 );
5865 MSI_RecordSetStringW( uirow, 1, desc );
5866 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5867 MSI_RecordSetInteger( uirow, 3, request );
5868 ui_actiondata( package, szInstallODBC, uirow );
5869 msiobj_release( &uirow->hdr );
5876 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5881 static const WCHAR driver_query[] = {
5882 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5883 'O','D','B','C','D','r','i','v','e','r',0 };
5885 static const WCHAR translator_query[] = {
5886 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5887 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5889 static const WCHAR source_query[] = {
5890 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5891 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5893 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5894 if (rc != ERROR_SUCCESS)
5895 return ERROR_SUCCESS;
5897 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5898 msiobj_release(&view->hdr);
5900 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5901 if (rc != ERROR_SUCCESS)
5902 return ERROR_SUCCESS;
5904 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5905 msiobj_release(&view->hdr);
5907 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5908 if (rc != ERROR_SUCCESS)
5909 return ERROR_SUCCESS;
5911 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5912 msiobj_release(&view->hdr);
5917 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5919 MSIPACKAGE *package = param;
5924 desc = MSI_RecordGetString( rec, 3 );
5925 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5927 WARN("Failed to remove ODBC driver\n");
5931 FIXME("Usage count reached 0\n");
5934 uirow = MSI_CreateRecord( 2 );
5935 MSI_RecordSetStringW( uirow, 1, desc );
5936 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5937 ui_actiondata( package, szRemoveODBC, uirow );
5938 msiobj_release( &uirow->hdr );
5940 return ERROR_SUCCESS;
5943 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5945 MSIPACKAGE *package = param;
5950 desc = MSI_RecordGetString( rec, 3 );
5951 if (!SQLRemoveTranslatorW( desc, &usage ))
5953 WARN("Failed to remove ODBC translator\n");
5957 FIXME("Usage count reached 0\n");
5960 uirow = MSI_CreateRecord( 2 );
5961 MSI_RecordSetStringW( uirow, 1, desc );
5962 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5963 ui_actiondata( package, szRemoveODBC, uirow );
5964 msiobj_release( &uirow->hdr );
5966 return ERROR_SUCCESS;
5969 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5971 MSIPACKAGE *package = param;
5974 LPCWSTR desc, driver;
5975 WORD request = ODBC_REMOVE_SYS_DSN;
5979 static const WCHAR attrs_fmt[] = {
5980 'D','S','N','=','%','s',0 };
5982 desc = MSI_RecordGetString( rec, 3 );
5983 driver = MSI_RecordGetString( rec, 4 );
5984 registration = MSI_RecordGetInteger( rec, 5 );
5986 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5987 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5989 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5990 attrs = msi_alloc( len * sizeof(WCHAR) );
5992 return ERROR_OUTOFMEMORY;
5994 FIXME("Use ODBCSourceAttribute table\n");
5996 len = sprintfW( attrs, attrs_fmt, desc );
5999 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6001 WARN("Failed to remove ODBC data source\n");
6005 uirow = MSI_CreateRecord( 3 );
6006 MSI_RecordSetStringW( uirow, 1, desc );
6007 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6008 MSI_RecordSetInteger( uirow, 3, request );
6009 ui_actiondata( package, szRemoveODBC, uirow );
6010 msiobj_release( &uirow->hdr );
6012 return ERROR_SUCCESS;
6015 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6020 static const WCHAR driver_query[] = {
6021 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6022 'O','D','B','C','D','r','i','v','e','r',0 };
6024 static const WCHAR translator_query[] = {
6025 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6026 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6028 static const WCHAR source_query[] = {
6029 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6030 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6032 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6033 if (rc != ERROR_SUCCESS)
6034 return ERROR_SUCCESS;
6036 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6037 msiobj_release( &view->hdr );
6039 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6040 if (rc != ERROR_SUCCESS)
6041 return ERROR_SUCCESS;
6043 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6044 msiobj_release( &view->hdr );
6046 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6047 if (rc != ERROR_SUCCESS)
6048 return ERROR_SUCCESS;
6050 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6051 msiobj_release( &view->hdr );
6056 #define ENV_ACT_SETALWAYS 0x1
6057 #define ENV_ACT_SETABSENT 0x2
6058 #define ENV_ACT_REMOVE 0x4
6059 #define ENV_ACT_REMOVEMATCH 0x8
6061 #define ENV_MOD_MACHINE 0x20000000
6062 #define ENV_MOD_APPEND 0x40000000
6063 #define ENV_MOD_PREFIX 0x80000000
6064 #define ENV_MOD_MASK 0xC0000000
6066 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6068 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6070 LPCWSTR cptr = *name;
6072 static const WCHAR prefix[] = {'[','~',']',0};
6073 static const int prefix_len = 3;
6079 *flags |= ENV_ACT_SETALWAYS;
6080 else if (*cptr == '+')
6081 *flags |= ENV_ACT_SETABSENT;
6082 else if (*cptr == '-')
6083 *flags |= ENV_ACT_REMOVE;
6084 else if (*cptr == '!')
6085 *flags |= ENV_ACT_REMOVEMATCH;
6086 else if (*cptr == '*')
6087 *flags |= ENV_MOD_MACHINE;
6097 ERR("Missing environment variable\n");
6098 return ERROR_FUNCTION_FAILED;
6103 LPCWSTR ptr = *value;
6104 if (!strncmpW(ptr, prefix, prefix_len))
6106 if (ptr[prefix_len] == szSemiColon[0])
6108 *flags |= ENV_MOD_APPEND;
6109 *value += lstrlenW(prefix);
6116 else if (lstrlenW(*value) >= prefix_len)
6118 ptr += lstrlenW(ptr) - prefix_len;
6119 if (!lstrcmpW(ptr, prefix))
6121 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6123 *flags |= ENV_MOD_PREFIX;
6124 /* the "[~]" will be removed by deformat_string */;
6134 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6135 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6136 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6137 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6139 ERR("Invalid flags: %08x\n", *flags);
6140 return ERROR_FUNCTION_FAILED;
6144 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6146 return ERROR_SUCCESS;
6149 static UINT open_env_key( DWORD flags, HKEY *key )
6151 static const WCHAR user_env[] =
6152 {'E','n','v','i','r','o','n','m','e','n','t',0};
6153 static const WCHAR machine_env[] =
6154 {'S','y','s','t','e','m','\\',
6155 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6156 'C','o','n','t','r','o','l','\\',
6157 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6158 'E','n','v','i','r','o','n','m','e','n','t',0};
6163 if (flags & ENV_MOD_MACHINE)
6166 root = HKEY_LOCAL_MACHINE;
6171 root = HKEY_CURRENT_USER;
6174 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6175 if (res != ERROR_SUCCESS)
6177 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6178 return ERROR_FUNCTION_FAILED;
6181 return ERROR_SUCCESS;
6184 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6186 MSIPACKAGE *package = param;
6187 LPCWSTR name, value, component;
6188 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6189 DWORD flags, type, size;
6196 component = MSI_RecordGetString(rec, 4);
6197 comp = get_loaded_component(package, component);
6199 return ERROR_SUCCESS;
6201 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6203 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6204 comp->Action = comp->Installed;
6205 return ERROR_SUCCESS;
6207 comp->Action = INSTALLSTATE_LOCAL;
6209 name = MSI_RecordGetString(rec, 2);
6210 value = MSI_RecordGetString(rec, 3);
6212 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6214 res = env_parse_flags(&name, &value, &flags);
6215 if (res != ERROR_SUCCESS || !value)
6218 if (value && !deformat_string(package, value, &deformatted))
6220 res = ERROR_OUTOFMEMORY;
6224 value = deformatted;
6226 res = open_env_key( flags, &env );
6227 if (res != ERROR_SUCCESS)
6230 if (flags & ENV_MOD_MACHINE)
6231 action |= 0x20000000;
6235 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6236 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6237 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6240 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6244 /* Nothing to do. */
6247 res = ERROR_SUCCESS;
6251 /* If we are appending but the string was empty, strip ; */
6252 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6254 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6255 newval = strdupW(value);
6258 res = ERROR_OUTOFMEMORY;
6266 /* Contrary to MSDN, +-variable to [~];path works */
6267 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6269 res = ERROR_SUCCESS;
6273 data = msi_alloc(size);
6277 return ERROR_OUTOFMEMORY;
6280 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6281 if (res != ERROR_SUCCESS)
6284 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6287 res = RegDeleteValueW(env, name);
6288 if (res != ERROR_SUCCESS)
6289 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6293 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6294 if (flags & ENV_MOD_MASK)
6298 if (flags & ENV_MOD_APPEND) multiplier++;
6299 if (flags & ENV_MOD_PREFIX) multiplier++;
6300 mod_size = lstrlenW(value) * multiplier;
6301 size += mod_size * sizeof(WCHAR);
6304 newval = msi_alloc(size);
6308 res = ERROR_OUTOFMEMORY;
6312 if (flags & ENV_MOD_PREFIX)
6314 lstrcpyW(newval, value);
6315 ptr = newval + lstrlenW(value);
6316 action |= 0x80000000;
6319 lstrcpyW(ptr, data);
6321 if (flags & ENV_MOD_APPEND)
6323 lstrcatW(newval, value);
6324 action |= 0x40000000;
6327 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6328 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6331 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6335 uirow = MSI_CreateRecord( 3 );
6336 MSI_RecordSetStringW( uirow, 1, name );
6337 MSI_RecordSetStringW( uirow, 2, newval );
6338 MSI_RecordSetInteger( uirow, 3, action );
6339 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6340 msiobj_release( &uirow->hdr );
6342 if (env) RegCloseKey(env);
6343 msi_free(deformatted);
6349 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6353 static const WCHAR ExecSeqQuery[] =
6354 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6355 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6356 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6357 if (rc != ERROR_SUCCESS)
6358 return ERROR_SUCCESS;
6360 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6361 msiobj_release(&view->hdr);
6366 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6368 MSIPACKAGE *package = param;
6369 LPCWSTR name, value, component;
6370 LPWSTR deformatted = NULL;
6379 component = MSI_RecordGetString( rec, 4 );
6380 comp = get_loaded_component( package, component );
6382 return ERROR_SUCCESS;
6384 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6386 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6387 comp->Action = comp->Installed;
6388 return ERROR_SUCCESS;
6390 comp->Action = INSTALLSTATE_ABSENT;
6392 name = MSI_RecordGetString( rec, 2 );
6393 value = MSI_RecordGetString( rec, 3 );
6395 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6397 r = env_parse_flags( &name, &value, &flags );
6398 if (r != ERROR_SUCCESS)
6401 if (!(flags & ENV_ACT_REMOVE))
6403 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6404 return ERROR_SUCCESS;
6407 if (value && !deformat_string( package, value, &deformatted ))
6408 return ERROR_OUTOFMEMORY;
6410 value = deformatted;
6412 r = open_env_key( flags, &env );
6413 if (r != ERROR_SUCCESS)
6419 if (flags & ENV_MOD_MACHINE)
6420 action |= 0x20000000;
6422 TRACE("Removing %s\n", debugstr_w(name));
6424 res = RegDeleteValueW( env, name );
6425 if (res != ERROR_SUCCESS)
6427 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6432 uirow = MSI_CreateRecord( 3 );
6433 MSI_RecordSetStringW( uirow, 1, name );
6434 MSI_RecordSetStringW( uirow, 2, value );
6435 MSI_RecordSetInteger( uirow, 3, action );
6436 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6437 msiobj_release( &uirow->hdr );
6439 if (env) RegCloseKey( env );
6440 msi_free( deformatted );
6444 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6448 static const WCHAR query[] =
6449 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6450 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6452 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6453 if (rc != ERROR_SUCCESS)
6454 return ERROR_SUCCESS;
6456 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6457 msiobj_release( &view->hdr );
6462 typedef struct tagMSIASSEMBLY
6465 MSICOMPONENT *component;
6466 MSIFEATURE *feature;
6470 LPWSTR display_name;
6475 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6477 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6478 LPVOID pvReserved, HMODULE *phModDll);
6480 static BOOL init_functionpointers(void)
6486 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6488 hmscoree = LoadLibraryA("mscoree.dll");
6491 WARN("mscoree.dll not available\n");
6495 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6496 if (!pLoadLibraryShim)
6498 WARN("LoadLibraryShim not available\n");
6499 FreeLibrary(hmscoree);
6503 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6506 WARN("fusion.dll not available\n");
6507 FreeLibrary(hmscoree);
6511 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6513 FreeLibrary(hmscoree);
6517 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6520 IAssemblyCache *cache;
6523 UINT r = ERROR_FUNCTION_FAILED;
6525 TRACE("installing assembly: %s\n", debugstr_w(path));
6527 uirow = MSI_CreateRecord( 2 );
6528 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6529 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6530 msiobj_release( &uirow->hdr );
6532 if (assembly->feature)
6533 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6535 if (assembly->manifest)
6536 FIXME("Manifest unhandled\n");
6538 if (assembly->application)
6540 FIXME("Assembly should be privately installed\n");
6541 return ERROR_SUCCESS;
6544 if (assembly->attributes == msidbAssemblyAttributesWin32)
6546 FIXME("Win32 assemblies not handled\n");
6547 return ERROR_SUCCESS;
6550 hr = pCreateAssemblyCache(&cache, 0);
6554 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6556 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6561 IAssemblyCache_Release(cache);
6565 typedef struct tagASSEMBLY_LIST
6567 MSIPACKAGE *package;
6568 IAssemblyCache *cache;
6569 struct list *assemblies;
6572 typedef struct tagASSEMBLY_NAME
6580 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6582 ASSEMBLY_NAME *asmname = param;
6583 LPCWSTR name = MSI_RecordGetString(rec, 2);
6584 LPWSTR val = msi_dup_record_field(rec, 3);
6586 static const WCHAR Name[] = {'N','a','m','e',0};
6587 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6588 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6589 static const WCHAR PublicKeyToken[] = {
6590 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6592 if (!strcmpiW(name, Name))
6593 asmname->name = val;
6594 else if (!strcmpiW(name, Version))
6595 asmname->version = val;
6596 else if (!strcmpiW(name, Culture))
6597 asmname->culture = val;
6598 else if (!strcmpiW(name, PublicKeyToken))
6599 asmname->pubkeytoken = val;
6603 return ERROR_SUCCESS;
6606 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6610 *size = lstrlenW(append) + 1;
6611 *str = msi_alloc((*size) * sizeof(WCHAR));
6612 lstrcpyW(*str, append);
6616 (*size) += lstrlenW(append);
6617 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6618 lstrcatW(*str, append);
6621 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6623 static const WCHAR separator[] = {',',' ',0};
6624 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6625 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6626 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6627 static const WCHAR query[] = {
6628 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6629 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6630 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6631 '=','\'','%','s','\'',0};
6634 LPWSTR display_name;
6638 display_name = NULL;
6639 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6641 r = MSI_OpenQuery( db, &view, query, comp->Component );
6642 if (r != ERROR_SUCCESS)
6645 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6646 msiobj_release( &view->hdr );
6650 ERR("No assembly name specified!\n");
6654 append_str( &display_name, &size, name.name );
6658 append_str( &display_name, &size, separator );
6659 append_str( &display_name, &size, Version );
6660 append_str( &display_name, &size, name.version );
6664 append_str( &display_name, &size, separator );
6665 append_str( &display_name, &size, Culture );
6666 append_str( &display_name, &size, name.culture );
6668 if (name.pubkeytoken)
6670 append_str( &display_name, &size, separator );
6671 append_str( &display_name, &size, PublicKeyToken );
6672 append_str( &display_name, &size, name.pubkeytoken );
6675 msi_free( name.name );
6676 msi_free( name.version );
6677 msi_free( name.culture );
6678 msi_free( name.pubkeytoken );
6680 return display_name;
6683 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6685 ASSEMBLY_INFO asminfo;
6690 disp = get_assembly_display_name( db, comp );
6694 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6695 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6697 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6699 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6705 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6707 ASSEMBLY_LIST *list = param;
6708 MSIASSEMBLY *assembly;
6711 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6713 return ERROR_OUTOFMEMORY;
6715 component = MSI_RecordGetString(rec, 1);
6716 assembly->component = get_loaded_component(list->package, component);
6717 if (!assembly->component)
6718 return ERROR_SUCCESS;
6720 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6721 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6723 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6724 assembly->component->Action = assembly->component->Installed;
6725 return ERROR_SUCCESS;
6727 assembly->component->Action = assembly->component->ActionRequest;
6729 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6730 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6732 if (!assembly->file)
6734 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6735 return ERROR_FUNCTION_FAILED;
6738 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6739 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6740 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6742 if (assembly->application)
6745 DWORD size = sizeof(version)/sizeof(WCHAR);
6747 /* FIXME: we should probably check the manifest file here */
6749 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6750 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6752 assembly->installed = TRUE;
6756 assembly->installed = check_assembly_installed(list->package->db,
6758 assembly->component);
6760 list_add_head(list->assemblies, &assembly->entry);
6761 return ERROR_SUCCESS;
6764 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6766 IAssemblyCache *cache = NULL;
6772 static const WCHAR query[] =
6773 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6774 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6776 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6777 if (r != ERROR_SUCCESS)
6778 return ERROR_SUCCESS;
6780 hr = pCreateAssemblyCache(&cache, 0);
6782 return ERROR_FUNCTION_FAILED;
6784 list.package = package;
6786 list.assemblies = assemblies;
6788 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6789 msiobj_release(&view->hdr);
6791 IAssemblyCache_Release(cache);
6796 static void free_assemblies(struct list *assemblies)
6798 struct list *item, *cursor;
6800 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6802 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6804 list_remove(&assembly->entry);
6805 msi_free(assembly->application);
6806 msi_free(assembly->manifest);
6807 msi_free(assembly->display_name);
6812 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6814 MSIASSEMBLY *assembly;
6816 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6818 if (!lstrcmpW(assembly->file->File, file))
6828 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6829 LPWSTR *path, DWORD *attrs, PVOID user)
6831 MSIASSEMBLY *assembly;
6832 WCHAR temppath[MAX_PATH];
6833 struct list *assemblies = user;
6836 if (!find_assembly(assemblies, file, &assembly))
6839 GetTempPathW(MAX_PATH, temppath);
6840 PathAddBackslashW(temppath);
6841 lstrcatW(temppath, assembly->file->FileName);
6843 if (action == MSICABEXTRACT_BEGINEXTRACT)
6845 if (assembly->installed)
6848 *path = strdupW(temppath);
6849 *attrs = assembly->file->Attributes;
6851 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6853 assembly->installed = TRUE;
6855 r = install_assembly(package, assembly, temppath);
6856 if (r != ERROR_SUCCESS)
6857 ERR("Failed to install assembly\n");
6863 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6866 struct list assemblies = LIST_INIT(assemblies);
6867 MSIASSEMBLY *assembly;
6870 if (!init_functionpointers() || !pCreateAssemblyCache)
6871 return ERROR_FUNCTION_FAILED;
6873 r = load_assemblies(package, &assemblies);
6874 if (r != ERROR_SUCCESS)
6877 if (list_empty(&assemblies))
6880 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6883 r = ERROR_OUTOFMEMORY;
6887 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6889 if (assembly->installed && !mi->is_continuous)
6892 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6893 (assembly->file->IsCompressed && !mi->is_extracted))
6897 r = ready_media(package, assembly->file, mi);
6898 if (r != ERROR_SUCCESS)
6900 ERR("Failed to ready media\n");
6905 data.package = package;
6906 data.cb = installassembly_cb;
6907 data.user = &assemblies;
6909 if (assembly->file->IsCompressed &&
6910 !msi_cabextract(package, mi, &data))
6912 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6913 r = ERROR_FUNCTION_FAILED;
6918 if (!assembly->file->IsCompressed)
6920 LPWSTR source = resolve_file_source(package, assembly->file);
6922 r = install_assembly(package, assembly, source);
6923 if (r != ERROR_SUCCESS)
6924 ERR("Failed to install assembly\n");
6929 /* FIXME: write Installer assembly reg values */
6933 free_assemblies(&assemblies);
6937 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6939 LPWSTR key, template, id;
6940 UINT r = ERROR_SUCCESS;
6942 id = msi_dup_property( package->db, szProductID );
6946 return ERROR_SUCCESS;
6948 template = msi_dup_property( package->db, szPIDTemplate );
6949 key = msi_dup_property( package->db, szPIDKEY );
6951 if (key && template)
6953 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6954 r = msi_set_property( package->db, szProductID, key );
6956 msi_free( template );
6961 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6964 package->need_reboot = 1;
6965 return ERROR_SUCCESS;
6968 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6970 static const WCHAR szAvailableFreeReg[] =
6971 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6973 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6975 TRACE("%p %d kilobytes\n", package, space);
6977 uirow = MSI_CreateRecord( 1 );
6978 MSI_RecordSetInteger( uirow, 1, space );
6979 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6980 msiobj_release( &uirow->hdr );
6982 return ERROR_SUCCESS;
6985 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6987 FIXME("%p\n", package);
6988 return ERROR_SUCCESS;
6991 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6993 FIXME("%p\n", package);
6994 return ERROR_SUCCESS;
6997 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7002 static const WCHAR driver_query[] = {
7003 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7004 'O','D','B','C','D','r','i','v','e','r',0 };
7006 static const WCHAR translator_query[] = {
7007 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7008 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7010 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7011 if (r == ERROR_SUCCESS)
7014 r = MSI_IterateRecords( view, &count, NULL, package );
7015 msiobj_release( &view->hdr );
7016 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7019 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7020 if (r == ERROR_SUCCESS)
7023 r = MSI_IterateRecords( view, &count, NULL, package );
7024 msiobj_release( &view->hdr );
7025 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7028 return ERROR_SUCCESS;
7031 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7032 LPCSTR action, LPCWSTR table )
7034 static const WCHAR query[] = {
7035 'S','E','L','E','C','T',' ','*',' ',
7036 'F','R','O','M',' ','`','%','s','`',0 };
7037 MSIQUERY *view = NULL;
7041 r = MSI_OpenQuery( package->db, &view, query, table );
7042 if (r == ERROR_SUCCESS)
7044 r = MSI_IterateRecords(view, &count, NULL, package);
7045 msiobj_release(&view->hdr);
7049 FIXME("%s -> %u ignored %s table values\n",
7050 action, count, debugstr_w(table));
7052 return ERROR_SUCCESS;
7055 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7057 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7058 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7061 static UINT ACTION_BindImage( MSIPACKAGE *package )
7063 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7064 return msi_unimplemented_action_stub( package, "BindImage", table );
7067 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7069 static const WCHAR table[] = {
7070 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7071 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7074 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7076 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7077 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7080 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7082 static const WCHAR table[] = {
7083 'M','s','i','A','s','s','e','m','b','l','y',0 };
7084 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7087 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7089 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7090 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7093 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7095 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7096 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7099 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7101 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7102 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7105 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7107 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7108 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7111 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7113 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7114 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7117 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7121 const WCHAR *action;
7122 UINT (*handler)(MSIPACKAGE *);
7126 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
7127 { szAppSearch, ACTION_AppSearch },
7128 { szBindImage, ACTION_BindImage },
7129 { szCCPSearch, ACTION_CCPSearch },
7130 { szCostFinalize, ACTION_CostFinalize },
7131 { szCostInitialize, ACTION_CostInitialize },
7132 { szCreateFolders, ACTION_CreateFolders },
7133 { szCreateShortcuts, ACTION_CreateShortcuts },
7134 { szDeleteServices, ACTION_DeleteServices },
7135 { szDisableRollback, ACTION_DisableRollback },
7136 { szDuplicateFiles, ACTION_DuplicateFiles },
7137 { szExecuteAction, ACTION_ExecuteAction },
7138 { szFileCost, ACTION_FileCost },
7139 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7140 { szForceReboot, ACTION_ForceReboot },
7141 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7142 { szInstallExecute, ACTION_InstallExecute },
7143 { szInstallExecuteAgain, ACTION_InstallExecute },
7144 { szInstallFiles, ACTION_InstallFiles},
7145 { szInstallFinalize, ACTION_InstallFinalize },
7146 { szInstallInitialize, ACTION_InstallInitialize },
7147 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7148 { szInstallValidate, ACTION_InstallValidate },
7149 { szIsolateComponents, ACTION_IsolateComponents },
7150 { szLaunchConditions, ACTION_LaunchConditions },
7151 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7152 { szMoveFiles, ACTION_MoveFiles },
7153 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7154 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7155 { szInstallODBC, ACTION_InstallODBC },
7156 { szInstallServices, ACTION_InstallServices },
7157 { szPatchFiles, ACTION_PatchFiles },
7158 { szProcessComponents, ACTION_ProcessComponents },
7159 { szPublishComponents, ACTION_PublishComponents },
7160 { szPublishFeatures, ACTION_PublishFeatures },
7161 { szPublishProduct, ACTION_PublishProduct },
7162 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7163 { szRegisterComPlus, ACTION_RegisterComPlus},
7164 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7165 { szRegisterFonts, ACTION_RegisterFonts },
7166 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7167 { szRegisterProduct, ACTION_RegisterProduct },
7168 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7169 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7170 { szRegisterUser, ACTION_RegisterUser },
7171 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7172 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7173 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7174 { szRemoveFiles, ACTION_RemoveFiles },
7175 { szRemoveFolders, ACTION_RemoveFolders },
7176 { szRemoveIniValues, ACTION_RemoveIniValues },
7177 { szRemoveODBC, ACTION_RemoveODBC },
7178 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7179 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7180 { szResolveSource, ACTION_ResolveSource },
7181 { szRMCCPSearch, ACTION_RMCCPSearch },
7182 { szScheduleReboot, ACTION_ScheduleReboot },
7183 { szSelfRegModules, ACTION_SelfRegModules },
7184 { szSelfUnregModules, ACTION_SelfUnregModules },
7185 { szSetODBCFolders, ACTION_SetODBCFolders },
7186 { szStartServices, ACTION_StartServices },
7187 { szStopServices, ACTION_StopServices },
7188 { szUnpublishComponents, ACTION_UnpublishComponents },
7189 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7190 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7191 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7192 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7193 { szUnregisterFonts, ACTION_UnregisterFonts },
7194 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7195 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7196 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7197 { szValidateProductID, ACTION_ValidateProductID },
7198 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7199 { szWriteIniValues, ACTION_WriteIniValues },
7200 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7204 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7205 UINT* rc, BOOL force )
7211 if (!run && !package->script->CurrentlyScripting)
7216 if (strcmpW(action,szInstallFinalize) == 0 ||
7217 strcmpW(action,szInstallExecute) == 0 ||
7218 strcmpW(action,szInstallExecuteAgain) == 0)
7223 while (StandardActions[i].action != NULL)
7225 if (strcmpW(StandardActions[i].action, action)==0)
7229 ui_actioninfo(package, action, TRUE, 0);
7230 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7231 ui_actioninfo(package, action, FALSE, *rc);
7235 ui_actionstart(package, action);
7236 if (StandardActions[i].handler)
7238 *rc = StandardActions[i].handler(package);
7242 FIXME("unhandled standard action %s\n",debugstr_w(action));
7243 *rc = ERROR_SUCCESS;
7254 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7256 UINT rc = ERROR_SUCCESS;
7259 TRACE("Performing action (%s)\n", debugstr_w(action));
7261 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7264 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7268 WARN("unhandled msi action %s\n", debugstr_w(action));
7269 rc = ERROR_FUNCTION_NOT_CALLED;
7275 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7277 UINT rc = ERROR_SUCCESS;
7278 BOOL handled = FALSE;
7280 TRACE("Performing action (%s)\n", debugstr_w(action));
7282 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7285 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7287 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7292 WARN("unhandled msi action %s\n", debugstr_w(action));
7293 rc = ERROR_FUNCTION_NOT_CALLED;
7299 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7301 UINT rc = ERROR_SUCCESS;
7304 static const WCHAR ExecSeqQuery[] =
7305 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7306 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7307 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7308 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7309 static const WCHAR UISeqQuery[] =
7310 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7311 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7312 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7313 ' ', '=',' ','%','i',0};
7315 if (needs_ui_sequence(package))
7316 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7318 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7322 LPCWSTR action, cond;
7324 TRACE("Running the actions\n");
7326 /* check conditions */
7327 cond = MSI_RecordGetString(row, 2);
7329 /* this is a hack to skip errors in the condition code */
7330 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7332 msiobj_release(&row->hdr);
7333 return ERROR_SUCCESS;
7336 action = MSI_RecordGetString(row, 1);
7339 ERR("failed to fetch action\n");
7340 msiobj_release(&row->hdr);
7341 return ERROR_FUNCTION_FAILED;
7344 if (needs_ui_sequence(package))
7345 rc = ACTION_PerformUIAction(package, action, -1);
7347 rc = ACTION_PerformAction(package, action, -1, FALSE);
7349 msiobj_release(&row->hdr);
7355 /****************************************************
7356 * TOP level entry points
7357 *****************************************************/
7359 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7360 LPCWSTR szCommandLine )
7365 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7366 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7368 msi_set_property( package->db, szAction, szInstall );
7370 package->script->InWhatSequence = SEQUENCE_INSTALL;
7377 dir = strdupW(szPackagePath);
7378 p = strrchrW(dir, '\\');
7382 file = szPackagePath + (p - dir);
7387 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7388 GetCurrentDirectoryW(MAX_PATH, dir);
7389 lstrcatW(dir, szBackSlash);
7390 file = szPackagePath;
7393 msi_free( package->PackagePath );
7394 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7395 if (!package->PackagePath)
7398 return ERROR_OUTOFMEMORY;
7401 lstrcpyW(package->PackagePath, dir);
7402 lstrcatW(package->PackagePath, file);
7405 msi_set_sourcedir_props(package, FALSE);
7408 msi_parse_command_line( package, szCommandLine, FALSE );
7410 msi_apply_transforms( package );
7411 msi_apply_patches( package );
7413 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7415 TRACE("setting reinstall property\n");
7416 msi_set_property( package->db, szReinstall, szAll );
7419 /* properties may have been added by a transform */
7420 msi_clone_properties( package );
7421 msi_set_context( package );
7423 if (needs_ui_sequence( package))
7425 package->script->InWhatSequence |= SEQUENCE_UI;
7426 rc = ACTION_ProcessUISequence(package);
7427 ui_exists = ui_sequence_exists(package);
7428 if (rc == ERROR_SUCCESS || !ui_exists)
7430 package->script->InWhatSequence |= SEQUENCE_EXEC;
7431 rc = ACTION_ProcessExecSequence(package, ui_exists);
7435 rc = ACTION_ProcessExecSequence(package, FALSE);
7437 package->script->CurrentlyScripting = FALSE;
7439 /* process the ending type action */
7440 if (rc == ERROR_SUCCESS)
7441 ACTION_PerformActionSequence(package, -1);
7442 else if (rc == ERROR_INSTALL_USEREXIT)
7443 ACTION_PerformActionSequence(package, -2);
7444 else if (rc == ERROR_INSTALL_SUSPEND)
7445 ACTION_PerformActionSequence(package, -4);
7447 ACTION_PerformActionSequence(package, -3);
7449 /* finish up running custom actions */
7450 ACTION_FinishCustomActions(package);
7452 if (rc == ERROR_SUCCESS && package->need_reboot)
7453 return ERROR_SUCCESS_REBOOT_REQUIRED;