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 szRegisterFonts[] =
128 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
129 static const WCHAR szRegisterUser[] =
130 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
131 static const WCHAR szRemoveEnvironmentStrings[] =
132 {'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};
133 static const WCHAR szRemoveExistingProducts[] =
134 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
135 static const WCHAR szRemoveFolders[] =
136 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
137 static const WCHAR szRemoveIniValues[] =
138 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
139 static const WCHAR szRemoveODBC[] =
140 {'R','e','m','o','v','e','O','D','B','C',0};
141 static const WCHAR szRemoveRegistryValues[] =
142 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
143 static const WCHAR szRemoveShortcuts[] =
144 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
145 static const WCHAR szRMCCPSearch[] =
146 {'R','M','C','C','P','S','e','a','r','c','h',0};
147 static const WCHAR szScheduleReboot[] =
148 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
149 static const WCHAR szSelfUnregModules[] =
150 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
151 static const WCHAR szSetODBCFolders[] =
152 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
153 static const WCHAR szStartServices[] =
154 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szStopServices[] =
156 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szUnpublishComponents[] =
158 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szUnpublishFeatures[] =
160 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
161 static const WCHAR szUnregisterClassInfo[] =
162 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
163 static const WCHAR szUnregisterComPlus[] =
164 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
165 static const WCHAR szUnregisterExtensionInfo[] =
166 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
167 static const WCHAR szUnregisterFonts[] =
168 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 static const WCHAR szUnregisterMIMEInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szUnregisterProgIdInfo[] =
172 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
173 static const WCHAR szUnregisterTypeLibraries[] =
174 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
175 static const WCHAR szValidateProductID[] =
176 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
177 static const WCHAR szWriteEnvironmentStrings[] =
178 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
180 /********************************************************
182 ********************************************************/
184 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
186 static const WCHAR Query_t[] =
187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
188 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
189 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
190 ' ','\'','%','s','\'',0};
193 row = MSI_QueryGetRecord( package->db, Query_t, action );
196 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
197 msiobj_release(&row->hdr);
200 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
204 static const WCHAR template_s[]=
205 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
207 static const WCHAR template_e[]=
208 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
209 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
211 static const WCHAR format[] =
212 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
216 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
218 sprintfW(message,template_s,timet,action);
220 sprintfW(message,template_e,timet,action,rc);
222 row = MSI_CreateRecord(1);
223 MSI_RecordSetStringW(row,1,message);
225 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
226 msiobj_release(&row->hdr);
229 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
235 LPWSTR prop = NULL, val = NULL;
238 return ERROR_SUCCESS;
250 TRACE("Looking at %s\n",debugstr_w(ptr));
252 ptr2 = strchrW(ptr,'=');
255 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
262 prop = msi_alloc((len+1)*sizeof(WCHAR));
263 memcpy(prop,ptr,len*sizeof(WCHAR));
273 while (*ptr && (quote || (!quote && *ptr!=' ')))
286 val = msi_alloc((len+1)*sizeof(WCHAR));
287 memcpy(val,ptr2,len*sizeof(WCHAR));
290 if (lstrlenW(prop) > 0)
292 TRACE("Found commandline property (%s) = (%s)\n",
293 debugstr_w(prop), debugstr_w(val));
294 MSI_SetPropertyW(package,prop,val);
300 return ERROR_SUCCESS;
304 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
307 LPWSTR p, *ret = NULL;
313 /* count the number of substrings */
314 for ( pc = str, count = 0; pc; count++ )
316 pc = strchrW( pc, sep );
321 /* allocate space for an array of substring pointers and the substrings */
322 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
323 (lstrlenW(str)+1) * sizeof(WCHAR) );
327 /* copy the string and set the pointers */
328 p = (LPWSTR) &ret[count+1];
330 for( count = 0; (ret[count] = p); count++ )
332 p = strchrW( p, sep );
340 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
342 static const WCHAR szSystemLanguageID[] =
343 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
345 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
346 UINT ret = ERROR_FUNCTION_FAILED;
348 prod_code = msi_dup_property( package, szProductCode );
349 patch_product = msi_get_suminfo_product( patch );
351 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
353 if ( strstrW( patch_product, prod_code ) )
358 si = MSI_GetSummaryInformationW( patch, 0 );
361 ERR("no summary information!\n");
365 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
368 ERR("no template property!\n");
369 msiobj_release( &si->hdr );
376 msiobj_release( &si->hdr );
380 langid = msi_dup_property( package, szSystemLanguageID );
383 msiobj_release( &si->hdr );
387 p = strchrW( template, ';' );
388 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
390 TRACE("applicable transform\n");
394 /* FIXME: check platform */
396 msiobj_release( &si->hdr );
400 msi_free( patch_product );
401 msi_free( prod_code );
402 msi_free( template );
408 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
415 TRACE("%p %s\n", package, debugstr_w(name) );
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
426 ret = msi_check_transform_applicable( package, stg );
427 if (ret == ERROR_SUCCESS)
428 msi_table_apply_transform( package->db, stg );
430 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
431 IStorage_Release( stg );
434 ERR("failed to open substorage %s\n", debugstr_w(name));
436 return ERROR_SUCCESS;
439 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
441 LPWSTR guid_list, *guids, product_code;
442 UINT i, ret = ERROR_FUNCTION_FAILED;
444 product_code = msi_dup_property( package, szProductCode );
447 /* FIXME: the property ProductCode should be written into the DB somewhere */
448 ERR("no product code to check\n");
449 return ERROR_SUCCESS;
452 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
453 guids = msi_split_string( guid_list, ';' );
454 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
456 if (!lstrcmpW( guids[i], product_code ))
460 msi_free( guid_list );
461 msi_free( product_code );
466 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
469 MSIRECORD *rec = NULL;
474 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
475 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
476 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
477 '`','S','o','u','r','c','e','`',' ','I','S',' ',
478 'N','O','T',' ','N','U','L','L',0};
480 r = MSI_DatabaseOpenViewW(package->db, query, &view);
481 if (r != ERROR_SUCCESS)
484 r = MSI_ViewExecute(view, 0);
485 if (r != ERROR_SUCCESS)
488 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
490 prop = MSI_RecordGetString(rec, 1);
491 patch = msi_dup_property(package, szPatch);
492 MSI_SetPropertyW(package, prop, patch);
497 if (rec) msiobj_release(&rec->hdr);
498 msiobj_release(&view->hdr);
503 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
506 LPWSTR str, *substorage;
507 UINT i, r = ERROR_SUCCESS;
509 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
511 return ERROR_FUNCTION_FAILED;
513 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
515 TRACE("Patch not applicable\n");
516 return ERROR_SUCCESS;
519 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
521 return ERROR_OUTOFMEMORY;
523 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
524 if (!package->patch->patchcode)
525 return ERROR_OUTOFMEMORY;
527 /* enumerate the substorage */
528 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
529 package->patch->transforms = str;
531 substorage = msi_split_string( str, ';' );
532 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
533 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
535 msi_free( substorage );
536 msiobj_release( &si->hdr );
538 msi_set_media_source_prop(package);
543 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
545 MSIDATABASE *patch_db = NULL;
548 TRACE("%p %s\n", package, debugstr_w( file ) );
551 * We probably want to make sure we only open a patch collection here.
552 * Patch collections (.msp) and databases (.msi) have different GUIDs
553 * but currently MSI_OpenDatabaseW will accept both.
555 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
556 if ( r != ERROR_SUCCESS )
558 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
562 msi_parse_patch_summary( package, patch_db );
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storage to search for streams.
568 append_storage_to_db( package->db, patch_db->storage );
570 msiobj_release( &patch_db->hdr );
572 return ERROR_SUCCESS;
575 /* get the PATCH property, and apply all the patches it specifies */
576 static UINT msi_apply_patches( MSIPACKAGE *package )
578 LPWSTR patch_list, *patches;
579 UINT i, r = ERROR_SUCCESS;
581 patch_list = msi_dup_property( package, szPatch );
583 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
585 patches = msi_split_string( patch_list, ';' );
586 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
587 r = msi_apply_patch_package( package, patches[i] );
590 msi_free( patch_list );
595 static UINT msi_apply_transforms( MSIPACKAGE *package )
597 static const WCHAR szTransforms[] = {
598 'T','R','A','N','S','F','O','R','M','S',0 };
599 LPWSTR xform_list, *xforms;
600 UINT i, r = ERROR_SUCCESS;
602 xform_list = msi_dup_property( package, szTransforms );
603 xforms = msi_split_string( xform_list, ';' );
605 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
607 if (xforms[i][0] == ':')
608 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
610 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
614 msi_free( xform_list );
619 static BOOL ui_sequence_exists( MSIPACKAGE *package )
624 static const WCHAR ExecSeqQuery [] =
625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
626 '`','I','n','s','t','a','l','l',
627 'U','I','S','e','q','u','e','n','c','e','`',
628 ' ','W','H','E','R','E',' ',
629 '`','S','e','q','u','e','n','c','e','`',' ',
630 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
631 '`','S','e','q','u','e','n','c','e','`',0};
633 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
634 if (rc == ERROR_SUCCESS)
636 msiobj_release(&view->hdr);
643 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
646 LPWSTR source, check;
649 static const WCHAR szOriginalDatabase[] =
650 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
652 db = msi_dup_property( package, szOriginalDatabase );
654 return ERROR_OUTOFMEMORY;
656 p = strrchrW( db, '\\' );
659 p = strrchrW( db, '/' );
663 return ERROR_SUCCESS;
668 source = msi_alloc( len * sizeof(WCHAR) );
669 lstrcpynW( source, db, len );
671 check = msi_dup_property( package, cszSourceDir );
672 if (!check || replace)
673 MSI_SetPropertyW( package, cszSourceDir, source );
677 check = msi_dup_property( package, cszSOURCEDIR );
678 if (!check || replace)
679 MSI_SetPropertyW( package, cszSOURCEDIR, source );
685 return ERROR_SUCCESS;
688 static BOOL needs_ui_sequence(MSIPACKAGE *package)
690 INT level = msi_get_property_int(package, szUILevel, 0);
691 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
694 static UINT msi_set_context(MSIPACKAGE *package)
701 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
703 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
704 if (r == ERROR_SUCCESS)
707 if (num == 1 || num == 2)
708 package->Context = MSIINSTALLCONTEXT_MACHINE;
711 return ERROR_SUCCESS;
714 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
717 LPCWSTR cond, action;
718 MSIPACKAGE *package = param;
720 action = MSI_RecordGetString(row,1);
723 ERR("Error is retrieving action name\n");
724 return ERROR_FUNCTION_FAILED;
727 /* check conditions */
728 cond = MSI_RecordGetString(row,2);
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
733 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
734 return ERROR_SUCCESS;
737 if (needs_ui_sequence(package))
738 rc = ACTION_PerformUIAction(package, action, -1);
740 rc = ACTION_PerformAction(package, action, -1, FALSE);
742 msi_dialog_check_messages( NULL );
744 if (package->CurrentInstallState != ERROR_SUCCESS)
745 rc = package->CurrentInstallState;
747 if (rc == ERROR_FUNCTION_NOT_CALLED)
750 if (rc != ERROR_SUCCESS)
751 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
756 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
760 static const WCHAR query[] =
761 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
763 ' ','W','H','E','R','E',' ',
764 '`','S','e','q','u','e','n','c','e','`',' ',
765 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
766 '`','S','e','q','u','e','n','c','e','`',0};
768 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
770 r = MSI_OpenQuery( package->db, &view, query, szTable );
771 if (r == ERROR_SUCCESS)
773 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
774 msiobj_release(&view->hdr);
780 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
784 static const WCHAR ExecSeqQuery[] =
785 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
786 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
787 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
788 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
789 'O','R','D','E','R',' ', 'B','Y',' ',
790 '`','S','e','q','u','e','n','c','e','`',0 };
791 static const WCHAR IVQuery[] =
792 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
793 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
794 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
795 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
796 ' ','\'', 'I','n','s','t','a','l','l',
797 'V','a','l','i','d','a','t','e','\'', 0};
800 if (package->script->ExecuteSequenceRun)
802 TRACE("Execute Sequence already Run\n");
803 return ERROR_SUCCESS;
806 package->script->ExecuteSequenceRun = TRUE;
808 /* get the sequence number */
811 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
813 return ERROR_FUNCTION_FAILED;
814 seq = MSI_RecordGetInteger(row,1);
815 msiobj_release(&row->hdr);
818 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
819 if (rc == ERROR_SUCCESS)
821 TRACE("Running the actions\n");
823 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
824 msiobj_release(&view->hdr);
830 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
834 static const WCHAR ExecSeqQuery [] =
835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
836 '`','I','n','s','t','a','l','l',
837 'U','I','S','e','q','u','e','n','c','e','`',
838 ' ','W','H','E','R','E',' ',
839 '`','S','e','q','u','e','n','c','e','`',' ',
840 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
841 '`','S','e','q','u','e','n','c','e','`',0};
843 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
844 if (rc == ERROR_SUCCESS)
846 TRACE("Running the actions\n");
848 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
849 msiobj_release(&view->hdr);
855 /********************************************************
856 * ACTION helper functions and functions that perform the actions
857 *******************************************************/
858 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
859 UINT* rc, UINT script, BOOL force )
864 arc = ACTION_CustomAction(package, action, script, force);
866 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
875 * Actual Action Handlers
878 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
880 MSIPACKAGE *package = param;
881 LPCWSTR dir, component;
887 component = MSI_RecordGetString(row, 2);
888 comp = get_loaded_component(package, component);
890 return ERROR_SUCCESS;
892 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
894 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
895 comp->Action = comp->Installed;
896 return ERROR_SUCCESS;
898 comp->Action = INSTALLSTATE_LOCAL;
900 dir = MSI_RecordGetString(row,1);
903 ERR("Unable to get folder id\n");
904 return ERROR_SUCCESS;
907 uirow = MSI_CreateRecord(1);
908 MSI_RecordSetStringW(uirow, 1, dir);
909 ui_actiondata(package, szCreateFolders, uirow);
910 msiobj_release(&uirow->hdr);
912 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
915 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
916 return ERROR_SUCCESS;
919 TRACE("Folder is %s\n",debugstr_w(full_path));
921 if (folder->State == 0)
922 create_full_pathW(full_path);
927 return ERROR_SUCCESS;
930 /* FIXME: probably should merge this with the above function */
931 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
933 UINT rc = ERROR_SUCCESS;
937 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
939 return ERROR_FUNCTION_FAILED;
941 /* create the path */
942 if (folder->State == 0)
944 create_full_pathW(install_path);
947 msi_free(install_path);
952 UINT msi_create_component_directories( MSIPACKAGE *package )
956 /* create all the folders required by the components are going to install */
957 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
959 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
961 msi_create_directory( package, comp->Directory );
964 return ERROR_SUCCESS;
967 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
969 static const WCHAR ExecSeqQuery[] =
970 {'S','E','L','E','C','T',' ',
971 '`','D','i','r','e','c','t','o','r','y','_','`',
972 ' ','F','R','O','M',' ',
973 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
977 /* create all the empty folders specified in the CreateFolder table */
978 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
979 if (rc != ERROR_SUCCESS)
980 return ERROR_SUCCESS;
982 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
983 msiobj_release(&view->hdr);
988 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
990 MSIPACKAGE *package = param;
991 LPCWSTR dir, component;
997 component = MSI_RecordGetString(row, 2);
998 comp = get_loaded_component(package, component);
1000 return ERROR_SUCCESS;
1002 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1004 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1005 comp->Action = comp->Installed;
1006 return ERROR_SUCCESS;
1008 comp->Action = INSTALLSTATE_ABSENT;
1010 dir = MSI_RecordGetString( row, 1 );
1013 ERR("Unable to get folder id\n");
1014 return ERROR_SUCCESS;
1017 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1020 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1021 return ERROR_SUCCESS;
1024 TRACE("folder is %s\n", debugstr_w(full_path));
1026 uirow = MSI_CreateRecord( 1 );
1027 MSI_RecordSetStringW( uirow, 1, full_path );
1028 ui_actiondata( package, szRemoveFolders, uirow );
1029 msiobj_release( &uirow->hdr );
1031 RemoveDirectoryW( full_path );
1034 msi_free( full_path );
1035 return ERROR_SUCCESS;
1038 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1040 static const WCHAR query[] =
1041 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1042 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1047 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1048 if (rc != ERROR_SUCCESS)
1049 return ERROR_SUCCESS;
1051 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1052 msiobj_release( &view->hdr );
1057 static UINT load_component( MSIRECORD *row, LPVOID param )
1059 MSIPACKAGE *package = param;
1062 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1064 return ERROR_FUNCTION_FAILED;
1066 list_add_tail( &package->components, &comp->entry );
1068 /* fill in the data */
1069 comp->Component = msi_dup_record_field( row, 1 );
1071 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1073 comp->ComponentId = msi_dup_record_field( row, 2 );
1074 comp->Directory = msi_dup_record_field( row, 3 );
1075 comp->Attributes = MSI_RecordGetInteger(row,4);
1076 comp->Condition = msi_dup_record_field( row, 5 );
1077 comp->KeyPath = msi_dup_record_field( row, 6 );
1079 comp->Installed = INSTALLSTATE_UNKNOWN;
1080 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1082 return ERROR_SUCCESS;
1085 static UINT load_all_components( MSIPACKAGE *package )
1087 static const WCHAR query[] = {
1088 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1089 '`','C','o','m','p','o','n','e','n','t','`',0 };
1093 if (!list_empty(&package->components))
1094 return ERROR_SUCCESS;
1096 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1097 if (r != ERROR_SUCCESS)
1100 r = MSI_IterateRecords(view, NULL, load_component, package);
1101 msiobj_release(&view->hdr);
1106 MSIPACKAGE *package;
1107 MSIFEATURE *feature;
1110 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1114 cl = msi_alloc( sizeof (*cl) );
1116 return ERROR_NOT_ENOUGH_MEMORY;
1117 cl->component = comp;
1118 list_add_tail( &feature->Components, &cl->entry );
1120 return ERROR_SUCCESS;
1123 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1127 fl = msi_alloc( sizeof(*fl) );
1129 return ERROR_NOT_ENOUGH_MEMORY;
1130 fl->feature = child;
1131 list_add_tail( &parent->Children, &fl->entry );
1133 return ERROR_SUCCESS;
1136 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1138 _ilfs* ilfs = param;
1142 component = MSI_RecordGetString(row,1);
1144 /* check to see if the component is already loaded */
1145 comp = get_loaded_component( ilfs->package, component );
1148 ERR("unknown component %s\n", debugstr_w(component));
1149 return ERROR_FUNCTION_FAILED;
1152 add_feature_component( ilfs->feature, comp );
1153 comp->Enabled = TRUE;
1155 return ERROR_SUCCESS;
1158 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1160 MSIFEATURE *feature;
1165 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1167 if ( !lstrcmpW( feature->Feature, name ) )
1174 static UINT load_feature(MSIRECORD * row, LPVOID param)
1176 MSIPACKAGE* package = param;
1177 MSIFEATURE* feature;
1178 static const WCHAR Query1[] =
1179 {'S','E','L','E','C','T',' ',
1180 '`','C','o','m','p','o','n','e','n','t','_','`',
1181 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1182 'C','o','m','p','o','n','e','n','t','s','`',' ',
1183 'W','H','E','R','E',' ',
1184 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1189 /* fill in the data */
1191 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1193 return ERROR_NOT_ENOUGH_MEMORY;
1195 list_init( &feature->Children );
1196 list_init( &feature->Components );
1198 feature->Feature = msi_dup_record_field( row, 1 );
1200 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1202 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1203 feature->Title = msi_dup_record_field( row, 3 );
1204 feature->Description = msi_dup_record_field( row, 4 );
1206 if (!MSI_RecordIsNull(row,5))
1207 feature->Display = MSI_RecordGetInteger(row,5);
1209 feature->Level= MSI_RecordGetInteger(row,6);
1210 feature->Directory = msi_dup_record_field( row, 7 );
1211 feature->Attributes = MSI_RecordGetInteger(row,8);
1213 feature->Installed = INSTALLSTATE_UNKNOWN;
1214 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1216 list_add_tail( &package->features, &feature->entry );
1218 /* load feature components */
1220 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1221 if (rc != ERROR_SUCCESS)
1222 return ERROR_SUCCESS;
1224 ilfs.package = package;
1225 ilfs.feature = feature;
1227 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1228 msiobj_release(&view->hdr);
1230 return ERROR_SUCCESS;
1233 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1235 MSIPACKAGE* package = param;
1236 MSIFEATURE *parent, *child;
1238 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1240 return ERROR_FUNCTION_FAILED;
1242 if (!child->Feature_Parent)
1243 return ERROR_SUCCESS;
1245 parent = find_feature_by_name( package, child->Feature_Parent );
1247 return ERROR_FUNCTION_FAILED;
1249 add_feature_child( parent, child );
1250 return ERROR_SUCCESS;
1253 static UINT load_all_features( MSIPACKAGE *package )
1255 static const WCHAR query[] = {
1256 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1257 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1258 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1262 if (!list_empty(&package->features))
1263 return ERROR_SUCCESS;
1265 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1266 if (r != ERROR_SUCCESS)
1269 r = MSI_IterateRecords( view, NULL, load_feature, package );
1270 if (r != ERROR_SUCCESS)
1273 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1274 msiobj_release( &view->hdr );
1279 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1290 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1292 static const WCHAR query[] = {
1293 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1294 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1295 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1296 MSIQUERY *view = NULL;
1297 MSIRECORD *row = NULL;
1300 TRACE("%s\n", debugstr_w(file->File));
1302 r = MSI_OpenQuery(package->db, &view, query, file->File);
1303 if (r != ERROR_SUCCESS)
1306 r = MSI_ViewExecute(view, NULL);
1307 if (r != ERROR_SUCCESS)
1310 r = MSI_ViewFetch(view, &row);
1311 if (r != ERROR_SUCCESS)
1314 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1315 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1316 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1317 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1318 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1321 if (view) msiobj_release(&view->hdr);
1322 if (row) msiobj_release(&row->hdr);
1326 static UINT load_file(MSIRECORD *row, LPVOID param)
1328 MSIPACKAGE* package = param;
1332 /* fill in the data */
1334 file = msi_alloc_zero( sizeof (MSIFILE) );
1336 return ERROR_NOT_ENOUGH_MEMORY;
1338 file->File = msi_dup_record_field( row, 1 );
1340 component = MSI_RecordGetString( row, 2 );
1341 file->Component = get_loaded_component( package, component );
1343 if (!file->Component)
1345 WARN("Component not found: %s\n", debugstr_w(component));
1346 msi_free(file->File);
1348 return ERROR_SUCCESS;
1351 file->FileName = msi_dup_record_field( row, 3 );
1352 reduce_to_longfilename( file->FileName );
1354 file->ShortName = msi_dup_record_field( row, 3 );
1355 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1357 file->FileSize = MSI_RecordGetInteger( row, 4 );
1358 file->Version = msi_dup_record_field( row, 5 );
1359 file->Language = msi_dup_record_field( row, 6 );
1360 file->Attributes = MSI_RecordGetInteger( row, 7 );
1361 file->Sequence = MSI_RecordGetInteger( row, 8 );
1363 file->state = msifs_invalid;
1365 /* if the compressed bits are not set in the file attributes,
1366 * then read the information from the package word count property
1368 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1370 file->IsCompressed = FALSE;
1372 else if (file->Attributes &
1373 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1375 file->IsCompressed = TRUE;
1377 else if (file->Attributes & msidbFileAttributesNoncompressed)
1379 file->IsCompressed = FALSE;
1383 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1386 load_file_hash(package, file);
1388 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1390 list_add_tail( &package->files, &file->entry );
1392 return ERROR_SUCCESS;
1395 static UINT load_all_files(MSIPACKAGE *package)
1399 static const WCHAR Query[] =
1400 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1401 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1402 '`','S','e','q','u','e','n','c','e','`', 0};
1404 if (!list_empty(&package->files))
1405 return ERROR_SUCCESS;
1407 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1408 if (rc != ERROR_SUCCESS)
1409 return ERROR_SUCCESS;
1411 rc = MSI_IterateRecords(view, NULL, load_file, package);
1412 msiobj_release(&view->hdr);
1414 return ERROR_SUCCESS;
1417 static UINT load_folder( MSIRECORD *row, LPVOID param )
1419 MSIPACKAGE *package = param;
1420 static WCHAR szEmpty[] = { 0 };
1421 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1424 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1426 return ERROR_NOT_ENOUGH_MEMORY;
1428 folder->Directory = msi_dup_record_field( row, 1 );
1430 TRACE("%s\n", debugstr_w(folder->Directory));
1432 p = msi_dup_record_field(row, 3);
1434 /* split src and target dir */
1436 src_short = folder_split_path( p, ':' );
1438 /* split the long and short paths */
1439 tgt_long = folder_split_path( tgt_short, '|' );
1440 src_long = folder_split_path( src_short, '|' );
1442 /* check for no-op dirs */
1443 if (!lstrcmpW(szDot, tgt_short))
1444 tgt_short = szEmpty;
1445 if (!lstrcmpW(szDot, src_short))
1446 src_short = szEmpty;
1449 tgt_long = tgt_short;
1452 src_short = tgt_short;
1453 src_long = tgt_long;
1457 src_long = src_short;
1459 /* FIXME: use the target short path too */
1460 folder->TargetDefault = strdupW(tgt_long);
1461 folder->SourceShortPath = strdupW(src_short);
1462 folder->SourceLongPath = strdupW(src_long);
1465 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1466 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1467 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1469 folder->Parent = msi_dup_record_field( row, 2 );
1471 folder->Property = msi_dup_property( package, folder->Directory );
1473 list_add_tail( &package->folders, &folder->entry );
1475 TRACE("returning %p\n", folder);
1477 return ERROR_SUCCESS;
1480 static UINT load_all_folders( MSIPACKAGE *package )
1482 static const WCHAR query[] = {
1483 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1484 '`','D','i','r','e','c','t','o','r','y','`',0 };
1488 if (!list_empty(&package->folders))
1489 return ERROR_SUCCESS;
1491 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1492 if (r != ERROR_SUCCESS)
1495 r = MSI_IterateRecords(view, NULL, load_folder, package);
1496 msiobj_release(&view->hdr);
1501 * I am not doing any of the costing functionality yet.
1502 * Mostly looking at doing the Component and Feature loading
1504 * The native MSI does A LOT of modification to tables here. Mostly adding
1505 * a lot of temporary columns to the Feature and Component tables.
1507 * note: Native msi also tracks the short filename. But I am only going to
1508 * track the long ones. Also looking at this directory table
1509 * it appears that the directory table does not get the parents
1510 * resolved base on property only based on their entries in the
1513 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1515 static const WCHAR szCosting[] =
1516 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1518 MSI_SetPropertyW(package, szCosting, szZero);
1519 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1521 load_all_folders( package );
1522 load_all_components( package );
1523 load_all_features( package );
1524 load_all_files( package );
1526 return ERROR_SUCCESS;
1529 static UINT execute_script(MSIPACKAGE *package, UINT script )
1532 UINT rc = ERROR_SUCCESS;
1534 TRACE("Executing Script %i\n",script);
1536 if (!package->script)
1538 ERR("no script!\n");
1539 return ERROR_FUNCTION_FAILED;
1542 for (i = 0; i < package->script->ActionCount[script]; i++)
1545 action = package->script->Actions[script][i];
1546 ui_actionstart(package, action);
1547 TRACE("Executing Action (%s)\n",debugstr_w(action));
1548 rc = ACTION_PerformAction(package, action, script, TRUE);
1549 if (rc != ERROR_SUCCESS)
1552 msi_free_action_script(package, script);
1556 static UINT ACTION_FileCost(MSIPACKAGE *package)
1558 return ERROR_SUCCESS;
1561 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1567 state = MsiQueryProductStateW(package->ProductCode);
1569 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1571 if (!comp->ComponentId)
1574 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1575 comp->Installed = INSTALLSTATE_ABSENT;
1578 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1579 package->Context, comp->ComponentId,
1581 if (r != ERROR_SUCCESS)
1582 comp->Installed = INSTALLSTATE_ABSENT;
1587 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1589 MSIFEATURE *feature;
1592 state = MsiQueryProductStateW(package->ProductCode);
1594 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1596 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1597 feature->Installed = INSTALLSTATE_ABSENT;
1600 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1606 static BOOL process_state_property(MSIPACKAGE* package, int level,
1607 LPCWSTR property, INSTALLSTATE state)
1610 MSIFEATURE *feature;
1612 override = msi_dup_property( package, property );
1616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1618 if (lstrcmpW(property, szRemove) &&
1619 (feature->Level <= 0 || feature->Level > level))
1622 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1624 if (strcmpiW(override, szAll)==0)
1625 msi_feature_set_state(package, feature, state);
1628 LPWSTR ptr = override;
1629 LPWSTR ptr2 = strchrW(override,',');
1633 int len = ptr2 - ptr;
1635 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1636 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1638 msi_feature_set_state(package, feature, state);
1644 ptr2 = strchrW(ptr,',');
1656 static BOOL process_overrides( MSIPACKAGE *package, int level )
1658 static const WCHAR szAddLocal[] =
1659 {'A','D','D','L','O','C','A','L',0};
1660 static const WCHAR szAddSource[] =
1661 {'A','D','D','S','O','U','R','C','E',0};
1662 static const WCHAR szAdvertise[] =
1663 {'A','D','V','E','R','T','I','S','E',0};
1666 /* all these activation/deactivation things happen in order and things
1667 * later on the list override things earlier on the list.
1669 * 0 INSTALLLEVEL processing
1682 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1683 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1684 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1685 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1686 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1689 MSI_SetPropertyW( package, szPreselected, szOne );
1694 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1697 static const WCHAR szlevel[] =
1698 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1699 MSICOMPONENT* component;
1700 MSIFEATURE *feature;
1702 TRACE("Checking Install Level\n");
1704 level = msi_get_property_int(package, szlevel, 1);
1706 if (!msi_get_property_int( package, szPreselected, 0 ))
1708 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1710 BOOL feature_state = ((feature->Level > 0) &&
1711 (feature->Level <= level));
1713 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1715 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1716 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1717 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1718 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1720 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1724 /* disable child features of unselected parent features */
1725 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1729 if (feature->Level > 0 && feature->Level <= level)
1732 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1733 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1738 * now we want to enable or disable components base on feature
1741 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1745 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1746 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1748 if (!feature->Level)
1751 /* features with components that have compressed files are made local */
1752 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1754 if (cl->component->Enabled &&
1755 cl->component->ForceLocalState &&
1756 feature->Action == INSTALLSTATE_SOURCE)
1758 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1763 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1765 component = cl->component;
1767 if (!component->Enabled)
1770 switch (feature->Action)
1772 case INSTALLSTATE_ABSENT:
1773 component->anyAbsent = 1;
1775 case INSTALLSTATE_ADVERTISED:
1776 component->hasAdvertiseFeature = 1;
1778 case INSTALLSTATE_SOURCE:
1779 component->hasSourceFeature = 1;
1781 case INSTALLSTATE_LOCAL:
1782 component->hasLocalFeature = 1;
1784 case INSTALLSTATE_DEFAULT:
1785 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1786 component->hasAdvertiseFeature = 1;
1787 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 component->hasSourceFeature = 1;
1790 component->hasLocalFeature = 1;
1798 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1800 /* if the component isn't enabled, leave it alone */
1801 if (!component->Enabled)
1804 /* check if it's local or source */
1805 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1806 (component->hasLocalFeature || component->hasSourceFeature))
1808 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1809 !component->ForceLocalState)
1810 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1812 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1816 /* if any feature is local, the component must be local too */
1817 if (component->hasLocalFeature)
1819 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1823 if (component->hasSourceFeature)
1825 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1829 if (component->hasAdvertiseFeature)
1831 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1835 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1836 if (component->anyAbsent)
1837 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1840 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1842 if (component->Action == INSTALLSTATE_DEFAULT)
1844 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1845 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1848 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1849 debugstr_w(component->Component), component->Installed, component->Action);
1853 return ERROR_SUCCESS;
1856 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1858 MSIPACKAGE *package = param;
1863 name = MSI_RecordGetString(row,1);
1865 f = get_loaded_folder(package, name);
1866 if (!f) return ERROR_SUCCESS;
1868 /* reset the ResolvedTarget */
1869 msi_free(f->ResolvedTarget);
1870 f->ResolvedTarget = NULL;
1872 /* This helper function now does ALL the work */
1873 TRACE("Dir %s ...\n",debugstr_w(name));
1874 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1875 TRACE("resolves to %s\n",debugstr_w(path));
1878 return ERROR_SUCCESS;
1881 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1883 MSIPACKAGE *package = param;
1885 MSIFEATURE *feature;
1887 name = MSI_RecordGetString( row, 1 );
1889 feature = get_loaded_feature( package, name );
1891 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1895 Condition = MSI_RecordGetString(row,3);
1897 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1899 int level = MSI_RecordGetInteger(row,2);
1900 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1901 feature->Level = level;
1904 return ERROR_SUCCESS;
1907 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1909 static const WCHAR name_fmt[] =
1910 {'%','u','.','%','u','.','%','u','.','%','u',0};
1911 static const WCHAR name[] = {'\\',0};
1912 VS_FIXEDFILEINFO *lpVer;
1913 WCHAR filever[0x100];
1919 TRACE("%s\n", debugstr_w(filename));
1921 versize = GetFileVersionInfoSizeW( filename, &handle );
1925 version = msi_alloc( versize );
1926 GetFileVersionInfoW( filename, 0, versize, version );
1928 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1930 msi_free( version );
1934 sprintfW( filever, name_fmt,
1935 HIWORD(lpVer->dwFileVersionMS),
1936 LOWORD(lpVer->dwFileVersionMS),
1937 HIWORD(lpVer->dwFileVersionLS),
1938 LOWORD(lpVer->dwFileVersionLS));
1940 msi_free( version );
1942 return strdupW( filever );
1945 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1947 LPWSTR file_version;
1950 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1952 MSICOMPONENT* comp = file->Component;
1958 if (file->IsCompressed)
1959 comp->ForceLocalState = TRUE;
1961 /* calculate target */
1962 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1964 msi_free(file->TargetPath);
1966 TRACE("file %s is named %s\n",
1967 debugstr_w(file->File), debugstr_w(file->FileName));
1969 file->TargetPath = build_directory_name(2, p, file->FileName);
1973 TRACE("file %s resolves to %s\n",
1974 debugstr_w(file->File), debugstr_w(file->TargetPath));
1976 /* don't check files of components that aren't installed */
1977 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1978 comp->Installed == INSTALLSTATE_ABSENT)
1980 file->state = msifs_missing; /* assume files are missing */
1984 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1986 file->state = msifs_missing;
1987 comp->Cost += file->FileSize;
1991 if (file->Version &&
1992 (file_version = msi_get_disk_file_version( file->TargetPath )))
1994 TRACE("new %s old %s\n", debugstr_w(file->Version),
1995 debugstr_w(file_version));
1996 /* FIXME: seems like a bad way to compare version numbers */
1997 if (lstrcmpiW(file_version, file->Version)<0)
1999 file->state = msifs_overwrite;
2000 comp->Cost += file->FileSize;
2003 file->state = msifs_present;
2004 msi_free( file_version );
2007 file->state = msifs_present;
2010 return ERROR_SUCCESS;
2014 * A lot is done in this function aside from just the costing.
2015 * The costing needs to be implemented at some point but for now I am going
2016 * to focus on the directory building
2019 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2021 static const WCHAR ExecSeqQuery[] =
2022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023 '`','D','i','r','e','c','t','o','r','y','`',0};
2024 static const WCHAR ConditionQuery[] =
2025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026 '`','C','o','n','d','i','t','i','o','n','`',0};
2027 static const WCHAR szCosting[] =
2028 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029 static const WCHAR szlevel[] =
2030 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2031 static const WCHAR szOutOfDiskSpace[] =
2032 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2034 UINT rc = ERROR_SUCCESS;
2038 TRACE("Building Directory properties\n");
2040 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2041 if (rc == ERROR_SUCCESS)
2043 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2045 msiobj_release(&view->hdr);
2048 /* read components states from the registry */
2049 ACTION_GetComponentInstallStates(package);
2050 ACTION_GetFeatureInstallStates(package);
2052 TRACE("File calculations\n");
2053 msi_check_file_install_states( package );
2055 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2057 TRACE("Evaluating Condition Table\n");
2059 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2060 if (rc == ERROR_SUCCESS)
2062 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2063 msiobj_release( &view->hdr );
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2069 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2071 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2072 comp->Enabled = FALSE;
2075 comp->Enabled = TRUE;
2079 MSI_SetPropertyW(package,szCosting,szOne);
2080 /* set default run level if not set */
2081 level = msi_dup_property( package, szlevel );
2083 MSI_SetPropertyW(package,szlevel, szOne);
2086 /* FIXME: check volume disk space */
2087 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2089 return MSI_SetFeatureStates(package);
2092 /* OK this value is "interpreted" and then formatted based on the
2093 first few characters */
2094 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2099 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2105 LPWSTR deformated = NULL;
2108 deformat_string(package, &value[2], &deformated);
2110 /* binary value type */
2114 *size = (strlenW(ptr)/2)+1;
2116 *size = strlenW(ptr)/2;
2118 data = msi_alloc(*size);
2124 /* if uneven pad with a zero in front */
2130 data[count] = (BYTE)strtol(byte,NULL,0);
2132 TRACE("Uneven byte count\n");
2140 data[count] = (BYTE)strtol(byte,NULL,0);
2143 msi_free(deformated);
2145 TRACE("Data %i bytes(%i)\n",*size,count);
2152 deformat_string(package, &value[1], &deformated);
2155 *size = sizeof(DWORD);
2156 data = msi_alloc(*size);
2162 if ( (*p < '0') || (*p > '9') )
2168 if (deformated[0] == '-')
2171 TRACE("DWORD %i\n",*(LPDWORD)data);
2173 msi_free(deformated);
2178 static const WCHAR szMulti[] = {'[','~',']',0};
2187 *type=REG_EXPAND_SZ;
2195 if (strstrW(value,szMulti))
2196 *type = REG_MULTI_SZ;
2198 /* remove initial delimiter */
2199 if (!strncmpW(value, szMulti, 3))
2202 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2204 /* add double NULL terminator */
2205 if (*type == REG_MULTI_SZ)
2207 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2208 data = msi_realloc_zero(data, *size);
2214 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2221 if (msi_get_property_int( package, szAllUsers, 0 ))
2223 *root_key = HKEY_LOCAL_MACHINE;
2228 *root_key = HKEY_CURRENT_USER;
2233 *root_key = HKEY_CLASSES_ROOT;
2237 *root_key = HKEY_CURRENT_USER;
2241 *root_key = HKEY_LOCAL_MACHINE;
2245 *root_key = HKEY_USERS;
2249 ERR("Unknown root %i\n", root);
2256 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2258 MSIPACKAGE *package = param;
2259 LPSTR value_data = NULL;
2260 HKEY root_key, hkey;
2263 LPCWSTR szRoot, component, name, key, value;
2268 BOOL check_first = FALSE;
2271 ui_progress(package,2,0,0,0);
2278 component = MSI_RecordGetString(row, 6);
2279 comp = get_loaded_component(package,component);
2281 return ERROR_SUCCESS;
2283 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2285 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2286 comp->Action = comp->Installed;
2287 return ERROR_SUCCESS;
2289 comp->Action = INSTALLSTATE_LOCAL;
2291 name = MSI_RecordGetString(row, 4);
2292 if( MSI_RecordIsNull(row,5) && name )
2294 /* null values can have special meanings */
2295 if (name[0]=='-' && name[1] == 0)
2296 return ERROR_SUCCESS;
2297 else if ((name[0]=='+' && name[1] == 0) ||
2298 (name[0] == '*' && name[1] == 0))
2303 root = MSI_RecordGetInteger(row,2);
2304 key = MSI_RecordGetString(row, 3);
2306 szRoot = get_root_key( package, root, &root_key );
2308 return ERROR_SUCCESS;
2310 deformat_string(package, key , &deformated);
2311 size = strlenW(deformated) + strlenW(szRoot) + 1;
2312 uikey = msi_alloc(size*sizeof(WCHAR));
2313 strcpyW(uikey,szRoot);
2314 strcatW(uikey,deformated);
2316 if (RegCreateKeyW( root_key, deformated, &hkey))
2318 ERR("Could not create key %s\n",debugstr_w(deformated));
2319 msi_free(deformated);
2321 return ERROR_SUCCESS;
2323 msi_free(deformated);
2325 value = MSI_RecordGetString(row,5);
2327 value_data = parse_value(package, value, &type, &size);
2330 value_data = (LPSTR)strdupW(szEmpty);
2331 size = sizeof(szEmpty);
2335 deformat_string(package, name, &deformated);
2339 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2341 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2346 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2347 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2349 TRACE("value %s of %s checked already exists\n",
2350 debugstr_w(deformated), debugstr_w(uikey));
2354 TRACE("Checked and setting value %s of %s\n",
2355 debugstr_w(deformated), debugstr_w(uikey));
2356 if (deformated || size)
2357 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2362 uirow = MSI_CreateRecord(3);
2363 MSI_RecordSetStringW(uirow,2,deformated);
2364 MSI_RecordSetStringW(uirow,1,uikey);
2365 if (type == REG_SZ || type == REG_EXPAND_SZ)
2366 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2367 ui_actiondata(package,szWriteRegistryValues,uirow);
2368 msiobj_release( &uirow->hdr );
2370 msi_free(value_data);
2371 msi_free(deformated);
2374 return ERROR_SUCCESS;
2377 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2381 static const WCHAR ExecSeqQuery[] =
2382 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2383 '`','R','e','g','i','s','t','r','y','`',0 };
2385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2386 if (rc != ERROR_SUCCESS)
2387 return ERROR_SUCCESS;
2389 /* increment progress bar each time action data is sent */
2390 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2392 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2394 msiobj_release(&view->hdr);
2398 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2402 DWORD num_subkeys, num_values;
2406 if ((res = RegDeleteTreeW( hkey_root, key )))
2408 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2413 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2415 if ((res = RegDeleteValueW( hkey, value )))
2417 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2419 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2420 NULL, NULL, NULL, NULL );
2421 RegCloseKey( hkey );
2423 if (!res && !num_subkeys && !num_values)
2425 TRACE("Removing empty key %s\n", debugstr_w(key));
2426 RegDeleteKeyW( hkey_root, key );
2430 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2434 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2436 MSIPACKAGE *package = param;
2437 LPCWSTR component, name, key_str, root_key_str;
2438 LPWSTR deformated_key, deformated_name, ui_key_str;
2441 BOOL delete_key = FALSE;
2446 ui_progress( package, 2, 0, 0, 0 );
2448 component = MSI_RecordGetString( row, 6 );
2449 comp = get_loaded_component( package, component );
2451 return ERROR_SUCCESS;
2453 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2455 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2456 comp->Action = comp->Installed;
2457 return ERROR_SUCCESS;
2459 comp->Action = INSTALLSTATE_ABSENT;
2461 name = MSI_RecordGetString( row, 4 );
2462 if (MSI_RecordIsNull( row, 5 ) && name )
2464 if (name[0] == '+' && !name[1])
2465 return ERROR_SUCCESS;
2466 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2473 root = MSI_RecordGetInteger( row, 2 );
2474 key_str = MSI_RecordGetString( row, 3 );
2476 root_key_str = get_root_key( package, root, &hkey_root );
2478 return ERROR_SUCCESS;
2480 deformat_string( package, key_str, &deformated_key );
2481 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2482 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2483 strcpyW( ui_key_str, root_key_str );
2484 strcatW( ui_key_str, deformated_key );
2486 deformat_string( package, name, &deformated_name );
2488 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2489 msi_free( deformated_key );
2491 uirow = MSI_CreateRecord( 2 );
2492 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2493 MSI_RecordSetStringW( uirow, 2, deformated_name );
2495 ui_actiondata( package, szRemoveRegistryValues, uirow );
2496 msiobj_release( &uirow->hdr );
2498 msi_free( ui_key_str );
2499 msi_free( deformated_name );
2500 return ERROR_SUCCESS;
2503 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2505 MSIPACKAGE *package = param;
2506 LPCWSTR component, name, key_str, root_key_str;
2507 LPWSTR deformated_key, deformated_name, ui_key_str;
2510 BOOL delete_key = FALSE;
2515 ui_progress( package, 2, 0, 0, 0 );
2517 component = MSI_RecordGetString( row, 5 );
2518 comp = get_loaded_component( package, component );
2520 return ERROR_SUCCESS;
2522 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2524 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2525 comp->Action = comp->Installed;
2526 return ERROR_SUCCESS;
2528 comp->Action = INSTALLSTATE_LOCAL;
2530 if ((name = MSI_RecordGetString( row, 4 )))
2532 if (name[0] == '-' && !name[1])
2539 root = MSI_RecordGetInteger( row, 2 );
2540 key_str = MSI_RecordGetString( row, 3 );
2542 root_key_str = get_root_key( package, root, &hkey_root );
2544 return ERROR_SUCCESS;
2546 deformat_string( package, key_str, &deformated_key );
2547 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2548 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2549 strcpyW( ui_key_str, root_key_str );
2550 strcatW( ui_key_str, deformated_key );
2552 deformat_string( package, name, &deformated_name );
2554 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2555 msi_free( deformated_key );
2557 uirow = MSI_CreateRecord( 2 );
2558 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2559 MSI_RecordSetStringW( uirow, 2, deformated_name );
2561 ui_actiondata( package, szRemoveRegistryValues, uirow );
2562 msiobj_release( &uirow->hdr );
2564 msi_free( ui_key_str );
2565 msi_free( deformated_name );
2566 return ERROR_SUCCESS;
2569 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2573 static const WCHAR registry_query[] =
2574 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2575 '`','R','e','g','i','s','t','r','y','`',0 };
2576 static const WCHAR remove_registry_query[] =
2577 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2578 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2580 /* increment progress bar each time action data is sent */
2581 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2583 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2584 if (rc == ERROR_SUCCESS)
2586 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2587 msiobj_release( &view->hdr );
2588 if (rc != ERROR_SUCCESS)
2592 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2593 if (rc == ERROR_SUCCESS)
2595 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2596 msiobj_release( &view->hdr );
2597 if (rc != ERROR_SUCCESS)
2601 return ERROR_SUCCESS;
2604 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2606 package->script->CurrentlyScripting = TRUE;
2608 return ERROR_SUCCESS;
2612 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2617 static const WCHAR q1[]=
2618 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2619 '`','R','e','g','i','s','t','r','y','`',0};
2622 MSIFEATURE *feature;
2625 TRACE("InstallValidate\n");
2627 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2628 if (rc == ERROR_SUCCESS)
2630 MSI_IterateRecords( view, &progress, NULL, package );
2631 msiobj_release( &view->hdr );
2632 total += progress * REG_PROGRESS_VALUE;
2635 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2636 total += COMPONENT_PROGRESS_VALUE;
2638 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2639 total += file->FileSize;
2641 ui_progress(package,0,total,0,0);
2643 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2645 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2646 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2647 feature->ActionRequest);
2650 return ERROR_SUCCESS;
2653 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2655 MSIPACKAGE* package = param;
2656 LPCWSTR cond = NULL;
2657 LPCWSTR message = NULL;
2660 static const WCHAR title[]=
2661 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2663 cond = MSI_RecordGetString(row,1);
2665 r = MSI_EvaluateConditionW(package,cond);
2666 if (r == MSICONDITION_FALSE)
2668 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2671 message = MSI_RecordGetString(row,2);
2672 deformat_string(package,message,&deformated);
2673 MessageBoxW(NULL,deformated,title,MB_OK);
2674 msi_free(deformated);
2677 return ERROR_INSTALL_FAILURE;
2680 return ERROR_SUCCESS;
2683 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2686 MSIQUERY * view = NULL;
2687 static const WCHAR ExecSeqQuery[] =
2688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2689 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2691 TRACE("Checking launch conditions\n");
2693 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2694 if (rc != ERROR_SUCCESS)
2695 return ERROR_SUCCESS;
2697 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2698 msiobj_release(&view->hdr);
2703 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2707 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2709 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2711 MSIRECORD * row = 0;
2713 LPWSTR deformated,buffer,deformated_name;
2715 static const WCHAR ExecSeqQuery[] =
2716 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2717 '`','R','e','g','i','s','t','r','y','`',' ',
2718 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2719 ' ','=',' ' ,'\'','%','s','\'',0 };
2720 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2721 static const WCHAR fmt2[]=
2722 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2724 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2728 root = MSI_RecordGetInteger(row,2);
2729 key = MSI_RecordGetString(row, 3);
2730 name = MSI_RecordGetString(row, 4);
2731 deformat_string(package, key , &deformated);
2732 deformat_string(package, name, &deformated_name);
2734 len = strlenW(deformated) + 6;
2735 if (deformated_name)
2736 len+=strlenW(deformated_name);
2738 buffer = msi_alloc( len *sizeof(WCHAR));
2740 if (deformated_name)
2741 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2743 sprintfW(buffer,fmt,root,deformated);
2745 msi_free(deformated);
2746 msi_free(deformated_name);
2747 msiobj_release(&row->hdr);
2751 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2753 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2758 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2761 return strdupW( file->TargetPath );
2766 static HKEY openSharedDLLsKey(void)
2769 static const WCHAR path[] =
2770 {'S','o','f','t','w','a','r','e','\\',
2771 'M','i','c','r','o','s','o','f','t','\\',
2772 'W','i','n','d','o','w','s','\\',
2773 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2774 'S','h','a','r','e','d','D','L','L','s',0};
2776 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2780 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2785 DWORD sz = sizeof(count);
2788 hkey = openSharedDLLsKey();
2789 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2790 if (rc != ERROR_SUCCESS)
2796 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2800 hkey = openSharedDLLsKey();
2802 msi_reg_set_val_dword( hkey, path, count );
2804 RegDeleteValueW(hkey,path);
2810 * Return TRUE if the count should be written out and FALSE if not
2812 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2814 MSIFEATURE *feature;
2818 /* only refcount DLLs */
2819 if (comp->KeyPath == NULL ||
2820 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2821 comp->Attributes & msidbComponentAttributesODBCDataSource)
2825 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2826 write = (count > 0);
2828 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2832 /* increment counts */
2833 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2837 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2840 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2842 if ( cl->component == comp )
2847 /* decrement counts */
2848 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2852 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2855 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2857 if ( cl->component == comp )
2862 /* ref count all the files in the component */
2867 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2869 if (file->Component == comp)
2870 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2874 /* add a count for permanent */
2875 if (comp->Attributes & msidbComponentAttributesPermanent)
2878 comp->RefCount = count;
2881 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2884 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2886 WCHAR squished_pc[GUID_SIZE];
2887 WCHAR squished_cc[GUID_SIZE];
2894 squash_guid(package->ProductCode,squished_pc);
2895 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2897 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2901 ui_progress(package,2,0,0,0);
2902 if (!comp->ComponentId)
2905 squash_guid(comp->ComponentId,squished_cc);
2907 msi_free(comp->FullKeypath);
2908 comp->FullKeypath = resolve_keypath( package, comp );
2910 ACTION_RefCountComponent( package, comp );
2912 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2913 debugstr_w(comp->Component),
2914 debugstr_w(squished_cc),
2915 debugstr_w(comp->FullKeypath),
2918 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2919 comp->ActionRequest == INSTALLSTATE_SOURCE)
2921 if (!comp->FullKeypath)
2924 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2925 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2928 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2931 if (rc != ERROR_SUCCESS)
2934 if (comp->Attributes & msidbComponentAttributesPermanent)
2936 static const WCHAR szPermKey[] =
2937 { '0','0','0','0','0','0','0','0','0','0','0','0',
2938 '0','0','0','0','0','0','0','0','0','0','0','0',
2939 '0','0','0','0','0','0','0','0',0 };
2941 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2944 if (comp->Action == INSTALLSTATE_LOCAL)
2945 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2951 WCHAR source[MAX_PATH];
2952 WCHAR base[MAX_PATH];
2955 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2956 static const WCHAR query[] = {
2957 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2958 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2959 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2960 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2961 '`','D','i','s','k','I','d','`',0};
2963 file = get_loaded_file(package, comp->KeyPath);
2967 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2968 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2969 ptr2 = strrchrW(source, '\\') + 1;
2970 msiobj_release(&row->hdr);
2972 lstrcpyW(base, package->PackagePath);
2973 ptr = strrchrW(base, '\\');
2976 sourcepath = resolve_file_source(package, file);
2977 ptr = sourcepath + lstrlenW(base);
2978 lstrcpyW(ptr2, ptr);
2979 msi_free(sourcepath);
2981 msi_reg_set_val_str(hkey, squished_pc, source);
2985 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2987 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2988 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2990 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2992 comp->Action = comp->ActionRequest;
2995 uirow = MSI_CreateRecord(3);
2996 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2997 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2998 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2999 ui_actiondata(package,szProcessComponents,uirow);
3000 msiobj_release( &uirow->hdr );
3003 return ERROR_SUCCESS;
3014 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3015 LPWSTR lpszName, LONG_PTR lParam)
3018 typelib_struct *tl_struct = (typelib_struct*) lParam;
3019 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3023 if (!IS_INTRESOURCE(lpszName))
3025 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3029 sz = strlenW(tl_struct->source)+4;
3030 sz *= sizeof(WCHAR);
3032 if ((INT_PTR)lpszName == 1)
3033 tl_struct->path = strdupW(tl_struct->source);
3036 tl_struct->path = msi_alloc(sz);
3037 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3040 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3041 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3044 msi_free(tl_struct->path);
3045 tl_struct->path = NULL;
3050 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3051 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3053 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3057 msi_free(tl_struct->path);
3058 tl_struct->path = NULL;
3060 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3061 ITypeLib_Release(tl_struct->ptLib);
3066 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3068 MSIPACKAGE* package = param;
3072 typelib_struct tl_struct;
3077 component = MSI_RecordGetString(row,3);
3078 comp = get_loaded_component(package,component);
3080 return ERROR_SUCCESS;
3082 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3084 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3085 comp->Action = comp->Installed;
3086 return ERROR_SUCCESS;
3088 comp->Action = INSTALLSTATE_LOCAL;
3090 file = get_loaded_file( package, comp->KeyPath );
3092 return ERROR_SUCCESS;
3094 ui_actiondata( package, szRegisterTypeLibraries, row );
3096 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3100 guid = MSI_RecordGetString(row,1);
3101 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3102 tl_struct.source = strdupW( file->TargetPath );
3103 tl_struct.path = NULL;
3105 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3106 (LONG_PTR)&tl_struct);
3114 helpid = MSI_RecordGetString(row,6);
3117 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3118 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3122 ERR("Failed to register type library %s\n",
3123 debugstr_w(tl_struct.path));
3125 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3127 ITypeLib_Release(tl_struct.ptLib);
3128 msi_free(tl_struct.path);
3131 ERR("Failed to load type library %s\n",
3132 debugstr_w(tl_struct.source));
3134 FreeLibrary(module);
3135 msi_free(tl_struct.source);
3139 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3142 ERR("Failed to load type library: %08x\n", hr);
3143 return ERROR_INSTALL_FAILURE;
3146 ITypeLib_Release(tlib);
3149 return ERROR_SUCCESS;
3152 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3155 * OK this is a bit confusing.. I am given a _Component key and I believe
3156 * that the file that is being registered as a type library is the "key file
3157 * of that component" which I interpret to mean "The file in the KeyPath of
3162 static const WCHAR Query[] =
3163 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3164 '`','T','y','p','e','L','i','b','`',0};
3166 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3167 if (rc != ERROR_SUCCESS)
3168 return ERROR_SUCCESS;
3170 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3171 msiobj_release(&view->hdr);
3175 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3177 MSIPACKAGE *package = param;
3178 LPCWSTR component, guid;
3186 component = MSI_RecordGetString( row, 3 );
3187 comp = get_loaded_component( package, component );
3189 return ERROR_SUCCESS;
3191 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3193 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3194 comp->Action = comp->Installed;
3195 return ERROR_SUCCESS;
3197 comp->Action = INSTALLSTATE_ABSENT;
3199 ui_actiondata( package, szUnregisterTypeLibraries, row );
3201 guid = MSI_RecordGetString( row, 1 );
3202 CLSIDFromString( (LPCWSTR)guid, &libid );
3203 version = MSI_RecordGetInteger( row, 4 );
3204 language = MSI_RecordGetInteger( row, 2 );
3207 syskind = SYS_WIN64;
3209 syskind = SYS_WIN32;
3212 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3215 WARN("Failed to unregister typelib: %08x\n", hr);
3218 return ERROR_SUCCESS;
3221 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3225 static const WCHAR query[] =
3226 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3227 '`','T','y','p','e','L','i','b','`',0};
3229 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3230 if (rc != ERROR_SUCCESS)
3231 return ERROR_SUCCESS;
3233 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3234 msiobj_release( &view->hdr );
3238 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3240 static const WCHAR szlnk[] = {'.','l','n','k',0};
3241 LPCWSTR directory, extension;
3242 LPWSTR link_folder, link_file, filename;
3244 directory = MSI_RecordGetString( row, 2 );
3245 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3247 /* may be needed because of a bug somewhere else */
3248 create_full_pathW( link_folder );
3250 filename = msi_dup_record_field( row, 3 );
3251 reduce_to_longfilename( filename );
3253 extension = strchrW( filename, '.' );
3254 if (!extension || strcmpiW( extension, szlnk ))
3256 int len = strlenW( filename );
3257 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3258 memcpy( filename + len, szlnk, sizeof(szlnk) );
3260 link_file = build_directory_name( 2, link_folder, filename );
3261 msi_free( link_folder );
3262 msi_free( filename );
3267 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3269 MSIPACKAGE *package = param;
3270 LPWSTR link_file, deformated, path;
3271 LPCWSTR component, target;
3273 IShellLinkW *sl = NULL;
3274 IPersistFile *pf = NULL;
3277 component = MSI_RecordGetString(row, 4);
3278 comp = get_loaded_component(package, component);
3280 return ERROR_SUCCESS;
3282 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3284 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3285 comp->Action = comp->Installed;
3286 return ERROR_SUCCESS;
3288 comp->Action = INSTALLSTATE_LOCAL;
3290 ui_actiondata(package,szCreateShortcuts,row);
3292 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3293 &IID_IShellLinkW, (LPVOID *) &sl );
3297 ERR("CLSID_ShellLink not available\n");
3301 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3304 ERR("QueryInterface(IID_IPersistFile) failed\n");
3308 target = MSI_RecordGetString(row, 5);
3309 if (strchrW(target, '['))
3311 deformat_string(package, target, &deformated);
3312 IShellLinkW_SetPath(sl,deformated);
3313 msi_free(deformated);
3317 FIXME("poorly handled shortcut format, advertised shortcut\n");
3318 IShellLinkW_SetPath(sl,comp->FullKeypath);
3321 if (!MSI_RecordIsNull(row,6))
3323 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3324 deformat_string(package, arguments, &deformated);
3325 IShellLinkW_SetArguments(sl,deformated);
3326 msi_free(deformated);
3329 if (!MSI_RecordIsNull(row,7))
3331 LPCWSTR description = MSI_RecordGetString(row, 7);
3332 IShellLinkW_SetDescription(sl, description);
3335 if (!MSI_RecordIsNull(row,8))
3336 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3338 if (!MSI_RecordIsNull(row,9))
3341 LPCWSTR icon = MSI_RecordGetString(row, 9);
3343 path = build_icon_path(package, icon);
3344 index = MSI_RecordGetInteger(row,10);
3346 /* no value means 0 */
3347 if (index == MSI_NULL_INTEGER)
3350 IShellLinkW_SetIconLocation(sl, path, index);
3354 if (!MSI_RecordIsNull(row,11))
3355 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3357 if (!MSI_RecordIsNull(row,12))
3359 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3360 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3362 IShellLinkW_SetWorkingDirectory(sl, path);
3366 link_file = get_link_file(package, row);
3368 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3369 IPersistFile_Save(pf, link_file, FALSE);
3371 msi_free(link_file);
3375 IPersistFile_Release( pf );
3377 IShellLinkW_Release( sl );
3379 return ERROR_SUCCESS;
3382 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3387 static const WCHAR Query[] =
3388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3389 '`','S','h','o','r','t','c','u','t','`',0};
3391 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3392 if (rc != ERROR_SUCCESS)
3393 return ERROR_SUCCESS;
3395 res = CoInitialize( NULL );
3397 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3398 msiobj_release(&view->hdr);
3406 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3408 MSIPACKAGE *package = param;
3413 component = MSI_RecordGetString( row, 4 );
3414 comp = get_loaded_component( package, component );
3416 return ERROR_SUCCESS;
3418 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3420 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3421 comp->Action = comp->Installed;
3422 return ERROR_SUCCESS;
3424 comp->Action = INSTALLSTATE_ABSENT;
3426 ui_actiondata( package, szRemoveShortcuts, row );
3428 link_file = get_link_file( package, row );
3430 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3431 if (!DeleteFileW( link_file ))
3433 WARN("Failed to remove shortcut file %u\n", GetLastError());
3435 msi_free( link_file );
3437 return ERROR_SUCCESS;
3440 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3444 static const WCHAR query[] =
3445 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3446 '`','S','h','o','r','t','c','u','t','`',0};
3448 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3449 if (rc != ERROR_SUCCESS)
3450 return ERROR_SUCCESS;
3452 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3453 msiobj_release( &view->hdr );
3458 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3460 MSIPACKAGE* package = param;
3468 FileName = MSI_RecordGetString(row,1);
3471 ERR("Unable to get FileName\n");
3472 return ERROR_SUCCESS;
3475 FilePath = build_icon_path(package,FileName);
3477 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3479 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3480 FILE_ATTRIBUTE_NORMAL, NULL);
3482 if (the_file == INVALID_HANDLE_VALUE)
3484 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3486 return ERROR_SUCCESS;
3493 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3494 if (rc != ERROR_SUCCESS)
3496 ERR("Failed to get stream\n");
3497 CloseHandle(the_file);
3498 DeleteFileW(FilePath);
3501 WriteFile(the_file,buffer,sz,&write,NULL);
3502 } while (sz == 1024);
3505 CloseHandle(the_file);
3507 return ERROR_SUCCESS;
3510 static UINT msi_publish_icons(MSIPACKAGE *package)
3515 static const WCHAR query[]= {
3516 'S','E','L','E','C','T',' ','*',' ',
3517 'F','R','O','M',' ','`','I','c','o','n','`',0};
3519 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3520 if (r == ERROR_SUCCESS)
3522 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3523 msiobj_release(&view->hdr);
3526 return ERROR_SUCCESS;
3529 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3535 MSISOURCELISTINFO *info;
3537 r = RegCreateKeyW(hkey, szSourceList, &source);
3538 if (r != ERROR_SUCCESS)
3541 RegCloseKey(source);
3543 buffer = strrchrW(package->PackagePath, '\\') + 1;
3544 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3545 package->Context, MSICODE_PRODUCT,
3546 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3547 if (r != ERROR_SUCCESS)
3550 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3551 package->Context, MSICODE_PRODUCT,
3552 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3553 if (r != ERROR_SUCCESS)
3556 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3557 package->Context, MSICODE_PRODUCT,
3558 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3559 if (r != ERROR_SUCCESS)
3562 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3564 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3565 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3566 info->options, info->value);
3568 MsiSourceListSetInfoW(package->ProductCode, NULL,
3569 info->context, info->options,
3570 info->property, info->value);
3573 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3575 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3576 disk->context, disk->options,
3577 disk->disk_id, disk->volume_label, disk->disk_prompt);
3580 return ERROR_SUCCESS;
3583 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3585 MSIHANDLE hdb, suminfo;
3586 WCHAR guids[MAX_PATH];
3587 WCHAR packcode[SQUISH_GUID_SIZE];
3594 static const WCHAR szProductLanguage[] =
3595 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3596 static const WCHAR szARPProductIcon[] =
3597 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3598 static const WCHAR szProductVersion[] =
3599 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3600 static const WCHAR szAssignment[] =
3601 {'A','s','s','i','g','n','m','e','n','t',0};
3602 static const WCHAR szAdvertiseFlags[] =
3603 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3604 static const WCHAR szClients[] =
3605 {'C','l','i','e','n','t','s',0};
3606 static const WCHAR szColon[] = {':',0};
3608 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3609 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3612 langid = msi_get_property_int(package, szProductLanguage, 0);
3613 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3616 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3618 buffer = msi_dup_property(package, szARPProductIcon);
3621 LPWSTR path = build_icon_path(package,buffer);
3622 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3627 buffer = msi_dup_property(package, szProductVersion);
3630 DWORD verdword = msi_version_str_to_dword(buffer);
3631 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3635 msi_reg_set_val_dword(hkey, szAssignment, 0);
3636 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3637 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3638 msi_reg_set_val_str(hkey, szClients, szColon);
3640 hdb = alloc_msihandle(&package->db->hdr);
3642 return ERROR_NOT_ENOUGH_MEMORY;
3644 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3645 MsiCloseHandle(hdb);
3646 if (r != ERROR_SUCCESS)
3650 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3651 NULL, guids, &size);
3652 if (r != ERROR_SUCCESS)
3655 ptr = strchrW(guids, ';');
3657 squash_guid(guids, packcode);
3658 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3661 MsiCloseHandle(suminfo);
3662 return ERROR_SUCCESS;
3665 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3670 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3672 static const WCHAR szUpgradeCode[] =
3673 {'U','p','g','r','a','d','e','C','o','d','e',0};
3675 upgrade = msi_dup_property(package, szUpgradeCode);
3677 return ERROR_SUCCESS;
3679 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3681 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3682 if (r != ERROR_SUCCESS)
3687 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3688 if (r != ERROR_SUCCESS)
3692 squash_guid(package->ProductCode, squashed_pc);
3693 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3702 static BOOL msi_check_publish(MSIPACKAGE *package)
3704 MSIFEATURE *feature;
3706 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3708 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3715 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3717 MSIFEATURE *feature;
3719 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3721 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3728 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3730 WCHAR patch_squashed[GUID_SIZE];
3733 UINT r = ERROR_FUNCTION_FAILED;
3735 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3737 if (res != ERROR_SUCCESS)
3738 return ERROR_FUNCTION_FAILED;
3740 squash_guid(package->patch->patchcode, patch_squashed);
3742 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3743 (const BYTE *)patch_squashed,
3744 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3745 if (res != ERROR_SUCCESS)
3748 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3749 (const BYTE *)package->patch->transforms,
3750 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3751 if (res == ERROR_SUCCESS)
3755 RegCloseKey(patches);
3760 * 99% of the work done here is only done for
3761 * advertised installs. However this is where the
3762 * Icon table is processed and written out
3763 * so that is what I am going to do here.
3765 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3768 HKEY hukey = NULL, hudkey = NULL;
3771 /* FIXME: also need to publish if the product is in advertise mode */
3772 if (!msi_check_publish(package))
3773 return ERROR_SUCCESS;
3775 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3777 if (rc != ERROR_SUCCESS)
3780 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3781 NULL, &hudkey, TRUE);
3782 if (rc != ERROR_SUCCESS)
3785 rc = msi_publish_upgrade_code(package);
3786 if (rc != ERROR_SUCCESS)
3791 rc = msi_publish_patch(package, hukey, hudkey);
3792 if (rc != ERROR_SUCCESS)
3796 rc = msi_publish_product_properties(package, hukey);
3797 if (rc != ERROR_SUCCESS)
3800 rc = msi_publish_sourcelist(package, hukey);
3801 if (rc != ERROR_SUCCESS)
3804 rc = msi_publish_icons(package);
3807 uirow = MSI_CreateRecord( 1 );
3808 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3809 ui_actiondata( package, szPublishProduct, uirow );
3810 msiobj_release( &uirow->hdr );
3813 RegCloseKey(hudkey);
3818 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3820 WCHAR *filename, *ptr, *folder, *ret;
3821 const WCHAR *dirprop;
3823 filename = msi_dup_record_field( row, 2 );
3824 if (filename && (ptr = strchrW( filename, '|' )))
3829 dirprop = MSI_RecordGetString( row, 3 );
3832 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3834 folder = msi_dup_property( package, dirprop );
3837 folder = msi_dup_property( package, szWindowsFolder );
3841 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3842 msi_free( filename );
3846 ret = build_directory_name( 2, folder, ptr );
3848 msi_free( filename );
3853 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3855 MSIPACKAGE *package = param;
3856 LPCWSTR component, section, key, value, identifier;
3857 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3862 component = MSI_RecordGetString(row, 8);
3863 comp = get_loaded_component(package,component);
3865 return ERROR_SUCCESS;
3867 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3869 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3870 comp->Action = comp->Installed;
3871 return ERROR_SUCCESS;
3873 comp->Action = INSTALLSTATE_LOCAL;
3875 identifier = MSI_RecordGetString(row,1);
3876 section = MSI_RecordGetString(row,4);
3877 key = MSI_RecordGetString(row,5);
3878 value = MSI_RecordGetString(row,6);
3879 action = MSI_RecordGetInteger(row,7);
3881 deformat_string(package,section,&deformated_section);
3882 deformat_string(package,key,&deformated_key);
3883 deformat_string(package,value,&deformated_value);
3885 fullname = get_ini_file_name(package, row);
3889 TRACE("Adding value %s to section %s in %s\n",
3890 debugstr_w(deformated_key), debugstr_w(deformated_section),
3891 debugstr_w(fullname));
3892 WritePrivateProfileStringW(deformated_section, deformated_key,
3893 deformated_value, fullname);
3895 else if (action == 1)
3898 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3899 returned, 10, fullname);
3900 if (returned[0] == 0)
3902 TRACE("Adding value %s to section %s in %s\n",
3903 debugstr_w(deformated_key), debugstr_w(deformated_section),
3904 debugstr_w(fullname));
3906 WritePrivateProfileStringW(deformated_section, deformated_key,
3907 deformated_value, fullname);
3910 else if (action == 3)
3911 FIXME("Append to existing section not yet implemented\n");
3913 uirow = MSI_CreateRecord(4);
3914 MSI_RecordSetStringW(uirow,1,identifier);
3915 MSI_RecordSetStringW(uirow,2,deformated_section);
3916 MSI_RecordSetStringW(uirow,3,deformated_key);
3917 MSI_RecordSetStringW(uirow,4,deformated_value);
3918 ui_actiondata(package,szWriteIniValues,uirow);
3919 msiobj_release( &uirow->hdr );
3922 msi_free(deformated_key);
3923 msi_free(deformated_value);
3924 msi_free(deformated_section);
3925 return ERROR_SUCCESS;
3928 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3932 static const WCHAR ExecSeqQuery[] =
3933 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3934 '`','I','n','i','F','i','l','e','`',0};
3936 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3937 if (rc != ERROR_SUCCESS)
3939 TRACE("no IniFile table\n");
3940 return ERROR_SUCCESS;
3943 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3944 msiobj_release(&view->hdr);
3948 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3950 MSIPACKAGE *package = param;
3951 LPCWSTR component, section, key, value, identifier;
3952 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3957 component = MSI_RecordGetString( row, 8 );
3958 comp = get_loaded_component( package, component );
3960 return ERROR_SUCCESS;
3962 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3964 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3965 comp->Action = comp->Installed;
3966 return ERROR_SUCCESS;
3968 comp->Action = INSTALLSTATE_ABSENT;
3970 identifier = MSI_RecordGetString( row, 1 );
3971 section = MSI_RecordGetString( row, 4 );
3972 key = MSI_RecordGetString( row, 5 );
3973 value = MSI_RecordGetString( row, 6 );
3974 action = MSI_RecordGetInteger( row, 7 );
3976 deformat_string( package, section, &deformated_section );
3977 deformat_string( package, key, &deformated_key );
3978 deformat_string( package, value, &deformated_value );
3980 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3982 filename = get_ini_file_name( package, row );
3984 TRACE("Removing key %s from section %s in %s\n",
3985 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3987 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3989 WARN("Unable to remove key %u\n", GetLastError());
3991 msi_free( filename );
3994 FIXME("Unsupported action %d\n", action);
3997 uirow = MSI_CreateRecord( 4 );
3998 MSI_RecordSetStringW( uirow, 1, identifier );
3999 MSI_RecordSetStringW( uirow, 2, deformated_section );
4000 MSI_RecordSetStringW( uirow, 3, deformated_key );
4001 MSI_RecordSetStringW( uirow, 4, deformated_value );
4002 ui_actiondata( package, szRemoveIniValues, uirow );
4003 msiobj_release( &uirow->hdr );
4005 msi_free( deformated_key );
4006 msi_free( deformated_value );
4007 msi_free( deformated_section );
4008 return ERROR_SUCCESS;
4011 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4013 MSIPACKAGE *package = param;
4014 LPCWSTR component, section, key, value, identifier;
4015 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4020 component = MSI_RecordGetString( row, 8 );
4021 comp = get_loaded_component( package, component );
4023 return ERROR_SUCCESS;
4025 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4027 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4028 comp->Action = comp->Installed;
4029 return ERROR_SUCCESS;
4031 comp->Action = INSTALLSTATE_LOCAL;
4033 identifier = MSI_RecordGetString( row, 1 );
4034 section = MSI_RecordGetString( row, 4 );
4035 key = MSI_RecordGetString( row, 5 );
4036 value = MSI_RecordGetString( row, 6 );
4037 action = MSI_RecordGetInteger( row, 7 );
4039 deformat_string( package, section, &deformated_section );
4040 deformat_string( package, key, &deformated_key );
4041 deformat_string( package, value, &deformated_value );
4043 if (action == msidbIniFileActionRemoveLine)
4045 filename = get_ini_file_name( package, row );
4047 TRACE("Removing key %s from section %s in %s\n",
4048 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4050 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4052 WARN("Unable to remove key %u\n", GetLastError());
4054 msi_free( filename );
4057 FIXME("Unsupported action %d\n", action);
4059 uirow = MSI_CreateRecord( 4 );
4060 MSI_RecordSetStringW( uirow, 1, identifier );
4061 MSI_RecordSetStringW( uirow, 2, deformated_section );
4062 MSI_RecordSetStringW( uirow, 3, deformated_key );
4063 MSI_RecordSetStringW( uirow, 4, deformated_value );
4064 ui_actiondata( package, szRemoveIniValues, uirow );
4065 msiobj_release( &uirow->hdr );
4067 msi_free( deformated_key );
4068 msi_free( deformated_value );
4069 msi_free( deformated_section );
4070 return ERROR_SUCCESS;
4073 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4077 static const WCHAR query[] =
4078 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4079 '`','I','n','i','F','i','l','e','`',0};
4080 static const WCHAR remove_query[] =
4081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4082 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4084 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4085 if (rc == ERROR_SUCCESS)
4087 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4088 msiobj_release( &view->hdr );
4089 if (rc != ERROR_SUCCESS)
4093 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4094 if (rc == ERROR_SUCCESS)
4096 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4097 msiobj_release( &view->hdr );
4098 if (rc != ERROR_SUCCESS)
4102 return ERROR_SUCCESS;
4105 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4107 MSIPACKAGE *package = param;
4112 static const WCHAR ExeStr[] =
4113 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4114 static const WCHAR close[] = {'\"',0};
4116 PROCESS_INFORMATION info;
4121 memset(&si,0,sizeof(STARTUPINFOW));
4123 filename = MSI_RecordGetString(row,1);
4124 file = get_loaded_file( package, filename );
4128 ERR("Unable to find file id %s\n",debugstr_w(filename));
4129 return ERROR_SUCCESS;
4132 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4134 FullName = msi_alloc(len*sizeof(WCHAR));
4135 strcpyW(FullName,ExeStr);
4136 strcatW( FullName, file->TargetPath );
4137 strcatW(FullName,close);
4139 TRACE("Registering %s\n",debugstr_w(FullName));
4140 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4145 CloseHandle(info.hThread);
4146 msi_dialog_check_messages(info.hProcess);
4147 CloseHandle(info.hProcess);
4150 uirow = MSI_CreateRecord( 2 );
4151 MSI_RecordSetStringW( uirow, 1, filename );
4152 uipath = strdupW( file->TargetPath );
4153 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4154 MSI_RecordSetStringW( uirow, 2, uipath );
4155 ui_actiondata( package, szSelfRegModules, uirow );
4156 msiobj_release( &uirow->hdr );
4158 msi_free( FullName );
4160 return ERROR_SUCCESS;
4163 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4167 static const WCHAR ExecSeqQuery[] =
4168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4169 '`','S','e','l','f','R','e','g','`',0};
4171 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4172 if (rc != ERROR_SUCCESS)
4174 TRACE("no SelfReg table\n");
4175 return ERROR_SUCCESS;
4178 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4179 msiobj_release(&view->hdr);
4181 return ERROR_SUCCESS;
4184 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4186 static const WCHAR regsvr32[] =
4187 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4188 static const WCHAR close[] = {'\"',0};
4189 MSIPACKAGE *package = param;
4195 PROCESS_INFORMATION pi;
4200 memset( &si, 0, sizeof(STARTUPINFOW) );
4202 filename = MSI_RecordGetString( row, 1 );
4203 file = get_loaded_file( package, filename );
4207 ERR("Unable to find file id %s\n", debugstr_w(filename));
4208 return ERROR_SUCCESS;
4211 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4213 cmdline = msi_alloc( len * sizeof(WCHAR) );
4214 strcpyW( cmdline, regsvr32 );
4215 strcatW( cmdline, file->TargetPath );
4216 strcatW( cmdline, close );
4218 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4220 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4223 CloseHandle( pi.hThread );
4224 msi_dialog_check_messages( pi.hProcess );
4225 CloseHandle( pi.hProcess );
4228 uirow = MSI_CreateRecord( 2 );
4229 MSI_RecordSetStringW( uirow, 1, filename );
4230 uipath = strdupW( file->TargetPath );
4231 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4232 MSI_RecordSetStringW( uirow, 2, uipath );
4233 ui_actiondata( package, szSelfUnregModules, uirow );
4234 msiobj_release( &uirow->hdr );
4236 msi_free( cmdline );
4238 return ERROR_SUCCESS;
4241 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4245 static const WCHAR query[] =
4246 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4247 '`','S','e','l','f','R','e','g','`',0};
4249 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4250 if (rc != ERROR_SUCCESS)
4252 TRACE("no SelfReg table\n");
4253 return ERROR_SUCCESS;
4256 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4257 msiobj_release( &view->hdr );
4259 return ERROR_SUCCESS;
4262 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4264 MSIFEATURE *feature;
4266 HKEY hkey = NULL, userdata = NULL;
4268 if (!msi_check_publish(package))
4269 return ERROR_SUCCESS;
4271 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4273 if (rc != ERROR_SUCCESS)
4276 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4278 if (rc != ERROR_SUCCESS)
4281 /* here the guids are base 85 encoded */
4282 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4288 BOOL absent = FALSE;
4291 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4292 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4293 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4296 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4300 if (feature->Feature_Parent)
4301 size += strlenW( feature->Feature_Parent )+2;
4303 data = msi_alloc(size * sizeof(WCHAR));
4306 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4308 MSICOMPONENT* component = cl->component;
4312 if (component->ComponentId)
4314 TRACE("From %s\n",debugstr_w(component->ComponentId));
4315 CLSIDFromString(component->ComponentId, &clsid);
4316 encode_base85_guid(&clsid,buf);
4317 TRACE("to %s\n",debugstr_w(buf));
4322 if (feature->Feature_Parent)
4324 static const WCHAR sep[] = {'\2',0};
4326 strcatW(data,feature->Feature_Parent);
4329 msi_reg_set_val_str( userdata, feature->Feature, data );
4333 if (feature->Feature_Parent)
4334 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4337 size += sizeof(WCHAR);
4338 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4339 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4343 size += 2*sizeof(WCHAR);
4344 data = msi_alloc(size);
4347 if (feature->Feature_Parent)
4348 strcpyW( &data[1], feature->Feature_Parent );
4349 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4355 uirow = MSI_CreateRecord( 1 );
4356 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4357 ui_actiondata( package, szPublishFeatures, uirow);
4358 msiobj_release( &uirow->hdr );
4359 /* FIXME: call ui_progress? */
4364 RegCloseKey(userdata);
4368 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4374 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4376 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4378 if (r == ERROR_SUCCESS)
4380 RegDeleteValueW(hkey, feature->Feature);
4384 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4386 if (r == ERROR_SUCCESS)
4388 RegDeleteValueW(hkey, feature->Feature);
4392 uirow = MSI_CreateRecord( 1 );
4393 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4394 ui_actiondata( package, szUnpublishFeatures, uirow );
4395 msiobj_release( &uirow->hdr );
4397 return ERROR_SUCCESS;
4400 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4402 MSIFEATURE *feature;
4404 if (!msi_check_unpublish(package))
4405 return ERROR_SUCCESS;
4407 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4409 msi_unpublish_feature(package, feature);
4412 return ERROR_SUCCESS;
4415 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4417 LPWSTR prop, val, key;
4423 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4424 static const WCHAR szWindowsInstaller[] =
4425 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4426 static const WCHAR modpath_fmt[] =
4427 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4428 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4429 static const WCHAR szModifyPath[] =
4430 {'M','o','d','i','f','y','P','a','t','h',0};
4431 static const WCHAR szUninstallString[] =
4432 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4433 static const WCHAR szEstimatedSize[] =
4434 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4435 static const WCHAR szProductLanguage[] =
4436 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4437 static const WCHAR szProductVersion[] =
4438 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4439 static const WCHAR szProductName[] =
4440 {'P','r','o','d','u','c','t','N','a','m','e',0};
4441 static const WCHAR szDisplayName[] =
4442 {'D','i','s','p','l','a','y','N','a','m','e',0};
4443 static const WCHAR szDisplayVersion[] =
4444 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4445 static const WCHAR szManufacturer[] =
4446 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4448 static const LPCSTR propval[] = {
4449 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4450 "ARPCONTACT", "Contact",
4451 "ARPCOMMENTS", "Comments",
4452 "ProductName", "DisplayName",
4453 "ProductVersion", "DisplayVersion",
4454 "ARPHELPLINK", "HelpLink",
4455 "ARPHELPTELEPHONE", "HelpTelephone",
4456 "ARPINSTALLLOCATION", "InstallLocation",
4457 "SourceDir", "InstallSource",
4458 "Manufacturer", "Publisher",
4459 "ARPREADME", "Readme",
4461 "ARPURLINFOABOUT", "URLInfoAbout",
4462 "ARPURLUPDATEINFO", "URLUpdateInfo",
4465 const LPCSTR *p = propval;
4469 prop = strdupAtoW(*p++);
4470 key = strdupAtoW(*p++);
4471 val = msi_dup_property(package, prop);
4472 msi_reg_set_val_str(hkey, key, val);
4478 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4480 size = deformat_string(package, modpath_fmt, &buffer);
4481 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4482 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4485 /* FIXME: Write real Estimated Size when we have it */
4486 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4488 buffer = msi_dup_property(package, szProductName);
4489 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4492 buffer = msi_dup_property(package, cszSourceDir);
4493 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4496 buffer = msi_dup_property(package, szManufacturer);
4497 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4500 GetLocalTime(&systime);
4501 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4502 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4504 langid = msi_get_property_int(package, szProductLanguage, 0);
4505 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4507 buffer = msi_dup_property(package, szProductVersion);
4508 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4511 DWORD verdword = msi_version_str_to_dword(buffer);
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4514 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4515 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4519 return ERROR_SUCCESS;
4522 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4524 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4526 LPWSTR upgrade_code;
4531 static const WCHAR szUpgradeCode[] = {
4532 'U','p','g','r','a','d','e','C','o','d','e',0};
4534 /* FIXME: also need to publish if the product is in advertise mode */
4535 if (!msi_check_publish(package))
4536 return ERROR_SUCCESS;
4538 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4539 if (rc != ERROR_SUCCESS)
4542 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4543 NULL, &props, TRUE);
4544 if (rc != ERROR_SUCCESS)
4547 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4548 msi_free( package->db->localfile );
4549 package->db->localfile = NULL;
4551 rc = msi_publish_install_properties(package, hkey);
4552 if (rc != ERROR_SUCCESS)
4555 rc = msi_publish_install_properties(package, props);
4556 if (rc != ERROR_SUCCESS)
4559 upgrade_code = msi_dup_property(package, szUpgradeCode);
4562 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4563 squash_guid(package->ProductCode, squashed_pc);
4564 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4565 RegCloseKey(upgrade);
4566 msi_free(upgrade_code);
4570 uirow = MSI_CreateRecord( 1 );
4571 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4572 ui_actiondata( package, szRegisterProduct, uirow );
4573 msiobj_release( &uirow->hdr );
4576 return ERROR_SUCCESS;
4579 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4581 return execute_script(package,INSTALL_SCRIPT);
4584 static UINT msi_unpublish_product(MSIPACKAGE *package)
4587 LPWSTR remove = NULL;
4588 LPWSTR *features = NULL;
4589 BOOL full_uninstall = TRUE;
4590 MSIFEATURE *feature;
4592 static const WCHAR szUpgradeCode[] =
4593 {'U','p','g','r','a','d','e','C','o','d','e',0};
4595 remove = msi_dup_property(package, szRemove);
4597 return ERROR_SUCCESS;
4599 features = msi_split_string(remove, ',');
4603 ERR("REMOVE feature list is empty!\n");
4604 return ERROR_FUNCTION_FAILED;
4607 if (!lstrcmpW(features[0], szAll))
4608 full_uninstall = TRUE;
4611 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4613 if (feature->Action != INSTALLSTATE_ABSENT)
4614 full_uninstall = FALSE;
4618 if (!full_uninstall)
4621 MSIREG_DeleteProductKey(package->ProductCode);
4622 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4623 MSIREG_DeleteUninstallKey(package->ProductCode);
4625 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4627 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4628 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4632 MSIREG_DeleteUserProductKey(package->ProductCode);
4633 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4636 upgrade = msi_dup_property(package, szUpgradeCode);
4639 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4646 return ERROR_SUCCESS;
4649 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4653 rc = msi_unpublish_product(package);
4654 if (rc != ERROR_SUCCESS)
4657 /* turn off scheduling */
4658 package->script->CurrentlyScripting= FALSE;
4660 /* first do the same as an InstallExecute */
4661 rc = ACTION_InstallExecute(package);
4662 if (rc != ERROR_SUCCESS)
4665 /* then handle Commit Actions */
4666 rc = execute_script(package,COMMIT_SCRIPT);
4671 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4673 static const WCHAR RunOnce[] = {
4674 'S','o','f','t','w','a','r','e','\\',
4675 'M','i','c','r','o','s','o','f','t','\\',
4676 'W','i','n','d','o','w','s','\\',
4677 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4678 'R','u','n','O','n','c','e',0};
4679 static const WCHAR InstallRunOnce[] = {
4680 'S','o','f','t','w','a','r','e','\\',
4681 'M','i','c','r','o','s','o','f','t','\\',
4682 'W','i','n','d','o','w','s','\\',
4683 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4684 'I','n','s','t','a','l','l','e','r','\\',
4685 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4687 static const WCHAR msiexec_fmt[] = {
4689 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4690 '\"','%','s','\"',0};
4691 static const WCHAR install_fmt[] = {
4692 '/','I',' ','\"','%','s','\"',' ',
4693 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4694 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4695 WCHAR buffer[256], sysdir[MAX_PATH];
4697 WCHAR squished_pc[100];
4699 squash_guid(package->ProductCode,squished_pc);
4701 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4702 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4703 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4706 msi_reg_set_val_str( hkey, squished_pc, buffer );
4709 TRACE("Reboot command %s\n",debugstr_w(buffer));
4711 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4712 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4714 msi_reg_set_val_str( hkey, squished_pc, buffer );
4717 return ERROR_INSTALL_SUSPEND;
4720 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4726 * We are currently doing what should be done here in the top level Install
4727 * however for Administrative and uninstalls this step will be needed
4729 if (!package->PackagePath)
4730 return ERROR_SUCCESS;
4732 msi_set_sourcedir_props(package, TRUE);
4734 attrib = GetFileAttributesW(package->db->path);
4735 if (attrib == INVALID_FILE_ATTRIBUTES)
4741 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4742 package->Context, MSICODE_PRODUCT,
4743 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4744 if (rc == ERROR_MORE_DATA)
4746 prompt = msi_alloc(size * sizeof(WCHAR));
4747 MsiSourceListGetInfoW(package->ProductCode, NULL,
4748 package->Context, MSICODE_PRODUCT,
4749 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4752 prompt = strdupW(package->db->path);
4754 msg = generate_error_string(package,1302,1,prompt);
4755 while(attrib == INVALID_FILE_ATTRIBUTES)
4757 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4760 rc = ERROR_INSTALL_USEREXIT;
4763 attrib = GetFileAttributesW(package->db->path);
4769 return ERROR_SUCCESS;
4774 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4777 LPWSTR buffer, productid = NULL;
4778 UINT i, rc = ERROR_SUCCESS;
4781 static const WCHAR szPropKeys[][80] =
4783 {'P','r','o','d','u','c','t','I','D',0},
4784 {'U','S','E','R','N','A','M','E',0},
4785 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4789 static const WCHAR szRegKeys[][80] =
4791 {'P','r','o','d','u','c','t','I','D',0},
4792 {'R','e','g','O','w','n','e','r',0},
4793 {'R','e','g','C','o','m','p','a','n','y',0},
4797 if (msi_check_unpublish(package))
4799 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4803 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4807 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4809 if (rc != ERROR_SUCCESS)
4812 for( i = 0; szPropKeys[i][0]; i++ )
4814 buffer = msi_dup_property( package, szPropKeys[i] );
4815 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4820 uirow = MSI_CreateRecord( 1 );
4821 MSI_RecordSetStringW( uirow, 1, productid );
4822 ui_actiondata( package, szRegisterUser, uirow );
4823 msiobj_release( &uirow->hdr );
4825 msi_free(productid);
4831 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4835 package->script->InWhatSequence |= SEQUENCE_EXEC;
4836 rc = ACTION_ProcessExecSequence(package,FALSE);
4841 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4843 MSIPACKAGE *package = param;
4844 LPCWSTR compgroupid, component, feature, qualifier, text;
4845 LPWSTR advertise = NULL, output = NULL;
4853 feature = MSI_RecordGetString(rec, 5);
4854 feat = get_loaded_feature(package, feature);
4856 return ERROR_SUCCESS;
4858 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4859 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4860 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4862 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4863 feat->Action = feat->Installed;
4864 return ERROR_SUCCESS;
4867 component = MSI_RecordGetString(rec, 3);
4868 comp = get_loaded_component(package, component);
4870 return ERROR_SUCCESS;
4872 compgroupid = MSI_RecordGetString(rec,1);
4873 qualifier = MSI_RecordGetString(rec,2);
4875 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4876 if (rc != ERROR_SUCCESS)
4879 text = MSI_RecordGetString(rec,4);
4880 advertise = create_component_advertise_string(package, comp, feature);
4882 sz = strlenW(advertise);
4885 sz += lstrlenW(text);
4888 sz *= sizeof(WCHAR);
4890 output = msi_alloc_zero(sz);
4891 strcpyW(output,advertise);
4892 msi_free(advertise);
4895 strcatW(output,text);
4897 msi_reg_set_val_multi_str( hkey, qualifier, output );
4904 uirow = MSI_CreateRecord( 2 );
4905 MSI_RecordSetStringW( uirow, 1, compgroupid );
4906 MSI_RecordSetStringW( uirow, 2, qualifier);
4907 ui_actiondata( package, szPublishComponents, uirow);
4908 msiobj_release( &uirow->hdr );
4909 /* FIXME: call ui_progress? */
4915 * At present I am ignorning the advertised components part of this and only
4916 * focusing on the qualified component sets
4918 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4922 static const WCHAR ExecSeqQuery[] =
4923 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4924 '`','P','u','b','l','i','s','h',
4925 'C','o','m','p','o','n','e','n','t','`',0};
4927 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4928 if (rc != ERROR_SUCCESS)
4929 return ERROR_SUCCESS;
4931 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4932 msiobj_release(&view->hdr);
4937 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4939 static const WCHAR szInstallerComponents[] = {
4940 'S','o','f','t','w','a','r','e','\\',
4941 'M','i','c','r','o','s','o','f','t','\\',
4942 'I','n','s','t','a','l','l','e','r','\\',
4943 'C','o','m','p','o','n','e','n','t','s','\\',0};
4945 MSIPACKAGE *package = param;
4946 LPCWSTR compgroupid, component, feature, qualifier;
4950 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4953 feature = MSI_RecordGetString( rec, 5 );
4954 feat = get_loaded_feature( package, feature );
4956 return ERROR_SUCCESS;
4958 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4960 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4961 feat->Action = feat->Installed;
4962 return ERROR_SUCCESS;
4965 component = MSI_RecordGetString( rec, 3 );
4966 comp = get_loaded_component( package, component );
4968 return ERROR_SUCCESS;
4970 compgroupid = MSI_RecordGetString( rec, 1 );
4971 qualifier = MSI_RecordGetString( rec, 2 );
4973 squash_guid( compgroupid, squashed );
4974 strcpyW( keypath, szInstallerComponents );
4975 strcatW( keypath, squashed );
4977 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4978 if (res != ERROR_SUCCESS)
4980 WARN("Unable to delete component key %d\n", res);
4983 uirow = MSI_CreateRecord( 2 );
4984 MSI_RecordSetStringW( uirow, 1, compgroupid );
4985 MSI_RecordSetStringW( uirow, 2, qualifier );
4986 ui_actiondata( package, szUnpublishComponents, uirow );
4987 msiobj_release( &uirow->hdr );
4989 return ERROR_SUCCESS;
4992 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4996 static const WCHAR query[] =
4997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4998 '`','P','u','b','l','i','s','h',
4999 'C','o','m','p','o','n','e','n','t','`',0};
5001 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5002 if (rc != ERROR_SUCCESS)
5003 return ERROR_SUCCESS;
5005 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5006 msiobj_release( &view->hdr );
5011 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5013 MSIPACKAGE *package = param;
5016 SC_HANDLE hscm, service = NULL;
5017 LPCWSTR comp, depends, pass;
5018 LPWSTR name = NULL, disp = NULL;
5019 LPCWSTR load_order, serv_name, key;
5020 DWORD serv_type, start_type;
5023 static const WCHAR query[] =
5024 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5025 '`','C','o','m','p','o','n','e','n','t','`',' ',
5026 'W','H','E','R','E',' ',
5027 '`','C','o','m','p','o','n','e','n','t','`',' ',
5028 '=','\'','%','s','\'',0};
5030 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5033 ERR("Failed to open the SC Manager!\n");
5037 start_type = MSI_RecordGetInteger(rec, 5);
5038 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5041 depends = MSI_RecordGetString(rec, 8);
5042 if (depends && *depends)
5043 FIXME("Dependency list unhandled!\n");
5045 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5046 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5047 serv_type = MSI_RecordGetInteger(rec, 4);
5048 err_control = MSI_RecordGetInteger(rec, 6);
5049 load_order = MSI_RecordGetString(rec, 7);
5050 serv_name = MSI_RecordGetString(rec, 9);
5051 pass = MSI_RecordGetString(rec, 10);
5052 comp = MSI_RecordGetString(rec, 12);
5054 /* fetch the service path */
5055 row = MSI_QueryGetRecord(package->db, query, comp);
5058 ERR("Control query failed!\n");
5062 key = MSI_RecordGetString(row, 6);
5064 file = get_loaded_file(package, key);
5065 msiobj_release(&row->hdr);
5068 ERR("Failed to load the service file\n");
5072 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5073 start_type, err_control, file->TargetPath,
5074 load_order, NULL, NULL, serv_name, pass);
5077 if (GetLastError() != ERROR_SERVICE_EXISTS)
5078 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5082 CloseServiceHandle(service);
5083 CloseServiceHandle(hscm);
5087 return ERROR_SUCCESS;
5090 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5094 static const WCHAR ExecSeqQuery[] =
5095 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5096 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5098 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5099 if (rc != ERROR_SUCCESS)
5100 return ERROR_SUCCESS;
5102 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5103 msiobj_release(&view->hdr);
5108 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5109 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5111 LPCWSTR *vector, *temp_vector;
5115 static const WCHAR separator[] = {'[','~',']',0};
5118 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5123 vector = msi_alloc(sizeof(LPWSTR));
5131 vector[*numargs - 1] = p;
5133 if ((q = strstrW(p, separator)))
5137 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5143 vector = temp_vector;
5152 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5154 MSIPACKAGE *package = param;
5157 SC_HANDLE scm = NULL, service = NULL;
5158 LPCWSTR component, *vector = NULL;
5159 LPWSTR name, args, display_name = NULL;
5160 DWORD event, numargs, len;
5161 UINT r = ERROR_FUNCTION_FAILED;
5163 component = MSI_RecordGetString(rec, 6);
5164 comp = get_loaded_component(package, component);
5166 return ERROR_SUCCESS;
5168 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5170 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5171 comp->Action = comp->Installed;
5172 return ERROR_SUCCESS;
5174 comp->Action = INSTALLSTATE_LOCAL;
5176 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5177 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5178 event = MSI_RecordGetInteger(rec, 3);
5180 if (!(event & msidbServiceControlEventStart))
5186 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5189 ERR("Failed to open the service control manager\n");
5194 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5195 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5197 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5198 GetServiceDisplayNameW( scm, name, display_name, &len );
5201 service = OpenServiceW(scm, name, SERVICE_START);
5204 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5208 vector = msi_service_args_to_vector(args, &numargs);
5210 if (!StartServiceW(service, numargs, vector) &&
5211 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5213 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5220 uirow = MSI_CreateRecord( 2 );
5221 MSI_RecordSetStringW( uirow, 1, display_name );
5222 MSI_RecordSetStringW( uirow, 2, name );
5223 ui_actiondata( package, szStartServices, uirow );
5224 msiobj_release( &uirow->hdr );
5226 CloseServiceHandle(service);
5227 CloseServiceHandle(scm);
5232 msi_free(display_name);
5236 static UINT ACTION_StartServices( MSIPACKAGE *package )
5241 static const WCHAR query[] = {
5242 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5243 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5245 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5246 if (rc != ERROR_SUCCESS)
5247 return ERROR_SUCCESS;
5249 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5250 msiobj_release(&view->hdr);
5255 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5257 DWORD i, needed, count;
5258 ENUM_SERVICE_STATUSW *dependencies;
5262 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5263 0, &needed, &count))
5266 if (GetLastError() != ERROR_MORE_DATA)
5269 dependencies = msi_alloc(needed);
5273 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5274 needed, &needed, &count))
5277 for (i = 0; i < count; i++)
5279 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5280 SERVICE_STOP | SERVICE_QUERY_STATUS);
5284 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5291 msi_free(dependencies);
5295 static UINT stop_service( LPCWSTR name )
5297 SC_HANDLE scm = NULL, service = NULL;
5298 SERVICE_STATUS status;
5299 SERVICE_STATUS_PROCESS ssp;
5302 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5305 WARN("Failed to open the SCM: %d\n", GetLastError());
5309 service = OpenServiceW(scm, name,
5311 SERVICE_QUERY_STATUS |
5312 SERVICE_ENUMERATE_DEPENDENTS);
5315 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5319 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5320 sizeof(SERVICE_STATUS_PROCESS), &needed))
5322 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5326 if (ssp.dwCurrentState == SERVICE_STOPPED)
5329 stop_service_dependents(scm, service);
5331 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5332 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5335 CloseServiceHandle(service);
5336 CloseServiceHandle(scm);
5338 return ERROR_SUCCESS;
5341 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5343 MSIPACKAGE *package = param;
5347 LPWSTR name = NULL, display_name = NULL;
5351 event = MSI_RecordGetInteger( rec, 3 );
5352 if (!(event & msidbServiceControlEventStop))
5353 return ERROR_SUCCESS;
5355 component = MSI_RecordGetString( rec, 6 );
5356 comp = get_loaded_component( package, component );
5358 return ERROR_SUCCESS;
5360 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5362 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5363 comp->Action = comp->Installed;
5364 return ERROR_SUCCESS;
5366 comp->Action = INSTALLSTATE_ABSENT;
5368 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5371 ERR("Failed to open the service control manager\n");
5376 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5377 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5379 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5380 GetServiceDisplayNameW( scm, name, display_name, &len );
5382 CloseServiceHandle( scm );
5384 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5385 stop_service( name );
5388 uirow = MSI_CreateRecord( 2 );
5389 MSI_RecordSetStringW( uirow, 1, display_name );
5390 MSI_RecordSetStringW( uirow, 2, name );
5391 ui_actiondata( package, szStopServices, uirow );
5392 msiobj_release( &uirow->hdr );
5395 msi_free( display_name );
5396 return ERROR_SUCCESS;
5399 static UINT ACTION_StopServices( MSIPACKAGE *package )
5404 static const WCHAR query[] = {
5405 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5406 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5408 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5409 if (rc != ERROR_SUCCESS)
5410 return ERROR_SUCCESS;
5412 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5413 msiobj_release(&view->hdr);
5418 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5420 MSIPACKAGE *package = param;
5424 LPWSTR name = NULL, display_name = NULL;
5426 SC_HANDLE scm = NULL, service = NULL;
5428 event = MSI_RecordGetInteger( rec, 3 );
5429 if (!(event & msidbServiceControlEventDelete))
5430 return ERROR_SUCCESS;
5432 component = MSI_RecordGetString(rec, 6);
5433 comp = get_loaded_component(package, component);
5435 return ERROR_SUCCESS;
5437 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5439 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5440 comp->Action = comp->Installed;
5441 return ERROR_SUCCESS;
5443 comp->Action = INSTALLSTATE_ABSENT;
5445 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5446 stop_service( name );
5448 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5451 WARN("Failed to open the SCM: %d\n", GetLastError());
5456 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5457 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5459 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5460 GetServiceDisplayNameW( scm, name, display_name, &len );
5463 service = OpenServiceW( scm, name, DELETE );
5466 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5470 if (!DeleteService( service ))
5471 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5474 uirow = MSI_CreateRecord( 2 );
5475 MSI_RecordSetStringW( uirow, 1, display_name );
5476 MSI_RecordSetStringW( uirow, 2, name );
5477 ui_actiondata( package, szDeleteServices, uirow );
5478 msiobj_release( &uirow->hdr );
5480 CloseServiceHandle( service );
5481 CloseServiceHandle( scm );
5483 msi_free( display_name );
5485 return ERROR_SUCCESS;
5488 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5493 static const WCHAR query[] = {
5494 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5495 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5497 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5498 if (rc != ERROR_SUCCESS)
5499 return ERROR_SUCCESS;
5501 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5502 msiobj_release( &view->hdr );
5507 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5511 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5513 if (!lstrcmpW(file->File, filename))
5520 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5522 MSIPACKAGE *package = param;
5523 LPWSTR driver, driver_path, ptr;
5524 WCHAR outpath[MAX_PATH];
5525 MSIFILE *driver_file, *setup_file;
5529 UINT r = ERROR_SUCCESS;
5531 static const WCHAR driver_fmt[] = {
5532 'D','r','i','v','e','r','=','%','s',0};
5533 static const WCHAR setup_fmt[] = {
5534 'S','e','t','u','p','=','%','s',0};
5535 static const WCHAR usage_fmt[] = {
5536 'F','i','l','e','U','s','a','g','e','=','1',0};
5538 desc = MSI_RecordGetString(rec, 3);
5540 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5541 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5545 ERR("ODBC Driver entry not found!\n");
5546 return ERROR_FUNCTION_FAILED;
5549 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5551 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5552 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5554 driver = msi_alloc(len * sizeof(WCHAR));
5556 return ERROR_OUTOFMEMORY;
5559 lstrcpyW(ptr, desc);
5560 ptr += lstrlenW(ptr) + 1;
5562 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5567 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5571 lstrcpyW(ptr, usage_fmt);
5572 ptr += lstrlenW(ptr) + 1;
5575 driver_path = strdupW(driver_file->TargetPath);
5576 ptr = strrchrW(driver_path, '\\');
5577 if (ptr) *ptr = '\0';
5579 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5580 NULL, ODBC_INSTALL_COMPLETE, &usage))
5582 ERR("Failed to install SQL driver!\n");
5583 r = ERROR_FUNCTION_FAILED;
5586 uirow = MSI_CreateRecord( 5 );
5587 MSI_RecordSetStringW( uirow, 1, desc );
5588 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5589 MSI_RecordSetStringW( uirow, 3, driver_path );
5590 ui_actiondata( package, szInstallODBC, uirow );
5591 msiobj_release( &uirow->hdr );
5594 msi_free(driver_path);
5599 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5601 MSIPACKAGE *package = param;
5602 LPWSTR translator, translator_path, ptr;
5603 WCHAR outpath[MAX_PATH];
5604 MSIFILE *translator_file, *setup_file;
5608 UINT r = ERROR_SUCCESS;
5610 static const WCHAR translator_fmt[] = {
5611 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5612 static const WCHAR setup_fmt[] = {
5613 'S','e','t','u','p','=','%','s',0};
5615 desc = MSI_RecordGetString(rec, 3);
5617 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5618 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5620 if (!translator_file)
5622 ERR("ODBC Translator entry not found!\n");
5623 return ERROR_FUNCTION_FAILED;
5626 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5628 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5630 translator = msi_alloc(len * sizeof(WCHAR));
5632 return ERROR_OUTOFMEMORY;
5635 lstrcpyW(ptr, desc);
5636 ptr += lstrlenW(ptr) + 1;
5638 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5643 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5648 translator_path = strdupW(translator_file->TargetPath);
5649 ptr = strrchrW(translator_path, '\\');
5650 if (ptr) *ptr = '\0';
5652 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5653 NULL, ODBC_INSTALL_COMPLETE, &usage))
5655 ERR("Failed to install SQL translator!\n");
5656 r = ERROR_FUNCTION_FAILED;
5659 uirow = MSI_CreateRecord( 5 );
5660 MSI_RecordSetStringW( uirow, 1, desc );
5661 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5662 MSI_RecordSetStringW( uirow, 3, translator_path );
5663 ui_actiondata( package, szInstallODBC, uirow );
5664 msiobj_release( &uirow->hdr );
5666 msi_free(translator);
5667 msi_free(translator_path);
5672 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5674 MSIPACKAGE *package = param;
5676 LPCWSTR desc, driver;
5677 WORD request = ODBC_ADD_SYS_DSN;
5680 UINT r = ERROR_SUCCESS;
5683 static const WCHAR attrs_fmt[] = {
5684 'D','S','N','=','%','s',0 };
5686 desc = MSI_RecordGetString(rec, 3);
5687 driver = MSI_RecordGetString(rec, 4);
5688 registration = MSI_RecordGetInteger(rec, 5);
5690 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5691 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5693 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5694 attrs = msi_alloc(len * sizeof(WCHAR));
5696 return ERROR_OUTOFMEMORY;
5698 len = sprintfW(attrs, attrs_fmt, desc);
5701 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5703 ERR("Failed to install SQL data source!\n");
5704 r = ERROR_FUNCTION_FAILED;
5707 uirow = MSI_CreateRecord( 5 );
5708 MSI_RecordSetStringW( uirow, 1, desc );
5709 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5710 MSI_RecordSetInteger( uirow, 3, request );
5711 ui_actiondata( package, szInstallODBC, uirow );
5712 msiobj_release( &uirow->hdr );
5719 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5724 static const WCHAR driver_query[] = {
5725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 'O','D','B','C','D','r','i','v','e','r',0 };
5728 static const WCHAR translator_query[] = {
5729 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5730 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5732 static const WCHAR source_query[] = {
5733 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5734 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5736 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5737 if (rc != ERROR_SUCCESS)
5738 return ERROR_SUCCESS;
5740 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5741 msiobj_release(&view->hdr);
5743 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5744 if (rc != ERROR_SUCCESS)
5745 return ERROR_SUCCESS;
5747 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5748 msiobj_release(&view->hdr);
5750 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5751 if (rc != ERROR_SUCCESS)
5752 return ERROR_SUCCESS;
5754 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5755 msiobj_release(&view->hdr);
5760 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5762 MSIPACKAGE *package = param;
5767 desc = MSI_RecordGetString( rec, 3 );
5768 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5770 WARN("Failed to remove ODBC driver\n");
5774 FIXME("Usage count reached 0\n");
5777 uirow = MSI_CreateRecord( 2 );
5778 MSI_RecordSetStringW( uirow, 1, desc );
5779 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5780 ui_actiondata( package, szRemoveODBC, uirow );
5781 msiobj_release( &uirow->hdr );
5783 return ERROR_SUCCESS;
5786 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5788 MSIPACKAGE *package = param;
5793 desc = MSI_RecordGetString( rec, 3 );
5794 if (!SQLRemoveTranslatorW( desc, &usage ))
5796 WARN("Failed to remove ODBC translator\n");
5800 FIXME("Usage count reached 0\n");
5803 uirow = MSI_CreateRecord( 2 );
5804 MSI_RecordSetStringW( uirow, 1, desc );
5805 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5806 ui_actiondata( package, szRemoveODBC, uirow );
5807 msiobj_release( &uirow->hdr );
5809 return ERROR_SUCCESS;
5812 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5814 MSIPACKAGE *package = param;
5817 LPCWSTR desc, driver;
5818 WORD request = ODBC_REMOVE_SYS_DSN;
5822 static const WCHAR attrs_fmt[] = {
5823 'D','S','N','=','%','s',0 };
5825 desc = MSI_RecordGetString( rec, 3 );
5826 driver = MSI_RecordGetString( rec, 4 );
5827 registration = MSI_RecordGetInteger( rec, 5 );
5829 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5830 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5832 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5833 attrs = msi_alloc( len * sizeof(WCHAR) );
5835 return ERROR_OUTOFMEMORY;
5837 FIXME("Use ODBCSourceAttribute table\n");
5839 len = sprintfW( attrs, attrs_fmt, desc );
5842 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5844 WARN("Failed to remove ODBC data source\n");
5848 uirow = MSI_CreateRecord( 3 );
5849 MSI_RecordSetStringW( uirow, 1, desc );
5850 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5851 MSI_RecordSetInteger( uirow, 3, request );
5852 ui_actiondata( package, szRemoveODBC, uirow );
5853 msiobj_release( &uirow->hdr );
5855 return ERROR_SUCCESS;
5858 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5863 static const WCHAR driver_query[] = {
5864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5865 'O','D','B','C','D','r','i','v','e','r',0 };
5867 static const WCHAR translator_query[] = {
5868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5869 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5871 static const WCHAR source_query[] = {
5872 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5873 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5875 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5876 if (rc != ERROR_SUCCESS)
5877 return ERROR_SUCCESS;
5879 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5880 msiobj_release( &view->hdr );
5882 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5883 if (rc != ERROR_SUCCESS)
5884 return ERROR_SUCCESS;
5886 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5887 msiobj_release( &view->hdr );
5889 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5890 if (rc != ERROR_SUCCESS)
5891 return ERROR_SUCCESS;
5893 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5894 msiobj_release( &view->hdr );
5899 #define ENV_ACT_SETALWAYS 0x1
5900 #define ENV_ACT_SETABSENT 0x2
5901 #define ENV_ACT_REMOVE 0x4
5902 #define ENV_ACT_REMOVEMATCH 0x8
5904 #define ENV_MOD_MACHINE 0x20000000
5905 #define ENV_MOD_APPEND 0x40000000
5906 #define ENV_MOD_PREFIX 0x80000000
5907 #define ENV_MOD_MASK 0xC0000000
5909 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5911 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5913 LPCWSTR cptr = *name;
5915 static const WCHAR prefix[] = {'[','~',']',0};
5916 static const int prefix_len = 3;
5922 *flags |= ENV_ACT_SETALWAYS;
5923 else if (*cptr == '+')
5924 *flags |= ENV_ACT_SETABSENT;
5925 else if (*cptr == '-')
5926 *flags |= ENV_ACT_REMOVE;
5927 else if (*cptr == '!')
5928 *flags |= ENV_ACT_REMOVEMATCH;
5929 else if (*cptr == '*')
5930 *flags |= ENV_MOD_MACHINE;
5940 ERR("Missing environment variable\n");
5941 return ERROR_FUNCTION_FAILED;
5946 LPCWSTR ptr = *value;
5947 if (!strncmpW(ptr, prefix, prefix_len))
5949 if (ptr[prefix_len] == szSemiColon[0])
5951 *flags |= ENV_MOD_APPEND;
5952 *value += lstrlenW(prefix);
5959 else if (lstrlenW(*value) >= prefix_len)
5961 ptr += lstrlenW(ptr) - prefix_len;
5962 if (!lstrcmpW(ptr, prefix))
5964 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5966 *flags |= ENV_MOD_PREFIX;
5967 /* the "[~]" will be removed by deformat_string */;
5977 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5978 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5979 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5980 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5982 ERR("Invalid flags: %08x\n", *flags);
5983 return ERROR_FUNCTION_FAILED;
5987 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5989 return ERROR_SUCCESS;
5992 static UINT open_env_key( DWORD flags, HKEY *key )
5994 static const WCHAR user_env[] =
5995 {'E','n','v','i','r','o','n','m','e','n','t',0};
5996 static const WCHAR machine_env[] =
5997 {'S','y','s','t','e','m','\\',
5998 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5999 'C','o','n','t','r','o','l','\\',
6000 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6001 'E','n','v','i','r','o','n','m','e','n','t',0};
6006 if (flags & ENV_MOD_MACHINE)
6009 root = HKEY_LOCAL_MACHINE;
6014 root = HKEY_CURRENT_USER;
6017 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6018 if (res != ERROR_SUCCESS)
6020 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6021 return ERROR_FUNCTION_FAILED;
6024 return ERROR_SUCCESS;
6027 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6029 MSIPACKAGE *package = param;
6030 LPCWSTR name, value, component;
6031 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6032 DWORD flags, type, size;
6039 component = MSI_RecordGetString(rec, 4);
6040 comp = get_loaded_component(package, component);
6042 return ERROR_SUCCESS;
6044 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6046 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6047 comp->Action = comp->Installed;
6048 return ERROR_SUCCESS;
6050 comp->Action = INSTALLSTATE_LOCAL;
6052 name = MSI_RecordGetString(rec, 2);
6053 value = MSI_RecordGetString(rec, 3);
6055 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6057 res = env_parse_flags(&name, &value, &flags);
6058 if (res != ERROR_SUCCESS || !value)
6061 if (value && !deformat_string(package, value, &deformatted))
6063 res = ERROR_OUTOFMEMORY;
6067 value = deformatted;
6069 res = open_env_key( flags, &env );
6070 if (res != ERROR_SUCCESS)
6073 if (flags & ENV_MOD_MACHINE)
6074 action |= 0x20000000;
6078 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6079 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6080 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6083 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6087 /* Nothing to do. */
6090 res = ERROR_SUCCESS;
6094 /* If we are appending but the string was empty, strip ; */
6095 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6097 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6098 newval = strdupW(value);
6101 res = ERROR_OUTOFMEMORY;
6109 /* Contrary to MSDN, +-variable to [~];path works */
6110 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6112 res = ERROR_SUCCESS;
6116 data = msi_alloc(size);
6120 return ERROR_OUTOFMEMORY;
6123 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6124 if (res != ERROR_SUCCESS)
6127 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6130 res = RegDeleteValueW(env, name);
6131 if (res != ERROR_SUCCESS)
6132 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6136 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6137 if (flags & ENV_MOD_MASK)
6141 if (flags & ENV_MOD_APPEND) multiplier++;
6142 if (flags & ENV_MOD_PREFIX) multiplier++;
6143 mod_size = lstrlenW(value) * multiplier;
6144 size += mod_size * sizeof(WCHAR);
6147 newval = msi_alloc(size);
6151 res = ERROR_OUTOFMEMORY;
6155 if (flags & ENV_MOD_PREFIX)
6157 lstrcpyW(newval, value);
6158 ptr = newval + lstrlenW(value);
6159 action |= 0x80000000;
6162 lstrcpyW(ptr, data);
6164 if (flags & ENV_MOD_APPEND)
6166 lstrcatW(newval, value);
6167 action |= 0x40000000;
6170 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6171 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6174 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6178 uirow = MSI_CreateRecord( 3 );
6179 MSI_RecordSetStringW( uirow, 1, name );
6180 MSI_RecordSetStringW( uirow, 2, newval );
6181 MSI_RecordSetInteger( uirow, 3, action );
6182 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6183 msiobj_release( &uirow->hdr );
6185 if (env) RegCloseKey(env);
6186 msi_free(deformatted);
6192 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6196 static const WCHAR ExecSeqQuery[] =
6197 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6198 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6199 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6200 if (rc != ERROR_SUCCESS)
6201 return ERROR_SUCCESS;
6203 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6204 msiobj_release(&view->hdr);
6209 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6211 MSIPACKAGE *package = param;
6212 LPCWSTR name, value, component;
6213 LPWSTR deformatted = NULL;
6222 component = MSI_RecordGetString( rec, 4 );
6223 comp = get_loaded_component( package, component );
6225 return ERROR_SUCCESS;
6227 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6229 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6230 comp->Action = comp->Installed;
6231 return ERROR_SUCCESS;
6233 comp->Action = INSTALLSTATE_ABSENT;
6235 name = MSI_RecordGetString( rec, 2 );
6236 value = MSI_RecordGetString( rec, 3 );
6238 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6240 r = env_parse_flags( &name, &value, &flags );
6241 if (r != ERROR_SUCCESS)
6244 if (!(flags & ENV_ACT_REMOVE))
6246 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6247 return ERROR_SUCCESS;
6250 if (value && !deformat_string( package, value, &deformatted ))
6251 return ERROR_OUTOFMEMORY;
6253 value = deformatted;
6255 r = open_env_key( flags, &env );
6256 if (r != ERROR_SUCCESS)
6262 if (flags & ENV_MOD_MACHINE)
6263 action |= 0x20000000;
6265 TRACE("Removing %s\n", debugstr_w(name));
6267 res = RegDeleteValueW( env, name );
6268 if (res != ERROR_SUCCESS)
6270 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6275 uirow = MSI_CreateRecord( 3 );
6276 MSI_RecordSetStringW( uirow, 1, name );
6277 MSI_RecordSetStringW( uirow, 2, value );
6278 MSI_RecordSetInteger( uirow, 3, action );
6279 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6280 msiobj_release( &uirow->hdr );
6282 if (env) RegCloseKey( env );
6283 msi_free( deformatted );
6287 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6291 static const WCHAR query[] =
6292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6293 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6295 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6296 if (rc != ERROR_SUCCESS)
6297 return ERROR_SUCCESS;
6299 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6300 msiobj_release( &view->hdr );
6305 typedef struct tagMSIASSEMBLY
6308 MSICOMPONENT *component;
6309 MSIFEATURE *feature;
6313 LPWSTR display_name;
6318 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6320 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6321 LPVOID pvReserved, HMODULE *phModDll);
6323 static BOOL init_functionpointers(void)
6329 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6331 hmscoree = LoadLibraryA("mscoree.dll");
6334 WARN("mscoree.dll not available\n");
6338 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6339 if (!pLoadLibraryShim)
6341 WARN("LoadLibraryShim not available\n");
6342 FreeLibrary(hmscoree);
6346 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6349 WARN("fusion.dll not available\n");
6350 FreeLibrary(hmscoree);
6354 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6356 FreeLibrary(hmscoree);
6360 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6363 IAssemblyCache *cache;
6366 UINT r = ERROR_FUNCTION_FAILED;
6368 TRACE("installing assembly: %s\n", debugstr_w(path));
6370 uirow = MSI_CreateRecord( 2 );
6371 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6372 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6373 msiobj_release( &uirow->hdr );
6375 if (assembly->feature)
6376 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6378 if (assembly->manifest)
6379 FIXME("Manifest unhandled\n");
6381 if (assembly->application)
6383 FIXME("Assembly should be privately installed\n");
6384 return ERROR_SUCCESS;
6387 if (assembly->attributes == msidbAssemblyAttributesWin32)
6389 FIXME("Win32 assemblies not handled\n");
6390 return ERROR_SUCCESS;
6393 hr = pCreateAssemblyCache(&cache, 0);
6397 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6399 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6404 IAssemblyCache_Release(cache);
6408 typedef struct tagASSEMBLY_LIST
6410 MSIPACKAGE *package;
6411 IAssemblyCache *cache;
6412 struct list *assemblies;
6415 typedef struct tagASSEMBLY_NAME
6423 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6425 ASSEMBLY_NAME *asmname = param;
6426 LPCWSTR name = MSI_RecordGetString(rec, 2);
6427 LPWSTR val = msi_dup_record_field(rec, 3);
6429 static const WCHAR Name[] = {'N','a','m','e',0};
6430 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6431 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6432 static const WCHAR PublicKeyToken[] = {
6433 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6435 if (!strcmpiW(name, Name))
6436 asmname->name = val;
6437 else if (!strcmpiW(name, Version))
6438 asmname->version = val;
6439 else if (!strcmpiW(name, Culture))
6440 asmname->culture = val;
6441 else if (!strcmpiW(name, PublicKeyToken))
6442 asmname->pubkeytoken = val;
6446 return ERROR_SUCCESS;
6449 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6453 *size = lstrlenW(append) + 1;
6454 *str = msi_alloc((*size) * sizeof(WCHAR));
6455 lstrcpyW(*str, append);
6459 (*size) += lstrlenW(append);
6460 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6461 lstrcatW(*str, append);
6464 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6466 static const WCHAR separator[] = {',',' ',0};
6467 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6468 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6469 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6470 static const WCHAR query[] = {
6471 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6472 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6473 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6474 '=','\'','%','s','\'',0};
6477 LPWSTR display_name;
6481 display_name = NULL;
6482 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6484 r = MSI_OpenQuery( db, &view, query, comp->Component );
6485 if (r != ERROR_SUCCESS)
6488 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6489 msiobj_release( &view->hdr );
6493 ERR("No assembly name specified!\n");
6497 append_str( &display_name, &size, name.name );
6501 append_str( &display_name, &size, separator );
6502 append_str( &display_name, &size, Version );
6503 append_str( &display_name, &size, name.version );
6507 append_str( &display_name, &size, separator );
6508 append_str( &display_name, &size, Culture );
6509 append_str( &display_name, &size, name.culture );
6511 if (name.pubkeytoken)
6513 append_str( &display_name, &size, separator );
6514 append_str( &display_name, &size, PublicKeyToken );
6515 append_str( &display_name, &size, name.pubkeytoken );
6518 msi_free( name.name );
6519 msi_free( name.version );
6520 msi_free( name.culture );
6521 msi_free( name.pubkeytoken );
6523 return display_name;
6526 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6528 ASSEMBLY_INFO asminfo;
6533 disp = get_assembly_display_name( db, comp );
6537 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6538 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6540 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6542 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6548 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6550 ASSEMBLY_LIST *list = param;
6551 MSIASSEMBLY *assembly;
6554 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6556 return ERROR_OUTOFMEMORY;
6558 component = MSI_RecordGetString(rec, 1);
6559 assembly->component = get_loaded_component(list->package, component);
6560 if (!assembly->component)
6561 return ERROR_SUCCESS;
6563 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6564 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6566 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6567 assembly->component->Action = assembly->component->Installed;
6568 return ERROR_SUCCESS;
6570 assembly->component->Action = assembly->component->ActionRequest;
6572 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6573 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6575 if (!assembly->file)
6577 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6578 return ERROR_FUNCTION_FAILED;
6581 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6582 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6583 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6585 if (assembly->application)
6588 DWORD size = sizeof(version)/sizeof(WCHAR);
6590 /* FIXME: we should probably check the manifest file here */
6592 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6593 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6595 assembly->installed = TRUE;
6599 assembly->installed = check_assembly_installed(list->package->db,
6601 assembly->component);
6603 list_add_head(list->assemblies, &assembly->entry);
6604 return ERROR_SUCCESS;
6607 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6609 IAssemblyCache *cache = NULL;
6615 static const WCHAR query[] =
6616 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6617 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6619 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6620 if (r != ERROR_SUCCESS)
6621 return ERROR_SUCCESS;
6623 hr = pCreateAssemblyCache(&cache, 0);
6625 return ERROR_FUNCTION_FAILED;
6627 list.package = package;
6629 list.assemblies = assemblies;
6631 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6632 msiobj_release(&view->hdr);
6634 IAssemblyCache_Release(cache);
6639 static void free_assemblies(struct list *assemblies)
6641 struct list *item, *cursor;
6643 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6645 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6647 list_remove(&assembly->entry);
6648 msi_free(assembly->application);
6649 msi_free(assembly->manifest);
6650 msi_free(assembly->display_name);
6655 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6657 MSIASSEMBLY *assembly;
6659 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6661 if (!lstrcmpW(assembly->file->File, file))
6671 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6672 LPWSTR *path, DWORD *attrs, PVOID user)
6674 MSIASSEMBLY *assembly;
6675 WCHAR temppath[MAX_PATH];
6676 struct list *assemblies = user;
6679 if (!find_assembly(assemblies, file, &assembly))
6682 GetTempPathW(MAX_PATH, temppath);
6683 PathAddBackslashW(temppath);
6684 lstrcatW(temppath, assembly->file->FileName);
6686 if (action == MSICABEXTRACT_BEGINEXTRACT)
6688 if (assembly->installed)
6691 *path = strdupW(temppath);
6692 *attrs = assembly->file->Attributes;
6694 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6696 assembly->installed = TRUE;
6698 r = install_assembly(package, assembly, temppath);
6699 if (r != ERROR_SUCCESS)
6700 ERR("Failed to install assembly\n");
6706 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6709 struct list assemblies = LIST_INIT(assemblies);
6710 MSIASSEMBLY *assembly;
6713 if (!init_functionpointers() || !pCreateAssemblyCache)
6714 return ERROR_FUNCTION_FAILED;
6716 r = load_assemblies(package, &assemblies);
6717 if (r != ERROR_SUCCESS)
6720 if (list_empty(&assemblies))
6723 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6726 r = ERROR_OUTOFMEMORY;
6730 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6732 if (assembly->installed && !mi->is_continuous)
6735 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6736 (assembly->file->IsCompressed && !mi->is_extracted))
6740 r = ready_media(package, assembly->file, mi);
6741 if (r != ERROR_SUCCESS)
6743 ERR("Failed to ready media\n");
6748 data.package = package;
6749 data.cb = installassembly_cb;
6750 data.user = &assemblies;
6752 if (assembly->file->IsCompressed &&
6753 !msi_cabextract(package, mi, &data))
6755 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6756 r = ERROR_FUNCTION_FAILED;
6761 if (!assembly->file->IsCompressed)
6763 LPWSTR source = resolve_file_source(package, assembly->file);
6765 r = install_assembly(package, assembly, source);
6766 if (r != ERROR_SUCCESS)
6767 ERR("Failed to install assembly\n");
6772 /* FIXME: write Installer assembly reg values */
6776 free_assemblies(&assemblies);
6780 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6782 LPWSTR key, template, id;
6783 UINT r = ERROR_SUCCESS;
6785 id = msi_dup_property( package, szProductID );
6789 return ERROR_SUCCESS;
6791 template = msi_dup_property( package, szPIDTemplate );
6792 key = msi_dup_property( package, szPIDKEY );
6794 if (key && template)
6796 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6797 r = MSI_SetPropertyW( package, szProductID, key );
6799 msi_free( template );
6804 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6807 package->need_reboot = 1;
6808 return ERROR_SUCCESS;
6811 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6813 static const WCHAR szAvailableFreeReg[] =
6814 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6816 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6818 TRACE("%p %d kilobytes\n", package, space);
6820 uirow = MSI_CreateRecord( 1 );
6821 MSI_RecordSetInteger( uirow, 1, space );
6822 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6823 msiobj_release( &uirow->hdr );
6825 return ERROR_SUCCESS;
6828 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6830 FIXME("%p\n", package);
6831 return ERROR_SUCCESS;
6834 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6836 FIXME("%p\n", package);
6837 return ERROR_SUCCESS;
6840 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6845 static const WCHAR driver_query[] = {
6846 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6847 'O','D','B','C','D','r','i','v','e','r',0 };
6849 static const WCHAR translator_query[] = {
6850 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6851 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6853 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6854 if (r == ERROR_SUCCESS)
6857 r = MSI_IterateRecords( view, &count, NULL, package );
6858 msiobj_release( &view->hdr );
6859 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6862 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6863 if (r == ERROR_SUCCESS)
6866 r = MSI_IterateRecords( view, &count, NULL, package );
6867 msiobj_release( &view->hdr );
6868 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6871 return ERROR_SUCCESS;
6874 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6875 LPCSTR action, LPCWSTR table )
6877 static const WCHAR query[] = {
6878 'S','E','L','E','C','T',' ','*',' ',
6879 'F','R','O','M',' ','`','%','s','`',0 };
6880 MSIQUERY *view = NULL;
6884 r = MSI_OpenQuery( package->db, &view, query, table );
6885 if (r == ERROR_SUCCESS)
6887 r = MSI_IterateRecords(view, &count, NULL, package);
6888 msiobj_release(&view->hdr);
6892 FIXME("%s -> %u ignored %s table values\n",
6893 action, count, debugstr_w(table));
6895 return ERROR_SUCCESS;
6898 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6900 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6901 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6904 static UINT ACTION_BindImage( MSIPACKAGE *package )
6906 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6907 return msi_unimplemented_action_stub( package, "BindImage", table );
6910 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6912 static const WCHAR table[] = {
6913 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6914 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6917 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6919 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6920 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6923 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6925 static const WCHAR table[] = {
6926 'M','s','i','A','s','s','e','m','b','l','y',0 };
6927 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6930 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6932 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6933 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6936 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6938 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6939 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6942 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6944 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6945 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6948 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6950 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6951 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6954 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6956 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6957 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6960 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6962 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6963 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6966 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6968 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6969 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6972 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6974 static const WCHAR table[] = { 'M','I','M','E',0 };
6975 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6978 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6980 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6981 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6984 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6988 const WCHAR *action;
6989 UINT (*handler)(MSIPACKAGE *);
6993 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6994 { szAppSearch, ACTION_AppSearch },
6995 { szBindImage, ACTION_BindImage },
6996 { szCCPSearch, ACTION_CCPSearch },
6997 { szCostFinalize, ACTION_CostFinalize },
6998 { szCostInitialize, ACTION_CostInitialize },
6999 { szCreateFolders, ACTION_CreateFolders },
7000 { szCreateShortcuts, ACTION_CreateShortcuts },
7001 { szDeleteServices, ACTION_DeleteServices },
7002 { szDisableRollback, ACTION_DisableRollback },
7003 { szDuplicateFiles, ACTION_DuplicateFiles },
7004 { szExecuteAction, ACTION_ExecuteAction },
7005 { szFileCost, ACTION_FileCost },
7006 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7007 { szForceReboot, ACTION_ForceReboot },
7008 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7009 { szInstallExecute, ACTION_InstallExecute },
7010 { szInstallExecuteAgain, ACTION_InstallExecute },
7011 { szInstallFiles, ACTION_InstallFiles},
7012 { szInstallFinalize, ACTION_InstallFinalize },
7013 { szInstallInitialize, ACTION_InstallInitialize },
7014 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7015 { szInstallValidate, ACTION_InstallValidate },
7016 { szIsolateComponents, ACTION_IsolateComponents },
7017 { szLaunchConditions, ACTION_LaunchConditions },
7018 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7019 { szMoveFiles, ACTION_MoveFiles },
7020 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7021 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7022 { szInstallODBC, ACTION_InstallODBC },
7023 { szInstallServices, ACTION_InstallServices },
7024 { szPatchFiles, ACTION_PatchFiles },
7025 { szProcessComponents, ACTION_ProcessComponents },
7026 { szPublishComponents, ACTION_PublishComponents },
7027 { szPublishFeatures, ACTION_PublishFeatures },
7028 { szPublishProduct, ACTION_PublishProduct },
7029 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7030 { szRegisterComPlus, ACTION_RegisterComPlus},
7031 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7032 { szRegisterFonts, ACTION_RegisterFonts },
7033 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7034 { szRegisterProduct, ACTION_RegisterProduct },
7035 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7036 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7037 { szRegisterUser, ACTION_RegisterUser },
7038 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7039 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7040 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7041 { szRemoveFiles, ACTION_RemoveFiles },
7042 { szRemoveFolders, ACTION_RemoveFolders },
7043 { szRemoveIniValues, ACTION_RemoveIniValues },
7044 { szRemoveODBC, ACTION_RemoveODBC },
7045 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7046 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7047 { szResolveSource, ACTION_ResolveSource },
7048 { szRMCCPSearch, ACTION_RMCCPSearch },
7049 { szScheduleReboot, ACTION_ScheduleReboot },
7050 { szSelfRegModules, ACTION_SelfRegModules },
7051 { szSelfUnregModules, ACTION_SelfUnregModules },
7052 { szSetODBCFolders, ACTION_SetODBCFolders },
7053 { szStartServices, ACTION_StartServices },
7054 { szStopServices, ACTION_StopServices },
7055 { szUnpublishComponents, ACTION_UnpublishComponents },
7056 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7057 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7058 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7059 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7060 { szUnregisterFonts, ACTION_UnregisterFonts },
7061 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7062 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7063 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7064 { szValidateProductID, ACTION_ValidateProductID },
7065 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7066 { szWriteIniValues, ACTION_WriteIniValues },
7067 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7071 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7072 UINT* rc, BOOL force )
7078 if (!run && !package->script->CurrentlyScripting)
7083 if (strcmpW(action,szInstallFinalize) == 0 ||
7084 strcmpW(action,szInstallExecute) == 0 ||
7085 strcmpW(action,szInstallExecuteAgain) == 0)
7090 while (StandardActions[i].action != NULL)
7092 if (strcmpW(StandardActions[i].action, action)==0)
7096 ui_actioninfo(package, action, TRUE, 0);
7097 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7098 ui_actioninfo(package, action, FALSE, *rc);
7102 ui_actionstart(package, action);
7103 if (StandardActions[i].handler)
7105 *rc = StandardActions[i].handler(package);
7109 FIXME("unhandled standard action %s\n",debugstr_w(action));
7110 *rc = ERROR_SUCCESS;
7121 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7123 UINT rc = ERROR_SUCCESS;
7126 TRACE("Performing action (%s)\n", debugstr_w(action));
7128 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7131 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7135 WARN("unhandled msi action %s\n", debugstr_w(action));
7136 rc = ERROR_FUNCTION_NOT_CALLED;
7142 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7144 UINT rc = ERROR_SUCCESS;
7145 BOOL handled = FALSE;
7147 TRACE("Performing action (%s)\n", debugstr_w(action));
7149 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7152 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7154 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7159 WARN("unhandled msi action %s\n", debugstr_w(action));
7160 rc = ERROR_FUNCTION_NOT_CALLED;
7166 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7168 UINT rc = ERROR_SUCCESS;
7171 static const WCHAR ExecSeqQuery[] =
7172 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7173 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7174 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7175 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7176 static const WCHAR UISeqQuery[] =
7177 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7178 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7179 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7180 ' ', '=',' ','%','i',0};
7182 if (needs_ui_sequence(package))
7183 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7185 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7189 LPCWSTR action, cond;
7191 TRACE("Running the actions\n");
7193 /* check conditions */
7194 cond = MSI_RecordGetString(row, 2);
7196 /* this is a hack to skip errors in the condition code */
7197 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7199 msiobj_release(&row->hdr);
7200 return ERROR_SUCCESS;
7203 action = MSI_RecordGetString(row, 1);
7206 ERR("failed to fetch action\n");
7207 msiobj_release(&row->hdr);
7208 return ERROR_FUNCTION_FAILED;
7211 if (needs_ui_sequence(package))
7212 rc = ACTION_PerformUIAction(package, action, -1);
7214 rc = ACTION_PerformAction(package, action, -1, FALSE);
7216 msiobj_release(&row->hdr);
7222 /****************************************************
7223 * TOP level entry points
7224 *****************************************************/
7226 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7227 LPCWSTR szCommandLine )
7232 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7233 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7235 MSI_SetPropertyW(package, szAction, szInstall);
7237 package->script->InWhatSequence = SEQUENCE_INSTALL;
7244 dir = strdupW(szPackagePath);
7245 p = strrchrW(dir, '\\');
7249 file = szPackagePath + (p - dir);
7254 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7255 GetCurrentDirectoryW(MAX_PATH, dir);
7256 lstrcatW(dir, szBackSlash);
7257 file = szPackagePath;
7260 msi_free( package->PackagePath );
7261 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7262 if (!package->PackagePath)
7265 return ERROR_OUTOFMEMORY;
7268 lstrcpyW(package->PackagePath, dir);
7269 lstrcatW(package->PackagePath, file);
7272 msi_set_sourcedir_props(package, FALSE);
7275 msi_parse_command_line( package, szCommandLine, FALSE );
7277 msi_apply_transforms( package );
7278 msi_apply_patches( package );
7280 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7282 TRACE("setting reinstall property\n");
7283 MSI_SetPropertyW( package, szReinstall, szAll );
7286 /* properties may have been added by a transform */
7287 msi_clone_properties( package );
7288 msi_set_context( package );
7290 if (needs_ui_sequence( package))
7292 package->script->InWhatSequence |= SEQUENCE_UI;
7293 rc = ACTION_ProcessUISequence(package);
7294 ui_exists = ui_sequence_exists(package);
7295 if (rc == ERROR_SUCCESS || !ui_exists)
7297 package->script->InWhatSequence |= SEQUENCE_EXEC;
7298 rc = ACTION_ProcessExecSequence(package, ui_exists);
7302 rc = ACTION_ProcessExecSequence(package, FALSE);
7304 package->script->CurrentlyScripting = FALSE;
7306 /* process the ending type action */
7307 if (rc == ERROR_SUCCESS)
7308 ACTION_PerformActionSequence(package, -1);
7309 else if (rc == ERROR_INSTALL_USEREXIT)
7310 ACTION_PerformActionSequence(package, -2);
7311 else if (rc == ERROR_INSTALL_SUSPEND)
7312 ACTION_PerformActionSequence(package, -4);
7314 ACTION_PerformActionSequence(package, -3);
7316 /* finish up running custom actions */
7317 ACTION_FinishCustomActions(package);
7319 if (rc == ERROR_SUCCESS && package->need_reboot)
7320 return ERROR_SUCCESS_REBOOT_REQUIRED;