2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings[] =
130 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
131 static const WCHAR szRemoveExistingProducts[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterTypeLibraries[] =
162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
163 static const WCHAR szValidateProductID[] =
164 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
165 static const WCHAR szWriteEnvironmentStrings[] =
166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
168 /********************************************************
170 ********************************************************/
172 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
174 static const WCHAR Query_t[] =
175 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
176 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
177 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
178 ' ','\'','%','s','\'',0};
181 row = MSI_QueryGetRecord( package->db, Query_t, action );
184 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
185 msiobj_release(&row->hdr);
188 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
192 static const WCHAR template_s[]=
193 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
195 static const WCHAR template_e[]=
196 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
197 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
199 static const WCHAR format[] =
200 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
204 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
206 sprintfW(message,template_s,timet,action);
208 sprintfW(message,template_e,timet,action,rc);
210 row = MSI_CreateRecord(1);
211 MSI_RecordSetStringW(row,1,message);
213 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
214 msiobj_release(&row->hdr);
217 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
223 LPWSTR prop = NULL, val = NULL;
226 return ERROR_SUCCESS;
238 TRACE("Looking at %s\n",debugstr_w(ptr));
240 ptr2 = strchrW(ptr,'=');
243 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
250 prop = msi_alloc((len+1)*sizeof(WCHAR));
251 memcpy(prop,ptr,len*sizeof(WCHAR));
261 while (*ptr && (quote || (!quote && *ptr!=' ')))
274 val = msi_alloc((len+1)*sizeof(WCHAR));
275 memcpy(val,ptr2,len*sizeof(WCHAR));
278 if (lstrlenW(prop) > 0)
280 TRACE("Found commandline property (%s) = (%s)\n",
281 debugstr_w(prop), debugstr_w(val));
282 MSI_SetPropertyW(package,prop,val);
288 return ERROR_SUCCESS;
292 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
295 LPWSTR p, *ret = NULL;
301 /* count the number of substrings */
302 for ( pc = str, count = 0; pc; count++ )
304 pc = strchrW( pc, sep );
309 /* allocate space for an array of substring pointers and the substrings */
310 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
311 (lstrlenW(str)+1) * sizeof(WCHAR) );
315 /* copy the string and set the pointers */
316 p = (LPWSTR) &ret[count+1];
318 for( count = 0; (ret[count] = p); count++ )
320 p = strchrW( p, sep );
328 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
330 static const WCHAR szSystemLanguageID[] =
331 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
333 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
334 UINT ret = ERROR_FUNCTION_FAILED;
336 prod_code = msi_dup_property( package, szProductCode );
337 patch_product = msi_get_suminfo_product( patch );
339 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
341 if ( strstrW( patch_product, prod_code ) )
346 si = MSI_GetSummaryInformationW( patch, 0 );
349 ERR("no summary information!\n");
353 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
356 ERR("no template property!\n");
357 msiobj_release( &si->hdr );
364 msiobj_release( &si->hdr );
368 langid = msi_dup_property( package, szSystemLanguageID );
371 msiobj_release( &si->hdr );
375 p = strchrW( template, ';' );
376 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
378 TRACE("applicable transform\n");
382 /* FIXME: check platform */
384 msiobj_release( &si->hdr );
388 msi_free( patch_product );
389 msi_free( prod_code );
390 msi_free( template );
396 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
397 MSIDATABASE *patch_db, LPCWSTR name )
399 UINT ret = ERROR_FUNCTION_FAILED;
400 IStorage *stg = NULL;
403 TRACE("%p %s\n", package, debugstr_w(name) );
407 ERR("expected a colon in %s\n", debugstr_w(name));
408 return ERROR_FUNCTION_FAILED;
411 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
414 ret = msi_check_transform_applicable( package, stg );
415 if (ret == ERROR_SUCCESS)
416 msi_table_apply_transform( package->db, stg );
418 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
419 IStorage_Release( stg );
422 ERR("failed to open substorage %s\n", debugstr_w(name));
424 return ERROR_SUCCESS;
427 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
429 LPWSTR guid_list, *guids, product_code;
430 UINT i, ret = ERROR_FUNCTION_FAILED;
432 product_code = msi_dup_property( package, szProductCode );
435 /* FIXME: the property ProductCode should be written into the DB somewhere */
436 ERR("no product code to check\n");
437 return ERROR_SUCCESS;
440 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
441 guids = msi_split_string( guid_list, ';' );
442 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
444 if (!lstrcmpW( guids[i], product_code ))
448 msi_free( guid_list );
449 msi_free( product_code );
454 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
457 MSIRECORD *rec = NULL;
462 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
463 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
464 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
465 '`','S','o','u','r','c','e','`',' ','I','S',' ',
466 'N','O','T',' ','N','U','L','L',0};
468 r = MSI_DatabaseOpenViewW(package->db, query, &view);
469 if (r != ERROR_SUCCESS)
472 r = MSI_ViewExecute(view, 0);
473 if (r != ERROR_SUCCESS)
476 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
478 prop = MSI_RecordGetString(rec, 1);
479 patch = msi_dup_property(package, szPatch);
480 MSI_SetPropertyW(package, prop, patch);
485 if (rec) msiobj_release(&rec->hdr);
486 msiobj_release(&view->hdr);
491 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
494 LPWSTR str, *substorage;
495 UINT i, r = ERROR_SUCCESS;
497 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
499 return ERROR_FUNCTION_FAILED;
501 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
503 TRACE("Patch not applicable\n");
504 return ERROR_SUCCESS;
507 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
509 return ERROR_OUTOFMEMORY;
511 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
512 if (!package->patch->patchcode)
513 return ERROR_OUTOFMEMORY;
515 /* enumerate the substorage */
516 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
517 package->patch->transforms = str;
519 substorage = msi_split_string( str, ';' );
520 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
523 msi_free( substorage );
524 msiobj_release( &si->hdr );
526 msi_set_media_source_prop(package);
531 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
533 MSIDATABASE *patch_db = NULL;
536 TRACE("%p %s\n", package, debugstr_w( file ) );
539 * We probably want to make sure we only open a patch collection here.
540 * Patch collections (.msp) and databases (.msi) have different GUIDs
541 * but currently MSI_OpenDatabaseW will accept both.
543 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
544 if ( r != ERROR_SUCCESS )
546 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
550 msi_parse_patch_summary( package, patch_db );
553 * There might be a CAB file in the patch package,
554 * so append it to the list of storage to search for streams.
556 append_storage_to_db( package->db, patch_db->storage );
558 msiobj_release( &patch_db->hdr );
560 return ERROR_SUCCESS;
563 /* get the PATCH property, and apply all the patches it specifies */
564 static UINT msi_apply_patches( MSIPACKAGE *package )
566 LPWSTR patch_list, *patches;
567 UINT i, r = ERROR_SUCCESS;
569 patch_list = msi_dup_property( package, szPatch );
571 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
573 patches = msi_split_string( patch_list, ';' );
574 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
575 r = msi_apply_patch_package( package, patches[i] );
578 msi_free( patch_list );
583 static UINT msi_apply_transforms( MSIPACKAGE *package )
585 static const WCHAR szTransforms[] = {
586 'T','R','A','N','S','F','O','R','M','S',0 };
587 LPWSTR xform_list, *xforms;
588 UINT i, r = ERROR_SUCCESS;
590 xform_list = msi_dup_property( package, szTransforms );
591 xforms = msi_split_string( xform_list, ';' );
593 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
595 if (xforms[i][0] == ':')
596 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
598 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
602 msi_free( xform_list );
607 static BOOL ui_sequence_exists( MSIPACKAGE *package )
612 static const WCHAR ExecSeqQuery [] =
613 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
614 '`','I','n','s','t','a','l','l',
615 'U','I','S','e','q','u','e','n','c','e','`',
616 ' ','W','H','E','R','E',' ',
617 '`','S','e','q','u','e','n','c','e','`',' ',
618 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
619 '`','S','e','q','u','e','n','c','e','`',0};
621 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
622 if (rc == ERROR_SUCCESS)
624 msiobj_release(&view->hdr);
631 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
634 LPWSTR source, check;
637 static const WCHAR szOriginalDatabase[] =
638 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
640 db = msi_dup_property( package, szOriginalDatabase );
642 return ERROR_OUTOFMEMORY;
644 p = strrchrW( db, '\\' );
647 p = strrchrW( db, '/' );
651 return ERROR_SUCCESS;
656 source = msi_alloc( len * sizeof(WCHAR) );
657 lstrcpynW( source, db, len );
659 check = msi_dup_property( package, cszSourceDir );
660 if (!check || replace)
661 MSI_SetPropertyW( package, cszSourceDir, source );
665 check = msi_dup_property( package, cszSOURCEDIR );
666 if (!check || replace)
667 MSI_SetPropertyW( package, cszSOURCEDIR, source );
673 return ERROR_SUCCESS;
676 static BOOL needs_ui_sequence(MSIPACKAGE *package)
678 INT level = msi_get_property_int(package, szUILevel, 0);
679 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
682 static UINT msi_set_context(MSIPACKAGE *package)
689 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
691 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
692 if (r == ERROR_SUCCESS)
695 if (num == 1 || num == 2)
696 package->Context = MSIINSTALLCONTEXT_MACHINE;
699 return ERROR_SUCCESS;
702 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
705 LPCWSTR cond, action;
706 MSIPACKAGE *package = param;
708 action = MSI_RecordGetString(row,1);
711 ERR("Error is retrieving action name\n");
712 return ERROR_FUNCTION_FAILED;
715 /* check conditions */
716 cond = MSI_RecordGetString(row,2);
718 /* this is a hack to skip errors in the condition code */
719 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
721 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
722 return ERROR_SUCCESS;
725 if (needs_ui_sequence(package))
726 rc = ACTION_PerformUIAction(package, action, -1);
728 rc = ACTION_PerformAction(package, action, -1, FALSE);
730 msi_dialog_check_messages( NULL );
732 if (package->CurrentInstallState != ERROR_SUCCESS)
733 rc = package->CurrentInstallState;
735 if (rc == ERROR_FUNCTION_NOT_CALLED)
738 if (rc != ERROR_SUCCESS)
739 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
744 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
748 static const WCHAR query[] =
749 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
751 ' ','W','H','E','R','E',' ',
752 '`','S','e','q','u','e','n','c','e','`',' ',
753 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
754 '`','S','e','q','u','e','n','c','e','`',0};
756 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
758 r = MSI_OpenQuery( package->db, &view, query, szTable );
759 if (r == ERROR_SUCCESS)
761 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
762 msiobj_release(&view->hdr);
768 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
772 static const WCHAR ExecSeqQuery[] =
773 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
774 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
775 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
776 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
777 'O','R','D','E','R',' ', 'B','Y',' ',
778 '`','S','e','q','u','e','n','c','e','`',0 };
779 static const WCHAR IVQuery[] =
780 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
781 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
782 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
783 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
784 ' ','\'', 'I','n','s','t','a','l','l',
785 'V','a','l','i','d','a','t','e','\'', 0};
788 if (package->script->ExecuteSequenceRun)
790 TRACE("Execute Sequence already Run\n");
791 return ERROR_SUCCESS;
794 package->script->ExecuteSequenceRun = TRUE;
796 /* get the sequence number */
799 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
801 return ERROR_FUNCTION_FAILED;
802 seq = MSI_RecordGetInteger(row,1);
803 msiobj_release(&row->hdr);
806 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
807 if (rc == ERROR_SUCCESS)
809 TRACE("Running the actions\n");
811 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
812 msiobj_release(&view->hdr);
818 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
822 static const WCHAR ExecSeqQuery [] =
823 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
824 '`','I','n','s','t','a','l','l',
825 'U','I','S','e','q','u','e','n','c','e','`',
826 ' ','W','H','E','R','E',' ',
827 '`','S','e','q','u','e','n','c','e','`',' ',
828 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
829 '`','S','e','q','u','e','n','c','e','`',0};
831 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
832 if (rc == ERROR_SUCCESS)
834 TRACE("Running the actions\n");
836 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
837 msiobj_release(&view->hdr);
843 /********************************************************
844 * ACTION helper functions and functions that perform the actions
845 *******************************************************/
846 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
847 UINT* rc, UINT script, BOOL force )
852 arc = ACTION_CustomAction(package, action, script, force);
854 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
863 * Actual Action Handlers
866 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
868 MSIPACKAGE *package = param;
869 LPCWSTR dir, component;
875 component = MSI_RecordGetString(row, 2);
876 comp = get_loaded_component(package, component);
878 return ERROR_SUCCESS;
880 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
882 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
883 comp->Action = comp->Installed;
884 return ERROR_SUCCESS;
886 comp->Action = INSTALLSTATE_LOCAL;
888 dir = MSI_RecordGetString(row,1);
891 ERR("Unable to get folder id\n");
892 return ERROR_SUCCESS;
895 uirow = MSI_CreateRecord(1);
896 MSI_RecordSetStringW(uirow, 1, dir);
897 ui_actiondata(package, szCreateFolders, uirow);
898 msiobj_release(&uirow->hdr);
900 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
903 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
904 return ERROR_SUCCESS;
907 TRACE("Folder is %s\n",debugstr_w(full_path));
909 if (folder->State == 0)
910 create_full_pathW(full_path);
915 return ERROR_SUCCESS;
918 /* FIXME: probably should merge this with the above function */
919 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
921 UINT rc = ERROR_SUCCESS;
925 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
927 return ERROR_FUNCTION_FAILED;
929 /* create the path */
930 if (folder->State == 0)
932 create_full_pathW(install_path);
935 msi_free(install_path);
940 UINT msi_create_component_directories( MSIPACKAGE *package )
944 /* create all the folders required by the components are going to install */
945 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
947 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
949 msi_create_directory( package, comp->Directory );
952 return ERROR_SUCCESS;
955 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
957 static const WCHAR ExecSeqQuery[] =
958 {'S','E','L','E','C','T',' ',
959 '`','D','i','r','e','c','t','o','r','y','_','`',
960 ' ','F','R','O','M',' ',
961 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
965 /* create all the empty folders specified in the CreateFolder table */
966 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
967 if (rc != ERROR_SUCCESS)
968 return ERROR_SUCCESS;
970 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
971 msiobj_release(&view->hdr);
976 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
978 MSIPACKAGE *package = param;
979 LPCWSTR dir, component;
985 component = MSI_RecordGetString(row, 2);
986 comp = get_loaded_component(package, component);
988 return ERROR_SUCCESS;
990 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
992 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
993 comp->Action = comp->Installed;
994 return ERROR_SUCCESS;
996 comp->Action = INSTALLSTATE_ABSENT;
998 dir = MSI_RecordGetString( row, 1 );
1001 ERR("Unable to get folder id\n");
1002 return ERROR_SUCCESS;
1005 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1008 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1009 return ERROR_SUCCESS;
1012 TRACE("folder is %s\n", debugstr_w(full_path));
1014 uirow = MSI_CreateRecord( 1 );
1015 MSI_RecordSetStringW( uirow, 1, full_path );
1016 ui_actiondata( package, szRemoveFolders, uirow );
1017 msiobj_release( &uirow->hdr );
1019 RemoveDirectoryW( full_path );
1022 msi_free( full_path );
1023 return ERROR_SUCCESS;
1026 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1028 static const WCHAR query[] =
1029 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1030 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1035 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1036 if (rc != ERROR_SUCCESS)
1037 return ERROR_SUCCESS;
1039 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1040 msiobj_release( &view->hdr );
1045 static UINT load_component( MSIRECORD *row, LPVOID param )
1047 MSIPACKAGE *package = param;
1050 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1052 return ERROR_FUNCTION_FAILED;
1054 list_add_tail( &package->components, &comp->entry );
1056 /* fill in the data */
1057 comp->Component = msi_dup_record_field( row, 1 );
1059 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1061 comp->ComponentId = msi_dup_record_field( row, 2 );
1062 comp->Directory = msi_dup_record_field( row, 3 );
1063 comp->Attributes = MSI_RecordGetInteger(row,4);
1064 comp->Condition = msi_dup_record_field( row, 5 );
1065 comp->KeyPath = msi_dup_record_field( row, 6 );
1067 comp->Installed = INSTALLSTATE_UNKNOWN;
1068 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1070 return ERROR_SUCCESS;
1073 static UINT load_all_components( MSIPACKAGE *package )
1075 static const WCHAR query[] = {
1076 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1077 '`','C','o','m','p','o','n','e','n','t','`',0 };
1081 if (!list_empty(&package->components))
1082 return ERROR_SUCCESS;
1084 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1085 if (r != ERROR_SUCCESS)
1088 r = MSI_IterateRecords(view, NULL, load_component, package);
1089 msiobj_release(&view->hdr);
1094 MSIPACKAGE *package;
1095 MSIFEATURE *feature;
1098 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1102 cl = msi_alloc( sizeof (*cl) );
1104 return ERROR_NOT_ENOUGH_MEMORY;
1105 cl->component = comp;
1106 list_add_tail( &feature->Components, &cl->entry );
1108 return ERROR_SUCCESS;
1111 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1115 fl = msi_alloc( sizeof(*fl) );
1117 return ERROR_NOT_ENOUGH_MEMORY;
1118 fl->feature = child;
1119 list_add_tail( &parent->Children, &fl->entry );
1121 return ERROR_SUCCESS;
1124 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1126 _ilfs* ilfs = param;
1130 component = MSI_RecordGetString(row,1);
1132 /* check to see if the component is already loaded */
1133 comp = get_loaded_component( ilfs->package, component );
1136 ERR("unknown component %s\n", debugstr_w(component));
1137 return ERROR_FUNCTION_FAILED;
1140 add_feature_component( ilfs->feature, comp );
1141 comp->Enabled = TRUE;
1143 return ERROR_SUCCESS;
1146 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1148 MSIFEATURE *feature;
1153 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1155 if ( !lstrcmpW( feature->Feature, name ) )
1162 static UINT load_feature(MSIRECORD * row, LPVOID param)
1164 MSIPACKAGE* package = param;
1165 MSIFEATURE* feature;
1166 static const WCHAR Query1[] =
1167 {'S','E','L','E','C','T',' ',
1168 '`','C','o','m','p','o','n','e','n','t','_','`',
1169 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1170 'C','o','m','p','o','n','e','n','t','s','`',' ',
1171 'W','H','E','R','E',' ',
1172 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1177 /* fill in the data */
1179 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1181 return ERROR_NOT_ENOUGH_MEMORY;
1183 list_init( &feature->Children );
1184 list_init( &feature->Components );
1186 feature->Feature = msi_dup_record_field( row, 1 );
1188 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1190 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1191 feature->Title = msi_dup_record_field( row, 3 );
1192 feature->Description = msi_dup_record_field( row, 4 );
1194 if (!MSI_RecordIsNull(row,5))
1195 feature->Display = MSI_RecordGetInteger(row,5);
1197 feature->Level= MSI_RecordGetInteger(row,6);
1198 feature->Directory = msi_dup_record_field( row, 7 );
1199 feature->Attributes = MSI_RecordGetInteger(row,8);
1201 feature->Installed = INSTALLSTATE_UNKNOWN;
1202 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1204 list_add_tail( &package->features, &feature->entry );
1206 /* load feature components */
1208 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1209 if (rc != ERROR_SUCCESS)
1210 return ERROR_SUCCESS;
1212 ilfs.package = package;
1213 ilfs.feature = feature;
1215 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1216 msiobj_release(&view->hdr);
1218 return ERROR_SUCCESS;
1221 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1223 MSIPACKAGE* package = param;
1224 MSIFEATURE *parent, *child;
1226 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1228 return ERROR_FUNCTION_FAILED;
1230 if (!child->Feature_Parent)
1231 return ERROR_SUCCESS;
1233 parent = find_feature_by_name( package, child->Feature_Parent );
1235 return ERROR_FUNCTION_FAILED;
1237 add_feature_child( parent, child );
1238 return ERROR_SUCCESS;
1241 static UINT load_all_features( MSIPACKAGE *package )
1243 static const WCHAR query[] = {
1244 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1245 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1246 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1250 if (!list_empty(&package->features))
1251 return ERROR_SUCCESS;
1253 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1254 if (r != ERROR_SUCCESS)
1257 r = MSI_IterateRecords( view, NULL, load_feature, package );
1258 if (r != ERROR_SUCCESS)
1261 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1262 msiobj_release( &view->hdr );
1267 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1278 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1280 static const WCHAR query[] = {
1281 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1282 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1283 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1284 MSIQUERY *view = NULL;
1285 MSIRECORD *row = NULL;
1288 TRACE("%s\n", debugstr_w(file->File));
1290 r = MSI_OpenQuery(package->db, &view, query, file->File);
1291 if (r != ERROR_SUCCESS)
1294 r = MSI_ViewExecute(view, NULL);
1295 if (r != ERROR_SUCCESS)
1298 r = MSI_ViewFetch(view, &row);
1299 if (r != ERROR_SUCCESS)
1302 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1303 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1304 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1305 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1306 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1309 if (view) msiobj_release(&view->hdr);
1310 if (row) msiobj_release(&row->hdr);
1314 static UINT load_file(MSIRECORD *row, LPVOID param)
1316 MSIPACKAGE* package = param;
1320 /* fill in the data */
1322 file = msi_alloc_zero( sizeof (MSIFILE) );
1324 return ERROR_NOT_ENOUGH_MEMORY;
1326 file->File = msi_dup_record_field( row, 1 );
1328 component = MSI_RecordGetString( row, 2 );
1329 file->Component = get_loaded_component( package, component );
1331 if (!file->Component)
1333 WARN("Component not found: %s\n", debugstr_w(component));
1334 msi_free(file->File);
1336 return ERROR_SUCCESS;
1339 file->FileName = msi_dup_record_field( row, 3 );
1340 reduce_to_longfilename( file->FileName );
1342 file->ShortName = msi_dup_record_field( row, 3 );
1343 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1345 file->FileSize = MSI_RecordGetInteger( row, 4 );
1346 file->Version = msi_dup_record_field( row, 5 );
1347 file->Language = msi_dup_record_field( row, 6 );
1348 file->Attributes = MSI_RecordGetInteger( row, 7 );
1349 file->Sequence = MSI_RecordGetInteger( row, 8 );
1351 file->state = msifs_invalid;
1353 /* if the compressed bits are not set in the file attributes,
1354 * then read the information from the package word count property
1356 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1358 file->IsCompressed = FALSE;
1360 else if (file->Attributes &
1361 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1363 file->IsCompressed = TRUE;
1365 else if (file->Attributes & msidbFileAttributesNoncompressed)
1367 file->IsCompressed = FALSE;
1371 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1374 load_file_hash(package, file);
1376 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1378 list_add_tail( &package->files, &file->entry );
1380 return ERROR_SUCCESS;
1383 static UINT load_all_files(MSIPACKAGE *package)
1387 static const WCHAR Query[] =
1388 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1389 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1390 '`','S','e','q','u','e','n','c','e','`', 0};
1392 if (!list_empty(&package->files))
1393 return ERROR_SUCCESS;
1395 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1396 if (rc != ERROR_SUCCESS)
1397 return ERROR_SUCCESS;
1399 rc = MSI_IterateRecords(view, NULL, load_file, package);
1400 msiobj_release(&view->hdr);
1402 return ERROR_SUCCESS;
1405 static UINT load_folder( MSIRECORD *row, LPVOID param )
1407 MSIPACKAGE *package = param;
1408 static WCHAR szEmpty[] = { 0 };
1409 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1412 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1414 return ERROR_NOT_ENOUGH_MEMORY;
1416 folder->Directory = msi_dup_record_field( row, 1 );
1418 TRACE("%s\n", debugstr_w(folder->Directory));
1420 p = msi_dup_record_field(row, 3);
1422 /* split src and target dir */
1424 src_short = folder_split_path( p, ':' );
1426 /* split the long and short paths */
1427 tgt_long = folder_split_path( tgt_short, '|' );
1428 src_long = folder_split_path( src_short, '|' );
1430 /* check for no-op dirs */
1431 if (!lstrcmpW(szDot, tgt_short))
1432 tgt_short = szEmpty;
1433 if (!lstrcmpW(szDot, src_short))
1434 src_short = szEmpty;
1437 tgt_long = tgt_short;
1440 src_short = tgt_short;
1441 src_long = tgt_long;
1445 src_long = src_short;
1447 /* FIXME: use the target short path too */
1448 folder->TargetDefault = strdupW(tgt_long);
1449 folder->SourceShortPath = strdupW(src_short);
1450 folder->SourceLongPath = strdupW(src_long);
1453 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1454 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1455 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1457 folder->Parent = msi_dup_record_field( row, 2 );
1459 folder->Property = msi_dup_property( package, folder->Directory );
1461 list_add_tail( &package->folders, &folder->entry );
1463 TRACE("returning %p\n", folder);
1465 return ERROR_SUCCESS;
1468 static UINT load_all_folders( MSIPACKAGE *package )
1470 static const WCHAR query[] = {
1471 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1472 '`','D','i','r','e','c','t','o','r','y','`',0 };
1476 if (!list_empty(&package->folders))
1477 return ERROR_SUCCESS;
1479 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1480 if (r != ERROR_SUCCESS)
1483 r = MSI_IterateRecords(view, NULL, load_folder, package);
1484 msiobj_release(&view->hdr);
1489 * I am not doing any of the costing functionality yet.
1490 * Mostly looking at doing the Component and Feature loading
1492 * The native MSI does A LOT of modification to tables here. Mostly adding
1493 * a lot of temporary columns to the Feature and Component tables.
1495 * note: Native msi also tracks the short filename. But I am only going to
1496 * track the long ones. Also looking at this directory table
1497 * it appears that the directory table does not get the parents
1498 * resolved base on property only based on their entries in the
1501 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1503 static const WCHAR szCosting[] =
1504 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1506 MSI_SetPropertyW(package, szCosting, szZero);
1507 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1509 load_all_folders( package );
1510 load_all_components( package );
1511 load_all_features( package );
1512 load_all_files( package );
1514 return ERROR_SUCCESS;
1517 static UINT execute_script(MSIPACKAGE *package, UINT script )
1520 UINT rc = ERROR_SUCCESS;
1522 TRACE("Executing Script %i\n",script);
1524 if (!package->script)
1526 ERR("no script!\n");
1527 return ERROR_FUNCTION_FAILED;
1530 for (i = 0; i < package->script->ActionCount[script]; i++)
1533 action = package->script->Actions[script][i];
1534 ui_actionstart(package, action);
1535 TRACE("Executing Action (%s)\n",debugstr_w(action));
1536 rc = ACTION_PerformAction(package, action, script, TRUE);
1537 if (rc != ERROR_SUCCESS)
1540 msi_free_action_script(package, script);
1544 static UINT ACTION_FileCost(MSIPACKAGE *package)
1546 return ERROR_SUCCESS;
1549 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1555 state = MsiQueryProductStateW(package->ProductCode);
1557 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1559 if (!comp->ComponentId)
1562 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1563 comp->Installed = INSTALLSTATE_ABSENT;
1566 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1567 package->Context, comp->ComponentId,
1569 if (r != ERROR_SUCCESS)
1570 comp->Installed = INSTALLSTATE_ABSENT;
1575 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1577 MSIFEATURE *feature;
1580 state = MsiQueryProductStateW(package->ProductCode);
1582 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1584 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1585 feature->Installed = INSTALLSTATE_ABSENT;
1588 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1594 static BOOL process_state_property(MSIPACKAGE* package, int level,
1595 LPCWSTR property, INSTALLSTATE state)
1598 MSIFEATURE *feature;
1600 override = msi_dup_property( package, property );
1604 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1606 if (lstrcmpW(property, szRemove) &&
1607 (feature->Level <= 0 || feature->Level > level))
1610 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1612 if (strcmpiW(override, szAll)==0)
1613 msi_feature_set_state(package, feature, state);
1616 LPWSTR ptr = override;
1617 LPWSTR ptr2 = strchrW(override,',');
1621 int len = ptr2 - ptr;
1623 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1624 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1626 msi_feature_set_state(package, feature, state);
1632 ptr2 = strchrW(ptr,',');
1644 static BOOL process_overrides( MSIPACKAGE *package, int level )
1646 static const WCHAR szAddLocal[] =
1647 {'A','D','D','L','O','C','A','L',0};
1648 static const WCHAR szAddSource[] =
1649 {'A','D','D','S','O','U','R','C','E',0};
1650 static const WCHAR szAdvertise[] =
1651 {'A','D','V','E','R','T','I','S','E',0};
1654 /* all these activation/deactivation things happen in order and things
1655 * later on the list override things earlier on the list.
1657 * 0 INSTALLLEVEL processing
1670 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1671 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1672 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1673 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1674 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1677 MSI_SetPropertyW( package, szPreselected, szOne );
1682 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1685 static const WCHAR szlevel[] =
1686 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1687 MSICOMPONENT* component;
1688 MSIFEATURE *feature;
1690 TRACE("Checking Install Level\n");
1692 level = msi_get_property_int(package, szlevel, 1);
1694 if (!msi_get_property_int( package, szPreselected, 0 ))
1696 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1698 BOOL feature_state = ((feature->Level > 0) &&
1699 (feature->Level <= level));
1701 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1703 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1704 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1705 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1706 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1708 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1712 /* disable child features of unselected parent features */
1713 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1717 if (feature->Level > 0 && feature->Level <= level)
1720 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1721 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1726 * now we want to enable or disable components base on feature
1729 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1733 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1734 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1736 if (!feature->Level)
1739 /* features with components that have compressed files are made local */
1740 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1742 if (cl->component->Enabled &&
1743 cl->component->ForceLocalState &&
1744 feature->Action == INSTALLSTATE_SOURCE)
1746 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1751 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1753 component = cl->component;
1755 if (!component->Enabled)
1758 switch (feature->Action)
1760 case INSTALLSTATE_ABSENT:
1761 component->anyAbsent = 1;
1763 case INSTALLSTATE_ADVERTISED:
1764 component->hasAdvertiseFeature = 1;
1766 case INSTALLSTATE_SOURCE:
1767 component->hasSourceFeature = 1;
1769 case INSTALLSTATE_LOCAL:
1770 component->hasLocalFeature = 1;
1772 case INSTALLSTATE_DEFAULT:
1773 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1774 component->hasAdvertiseFeature = 1;
1775 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1776 component->hasSourceFeature = 1;
1778 component->hasLocalFeature = 1;
1786 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1788 /* if the component isn't enabled, leave it alone */
1789 if (!component->Enabled)
1792 /* check if it's local or source */
1793 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1794 (component->hasLocalFeature || component->hasSourceFeature))
1796 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1797 !component->ForceLocalState)
1798 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1800 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1804 /* if any feature is local, the component must be local too */
1805 if (component->hasLocalFeature)
1807 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1811 if (component->hasSourceFeature)
1813 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1817 if (component->hasAdvertiseFeature)
1819 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1823 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1824 if (component->anyAbsent)
1825 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1828 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1830 if (component->Action == INSTALLSTATE_DEFAULT)
1832 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1833 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1836 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1837 debugstr_w(component->Component), component->Installed, component->Action);
1841 return ERROR_SUCCESS;
1844 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1846 MSIPACKAGE *package = param;
1851 name = MSI_RecordGetString(row,1);
1853 f = get_loaded_folder(package, name);
1854 if (!f) return ERROR_SUCCESS;
1856 /* reset the ResolvedTarget */
1857 msi_free(f->ResolvedTarget);
1858 f->ResolvedTarget = NULL;
1860 /* This helper function now does ALL the work */
1861 TRACE("Dir %s ...\n",debugstr_w(name));
1862 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1863 TRACE("resolves to %s\n",debugstr_w(path));
1866 return ERROR_SUCCESS;
1869 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1871 MSIPACKAGE *package = param;
1873 MSIFEATURE *feature;
1875 name = MSI_RecordGetString( row, 1 );
1877 feature = get_loaded_feature( package, name );
1879 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1883 Condition = MSI_RecordGetString(row,3);
1885 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1887 int level = MSI_RecordGetInteger(row,2);
1888 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1889 feature->Level = level;
1892 return ERROR_SUCCESS;
1895 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1897 static const WCHAR name_fmt[] =
1898 {'%','u','.','%','u','.','%','u','.','%','u',0};
1899 static const WCHAR name[] = {'\\',0};
1900 VS_FIXEDFILEINFO *lpVer;
1901 WCHAR filever[0x100];
1907 TRACE("%s\n", debugstr_w(filename));
1909 versize = GetFileVersionInfoSizeW( filename, &handle );
1913 version = msi_alloc( versize );
1914 GetFileVersionInfoW( filename, 0, versize, version );
1916 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1918 msi_free( version );
1922 sprintfW( filever, name_fmt,
1923 HIWORD(lpVer->dwFileVersionMS),
1924 LOWORD(lpVer->dwFileVersionMS),
1925 HIWORD(lpVer->dwFileVersionLS),
1926 LOWORD(lpVer->dwFileVersionLS));
1928 msi_free( version );
1930 return strdupW( filever );
1933 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1935 LPWSTR file_version;
1938 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1940 MSICOMPONENT* comp = file->Component;
1946 if (file->IsCompressed)
1947 comp->ForceLocalState = TRUE;
1949 /* calculate target */
1950 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1952 msi_free(file->TargetPath);
1954 TRACE("file %s is named %s\n",
1955 debugstr_w(file->File), debugstr_w(file->FileName));
1957 file->TargetPath = build_directory_name(2, p, file->FileName);
1961 TRACE("file %s resolves to %s\n",
1962 debugstr_w(file->File), debugstr_w(file->TargetPath));
1964 /* don't check files of components that aren't installed */
1965 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1966 comp->Installed == INSTALLSTATE_ABSENT)
1968 file->state = msifs_missing; /* assume files are missing */
1972 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1974 file->state = msifs_missing;
1975 comp->Cost += file->FileSize;
1979 if (file->Version &&
1980 (file_version = msi_get_disk_file_version( file->TargetPath )))
1982 TRACE("new %s old %s\n", debugstr_w(file->Version),
1983 debugstr_w(file_version));
1984 /* FIXME: seems like a bad way to compare version numbers */
1985 if (lstrcmpiW(file_version, file->Version)<0)
1987 file->state = msifs_overwrite;
1988 comp->Cost += file->FileSize;
1991 file->state = msifs_present;
1992 msi_free( file_version );
1995 file->state = msifs_present;
1998 return ERROR_SUCCESS;
2002 * A lot is done in this function aside from just the costing.
2003 * The costing needs to be implemented at some point but for now I am going
2004 * to focus on the directory building
2007 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2009 static const WCHAR ExecSeqQuery[] =
2010 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2011 '`','D','i','r','e','c','t','o','r','y','`',0};
2012 static const WCHAR ConditionQuery[] =
2013 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2014 '`','C','o','n','d','i','t','i','o','n','`',0};
2015 static const WCHAR szCosting[] =
2016 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2017 static const WCHAR szlevel[] =
2018 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2019 static const WCHAR szOutOfDiskSpace[] =
2020 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2022 UINT rc = ERROR_SUCCESS;
2026 TRACE("Building Directory properties\n");
2028 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2029 if (rc == ERROR_SUCCESS)
2031 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2033 msiobj_release(&view->hdr);
2036 /* read components states from the registry */
2037 ACTION_GetComponentInstallStates(package);
2038 ACTION_GetFeatureInstallStates(package);
2040 TRACE("File calculations\n");
2041 msi_check_file_install_states( package );
2043 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2045 TRACE("Evaluating Condition Table\n");
2047 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2048 if (rc == ERROR_SUCCESS)
2050 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2051 msiobj_release( &view->hdr );
2054 TRACE("Enabling or Disabling Components\n");
2055 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2057 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2059 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2060 comp->Enabled = FALSE;
2063 comp->Enabled = TRUE;
2067 MSI_SetPropertyW(package,szCosting,szOne);
2068 /* set default run level if not set */
2069 level = msi_dup_property( package, szlevel );
2071 MSI_SetPropertyW(package,szlevel, szOne);
2074 /* FIXME: check volume disk space */
2075 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2077 return MSI_SetFeatureStates(package);
2080 /* OK this value is "interpreted" and then formatted based on the
2081 first few characters */
2082 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2087 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2093 LPWSTR deformated = NULL;
2096 deformat_string(package, &value[2], &deformated);
2098 /* binary value type */
2102 *size = (strlenW(ptr)/2)+1;
2104 *size = strlenW(ptr)/2;
2106 data = msi_alloc(*size);
2112 /* if uneven pad with a zero in front */
2118 data[count] = (BYTE)strtol(byte,NULL,0);
2120 TRACE("Uneven byte count\n");
2128 data[count] = (BYTE)strtol(byte,NULL,0);
2131 msi_free(deformated);
2133 TRACE("Data %i bytes(%i)\n",*size,count);
2140 deformat_string(package, &value[1], &deformated);
2143 *size = sizeof(DWORD);
2144 data = msi_alloc(*size);
2150 if ( (*p < '0') || (*p > '9') )
2156 if (deformated[0] == '-')
2159 TRACE("DWORD %i\n",*(LPDWORD)data);
2161 msi_free(deformated);
2166 static const WCHAR szMulti[] = {'[','~',']',0};
2175 *type=REG_EXPAND_SZ;
2183 if (strstrW(value,szMulti))
2184 *type = REG_MULTI_SZ;
2186 /* remove initial delimiter */
2187 if (!strncmpW(value, szMulti, 3))
2190 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2192 /* add double NULL terminator */
2193 if (*type == REG_MULTI_SZ)
2195 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2196 data = msi_realloc_zero(data, *size);
2202 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2209 if (msi_get_property_int( package, szAllUsers, 0 ))
2211 *root_key = HKEY_LOCAL_MACHINE;
2216 *root_key = HKEY_CURRENT_USER;
2221 *root_key = HKEY_CLASSES_ROOT;
2225 *root_key = HKEY_CURRENT_USER;
2229 *root_key = HKEY_LOCAL_MACHINE;
2233 *root_key = HKEY_USERS;
2237 ERR("Unknown root %i\n", root);
2244 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2246 MSIPACKAGE *package = param;
2247 LPSTR value_data = NULL;
2248 HKEY root_key, hkey;
2251 LPCWSTR szRoot, component, name, key, value;
2256 BOOL check_first = FALSE;
2259 ui_progress(package,2,0,0,0);
2266 component = MSI_RecordGetString(row, 6);
2267 comp = get_loaded_component(package,component);
2269 return ERROR_SUCCESS;
2271 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2273 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2274 comp->Action = comp->Installed;
2275 return ERROR_SUCCESS;
2277 comp->Action = INSTALLSTATE_LOCAL;
2279 name = MSI_RecordGetString(row, 4);
2280 if( MSI_RecordIsNull(row,5) && name )
2282 /* null values can have special meanings */
2283 if (name[0]=='-' && name[1] == 0)
2284 return ERROR_SUCCESS;
2285 else if ((name[0]=='+' && name[1] == 0) ||
2286 (name[0] == '*' && name[1] == 0))
2291 root = MSI_RecordGetInteger(row,2);
2292 key = MSI_RecordGetString(row, 3);
2294 szRoot = get_root_key( package, root, &root_key );
2296 return ERROR_SUCCESS;
2298 deformat_string(package, key , &deformated);
2299 size = strlenW(deformated) + strlenW(szRoot) + 1;
2300 uikey = msi_alloc(size*sizeof(WCHAR));
2301 strcpyW(uikey,szRoot);
2302 strcatW(uikey,deformated);
2304 if (RegCreateKeyW( root_key, deformated, &hkey))
2306 ERR("Could not create key %s\n",debugstr_w(deformated));
2307 msi_free(deformated);
2309 return ERROR_SUCCESS;
2311 msi_free(deformated);
2313 value = MSI_RecordGetString(row,5);
2315 value_data = parse_value(package, value, &type, &size);
2318 value_data = (LPSTR)strdupW(szEmpty);
2319 size = sizeof(szEmpty);
2323 deformat_string(package, name, &deformated);
2327 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2329 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2334 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2335 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2337 TRACE("value %s of %s checked already exists\n",
2338 debugstr_w(deformated), debugstr_w(uikey));
2342 TRACE("Checked and setting value %s of %s\n",
2343 debugstr_w(deformated), debugstr_w(uikey));
2344 if (deformated || size)
2345 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2350 uirow = MSI_CreateRecord(3);
2351 MSI_RecordSetStringW(uirow,2,deformated);
2352 MSI_RecordSetStringW(uirow,1,uikey);
2353 if (type == REG_SZ || type == REG_EXPAND_SZ)
2354 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2355 ui_actiondata(package,szWriteRegistryValues,uirow);
2356 msiobj_release( &uirow->hdr );
2358 msi_free(value_data);
2359 msi_free(deformated);
2362 return ERROR_SUCCESS;
2365 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2369 static const WCHAR ExecSeqQuery[] =
2370 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2371 '`','R','e','g','i','s','t','r','y','`',0 };
2373 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2374 if (rc != ERROR_SUCCESS)
2375 return ERROR_SUCCESS;
2377 /* increment progress bar each time action data is sent */
2378 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2380 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2382 msiobj_release(&view->hdr);
2386 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2390 DWORD num_subkeys, num_values;
2394 if ((res = RegDeleteTreeW( hkey_root, key )))
2396 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2401 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2403 if ((res = RegDeleteValueW( hkey, value )))
2405 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2407 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2408 NULL, NULL, NULL, NULL );
2409 RegCloseKey( hkey );
2411 if (!res && !num_subkeys && !num_values)
2413 TRACE("Removing empty key %s\n", debugstr_w(key));
2414 RegDeleteKeyW( hkey_root, key );
2418 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2422 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2424 MSIPACKAGE *package = param;
2425 LPCWSTR component, name, key_str, root_key_str;
2426 LPWSTR deformated_key, deformated_name, ui_key_str;
2429 BOOL delete_key = FALSE;
2434 ui_progress( package, 2, 0, 0, 0 );
2436 component = MSI_RecordGetString( row, 6 );
2437 comp = get_loaded_component( package, component );
2439 return ERROR_SUCCESS;
2441 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2443 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2444 comp->Action = comp->Installed;
2445 return ERROR_SUCCESS;
2447 comp->Action = INSTALLSTATE_ABSENT;
2449 name = MSI_RecordGetString( row, 4 );
2450 if (MSI_RecordIsNull( row, 5 ) && name )
2452 if (name[0] == '+' && !name[1])
2453 return ERROR_SUCCESS;
2454 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2461 root = MSI_RecordGetInteger( row, 2 );
2462 key_str = MSI_RecordGetString( row, 3 );
2464 root_key_str = get_root_key( package, root, &hkey_root );
2466 return ERROR_SUCCESS;
2468 deformat_string( package, key_str, &deformated_key );
2469 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2470 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2471 strcpyW( ui_key_str, root_key_str );
2472 strcatW( ui_key_str, deformated_key );
2474 deformat_string( package, name, &deformated_name );
2476 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2477 msi_free( deformated_key );
2479 uirow = MSI_CreateRecord( 2 );
2480 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2481 MSI_RecordSetStringW( uirow, 2, deformated_name );
2483 ui_actiondata( package, szRemoveRegistryValues, uirow );
2484 msiobj_release( &uirow->hdr );
2486 msi_free( ui_key_str );
2487 msi_free( deformated_name );
2488 return ERROR_SUCCESS;
2491 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2493 MSIPACKAGE *package = param;
2494 LPCWSTR component, name, key_str, root_key_str;
2495 LPWSTR deformated_key, deformated_name, ui_key_str;
2498 BOOL delete_key = FALSE;
2503 ui_progress( package, 2, 0, 0, 0 );
2505 component = MSI_RecordGetString( row, 5 );
2506 comp = get_loaded_component( package, component );
2508 return ERROR_SUCCESS;
2510 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2512 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2513 comp->Action = comp->Installed;
2514 return ERROR_SUCCESS;
2516 comp->Action = INSTALLSTATE_LOCAL;
2518 if ((name = MSI_RecordGetString( row, 4 )))
2520 if (name[0] == '-' && !name[1])
2527 root = MSI_RecordGetInteger( row, 2 );
2528 key_str = MSI_RecordGetString( row, 3 );
2530 root_key_str = get_root_key( package, root, &hkey_root );
2532 return ERROR_SUCCESS;
2534 deformat_string( package, key_str, &deformated_key );
2535 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2536 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2537 strcpyW( ui_key_str, root_key_str );
2538 strcatW( ui_key_str, deformated_key );
2540 deformat_string( package, name, &deformated_name );
2542 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2543 msi_free( deformated_key );
2545 uirow = MSI_CreateRecord( 2 );
2546 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2547 MSI_RecordSetStringW( uirow, 2, deformated_name );
2549 ui_actiondata( package, szRemoveRegistryValues, uirow );
2550 msiobj_release( &uirow->hdr );
2552 msi_free( ui_key_str );
2553 msi_free( deformated_name );
2554 return ERROR_SUCCESS;
2557 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2561 static const WCHAR registry_query[] =
2562 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2563 '`','R','e','g','i','s','t','r','y','`',0 };
2564 static const WCHAR remove_registry_query[] =
2565 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2566 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2568 /* increment progress bar each time action data is sent */
2569 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2571 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2572 if (rc == ERROR_SUCCESS)
2574 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2575 msiobj_release( &view->hdr );
2576 if (rc != ERROR_SUCCESS)
2580 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2581 if (rc == ERROR_SUCCESS)
2583 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2584 msiobj_release( &view->hdr );
2585 if (rc != ERROR_SUCCESS)
2589 return ERROR_SUCCESS;
2592 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2594 package->script->CurrentlyScripting = TRUE;
2596 return ERROR_SUCCESS;
2600 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2605 static const WCHAR q1[]=
2606 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2607 '`','R','e','g','i','s','t','r','y','`',0};
2610 MSIFEATURE *feature;
2613 TRACE("InstallValidate\n");
2615 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2616 if (rc == ERROR_SUCCESS)
2618 MSI_IterateRecords( view, &progress, NULL, package );
2619 msiobj_release( &view->hdr );
2620 total += progress * REG_PROGRESS_VALUE;
2623 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2624 total += COMPONENT_PROGRESS_VALUE;
2626 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2627 total += file->FileSize;
2629 ui_progress(package,0,total,0,0);
2631 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2633 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2634 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2635 feature->ActionRequest);
2638 return ERROR_SUCCESS;
2641 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2643 MSIPACKAGE* package = param;
2644 LPCWSTR cond = NULL;
2645 LPCWSTR message = NULL;
2648 static const WCHAR title[]=
2649 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2651 cond = MSI_RecordGetString(row,1);
2653 r = MSI_EvaluateConditionW(package,cond);
2654 if (r == MSICONDITION_FALSE)
2656 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2659 message = MSI_RecordGetString(row,2);
2660 deformat_string(package,message,&deformated);
2661 MessageBoxW(NULL,deformated,title,MB_OK);
2662 msi_free(deformated);
2665 return ERROR_INSTALL_FAILURE;
2668 return ERROR_SUCCESS;
2671 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2674 MSIQUERY * view = NULL;
2675 static const WCHAR ExecSeqQuery[] =
2676 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2677 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2679 TRACE("Checking launch conditions\n");
2681 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2682 if (rc != ERROR_SUCCESS)
2683 return ERROR_SUCCESS;
2685 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2686 msiobj_release(&view->hdr);
2691 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2695 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2697 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2699 MSIRECORD * row = 0;
2701 LPWSTR deformated,buffer,deformated_name;
2703 static const WCHAR ExecSeqQuery[] =
2704 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2705 '`','R','e','g','i','s','t','r','y','`',' ',
2706 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2707 ' ','=',' ' ,'\'','%','s','\'',0 };
2708 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2709 static const WCHAR fmt2[]=
2710 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2712 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2716 root = MSI_RecordGetInteger(row,2);
2717 key = MSI_RecordGetString(row, 3);
2718 name = MSI_RecordGetString(row, 4);
2719 deformat_string(package, key , &deformated);
2720 deformat_string(package, name, &deformated_name);
2722 len = strlenW(deformated) + 6;
2723 if (deformated_name)
2724 len+=strlenW(deformated_name);
2726 buffer = msi_alloc( len *sizeof(WCHAR));
2728 if (deformated_name)
2729 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2731 sprintfW(buffer,fmt,root,deformated);
2733 msi_free(deformated);
2734 msi_free(deformated_name);
2735 msiobj_release(&row->hdr);
2739 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2741 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2746 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2749 return strdupW( file->TargetPath );
2754 static HKEY openSharedDLLsKey(void)
2757 static const WCHAR path[] =
2758 {'S','o','f','t','w','a','r','e','\\',
2759 'M','i','c','r','o','s','o','f','t','\\',
2760 'W','i','n','d','o','w','s','\\',
2761 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2762 'S','h','a','r','e','d','D','L','L','s',0};
2764 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2768 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2773 DWORD sz = sizeof(count);
2776 hkey = openSharedDLLsKey();
2777 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2778 if (rc != ERROR_SUCCESS)
2784 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2788 hkey = openSharedDLLsKey();
2790 msi_reg_set_val_dword( hkey, path, count );
2792 RegDeleteValueW(hkey,path);
2798 * Return TRUE if the count should be written out and FALSE if not
2800 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2802 MSIFEATURE *feature;
2806 /* only refcount DLLs */
2807 if (comp->KeyPath == NULL ||
2808 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2809 comp->Attributes & msidbComponentAttributesODBCDataSource)
2813 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2814 write = (count > 0);
2816 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2820 /* increment counts */
2821 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2825 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2828 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2830 if ( cl->component == comp )
2835 /* decrement counts */
2836 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2840 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2843 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2845 if ( cl->component == comp )
2850 /* ref count all the files in the component */
2855 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2857 if (file->Component == comp)
2858 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2862 /* add a count for permanent */
2863 if (comp->Attributes & msidbComponentAttributesPermanent)
2866 comp->RefCount = count;
2869 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2872 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2874 WCHAR squished_pc[GUID_SIZE];
2875 WCHAR squished_cc[GUID_SIZE];
2882 squash_guid(package->ProductCode,squished_pc);
2883 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2885 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2889 ui_progress(package,2,0,0,0);
2890 if (!comp->ComponentId)
2893 squash_guid(comp->ComponentId,squished_cc);
2895 msi_free(comp->FullKeypath);
2896 comp->FullKeypath = resolve_keypath( package, comp );
2898 ACTION_RefCountComponent( package, comp );
2900 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2901 debugstr_w(comp->Component),
2902 debugstr_w(squished_cc),
2903 debugstr_w(comp->FullKeypath),
2906 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2907 comp->ActionRequest == INSTALLSTATE_SOURCE)
2909 if (!comp->FullKeypath)
2912 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2913 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2916 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2919 if (rc != ERROR_SUCCESS)
2922 if (comp->Attributes & msidbComponentAttributesPermanent)
2924 static const WCHAR szPermKey[] =
2925 { '0','0','0','0','0','0','0','0','0','0','0','0',
2926 '0','0','0','0','0','0','0','0','0','0','0','0',
2927 '0','0','0','0','0','0','0','0',0 };
2929 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2932 if (comp->Action == INSTALLSTATE_LOCAL)
2933 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2939 WCHAR source[MAX_PATH];
2940 WCHAR base[MAX_PATH];
2943 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2944 static const WCHAR query[] = {
2945 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2946 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2947 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2948 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2949 '`','D','i','s','k','I','d','`',0};
2951 file = get_loaded_file(package, comp->KeyPath);
2955 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2956 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2957 ptr2 = strrchrW(source, '\\') + 1;
2958 msiobj_release(&row->hdr);
2960 lstrcpyW(base, package->PackagePath);
2961 ptr = strrchrW(base, '\\');
2964 sourcepath = resolve_file_source(package, file);
2965 ptr = sourcepath + lstrlenW(base);
2966 lstrcpyW(ptr2, ptr);
2967 msi_free(sourcepath);
2969 msi_reg_set_val_str(hkey, squished_pc, source);
2973 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2975 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2976 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2978 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2980 comp->Action = comp->ActionRequest;
2983 uirow = MSI_CreateRecord(3);
2984 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2985 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2986 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2987 ui_actiondata(package,szProcessComponents,uirow);
2988 msiobj_release( &uirow->hdr );
2991 return ERROR_SUCCESS;
3002 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3003 LPWSTR lpszName, LONG_PTR lParam)
3006 typelib_struct *tl_struct = (typelib_struct*) lParam;
3007 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3011 if (!IS_INTRESOURCE(lpszName))
3013 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3017 sz = strlenW(tl_struct->source)+4;
3018 sz *= sizeof(WCHAR);
3020 if ((INT_PTR)lpszName == 1)
3021 tl_struct->path = strdupW(tl_struct->source);
3024 tl_struct->path = msi_alloc(sz);
3025 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3028 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3029 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3032 msi_free(tl_struct->path);
3033 tl_struct->path = NULL;
3038 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3039 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3041 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3045 msi_free(tl_struct->path);
3046 tl_struct->path = NULL;
3048 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3049 ITypeLib_Release(tl_struct->ptLib);
3054 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3056 MSIPACKAGE* package = param;
3060 typelib_struct tl_struct;
3065 component = MSI_RecordGetString(row,3);
3066 comp = get_loaded_component(package,component);
3068 return ERROR_SUCCESS;
3070 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3072 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3073 comp->Action = comp->Installed;
3074 return ERROR_SUCCESS;
3076 comp->Action = INSTALLSTATE_LOCAL;
3078 file = get_loaded_file( package, comp->KeyPath );
3080 return ERROR_SUCCESS;
3082 ui_actiondata( package, szRegisterTypeLibraries, row );
3084 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3088 guid = MSI_RecordGetString(row,1);
3089 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3090 tl_struct.source = strdupW( file->TargetPath );
3091 tl_struct.path = NULL;
3093 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3094 (LONG_PTR)&tl_struct);
3102 helpid = MSI_RecordGetString(row,6);
3105 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3106 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3110 ERR("Failed to register type library %s\n",
3111 debugstr_w(tl_struct.path));
3113 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3115 ITypeLib_Release(tl_struct.ptLib);
3116 msi_free(tl_struct.path);
3119 ERR("Failed to load type library %s\n",
3120 debugstr_w(tl_struct.source));
3122 FreeLibrary(module);
3123 msi_free(tl_struct.source);
3127 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3130 ERR("Failed to load type library: %08x\n", hr);
3131 return ERROR_INSTALL_FAILURE;
3134 ITypeLib_Release(tlib);
3137 return ERROR_SUCCESS;
3140 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3143 * OK this is a bit confusing.. I am given a _Component key and I believe
3144 * that the file that is being registered as a type library is the "key file
3145 * of that component" which I interpret to mean "The file in the KeyPath of
3150 static const WCHAR Query[] =
3151 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3152 '`','T','y','p','e','L','i','b','`',0};
3154 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3155 if (rc != ERROR_SUCCESS)
3156 return ERROR_SUCCESS;
3158 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3159 msiobj_release(&view->hdr);
3163 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3165 MSIPACKAGE *package = param;
3166 LPCWSTR component, guid;
3174 component = MSI_RecordGetString( row, 3 );
3175 comp = get_loaded_component( package, component );
3177 return ERROR_SUCCESS;
3179 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3181 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3182 comp->Action = comp->Installed;
3183 return ERROR_SUCCESS;
3185 comp->Action = INSTALLSTATE_ABSENT;
3187 ui_actiondata( package, szUnregisterTypeLibraries, row );
3189 guid = MSI_RecordGetString( row, 1 );
3190 CLSIDFromString( (LPCWSTR)guid, &libid );
3191 version = MSI_RecordGetInteger( row, 4 );
3192 language = MSI_RecordGetInteger( row, 2 );
3195 syskind = SYS_WIN64;
3197 syskind = SYS_WIN32;
3200 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3203 WARN("Failed to unregister typelib: %08x\n", hr);
3206 return ERROR_SUCCESS;
3209 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3213 static const WCHAR query[] =
3214 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3215 '`','T','y','p','e','L','i','b','`',0};
3217 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3218 if (rc != ERROR_SUCCESS)
3219 return ERROR_SUCCESS;
3221 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3222 msiobj_release( &view->hdr );
3226 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3228 static const WCHAR szlnk[] = {'.','l','n','k',0};
3229 LPCWSTR directory, extension;
3230 LPWSTR link_folder, link_file, filename;
3232 directory = MSI_RecordGetString( row, 2 );
3233 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3235 /* may be needed because of a bug somewhere else */
3236 create_full_pathW( link_folder );
3238 filename = msi_dup_record_field( row, 3 );
3239 reduce_to_longfilename( filename );
3241 extension = strchrW( filename, '.' );
3242 if (!extension || strcmpiW( extension, szlnk ))
3244 int len = strlenW( filename );
3245 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3246 memcpy( filename + len, szlnk, sizeof(szlnk) );
3248 link_file = build_directory_name( 2, link_folder, filename );
3249 msi_free( link_folder );
3250 msi_free( filename );
3255 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3257 MSIPACKAGE *package = param;
3258 LPWSTR link_file, deformated, path;
3259 LPCWSTR component, target;
3261 IShellLinkW *sl = NULL;
3262 IPersistFile *pf = NULL;
3265 component = MSI_RecordGetString(row, 4);
3266 comp = get_loaded_component(package, component);
3268 return ERROR_SUCCESS;
3270 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3272 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3273 comp->Action = comp->Installed;
3274 return ERROR_SUCCESS;
3276 comp->Action = INSTALLSTATE_LOCAL;
3278 ui_actiondata(package,szCreateShortcuts,row);
3280 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3281 &IID_IShellLinkW, (LPVOID *) &sl );
3285 ERR("CLSID_ShellLink not available\n");
3289 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3292 ERR("QueryInterface(IID_IPersistFile) failed\n");
3296 target = MSI_RecordGetString(row, 5);
3297 if (strchrW(target, '['))
3299 deformat_string(package, target, &deformated);
3300 IShellLinkW_SetPath(sl,deformated);
3301 msi_free(deformated);
3305 FIXME("poorly handled shortcut format, advertised shortcut\n");
3306 IShellLinkW_SetPath(sl,comp->FullKeypath);
3309 if (!MSI_RecordIsNull(row,6))
3311 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3312 deformat_string(package, arguments, &deformated);
3313 IShellLinkW_SetArguments(sl,deformated);
3314 msi_free(deformated);
3317 if (!MSI_RecordIsNull(row,7))
3319 LPCWSTR description = MSI_RecordGetString(row, 7);
3320 IShellLinkW_SetDescription(sl, description);
3323 if (!MSI_RecordIsNull(row,8))
3324 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3326 if (!MSI_RecordIsNull(row,9))
3329 LPCWSTR icon = MSI_RecordGetString(row, 9);
3331 path = build_icon_path(package, icon);
3332 index = MSI_RecordGetInteger(row,10);
3334 /* no value means 0 */
3335 if (index == MSI_NULL_INTEGER)
3338 IShellLinkW_SetIconLocation(sl, path, index);
3342 if (!MSI_RecordIsNull(row,11))
3343 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3345 if (!MSI_RecordIsNull(row,12))
3347 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3348 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3350 IShellLinkW_SetWorkingDirectory(sl, path);
3354 link_file = get_link_file(package, row);
3356 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3357 IPersistFile_Save(pf, link_file, FALSE);
3359 msi_free(link_file);
3363 IPersistFile_Release( pf );
3365 IShellLinkW_Release( sl );
3367 return ERROR_SUCCESS;
3370 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3375 static const WCHAR Query[] =
3376 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3377 '`','S','h','o','r','t','c','u','t','`',0};
3379 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3380 if (rc != ERROR_SUCCESS)
3381 return ERROR_SUCCESS;
3383 res = CoInitialize( NULL );
3385 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3386 msiobj_release(&view->hdr);
3394 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3396 MSIPACKAGE *package = param;
3401 component = MSI_RecordGetString( row, 4 );
3402 comp = get_loaded_component( package, component );
3404 return ERROR_SUCCESS;
3406 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3408 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3409 comp->Action = comp->Installed;
3410 return ERROR_SUCCESS;
3412 comp->Action = INSTALLSTATE_ABSENT;
3414 ui_actiondata( package, szRemoveShortcuts, row );
3416 link_file = get_link_file( package, row );
3418 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3419 if (!DeleteFileW( link_file ))
3421 WARN("Failed to remove shortcut file %u\n", GetLastError());
3423 msi_free( link_file );
3425 return ERROR_SUCCESS;
3428 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3432 static const WCHAR query[] =
3433 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3434 '`','S','h','o','r','t','c','u','t','`',0};
3436 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3437 if (rc != ERROR_SUCCESS)
3438 return ERROR_SUCCESS;
3440 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3441 msiobj_release( &view->hdr );
3446 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3448 MSIPACKAGE* package = param;
3456 FileName = MSI_RecordGetString(row,1);
3459 ERR("Unable to get FileName\n");
3460 return ERROR_SUCCESS;
3463 FilePath = build_icon_path(package,FileName);
3465 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3467 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3468 FILE_ATTRIBUTE_NORMAL, NULL);
3470 if (the_file == INVALID_HANDLE_VALUE)
3472 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3474 return ERROR_SUCCESS;
3481 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3482 if (rc != ERROR_SUCCESS)
3484 ERR("Failed to get stream\n");
3485 CloseHandle(the_file);
3486 DeleteFileW(FilePath);
3489 WriteFile(the_file,buffer,sz,&write,NULL);
3490 } while (sz == 1024);
3493 CloseHandle(the_file);
3495 return ERROR_SUCCESS;
3498 static UINT msi_publish_icons(MSIPACKAGE *package)
3503 static const WCHAR query[]= {
3504 'S','E','L','E','C','T',' ','*',' ',
3505 'F','R','O','M',' ','`','I','c','o','n','`',0};
3507 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3508 if (r == ERROR_SUCCESS)
3510 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3511 msiobj_release(&view->hdr);
3514 return ERROR_SUCCESS;
3517 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3523 MSISOURCELISTINFO *info;
3525 r = RegCreateKeyW(hkey, szSourceList, &source);
3526 if (r != ERROR_SUCCESS)
3529 RegCloseKey(source);
3531 buffer = strrchrW(package->PackagePath, '\\') + 1;
3532 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3533 package->Context, MSICODE_PRODUCT,
3534 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3535 if (r != ERROR_SUCCESS)
3538 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3539 package->Context, MSICODE_PRODUCT,
3540 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3541 if (r != ERROR_SUCCESS)
3544 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3545 package->Context, MSICODE_PRODUCT,
3546 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3547 if (r != ERROR_SUCCESS)
3550 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3552 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3553 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3554 info->options, info->value);
3556 MsiSourceListSetInfoW(package->ProductCode, NULL,
3557 info->context, info->options,
3558 info->property, info->value);
3561 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3563 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3564 disk->context, disk->options,
3565 disk->disk_id, disk->volume_label, disk->disk_prompt);
3568 return ERROR_SUCCESS;
3571 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3573 MSIHANDLE hdb, suminfo;
3574 WCHAR guids[MAX_PATH];
3575 WCHAR packcode[SQUISH_GUID_SIZE];
3582 static const WCHAR szProductLanguage[] =
3583 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3584 static const WCHAR szARPProductIcon[] =
3585 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3586 static const WCHAR szProductVersion[] =
3587 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3588 static const WCHAR szAssignment[] =
3589 {'A','s','s','i','g','n','m','e','n','t',0};
3590 static const WCHAR szAdvertiseFlags[] =
3591 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3592 static const WCHAR szClients[] =
3593 {'C','l','i','e','n','t','s',0};
3594 static const WCHAR szColon[] = {':',0};
3596 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3597 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3600 langid = msi_get_property_int(package, szProductLanguage, 0);
3601 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3604 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3606 buffer = msi_dup_property(package, szARPProductIcon);
3609 LPWSTR path = build_icon_path(package,buffer);
3610 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3615 buffer = msi_dup_property(package, szProductVersion);
3618 DWORD verdword = msi_version_str_to_dword(buffer);
3619 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3623 msi_reg_set_val_dword(hkey, szAssignment, 0);
3624 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3625 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3626 msi_reg_set_val_str(hkey, szClients, szColon);
3628 hdb = alloc_msihandle(&package->db->hdr);
3630 return ERROR_NOT_ENOUGH_MEMORY;
3632 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3633 MsiCloseHandle(hdb);
3634 if (r != ERROR_SUCCESS)
3638 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3639 NULL, guids, &size);
3640 if (r != ERROR_SUCCESS)
3643 ptr = strchrW(guids, ';');
3645 squash_guid(guids, packcode);
3646 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3649 MsiCloseHandle(suminfo);
3650 return ERROR_SUCCESS;
3653 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3658 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3660 static const WCHAR szUpgradeCode[] =
3661 {'U','p','g','r','a','d','e','C','o','d','e',0};
3663 upgrade = msi_dup_property(package, szUpgradeCode);
3665 return ERROR_SUCCESS;
3667 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3669 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3670 if (r != ERROR_SUCCESS)
3675 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3676 if (r != ERROR_SUCCESS)
3680 squash_guid(package->ProductCode, squashed_pc);
3681 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3690 static BOOL msi_check_publish(MSIPACKAGE *package)
3692 MSIFEATURE *feature;
3694 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3696 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3703 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3705 MSIFEATURE *feature;
3707 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3709 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3716 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3718 WCHAR patch_squashed[GUID_SIZE];
3721 UINT r = ERROR_FUNCTION_FAILED;
3723 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3725 if (res != ERROR_SUCCESS)
3726 return ERROR_FUNCTION_FAILED;
3728 squash_guid(package->patch->patchcode, patch_squashed);
3730 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3731 (const BYTE *)patch_squashed,
3732 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3733 if (res != ERROR_SUCCESS)
3736 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3737 (const BYTE *)package->patch->transforms,
3738 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3739 if (res == ERROR_SUCCESS)
3743 RegCloseKey(patches);
3748 * 99% of the work done here is only done for
3749 * advertised installs. However this is where the
3750 * Icon table is processed and written out
3751 * so that is what I am going to do here.
3753 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3756 HKEY hukey = NULL, hudkey = NULL;
3759 /* FIXME: also need to publish if the product is in advertise mode */
3760 if (!msi_check_publish(package))
3761 return ERROR_SUCCESS;
3763 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3765 if (rc != ERROR_SUCCESS)
3768 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3769 NULL, &hudkey, TRUE);
3770 if (rc != ERROR_SUCCESS)
3773 rc = msi_publish_upgrade_code(package);
3774 if (rc != ERROR_SUCCESS)
3779 rc = msi_publish_patch(package, hukey, hudkey);
3780 if (rc != ERROR_SUCCESS)
3784 rc = msi_publish_product_properties(package, hukey);
3785 if (rc != ERROR_SUCCESS)
3788 rc = msi_publish_sourcelist(package, hukey);
3789 if (rc != ERROR_SUCCESS)
3792 rc = msi_publish_icons(package);
3795 uirow = MSI_CreateRecord( 1 );
3796 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3797 ui_actiondata( package, szPublishProduct, uirow );
3798 msiobj_release( &uirow->hdr );
3801 RegCloseKey(hudkey);
3806 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3808 WCHAR *filename, *ptr, *folder, *ret;
3809 const WCHAR *dirprop;
3811 filename = msi_dup_record_field( row, 2 );
3812 if (filename && (ptr = strchrW( filename, '|' )))
3817 dirprop = MSI_RecordGetString( row, 3 );
3820 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3822 folder = msi_dup_property( package, dirprop );
3825 folder = msi_dup_property( package, szWindowsFolder );
3829 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3830 msi_free( filename );
3834 ret = build_directory_name( 2, folder, ptr );
3836 msi_free( filename );
3841 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3843 MSIPACKAGE *package = param;
3844 LPCWSTR component, section, key, value, identifier;
3845 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3850 component = MSI_RecordGetString(row, 8);
3851 comp = get_loaded_component(package,component);
3853 return ERROR_SUCCESS;
3855 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3857 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3858 comp->Action = comp->Installed;
3859 return ERROR_SUCCESS;
3861 comp->Action = INSTALLSTATE_LOCAL;
3863 identifier = MSI_RecordGetString(row,1);
3864 section = MSI_RecordGetString(row,4);
3865 key = MSI_RecordGetString(row,5);
3866 value = MSI_RecordGetString(row,6);
3867 action = MSI_RecordGetInteger(row,7);
3869 deformat_string(package,section,&deformated_section);
3870 deformat_string(package,key,&deformated_key);
3871 deformat_string(package,value,&deformated_value);
3873 fullname = get_ini_file_name(package, row);
3877 TRACE("Adding value %s to section %s in %s\n",
3878 debugstr_w(deformated_key), debugstr_w(deformated_section),
3879 debugstr_w(fullname));
3880 WritePrivateProfileStringW(deformated_section, deformated_key,
3881 deformated_value, fullname);
3883 else if (action == 1)
3886 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3887 returned, 10, fullname);
3888 if (returned[0] == 0)
3890 TRACE("Adding value %s to section %s in %s\n",
3891 debugstr_w(deformated_key), debugstr_w(deformated_section),
3892 debugstr_w(fullname));
3894 WritePrivateProfileStringW(deformated_section, deformated_key,
3895 deformated_value, fullname);
3898 else if (action == 3)
3899 FIXME("Append to existing section not yet implemented\n");
3901 uirow = MSI_CreateRecord(4);
3902 MSI_RecordSetStringW(uirow,1,identifier);
3903 MSI_RecordSetStringW(uirow,2,deformated_section);
3904 MSI_RecordSetStringW(uirow,3,deformated_key);
3905 MSI_RecordSetStringW(uirow,4,deformated_value);
3906 ui_actiondata(package,szWriteIniValues,uirow);
3907 msiobj_release( &uirow->hdr );
3910 msi_free(deformated_key);
3911 msi_free(deformated_value);
3912 msi_free(deformated_section);
3913 return ERROR_SUCCESS;
3916 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3920 static const WCHAR ExecSeqQuery[] =
3921 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3922 '`','I','n','i','F','i','l','e','`',0};
3924 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3925 if (rc != ERROR_SUCCESS)
3927 TRACE("no IniFile table\n");
3928 return ERROR_SUCCESS;
3931 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3932 msiobj_release(&view->hdr);
3936 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3938 MSIPACKAGE *package = param;
3939 LPCWSTR component, section, key, value, identifier;
3940 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3945 component = MSI_RecordGetString( row, 8 );
3946 comp = get_loaded_component( package, component );
3948 return ERROR_SUCCESS;
3950 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3952 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3953 comp->Action = comp->Installed;
3954 return ERROR_SUCCESS;
3956 comp->Action = INSTALLSTATE_ABSENT;
3958 identifier = MSI_RecordGetString( row, 1 );
3959 section = MSI_RecordGetString( row, 4 );
3960 key = MSI_RecordGetString( row, 5 );
3961 value = MSI_RecordGetString( row, 6 );
3962 action = MSI_RecordGetInteger( row, 7 );
3964 deformat_string( package, section, &deformated_section );
3965 deformat_string( package, key, &deformated_key );
3966 deformat_string( package, value, &deformated_value );
3968 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3970 filename = get_ini_file_name( package, row );
3972 TRACE("Removing key %s from section %s in %s\n",
3973 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3975 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3977 WARN("Unable to remove key %u\n", GetLastError());
3979 msi_free( filename );
3982 FIXME("Unsupported action %d\n", action);
3985 uirow = MSI_CreateRecord( 4 );
3986 MSI_RecordSetStringW( uirow, 1, identifier );
3987 MSI_RecordSetStringW( uirow, 2, deformated_section );
3988 MSI_RecordSetStringW( uirow, 3, deformated_key );
3989 MSI_RecordSetStringW( uirow, 4, deformated_value );
3990 ui_actiondata( package, szRemoveIniValues, uirow );
3991 msiobj_release( &uirow->hdr );
3993 msi_free( deformated_key );
3994 msi_free( deformated_value );
3995 msi_free( deformated_section );
3996 return ERROR_SUCCESS;
3999 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4001 MSIPACKAGE *package = param;
4002 LPCWSTR component, section, key, value, identifier;
4003 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4008 component = MSI_RecordGetString( row, 8 );
4009 comp = get_loaded_component( package, component );
4011 return ERROR_SUCCESS;
4013 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4015 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4016 comp->Action = comp->Installed;
4017 return ERROR_SUCCESS;
4019 comp->Action = INSTALLSTATE_LOCAL;
4021 identifier = MSI_RecordGetString( row, 1 );
4022 section = MSI_RecordGetString( row, 4 );
4023 key = MSI_RecordGetString( row, 5 );
4024 value = MSI_RecordGetString( row, 6 );
4025 action = MSI_RecordGetInteger( row, 7 );
4027 deformat_string( package, section, &deformated_section );
4028 deformat_string( package, key, &deformated_key );
4029 deformat_string( package, value, &deformated_value );
4031 if (action == msidbIniFileActionRemoveLine)
4033 filename = get_ini_file_name( package, row );
4035 TRACE("Removing key %s from section %s in %s\n",
4036 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4038 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4040 WARN("Unable to remove key %u\n", GetLastError());
4042 msi_free( filename );
4045 FIXME("Unsupported action %d\n", action);
4047 uirow = MSI_CreateRecord( 4 );
4048 MSI_RecordSetStringW( uirow, 1, identifier );
4049 MSI_RecordSetStringW( uirow, 2, deformated_section );
4050 MSI_RecordSetStringW( uirow, 3, deformated_key );
4051 MSI_RecordSetStringW( uirow, 4, deformated_value );
4052 ui_actiondata( package, szRemoveIniValues, uirow );
4053 msiobj_release( &uirow->hdr );
4055 msi_free( deformated_key );
4056 msi_free( deformated_value );
4057 msi_free( deformated_section );
4058 return ERROR_SUCCESS;
4061 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4065 static const WCHAR query[] =
4066 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4067 '`','I','n','i','F','i','l','e','`',0};
4068 static const WCHAR remove_query[] =
4069 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4070 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4072 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4073 if (rc == ERROR_SUCCESS)
4075 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4076 msiobj_release( &view->hdr );
4077 if (rc != ERROR_SUCCESS)
4081 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4082 if (rc == ERROR_SUCCESS)
4084 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4085 msiobj_release( &view->hdr );
4086 if (rc != ERROR_SUCCESS)
4090 return ERROR_SUCCESS;
4093 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4095 MSIPACKAGE *package = param;
4100 static const WCHAR ExeStr[] =
4101 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4102 static const WCHAR close[] = {'\"',0};
4104 PROCESS_INFORMATION info;
4109 memset(&si,0,sizeof(STARTUPINFOW));
4111 filename = MSI_RecordGetString(row,1);
4112 file = get_loaded_file( package, filename );
4116 ERR("Unable to find file id %s\n",debugstr_w(filename));
4117 return ERROR_SUCCESS;
4120 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4122 FullName = msi_alloc(len*sizeof(WCHAR));
4123 strcpyW(FullName,ExeStr);
4124 strcatW( FullName, file->TargetPath );
4125 strcatW(FullName,close);
4127 TRACE("Registering %s\n",debugstr_w(FullName));
4128 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4133 CloseHandle(info.hThread);
4134 msi_dialog_check_messages(info.hProcess);
4135 CloseHandle(info.hProcess);
4138 uirow = MSI_CreateRecord( 2 );
4139 MSI_RecordSetStringW( uirow, 1, filename );
4140 uipath = strdupW( file->TargetPath );
4141 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4142 MSI_RecordSetStringW( uirow, 2, uipath );
4143 ui_actiondata( package, szSelfRegModules, uirow );
4144 msiobj_release( &uirow->hdr );
4146 msi_free( FullName );
4148 return ERROR_SUCCESS;
4151 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4155 static const WCHAR ExecSeqQuery[] =
4156 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4157 '`','S','e','l','f','R','e','g','`',0};
4159 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4160 if (rc != ERROR_SUCCESS)
4162 TRACE("no SelfReg table\n");
4163 return ERROR_SUCCESS;
4166 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4167 msiobj_release(&view->hdr);
4169 return ERROR_SUCCESS;
4172 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4174 static const WCHAR regsvr32[] =
4175 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4176 static const WCHAR close[] = {'\"',0};
4177 MSIPACKAGE *package = param;
4183 PROCESS_INFORMATION pi;
4188 memset( &si, 0, sizeof(STARTUPINFOW) );
4190 filename = MSI_RecordGetString( row, 1 );
4191 file = get_loaded_file( package, filename );
4195 ERR("Unable to find file id %s\n", debugstr_w(filename));
4196 return ERROR_SUCCESS;
4199 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4201 cmdline = msi_alloc( len * sizeof(WCHAR) );
4202 strcpyW( cmdline, regsvr32 );
4203 strcatW( cmdline, file->TargetPath );
4204 strcatW( cmdline, close );
4206 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4208 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4211 CloseHandle( pi.hThread );
4212 msi_dialog_check_messages( pi.hProcess );
4213 CloseHandle( pi.hProcess );
4216 uirow = MSI_CreateRecord( 2 );
4217 MSI_RecordSetStringW( uirow, 1, filename );
4218 uipath = strdupW( file->TargetPath );
4219 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4220 MSI_RecordSetStringW( uirow, 2, uipath );
4221 ui_actiondata( package, szSelfUnregModules, uirow );
4222 msiobj_release( &uirow->hdr );
4224 msi_free( cmdline );
4226 return ERROR_SUCCESS;
4229 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4233 static const WCHAR query[] =
4234 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4235 '`','S','e','l','f','R','e','g','`',0};
4237 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4238 if (rc != ERROR_SUCCESS)
4240 TRACE("no SelfReg table\n");
4241 return ERROR_SUCCESS;
4244 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4245 msiobj_release( &view->hdr );
4247 return ERROR_SUCCESS;
4250 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4252 MSIFEATURE *feature;
4254 HKEY hkey = NULL, userdata = NULL;
4256 if (!msi_check_publish(package))
4257 return ERROR_SUCCESS;
4259 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4261 if (rc != ERROR_SUCCESS)
4264 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4266 if (rc != ERROR_SUCCESS)
4269 /* here the guids are base 85 encoded */
4270 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4276 BOOL absent = FALSE;
4279 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4280 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4281 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4284 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4288 if (feature->Feature_Parent)
4289 size += strlenW( feature->Feature_Parent )+2;
4291 data = msi_alloc(size * sizeof(WCHAR));
4294 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4296 MSICOMPONENT* component = cl->component;
4300 if (component->ComponentId)
4302 TRACE("From %s\n",debugstr_w(component->ComponentId));
4303 CLSIDFromString(component->ComponentId, &clsid);
4304 encode_base85_guid(&clsid,buf);
4305 TRACE("to %s\n",debugstr_w(buf));
4310 if (feature->Feature_Parent)
4312 static const WCHAR sep[] = {'\2',0};
4314 strcatW(data,feature->Feature_Parent);
4317 msi_reg_set_val_str( userdata, feature->Feature, data );
4321 if (feature->Feature_Parent)
4322 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4325 size += sizeof(WCHAR);
4326 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4327 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4331 size += 2*sizeof(WCHAR);
4332 data = msi_alloc(size);
4335 if (feature->Feature_Parent)
4336 strcpyW( &data[1], feature->Feature_Parent );
4337 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4343 uirow = MSI_CreateRecord( 1 );
4344 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4345 ui_actiondata( package, szPublishFeatures, uirow);
4346 msiobj_release( &uirow->hdr );
4347 /* FIXME: call ui_progress? */
4352 RegCloseKey(userdata);
4356 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4362 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4364 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4366 if (r == ERROR_SUCCESS)
4368 RegDeleteValueW(hkey, feature->Feature);
4372 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4374 if (r == ERROR_SUCCESS)
4376 RegDeleteValueW(hkey, feature->Feature);
4380 uirow = MSI_CreateRecord( 1 );
4381 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4382 ui_actiondata( package, szUnpublishFeatures, uirow );
4383 msiobj_release( &uirow->hdr );
4385 return ERROR_SUCCESS;
4388 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4390 MSIFEATURE *feature;
4392 if (!msi_check_unpublish(package))
4393 return ERROR_SUCCESS;
4395 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4397 msi_unpublish_feature(package, feature);
4400 return ERROR_SUCCESS;
4403 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4405 LPWSTR prop, val, key;
4411 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4412 static const WCHAR szWindowsInstaller[] =
4413 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4414 static const WCHAR modpath_fmt[] =
4415 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4416 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4417 static const WCHAR szModifyPath[] =
4418 {'M','o','d','i','f','y','P','a','t','h',0};
4419 static const WCHAR szUninstallString[] =
4420 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4421 static const WCHAR szEstimatedSize[] =
4422 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4423 static const WCHAR szProductLanguage[] =
4424 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4425 static const WCHAR szProductVersion[] =
4426 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4427 static const WCHAR szProductName[] =
4428 {'P','r','o','d','u','c','t','N','a','m','e',0};
4429 static const WCHAR szDisplayName[] =
4430 {'D','i','s','p','l','a','y','N','a','m','e',0};
4431 static const WCHAR szDisplayVersion[] =
4432 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4433 static const WCHAR szManufacturer[] =
4434 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4436 static const LPCSTR propval[] = {
4437 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4438 "ARPCONTACT", "Contact",
4439 "ARPCOMMENTS", "Comments",
4440 "ProductName", "DisplayName",
4441 "ProductVersion", "DisplayVersion",
4442 "ARPHELPLINK", "HelpLink",
4443 "ARPHELPTELEPHONE", "HelpTelephone",
4444 "ARPINSTALLLOCATION", "InstallLocation",
4445 "SourceDir", "InstallSource",
4446 "Manufacturer", "Publisher",
4447 "ARPREADME", "Readme",
4449 "ARPURLINFOABOUT", "URLInfoAbout",
4450 "ARPURLUPDATEINFO", "URLUpdateInfo",
4453 const LPCSTR *p = propval;
4457 prop = strdupAtoW(*p++);
4458 key = strdupAtoW(*p++);
4459 val = msi_dup_property(package, prop);
4460 msi_reg_set_val_str(hkey, key, val);
4466 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4468 size = deformat_string(package, modpath_fmt, &buffer);
4469 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4470 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4473 /* FIXME: Write real Estimated Size when we have it */
4474 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4476 buffer = msi_dup_property(package, szProductName);
4477 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4480 buffer = msi_dup_property(package, cszSourceDir);
4481 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4484 buffer = msi_dup_property(package, szManufacturer);
4485 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4488 GetLocalTime(&systime);
4489 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4490 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4492 langid = msi_get_property_int(package, szProductLanguage, 0);
4493 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4495 buffer = msi_dup_property(package, szProductVersion);
4496 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4499 DWORD verdword = msi_version_str_to_dword(buffer);
4501 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4502 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4503 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4507 return ERROR_SUCCESS;
4510 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4512 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4514 LPWSTR upgrade_code;
4519 static const WCHAR szUpgradeCode[] = {
4520 'U','p','g','r','a','d','e','C','o','d','e',0};
4522 /* FIXME: also need to publish if the product is in advertise mode */
4523 if (!msi_check_publish(package))
4524 return ERROR_SUCCESS;
4526 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4527 if (rc != ERROR_SUCCESS)
4530 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4531 NULL, &props, TRUE);
4532 if (rc != ERROR_SUCCESS)
4535 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4536 msi_free( package->db->localfile );
4537 package->db->localfile = NULL;
4539 rc = msi_publish_install_properties(package, hkey);
4540 if (rc != ERROR_SUCCESS)
4543 rc = msi_publish_install_properties(package, props);
4544 if (rc != ERROR_SUCCESS)
4547 upgrade_code = msi_dup_property(package, szUpgradeCode);
4550 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4551 squash_guid(package->ProductCode, squashed_pc);
4552 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4553 RegCloseKey(upgrade);
4554 msi_free(upgrade_code);
4558 uirow = MSI_CreateRecord( 1 );
4559 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4560 ui_actiondata( package, szRegisterProduct, uirow );
4561 msiobj_release( &uirow->hdr );
4564 return ERROR_SUCCESS;
4567 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4569 return execute_script(package,INSTALL_SCRIPT);
4572 static UINT msi_unpublish_product(MSIPACKAGE *package)
4575 LPWSTR remove = NULL;
4576 LPWSTR *features = NULL;
4577 BOOL full_uninstall = TRUE;
4578 MSIFEATURE *feature;
4580 static const WCHAR szUpgradeCode[] =
4581 {'U','p','g','r','a','d','e','C','o','d','e',0};
4583 remove = msi_dup_property(package, szRemove);
4585 return ERROR_SUCCESS;
4587 features = msi_split_string(remove, ',');
4591 ERR("REMOVE feature list is empty!\n");
4592 return ERROR_FUNCTION_FAILED;
4595 if (!lstrcmpW(features[0], szAll))
4596 full_uninstall = TRUE;
4599 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4601 if (feature->Action != INSTALLSTATE_ABSENT)
4602 full_uninstall = FALSE;
4606 if (!full_uninstall)
4609 MSIREG_DeleteProductKey(package->ProductCode);
4610 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4611 MSIREG_DeleteUninstallKey(package->ProductCode);
4613 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4615 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4616 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4620 MSIREG_DeleteUserProductKey(package->ProductCode);
4621 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4624 upgrade = msi_dup_property(package, szUpgradeCode);
4627 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4634 return ERROR_SUCCESS;
4637 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4641 rc = msi_unpublish_product(package);
4642 if (rc != ERROR_SUCCESS)
4645 /* turn off scheduling */
4646 package->script->CurrentlyScripting= FALSE;
4648 /* first do the same as an InstallExecute */
4649 rc = ACTION_InstallExecute(package);
4650 if (rc != ERROR_SUCCESS)
4653 /* then handle Commit Actions */
4654 rc = execute_script(package,COMMIT_SCRIPT);
4659 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4661 static const WCHAR RunOnce[] = {
4662 'S','o','f','t','w','a','r','e','\\',
4663 'M','i','c','r','o','s','o','f','t','\\',
4664 'W','i','n','d','o','w','s','\\',
4665 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4666 'R','u','n','O','n','c','e',0};
4667 static const WCHAR InstallRunOnce[] = {
4668 'S','o','f','t','w','a','r','e','\\',
4669 'M','i','c','r','o','s','o','f','t','\\',
4670 'W','i','n','d','o','w','s','\\',
4671 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4672 'I','n','s','t','a','l','l','e','r','\\',
4673 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4675 static const WCHAR msiexec_fmt[] = {
4677 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4678 '\"','%','s','\"',0};
4679 static const WCHAR install_fmt[] = {
4680 '/','I',' ','\"','%','s','\"',' ',
4681 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4682 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4683 WCHAR buffer[256], sysdir[MAX_PATH];
4685 WCHAR squished_pc[100];
4687 squash_guid(package->ProductCode,squished_pc);
4689 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4690 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4691 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4694 msi_reg_set_val_str( hkey, squished_pc, buffer );
4697 TRACE("Reboot command %s\n",debugstr_w(buffer));
4699 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4700 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4702 msi_reg_set_val_str( hkey, squished_pc, buffer );
4705 return ERROR_INSTALL_SUSPEND;
4708 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4714 * We are currently doing what should be done here in the top level Install
4715 * however for Administrative and uninstalls this step will be needed
4717 if (!package->PackagePath)
4718 return ERROR_SUCCESS;
4720 msi_set_sourcedir_props(package, TRUE);
4722 attrib = GetFileAttributesW(package->db->path);
4723 if (attrib == INVALID_FILE_ATTRIBUTES)
4729 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4730 package->Context, MSICODE_PRODUCT,
4731 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4732 if (rc == ERROR_MORE_DATA)
4734 prompt = msi_alloc(size * sizeof(WCHAR));
4735 MsiSourceListGetInfoW(package->ProductCode, NULL,
4736 package->Context, MSICODE_PRODUCT,
4737 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4740 prompt = strdupW(package->db->path);
4742 msg = generate_error_string(package,1302,1,prompt);
4743 while(attrib == INVALID_FILE_ATTRIBUTES)
4745 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4748 rc = ERROR_INSTALL_USEREXIT;
4751 attrib = GetFileAttributesW(package->db->path);
4757 return ERROR_SUCCESS;
4762 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4765 LPWSTR buffer, productid = NULL;
4766 UINT i, rc = ERROR_SUCCESS;
4769 static const WCHAR szPropKeys[][80] =
4771 {'P','r','o','d','u','c','t','I','D',0},
4772 {'U','S','E','R','N','A','M','E',0},
4773 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4777 static const WCHAR szRegKeys[][80] =
4779 {'P','r','o','d','u','c','t','I','D',0},
4780 {'R','e','g','O','w','n','e','r',0},
4781 {'R','e','g','C','o','m','p','a','n','y',0},
4785 if (msi_check_unpublish(package))
4787 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4791 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4795 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4797 if (rc != ERROR_SUCCESS)
4800 for( i = 0; szPropKeys[i][0]; i++ )
4802 buffer = msi_dup_property( package, szPropKeys[i] );
4803 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4808 uirow = MSI_CreateRecord( 1 );
4809 MSI_RecordSetStringW( uirow, 1, productid );
4810 ui_actiondata( package, szRegisterUser, uirow );
4811 msiobj_release( &uirow->hdr );
4813 msi_free(productid);
4819 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4823 package->script->InWhatSequence |= SEQUENCE_EXEC;
4824 rc = ACTION_ProcessExecSequence(package,FALSE);
4829 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4831 MSIPACKAGE *package = param;
4832 LPCWSTR compgroupid, component, feature, qualifier, text;
4833 LPWSTR advertise = NULL, output = NULL;
4841 feature = MSI_RecordGetString(rec, 5);
4842 feat = get_loaded_feature(package, feature);
4844 return ERROR_SUCCESS;
4846 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4847 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4848 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4850 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4851 feat->Action = feat->Installed;
4852 return ERROR_SUCCESS;
4855 component = MSI_RecordGetString(rec, 3);
4856 comp = get_loaded_component(package, component);
4858 return ERROR_SUCCESS;
4860 compgroupid = MSI_RecordGetString(rec,1);
4861 qualifier = MSI_RecordGetString(rec,2);
4863 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4864 if (rc != ERROR_SUCCESS)
4867 text = MSI_RecordGetString(rec,4);
4868 advertise = create_component_advertise_string(package, comp, feature);
4870 sz = strlenW(advertise);
4873 sz += lstrlenW(text);
4876 sz *= sizeof(WCHAR);
4878 output = msi_alloc_zero(sz);
4879 strcpyW(output,advertise);
4880 msi_free(advertise);
4883 strcatW(output,text);
4885 msi_reg_set_val_multi_str( hkey, qualifier, output );
4892 uirow = MSI_CreateRecord( 2 );
4893 MSI_RecordSetStringW( uirow, 1, compgroupid );
4894 MSI_RecordSetStringW( uirow, 2, qualifier);
4895 ui_actiondata( package, szPublishComponents, uirow);
4896 msiobj_release( &uirow->hdr );
4897 /* FIXME: call ui_progress? */
4903 * At present I am ignorning the advertised components part of this and only
4904 * focusing on the qualified component sets
4906 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4910 static const WCHAR ExecSeqQuery[] =
4911 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4912 '`','P','u','b','l','i','s','h',
4913 'C','o','m','p','o','n','e','n','t','`',0};
4915 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4916 if (rc != ERROR_SUCCESS)
4917 return ERROR_SUCCESS;
4919 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4920 msiobj_release(&view->hdr);
4925 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4927 static const WCHAR szInstallerComponents[] = {
4928 'S','o','f','t','w','a','r','e','\\',
4929 'M','i','c','r','o','s','o','f','t','\\',
4930 'I','n','s','t','a','l','l','e','r','\\',
4931 'C','o','m','p','o','n','e','n','t','s','\\',0};
4933 MSIPACKAGE *package = param;
4934 LPCWSTR compgroupid, component, feature, qualifier;
4938 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4941 feature = MSI_RecordGetString( rec, 5 );
4942 feat = get_loaded_feature( package, feature );
4944 return ERROR_SUCCESS;
4946 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4948 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4949 feat->Action = feat->Installed;
4950 return ERROR_SUCCESS;
4953 component = MSI_RecordGetString( rec, 3 );
4954 comp = get_loaded_component( package, component );
4956 return ERROR_SUCCESS;
4958 compgroupid = MSI_RecordGetString( rec, 1 );
4959 qualifier = MSI_RecordGetString( rec, 2 );
4961 squash_guid( compgroupid, squashed );
4962 strcpyW( keypath, szInstallerComponents );
4963 strcatW( keypath, squashed );
4965 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4966 if (res != ERROR_SUCCESS)
4968 WARN("Unable to delete component key %d\n", res);
4971 uirow = MSI_CreateRecord( 2 );
4972 MSI_RecordSetStringW( uirow, 1, compgroupid );
4973 MSI_RecordSetStringW( uirow, 2, qualifier );
4974 ui_actiondata( package, szUnpublishComponents, uirow );
4975 msiobj_release( &uirow->hdr );
4977 return ERROR_SUCCESS;
4980 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4984 static const WCHAR query[] =
4985 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4986 '`','P','u','b','l','i','s','h',
4987 'C','o','m','p','o','n','e','n','t','`',0};
4989 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4990 if (rc != ERROR_SUCCESS)
4991 return ERROR_SUCCESS;
4993 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
4994 msiobj_release( &view->hdr );
4999 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5001 MSIPACKAGE *package = param;
5004 SC_HANDLE hscm, service = NULL;
5005 LPCWSTR comp, depends, pass;
5006 LPWSTR name = NULL, disp = NULL;
5007 LPCWSTR load_order, serv_name, key;
5008 DWORD serv_type, start_type;
5011 static const WCHAR query[] =
5012 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5013 '`','C','o','m','p','o','n','e','n','t','`',' ',
5014 'W','H','E','R','E',' ',
5015 '`','C','o','m','p','o','n','e','n','t','`',' ',
5016 '=','\'','%','s','\'',0};
5018 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5021 ERR("Failed to open the SC Manager!\n");
5025 start_type = MSI_RecordGetInteger(rec, 5);
5026 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5029 depends = MSI_RecordGetString(rec, 8);
5030 if (depends && *depends)
5031 FIXME("Dependency list unhandled!\n");
5033 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5034 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5035 serv_type = MSI_RecordGetInteger(rec, 4);
5036 err_control = MSI_RecordGetInteger(rec, 6);
5037 load_order = MSI_RecordGetString(rec, 7);
5038 serv_name = MSI_RecordGetString(rec, 9);
5039 pass = MSI_RecordGetString(rec, 10);
5040 comp = MSI_RecordGetString(rec, 12);
5042 /* fetch the service path */
5043 row = MSI_QueryGetRecord(package->db, query, comp);
5046 ERR("Control query failed!\n");
5050 key = MSI_RecordGetString(row, 6);
5052 file = get_loaded_file(package, key);
5053 msiobj_release(&row->hdr);
5056 ERR("Failed to load the service file\n");
5060 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5061 start_type, err_control, file->TargetPath,
5062 load_order, NULL, NULL, serv_name, pass);
5065 if (GetLastError() != ERROR_SERVICE_EXISTS)
5066 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5070 CloseServiceHandle(service);
5071 CloseServiceHandle(hscm);
5075 return ERROR_SUCCESS;
5078 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5082 static const WCHAR ExecSeqQuery[] =
5083 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5084 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5086 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5087 if (rc != ERROR_SUCCESS)
5088 return ERROR_SUCCESS;
5090 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5091 msiobj_release(&view->hdr);
5096 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5097 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5099 LPCWSTR *vector, *temp_vector;
5103 static const WCHAR separator[] = {'[','~',']',0};
5106 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5111 vector = msi_alloc(sizeof(LPWSTR));
5119 vector[*numargs - 1] = p;
5121 if ((q = strstrW(p, separator)))
5125 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5131 vector = temp_vector;
5140 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5142 MSIPACKAGE *package = param;
5145 SC_HANDLE scm = NULL, service = NULL;
5146 LPCWSTR component, *vector = NULL;
5147 LPWSTR name, args, display_name = NULL;
5148 DWORD event, numargs, len;
5149 UINT r = ERROR_FUNCTION_FAILED;
5151 component = MSI_RecordGetString(rec, 6);
5152 comp = get_loaded_component(package, component);
5154 return ERROR_SUCCESS;
5156 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5158 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5159 comp->Action = comp->Installed;
5160 return ERROR_SUCCESS;
5162 comp->Action = INSTALLSTATE_LOCAL;
5164 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5165 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5166 event = MSI_RecordGetInteger(rec, 3);
5168 if (!(event & msidbServiceControlEventStart))
5174 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5177 ERR("Failed to open the service control manager\n");
5182 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5183 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5185 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5186 GetServiceDisplayNameW( scm, name, display_name, &len );
5189 service = OpenServiceW(scm, name, SERVICE_START);
5192 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5196 vector = msi_service_args_to_vector(args, &numargs);
5198 if (!StartServiceW(service, numargs, vector) &&
5199 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5201 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5208 uirow = MSI_CreateRecord( 2 );
5209 MSI_RecordSetStringW( uirow, 1, display_name );
5210 MSI_RecordSetStringW( uirow, 2, name );
5211 ui_actiondata( package, szStartServices, uirow );
5212 msiobj_release( &uirow->hdr );
5214 CloseServiceHandle(service);
5215 CloseServiceHandle(scm);
5220 msi_free(display_name);
5224 static UINT ACTION_StartServices( MSIPACKAGE *package )
5229 static const WCHAR query[] = {
5230 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5231 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5233 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5234 if (rc != ERROR_SUCCESS)
5235 return ERROR_SUCCESS;
5237 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5238 msiobj_release(&view->hdr);
5243 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5245 DWORD i, needed, count;
5246 ENUM_SERVICE_STATUSW *dependencies;
5250 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5251 0, &needed, &count))
5254 if (GetLastError() != ERROR_MORE_DATA)
5257 dependencies = msi_alloc(needed);
5261 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5262 needed, &needed, &count))
5265 for (i = 0; i < count; i++)
5267 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5268 SERVICE_STOP | SERVICE_QUERY_STATUS);
5272 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5279 msi_free(dependencies);
5283 static UINT stop_service( LPCWSTR name )
5285 SC_HANDLE scm = NULL, service = NULL;
5286 SERVICE_STATUS status;
5287 SERVICE_STATUS_PROCESS ssp;
5290 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5293 WARN("Failed to open the SCM: %d\n", GetLastError());
5297 service = OpenServiceW(scm, name,
5299 SERVICE_QUERY_STATUS |
5300 SERVICE_ENUMERATE_DEPENDENTS);
5303 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5307 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5308 sizeof(SERVICE_STATUS_PROCESS), &needed))
5310 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5314 if (ssp.dwCurrentState == SERVICE_STOPPED)
5317 stop_service_dependents(scm, service);
5319 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5320 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5323 CloseServiceHandle(service);
5324 CloseServiceHandle(scm);
5326 return ERROR_SUCCESS;
5329 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5331 MSIPACKAGE *package = param;
5335 LPWSTR name = NULL, display_name = NULL;
5339 event = MSI_RecordGetInteger( rec, 3 );
5340 if (!(event & msidbServiceControlEventStop))
5341 return ERROR_SUCCESS;
5343 component = MSI_RecordGetString( rec, 6 );
5344 comp = get_loaded_component( package, component );
5346 return ERROR_SUCCESS;
5348 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5350 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5351 comp->Action = comp->Installed;
5352 return ERROR_SUCCESS;
5354 comp->Action = INSTALLSTATE_ABSENT;
5356 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5359 ERR("Failed to open the service control manager\n");
5364 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5365 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5367 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5368 GetServiceDisplayNameW( scm, name, display_name, &len );
5370 CloseServiceHandle( scm );
5372 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5373 stop_service( name );
5376 uirow = MSI_CreateRecord( 2 );
5377 MSI_RecordSetStringW( uirow, 1, display_name );
5378 MSI_RecordSetStringW( uirow, 2, name );
5379 ui_actiondata( package, szStopServices, uirow );
5380 msiobj_release( &uirow->hdr );
5383 msi_free( display_name );
5384 return ERROR_SUCCESS;
5387 static UINT ACTION_StopServices( MSIPACKAGE *package )
5392 static const WCHAR query[] = {
5393 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5394 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5396 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5397 if (rc != ERROR_SUCCESS)
5398 return ERROR_SUCCESS;
5400 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5401 msiobj_release(&view->hdr);
5406 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5408 MSIPACKAGE *package = param;
5412 LPWSTR name = NULL, display_name = NULL;
5414 SC_HANDLE scm = NULL, service = NULL;
5416 event = MSI_RecordGetInteger( rec, 3 );
5417 if (!(event & msidbServiceControlEventDelete))
5418 return ERROR_SUCCESS;
5420 component = MSI_RecordGetString(rec, 6);
5421 comp = get_loaded_component(package, component);
5423 return ERROR_SUCCESS;
5425 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5427 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5428 comp->Action = comp->Installed;
5429 return ERROR_SUCCESS;
5431 comp->Action = INSTALLSTATE_ABSENT;
5433 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5434 stop_service( name );
5436 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5439 WARN("Failed to open the SCM: %d\n", GetLastError());
5444 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5445 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5447 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5448 GetServiceDisplayNameW( scm, name, display_name, &len );
5451 service = OpenServiceW( scm, name, DELETE );
5454 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5458 if (!DeleteService( service ))
5459 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5462 uirow = MSI_CreateRecord( 2 );
5463 MSI_RecordSetStringW( uirow, 1, display_name );
5464 MSI_RecordSetStringW( uirow, 2, name );
5465 ui_actiondata( package, szDeleteServices, uirow );
5466 msiobj_release( &uirow->hdr );
5468 CloseServiceHandle( service );
5469 CloseServiceHandle( scm );
5471 msi_free( display_name );
5473 return ERROR_SUCCESS;
5476 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5481 static const WCHAR query[] = {
5482 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5483 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5485 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5486 if (rc != ERROR_SUCCESS)
5487 return ERROR_SUCCESS;
5489 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5490 msiobj_release( &view->hdr );
5495 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5499 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5501 if (!lstrcmpW(file->File, filename))
5508 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5510 MSIPACKAGE *package = param;
5511 LPWSTR driver, driver_path, ptr;
5512 WCHAR outpath[MAX_PATH];
5513 MSIFILE *driver_file, *setup_file;
5517 UINT r = ERROR_SUCCESS;
5519 static const WCHAR driver_fmt[] = {
5520 'D','r','i','v','e','r','=','%','s',0};
5521 static const WCHAR setup_fmt[] = {
5522 'S','e','t','u','p','=','%','s',0};
5523 static const WCHAR usage_fmt[] = {
5524 'F','i','l','e','U','s','a','g','e','=','1',0};
5526 desc = MSI_RecordGetString(rec, 3);
5528 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5529 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5533 ERR("ODBC Driver entry not found!\n");
5534 return ERROR_FUNCTION_FAILED;
5537 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5539 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5540 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5542 driver = msi_alloc(len * sizeof(WCHAR));
5544 return ERROR_OUTOFMEMORY;
5547 lstrcpyW(ptr, desc);
5548 ptr += lstrlenW(ptr) + 1;
5550 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5555 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5559 lstrcpyW(ptr, usage_fmt);
5560 ptr += lstrlenW(ptr) + 1;
5563 driver_path = strdupW(driver_file->TargetPath);
5564 ptr = strrchrW(driver_path, '\\');
5565 if (ptr) *ptr = '\0';
5567 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5568 NULL, ODBC_INSTALL_COMPLETE, &usage))
5570 ERR("Failed to install SQL driver!\n");
5571 r = ERROR_FUNCTION_FAILED;
5574 uirow = MSI_CreateRecord( 5 );
5575 MSI_RecordSetStringW( uirow, 1, desc );
5576 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5577 MSI_RecordSetStringW( uirow, 3, driver_path );
5578 ui_actiondata( package, szInstallODBC, uirow );
5579 msiobj_release( &uirow->hdr );
5582 msi_free(driver_path);
5587 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5589 MSIPACKAGE *package = param;
5590 LPWSTR translator, translator_path, ptr;
5591 WCHAR outpath[MAX_PATH];
5592 MSIFILE *translator_file, *setup_file;
5596 UINT r = ERROR_SUCCESS;
5598 static const WCHAR translator_fmt[] = {
5599 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5600 static const WCHAR setup_fmt[] = {
5601 'S','e','t','u','p','=','%','s',0};
5603 desc = MSI_RecordGetString(rec, 3);
5605 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5606 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5608 if (!translator_file)
5610 ERR("ODBC Translator entry not found!\n");
5611 return ERROR_FUNCTION_FAILED;
5614 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5616 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5618 translator = msi_alloc(len * sizeof(WCHAR));
5620 return ERROR_OUTOFMEMORY;
5623 lstrcpyW(ptr, desc);
5624 ptr += lstrlenW(ptr) + 1;
5626 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5631 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5636 translator_path = strdupW(translator_file->TargetPath);
5637 ptr = strrchrW(translator_path, '\\');
5638 if (ptr) *ptr = '\0';
5640 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5641 NULL, ODBC_INSTALL_COMPLETE, &usage))
5643 ERR("Failed to install SQL translator!\n");
5644 r = ERROR_FUNCTION_FAILED;
5647 uirow = MSI_CreateRecord( 5 );
5648 MSI_RecordSetStringW( uirow, 1, desc );
5649 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5650 MSI_RecordSetStringW( uirow, 3, translator_path );
5651 ui_actiondata( package, szInstallODBC, uirow );
5652 msiobj_release( &uirow->hdr );
5654 msi_free(translator);
5655 msi_free(translator_path);
5660 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5662 MSIPACKAGE *package = param;
5664 LPCWSTR desc, driver;
5665 WORD request = ODBC_ADD_SYS_DSN;
5668 UINT r = ERROR_SUCCESS;
5671 static const WCHAR attrs_fmt[] = {
5672 'D','S','N','=','%','s',0 };
5674 desc = MSI_RecordGetString(rec, 3);
5675 driver = MSI_RecordGetString(rec, 4);
5676 registration = MSI_RecordGetInteger(rec, 5);
5678 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5679 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5681 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5682 attrs = msi_alloc(len * sizeof(WCHAR));
5684 return ERROR_OUTOFMEMORY;
5686 len = sprintfW(attrs, attrs_fmt, desc);
5689 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5691 ERR("Failed to install SQL data source!\n");
5692 r = ERROR_FUNCTION_FAILED;
5695 uirow = MSI_CreateRecord( 5 );
5696 MSI_RecordSetStringW( uirow, 1, desc );
5697 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5698 MSI_RecordSetInteger( uirow, 3, request );
5699 ui_actiondata( package, szInstallODBC, uirow );
5700 msiobj_release( &uirow->hdr );
5707 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5712 static const WCHAR driver_query[] = {
5713 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 'O','D','B','C','D','r','i','v','e','r',0 };
5716 static const WCHAR translator_query[] = {
5717 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5718 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5720 static const WCHAR source_query[] = {
5721 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5722 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5724 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5725 if (rc != ERROR_SUCCESS)
5726 return ERROR_SUCCESS;
5728 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5729 msiobj_release(&view->hdr);
5731 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5732 if (rc != ERROR_SUCCESS)
5733 return ERROR_SUCCESS;
5735 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5736 msiobj_release(&view->hdr);
5738 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5739 if (rc != ERROR_SUCCESS)
5740 return ERROR_SUCCESS;
5742 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5743 msiobj_release(&view->hdr);
5748 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5750 MSIPACKAGE *package = param;
5755 desc = MSI_RecordGetString( rec, 3 );
5756 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5758 WARN("Failed to remove ODBC driver\n");
5762 FIXME("Usage count reached 0\n");
5765 uirow = MSI_CreateRecord( 2 );
5766 MSI_RecordSetStringW( uirow, 1, desc );
5767 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5768 ui_actiondata( package, szRemoveODBC, uirow );
5769 msiobj_release( &uirow->hdr );
5771 return ERROR_SUCCESS;
5774 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5776 MSIPACKAGE *package = param;
5781 desc = MSI_RecordGetString( rec, 3 );
5782 if (!SQLRemoveTranslatorW( desc, &usage ))
5784 WARN("Failed to remove ODBC translator\n");
5788 FIXME("Usage count reached 0\n");
5791 uirow = MSI_CreateRecord( 2 );
5792 MSI_RecordSetStringW( uirow, 1, desc );
5793 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5794 ui_actiondata( package, szRemoveODBC, uirow );
5795 msiobj_release( &uirow->hdr );
5797 return ERROR_SUCCESS;
5800 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5802 MSIPACKAGE *package = param;
5805 LPCWSTR desc, driver;
5806 WORD request = ODBC_REMOVE_SYS_DSN;
5810 static const WCHAR attrs_fmt[] = {
5811 'D','S','N','=','%','s',0 };
5813 desc = MSI_RecordGetString( rec, 3 );
5814 driver = MSI_RecordGetString( rec, 4 );
5815 registration = MSI_RecordGetInteger( rec, 5 );
5817 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5818 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5820 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5821 attrs = msi_alloc( len * sizeof(WCHAR) );
5823 return ERROR_OUTOFMEMORY;
5825 FIXME("Use ODBCSourceAttribute table\n");
5827 len = sprintfW( attrs, attrs_fmt, desc );
5830 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5832 WARN("Failed to remove ODBC data source\n");
5836 uirow = MSI_CreateRecord( 3 );
5837 MSI_RecordSetStringW( uirow, 1, desc );
5838 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5839 MSI_RecordSetInteger( uirow, 3, request );
5840 ui_actiondata( package, szRemoveODBC, uirow );
5841 msiobj_release( &uirow->hdr );
5843 return ERROR_SUCCESS;
5846 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5851 static const WCHAR driver_query[] = {
5852 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5853 'O','D','B','C','D','r','i','v','e','r',0 };
5855 static const WCHAR translator_query[] = {
5856 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5857 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5859 static const WCHAR source_query[] = {
5860 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5861 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5863 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5864 if (rc != ERROR_SUCCESS)
5865 return ERROR_SUCCESS;
5867 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5868 msiobj_release( &view->hdr );
5870 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5871 if (rc != ERROR_SUCCESS)
5872 return ERROR_SUCCESS;
5874 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5875 msiobj_release( &view->hdr );
5877 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5878 if (rc != ERROR_SUCCESS)
5879 return ERROR_SUCCESS;
5881 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5882 msiobj_release( &view->hdr );
5887 #define ENV_ACT_SETALWAYS 0x1
5888 #define ENV_ACT_SETABSENT 0x2
5889 #define ENV_ACT_REMOVE 0x4
5890 #define ENV_ACT_REMOVEMATCH 0x8
5892 #define ENV_MOD_MACHINE 0x20000000
5893 #define ENV_MOD_APPEND 0x40000000
5894 #define ENV_MOD_PREFIX 0x80000000
5895 #define ENV_MOD_MASK 0xC0000000
5897 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5899 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5901 LPCWSTR cptr = *name;
5903 static const WCHAR prefix[] = {'[','~',']',0};
5904 static const int prefix_len = 3;
5910 *flags |= ENV_ACT_SETALWAYS;
5911 else if (*cptr == '+')
5912 *flags |= ENV_ACT_SETABSENT;
5913 else if (*cptr == '-')
5914 *flags |= ENV_ACT_REMOVE;
5915 else if (*cptr == '!')
5916 *flags |= ENV_ACT_REMOVEMATCH;
5917 else if (*cptr == '*')
5918 *flags |= ENV_MOD_MACHINE;
5928 ERR("Missing environment variable\n");
5929 return ERROR_FUNCTION_FAILED;
5934 LPCWSTR ptr = *value;
5935 if (!strncmpW(ptr, prefix, prefix_len))
5937 if (ptr[prefix_len] == szSemiColon[0])
5939 *flags |= ENV_MOD_APPEND;
5940 *value += lstrlenW(prefix);
5947 else if (lstrlenW(*value) >= prefix_len)
5949 ptr += lstrlenW(ptr) - prefix_len;
5950 if (!lstrcmpW(ptr, prefix))
5952 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5954 *flags |= ENV_MOD_PREFIX;
5955 /* the "[~]" will be removed by deformat_string */;
5965 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5966 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5967 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5968 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5970 ERR("Invalid flags: %08x\n", *flags);
5971 return ERROR_FUNCTION_FAILED;
5975 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5977 return ERROR_SUCCESS;
5980 static UINT open_env_key( DWORD flags, HKEY *key )
5982 static const WCHAR user_env[] =
5983 {'E','n','v','i','r','o','n','m','e','n','t',0};
5984 static const WCHAR machine_env[] =
5985 {'S','y','s','t','e','m','\\',
5986 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5987 'C','o','n','t','r','o','l','\\',
5988 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5989 'E','n','v','i','r','o','n','m','e','n','t',0};
5994 if (flags & ENV_MOD_MACHINE)
5997 root = HKEY_LOCAL_MACHINE;
6002 root = HKEY_CURRENT_USER;
6005 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6006 if (res != ERROR_SUCCESS)
6008 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6009 return ERROR_FUNCTION_FAILED;
6012 return ERROR_SUCCESS;
6015 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6017 MSIPACKAGE *package = param;
6018 LPCWSTR name, value, component;
6019 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6020 DWORD flags, type, size;
6027 component = MSI_RecordGetString(rec, 4);
6028 comp = get_loaded_component(package, component);
6030 return ERROR_SUCCESS;
6032 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6034 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6035 comp->Action = comp->Installed;
6036 return ERROR_SUCCESS;
6038 comp->Action = INSTALLSTATE_LOCAL;
6040 name = MSI_RecordGetString(rec, 2);
6041 value = MSI_RecordGetString(rec, 3);
6043 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6045 res = env_parse_flags(&name, &value, &flags);
6046 if (res != ERROR_SUCCESS || !value)
6049 if (value && !deformat_string(package, value, &deformatted))
6051 res = ERROR_OUTOFMEMORY;
6055 value = deformatted;
6057 res = open_env_key( flags, &env );
6058 if (res != ERROR_SUCCESS)
6061 if (flags & ENV_MOD_MACHINE)
6062 action |= 0x20000000;
6066 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6067 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6068 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6071 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6075 /* Nothing to do. */
6078 res = ERROR_SUCCESS;
6082 /* If we are appending but the string was empty, strip ; */
6083 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6085 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6086 newval = strdupW(value);
6089 res = ERROR_OUTOFMEMORY;
6097 /* Contrary to MSDN, +-variable to [~];path works */
6098 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6100 res = ERROR_SUCCESS;
6104 data = msi_alloc(size);
6108 return ERROR_OUTOFMEMORY;
6111 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6112 if (res != ERROR_SUCCESS)
6115 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6118 res = RegDeleteValueW(env, name);
6119 if (res != ERROR_SUCCESS)
6120 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6124 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6125 if (flags & ENV_MOD_MASK)
6129 if (flags & ENV_MOD_APPEND) multiplier++;
6130 if (flags & ENV_MOD_PREFIX) multiplier++;
6131 mod_size = lstrlenW(value) * multiplier;
6132 size += mod_size * sizeof(WCHAR);
6135 newval = msi_alloc(size);
6139 res = ERROR_OUTOFMEMORY;
6143 if (flags & ENV_MOD_PREFIX)
6145 lstrcpyW(newval, value);
6146 ptr = newval + lstrlenW(value);
6147 action |= 0x80000000;
6150 lstrcpyW(ptr, data);
6152 if (flags & ENV_MOD_APPEND)
6154 lstrcatW(newval, value);
6155 action |= 0x40000000;
6158 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6159 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6162 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6166 uirow = MSI_CreateRecord( 3 );
6167 MSI_RecordSetStringW( uirow, 1, name );
6168 MSI_RecordSetStringW( uirow, 2, newval );
6169 MSI_RecordSetInteger( uirow, 3, action );
6170 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6171 msiobj_release( &uirow->hdr );
6173 if (env) RegCloseKey(env);
6174 msi_free(deformatted);
6180 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6184 static const WCHAR ExecSeqQuery[] =
6185 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6186 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6187 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6188 if (rc != ERROR_SUCCESS)
6189 return ERROR_SUCCESS;
6191 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6192 msiobj_release(&view->hdr);
6197 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6199 MSIPACKAGE *package = param;
6200 LPCWSTR name, value, component;
6201 LPWSTR deformatted = NULL;
6210 component = MSI_RecordGetString( rec, 4 );
6211 comp = get_loaded_component( package, component );
6213 return ERROR_SUCCESS;
6215 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6217 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6218 comp->Action = comp->Installed;
6219 return ERROR_SUCCESS;
6221 comp->Action = INSTALLSTATE_ABSENT;
6223 name = MSI_RecordGetString( rec, 2 );
6224 value = MSI_RecordGetString( rec, 3 );
6226 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6228 r = env_parse_flags( &name, &value, &flags );
6229 if (r != ERROR_SUCCESS)
6232 if (!(flags & ENV_ACT_REMOVE))
6234 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6235 return ERROR_SUCCESS;
6238 if (value && !deformat_string( package, value, &deformatted ))
6239 return ERROR_OUTOFMEMORY;
6241 value = deformatted;
6243 r = open_env_key( flags, &env );
6244 if (r != ERROR_SUCCESS)
6250 if (flags & ENV_MOD_MACHINE)
6251 action |= 0x20000000;
6253 TRACE("Removing %s\n", debugstr_w(name));
6255 res = RegDeleteValueW( env, name );
6256 if (res != ERROR_SUCCESS)
6258 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6263 uirow = MSI_CreateRecord( 3 );
6264 MSI_RecordSetStringW( uirow, 1, name );
6265 MSI_RecordSetStringW( uirow, 2, value );
6266 MSI_RecordSetInteger( uirow, 3, action );
6267 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6268 msiobj_release( &uirow->hdr );
6270 if (env) RegCloseKey( env );
6271 msi_free( deformatted );
6275 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6279 static const WCHAR query[] =
6280 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6281 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6283 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6284 if (rc != ERROR_SUCCESS)
6285 return ERROR_SUCCESS;
6287 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6288 msiobj_release( &view->hdr );
6293 typedef struct tagMSIASSEMBLY
6296 MSICOMPONENT *component;
6297 MSIFEATURE *feature;
6301 LPWSTR display_name;
6306 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6308 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6309 LPVOID pvReserved, HMODULE *phModDll);
6311 static BOOL init_functionpointers(void)
6317 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6319 hmscoree = LoadLibraryA("mscoree.dll");
6322 WARN("mscoree.dll not available\n");
6326 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6327 if (!pLoadLibraryShim)
6329 WARN("LoadLibraryShim not available\n");
6330 FreeLibrary(hmscoree);
6334 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6337 WARN("fusion.dll not available\n");
6338 FreeLibrary(hmscoree);
6342 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6344 FreeLibrary(hmscoree);
6348 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6351 IAssemblyCache *cache;
6354 UINT r = ERROR_FUNCTION_FAILED;
6356 TRACE("installing assembly: %s\n", debugstr_w(path));
6358 uirow = MSI_CreateRecord( 2 );
6359 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6360 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6361 msiobj_release( &uirow->hdr );
6363 if (assembly->feature)
6364 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6366 if (assembly->manifest)
6367 FIXME("Manifest unhandled\n");
6369 if (assembly->application)
6371 FIXME("Assembly should be privately installed\n");
6372 return ERROR_SUCCESS;
6375 if (assembly->attributes == msidbAssemblyAttributesWin32)
6377 FIXME("Win32 assemblies not handled\n");
6378 return ERROR_SUCCESS;
6381 hr = pCreateAssemblyCache(&cache, 0);
6385 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6387 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6392 IAssemblyCache_Release(cache);
6396 typedef struct tagASSEMBLY_LIST
6398 MSIPACKAGE *package;
6399 IAssemblyCache *cache;
6400 struct list *assemblies;
6403 typedef struct tagASSEMBLY_NAME
6411 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6413 ASSEMBLY_NAME *asmname = param;
6414 LPCWSTR name = MSI_RecordGetString(rec, 2);
6415 LPWSTR val = msi_dup_record_field(rec, 3);
6417 static const WCHAR Name[] = {'N','a','m','e',0};
6418 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6419 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6420 static const WCHAR PublicKeyToken[] = {
6421 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6423 if (!strcmpiW(name, Name))
6424 asmname->name = val;
6425 else if (!strcmpiW(name, Version))
6426 asmname->version = val;
6427 else if (!strcmpiW(name, Culture))
6428 asmname->culture = val;
6429 else if (!strcmpiW(name, PublicKeyToken))
6430 asmname->pubkeytoken = val;
6434 return ERROR_SUCCESS;
6437 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6441 *size = lstrlenW(append) + 1;
6442 *str = msi_alloc((*size) * sizeof(WCHAR));
6443 lstrcpyW(*str, append);
6447 (*size) += lstrlenW(append);
6448 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6449 lstrcatW(*str, append);
6452 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6454 static const WCHAR separator[] = {',',' ',0};
6455 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6456 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6457 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6458 static const WCHAR query[] = {
6459 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6460 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6461 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6462 '=','\'','%','s','\'',0};
6465 LPWSTR display_name;
6469 display_name = NULL;
6470 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6472 r = MSI_OpenQuery( db, &view, query, comp->Component );
6473 if (r != ERROR_SUCCESS)
6476 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6477 msiobj_release( &view->hdr );
6481 ERR("No assembly name specified!\n");
6485 append_str( &display_name, &size, name.name );
6489 append_str( &display_name, &size, separator );
6490 append_str( &display_name, &size, Version );
6491 append_str( &display_name, &size, name.version );
6495 append_str( &display_name, &size, separator );
6496 append_str( &display_name, &size, Culture );
6497 append_str( &display_name, &size, name.culture );
6499 if (name.pubkeytoken)
6501 append_str( &display_name, &size, separator );
6502 append_str( &display_name, &size, PublicKeyToken );
6503 append_str( &display_name, &size, name.pubkeytoken );
6506 msi_free( name.name );
6507 msi_free( name.version );
6508 msi_free( name.culture );
6509 msi_free( name.pubkeytoken );
6511 return display_name;
6514 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6516 ASSEMBLY_INFO asminfo;
6521 disp = get_assembly_display_name( db, comp );
6525 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6526 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6528 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6530 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6536 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6538 ASSEMBLY_LIST *list = param;
6539 MSIASSEMBLY *assembly;
6542 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6544 return ERROR_OUTOFMEMORY;
6546 component = MSI_RecordGetString(rec, 1);
6547 assembly->component = get_loaded_component(list->package, component);
6548 if (!assembly->component)
6549 return ERROR_SUCCESS;
6551 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6552 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6554 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6555 assembly->component->Action = assembly->component->Installed;
6556 return ERROR_SUCCESS;
6558 assembly->component->Action = assembly->component->ActionRequest;
6560 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6561 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6563 if (!assembly->file)
6565 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6566 return ERROR_FUNCTION_FAILED;
6569 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6570 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6571 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6573 if (assembly->application)
6576 DWORD size = sizeof(version)/sizeof(WCHAR);
6578 /* FIXME: we should probably check the manifest file here */
6580 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6581 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6583 assembly->installed = TRUE;
6587 assembly->installed = check_assembly_installed(list->package->db,
6589 assembly->component);
6591 list_add_head(list->assemblies, &assembly->entry);
6592 return ERROR_SUCCESS;
6595 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6597 IAssemblyCache *cache = NULL;
6603 static const WCHAR query[] =
6604 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6605 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6607 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6608 if (r != ERROR_SUCCESS)
6609 return ERROR_SUCCESS;
6611 hr = pCreateAssemblyCache(&cache, 0);
6613 return ERROR_FUNCTION_FAILED;
6615 list.package = package;
6617 list.assemblies = assemblies;
6619 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6620 msiobj_release(&view->hdr);
6622 IAssemblyCache_Release(cache);
6627 static void free_assemblies(struct list *assemblies)
6629 struct list *item, *cursor;
6631 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6633 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6635 list_remove(&assembly->entry);
6636 msi_free(assembly->application);
6637 msi_free(assembly->manifest);
6638 msi_free(assembly->display_name);
6643 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6645 MSIASSEMBLY *assembly;
6647 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6649 if (!lstrcmpW(assembly->file->File, file))
6659 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6660 LPWSTR *path, DWORD *attrs, PVOID user)
6662 MSIASSEMBLY *assembly;
6663 WCHAR temppath[MAX_PATH];
6664 struct list *assemblies = user;
6667 if (!find_assembly(assemblies, file, &assembly))
6670 GetTempPathW(MAX_PATH, temppath);
6671 PathAddBackslashW(temppath);
6672 lstrcatW(temppath, assembly->file->FileName);
6674 if (action == MSICABEXTRACT_BEGINEXTRACT)
6676 if (assembly->installed)
6679 *path = strdupW(temppath);
6680 *attrs = assembly->file->Attributes;
6682 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6684 assembly->installed = TRUE;
6686 r = install_assembly(package, assembly, temppath);
6687 if (r != ERROR_SUCCESS)
6688 ERR("Failed to install assembly\n");
6694 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6697 struct list assemblies = LIST_INIT(assemblies);
6698 MSIASSEMBLY *assembly;
6701 if (!init_functionpointers() || !pCreateAssemblyCache)
6702 return ERROR_FUNCTION_FAILED;
6704 r = load_assemblies(package, &assemblies);
6705 if (r != ERROR_SUCCESS)
6708 if (list_empty(&assemblies))
6711 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6714 r = ERROR_OUTOFMEMORY;
6718 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6720 if (assembly->installed && !mi->is_continuous)
6723 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6724 (assembly->file->IsCompressed && !mi->is_extracted))
6728 r = ready_media(package, assembly->file, mi);
6729 if (r != ERROR_SUCCESS)
6731 ERR("Failed to ready media\n");
6736 data.package = package;
6737 data.cb = installassembly_cb;
6738 data.user = &assemblies;
6740 if (assembly->file->IsCompressed &&
6741 !msi_cabextract(package, mi, &data))
6743 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6744 r = ERROR_FUNCTION_FAILED;
6749 if (!assembly->file->IsCompressed)
6751 LPWSTR source = resolve_file_source(package, assembly->file);
6753 r = install_assembly(package, assembly, source);
6754 if (r != ERROR_SUCCESS)
6755 ERR("Failed to install assembly\n");
6760 /* FIXME: write Installer assembly reg values */
6764 free_assemblies(&assemblies);
6768 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6770 LPWSTR key, template, id;
6771 UINT r = ERROR_SUCCESS;
6773 id = msi_dup_property( package, szProductID );
6777 return ERROR_SUCCESS;
6779 template = msi_dup_property( package, szPIDTemplate );
6780 key = msi_dup_property( package, szPIDKEY );
6782 if (key && template)
6784 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6785 r = MSI_SetPropertyW( package, szProductID, key );
6787 msi_free( template );
6792 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6795 package->need_reboot = 1;
6796 return ERROR_SUCCESS;
6799 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6801 static const WCHAR szAvailableFreeReg[] =
6802 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6804 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6806 TRACE("%p %d kilobytes\n", package, space);
6808 uirow = MSI_CreateRecord( 1 );
6809 MSI_RecordSetInteger( uirow, 1, space );
6810 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6811 msiobj_release( &uirow->hdr );
6813 return ERROR_SUCCESS;
6816 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6818 FIXME("%p\n", package);
6819 return ERROR_SUCCESS;
6822 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6824 FIXME("%p\n", package);
6825 return ERROR_SUCCESS;
6828 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6833 static const WCHAR driver_query[] = {
6834 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6835 'O','D','B','C','D','r','i','v','e','r',0 };
6837 static const WCHAR translator_query[] = {
6838 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6839 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6841 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6842 if (r == ERROR_SUCCESS)
6845 r = MSI_IterateRecords( view, &count, NULL, package );
6846 msiobj_release( &view->hdr );
6847 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6850 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6851 if (r == ERROR_SUCCESS)
6854 r = MSI_IterateRecords( view, &count, NULL, package );
6855 msiobj_release( &view->hdr );
6856 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6859 return ERROR_SUCCESS;
6862 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6863 LPCSTR action, LPCWSTR table )
6865 static const WCHAR query[] = {
6866 'S','E','L','E','C','T',' ','*',' ',
6867 'F','R','O','M',' ','`','%','s','`',0 };
6868 MSIQUERY *view = NULL;
6872 r = MSI_OpenQuery( package->db, &view, query, table );
6873 if (r == ERROR_SUCCESS)
6875 r = MSI_IterateRecords(view, &count, NULL, package);
6876 msiobj_release(&view->hdr);
6880 FIXME("%s -> %u ignored %s table values\n",
6881 action, count, debugstr_w(table));
6883 return ERROR_SUCCESS;
6886 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6888 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6889 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6892 static UINT ACTION_BindImage( MSIPACKAGE *package )
6894 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6895 return msi_unimplemented_action_stub( package, "BindImage", table );
6898 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6900 static const WCHAR table[] = {
6901 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6902 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6905 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6907 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6908 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6911 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6913 static const WCHAR table[] = {
6914 'M','s','i','A','s','s','e','m','b','l','y',0 };
6915 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6918 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6920 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6921 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6924 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6926 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6927 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6930 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6932 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6933 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6936 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6938 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6939 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6942 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6944 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6945 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6948 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6952 const WCHAR *action;
6953 UINT (*handler)(MSIPACKAGE *);
6957 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6958 { szAppSearch, ACTION_AppSearch },
6959 { szBindImage, ACTION_BindImage },
6960 { szCCPSearch, ACTION_CCPSearch },
6961 { szCostFinalize, ACTION_CostFinalize },
6962 { szCostInitialize, ACTION_CostInitialize },
6963 { szCreateFolders, ACTION_CreateFolders },
6964 { szCreateShortcuts, ACTION_CreateShortcuts },
6965 { szDeleteServices, ACTION_DeleteServices },
6966 { szDisableRollback, ACTION_DisableRollback },
6967 { szDuplicateFiles, ACTION_DuplicateFiles },
6968 { szExecuteAction, ACTION_ExecuteAction },
6969 { szFileCost, ACTION_FileCost },
6970 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6971 { szForceReboot, ACTION_ForceReboot },
6972 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6973 { szInstallExecute, ACTION_InstallExecute },
6974 { szInstallExecuteAgain, ACTION_InstallExecute },
6975 { szInstallFiles, ACTION_InstallFiles},
6976 { szInstallFinalize, ACTION_InstallFinalize },
6977 { szInstallInitialize, ACTION_InstallInitialize },
6978 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6979 { szInstallValidate, ACTION_InstallValidate },
6980 { szIsolateComponents, ACTION_IsolateComponents },
6981 { szLaunchConditions, ACTION_LaunchConditions },
6982 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6983 { szMoveFiles, ACTION_MoveFiles },
6984 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6985 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6986 { szInstallODBC, ACTION_InstallODBC },
6987 { szInstallServices, ACTION_InstallServices },
6988 { szPatchFiles, ACTION_PatchFiles },
6989 { szProcessComponents, ACTION_ProcessComponents },
6990 { szPublishComponents, ACTION_PublishComponents },
6991 { szPublishFeatures, ACTION_PublishFeatures },
6992 { szPublishProduct, ACTION_PublishProduct },
6993 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6994 { szRegisterComPlus, ACTION_RegisterComPlus},
6995 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6996 { szRegisterFonts, ACTION_RegisterFonts },
6997 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6998 { szRegisterProduct, ACTION_RegisterProduct },
6999 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7000 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7001 { szRegisterUser, ACTION_RegisterUser },
7002 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7003 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7004 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7005 { szRemoveFiles, ACTION_RemoveFiles },
7006 { szRemoveFolders, ACTION_RemoveFolders },
7007 { szRemoveIniValues, ACTION_RemoveIniValues },
7008 { szRemoveODBC, ACTION_RemoveODBC },
7009 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7010 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7011 { szResolveSource, ACTION_ResolveSource },
7012 { szRMCCPSearch, ACTION_RMCCPSearch },
7013 { szScheduleReboot, ACTION_ScheduleReboot },
7014 { szSelfRegModules, ACTION_SelfRegModules },
7015 { szSelfUnregModules, ACTION_SelfUnregModules },
7016 { szSetODBCFolders, ACTION_SetODBCFolders },
7017 { szStartServices, ACTION_StartServices },
7018 { szStopServices, ACTION_StopServices },
7019 { szUnpublishComponents, ACTION_UnpublishComponents },
7020 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7021 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7022 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7023 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7024 { szUnregisterFonts, ACTION_UnregisterFonts },
7025 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7026 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7027 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7028 { szValidateProductID, ACTION_ValidateProductID },
7029 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7030 { szWriteIniValues, ACTION_WriteIniValues },
7031 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7035 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7036 UINT* rc, BOOL force )
7042 if (!run && !package->script->CurrentlyScripting)
7047 if (strcmpW(action,szInstallFinalize) == 0 ||
7048 strcmpW(action,szInstallExecute) == 0 ||
7049 strcmpW(action,szInstallExecuteAgain) == 0)
7054 while (StandardActions[i].action != NULL)
7056 if (strcmpW(StandardActions[i].action, action)==0)
7060 ui_actioninfo(package, action, TRUE, 0);
7061 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7062 ui_actioninfo(package, action, FALSE, *rc);
7066 ui_actionstart(package, action);
7067 if (StandardActions[i].handler)
7069 *rc = StandardActions[i].handler(package);
7073 FIXME("unhandled standard action %s\n",debugstr_w(action));
7074 *rc = ERROR_SUCCESS;
7085 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7087 UINT rc = ERROR_SUCCESS;
7090 TRACE("Performing action (%s)\n", debugstr_w(action));
7092 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7095 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7099 WARN("unhandled msi action %s\n", debugstr_w(action));
7100 rc = ERROR_FUNCTION_NOT_CALLED;
7106 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7108 UINT rc = ERROR_SUCCESS;
7109 BOOL handled = FALSE;
7111 TRACE("Performing action (%s)\n", debugstr_w(action));
7113 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7116 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7118 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7123 WARN("unhandled msi action %s\n", debugstr_w(action));
7124 rc = ERROR_FUNCTION_NOT_CALLED;
7130 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7132 UINT rc = ERROR_SUCCESS;
7135 static const WCHAR ExecSeqQuery[] =
7136 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7137 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7138 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7139 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7140 static const WCHAR UISeqQuery[] =
7141 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7142 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7143 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7144 ' ', '=',' ','%','i',0};
7146 if (needs_ui_sequence(package))
7147 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7149 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7153 LPCWSTR action, cond;
7155 TRACE("Running the actions\n");
7157 /* check conditions */
7158 cond = MSI_RecordGetString(row, 2);
7160 /* this is a hack to skip errors in the condition code */
7161 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7163 msiobj_release(&row->hdr);
7164 return ERROR_SUCCESS;
7167 action = MSI_RecordGetString(row, 1);
7170 ERR("failed to fetch action\n");
7171 msiobj_release(&row->hdr);
7172 return ERROR_FUNCTION_FAILED;
7175 if (needs_ui_sequence(package))
7176 rc = ACTION_PerformUIAction(package, action, -1);
7178 rc = ACTION_PerformAction(package, action, -1, FALSE);
7180 msiobj_release(&row->hdr);
7186 /****************************************************
7187 * TOP level entry points
7188 *****************************************************/
7190 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7191 LPCWSTR szCommandLine )
7196 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7197 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7199 MSI_SetPropertyW(package, szAction, szInstall);
7201 package->script->InWhatSequence = SEQUENCE_INSTALL;
7208 dir = strdupW(szPackagePath);
7209 p = strrchrW(dir, '\\');
7213 file = szPackagePath + (p - dir);
7218 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7219 GetCurrentDirectoryW(MAX_PATH, dir);
7220 lstrcatW(dir, szBackSlash);
7221 file = szPackagePath;
7224 msi_free( package->PackagePath );
7225 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7226 if (!package->PackagePath)
7229 return ERROR_OUTOFMEMORY;
7232 lstrcpyW(package->PackagePath, dir);
7233 lstrcatW(package->PackagePath, file);
7236 msi_set_sourcedir_props(package, FALSE);
7239 msi_parse_command_line( package, szCommandLine, FALSE );
7241 msi_apply_transforms( package );
7242 msi_apply_patches( package );
7244 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7246 TRACE("setting reinstall property\n");
7247 MSI_SetPropertyW( package, szReinstall, szAll );
7250 /* properties may have been added by a transform */
7251 msi_clone_properties( package );
7252 msi_set_context( package );
7254 if (needs_ui_sequence( package))
7256 package->script->InWhatSequence |= SEQUENCE_UI;
7257 rc = ACTION_ProcessUISequence(package);
7258 ui_exists = ui_sequence_exists(package);
7259 if (rc == ERROR_SUCCESS || !ui_exists)
7261 package->script->InWhatSequence |= SEQUENCE_EXEC;
7262 rc = ACTION_ProcessExecSequence(package, ui_exists);
7266 rc = ACTION_ProcessExecSequence(package, FALSE);
7268 package->script->CurrentlyScripting = FALSE;
7270 /* process the ending type action */
7271 if (rc == ERROR_SUCCESS)
7272 ACTION_PerformActionSequence(package, -1);
7273 else if (rc == ERROR_INSTALL_USEREXIT)
7274 ACTION_PerformActionSequence(package, -2);
7275 else if (rc == ERROR_INSTALL_SUSPEND)
7276 ACTION_PerformActionSequence(package, -4);
7278 ACTION_PerformActionSequence(package, -3);
7280 /* finish up running custom actions */
7281 ACTION_FinishCustomActions(package);
7283 if (rc == ERROR_SUCCESS && package->need_reboot)
7284 return ERROR_SUCCESS_REBOOT_REQUIRED;