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->db, 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->db, 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->db, 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->db, 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 UINT r = ERROR_SUCCESS;
496 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
498 return ERROR_FUNCTION_FAILED;
500 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
502 TRACE("Patch not applicable\n");
503 msiobj_release( &si->hdr );
504 return ERROR_SUCCESS;
507 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
510 msiobj_release( &si->hdr );
511 return ERROR_OUTOFMEMORY;
514 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
515 if (!package->patch->patchcode)
517 msiobj_release( &si->hdr );
518 return ERROR_OUTOFMEMORY;
521 package->patch->transforms = msi_suminfo_dup_string(si, PID_LASTAUTHOR);
522 if (!package->patch->transforms)
524 msiobj_release( &si->hdr );
525 return ERROR_OUTOFMEMORY;
528 msiobj_release( &si->hdr );
532 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
534 MSIDATABASE *patch_db = NULL;
538 TRACE("%p %s\n", package, debugstr_w( file ) );
541 * We probably want to make sure we only open a patch collection here.
542 * Patch collections (.msp) and databases (.msi) have different GUIDs
543 * but currently MSI_OpenDatabaseW will accept both.
545 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
546 if ( r != ERROR_SUCCESS )
548 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
552 msi_parse_patch_summary( package, patch_db );
554 /* apply substorage transforms */
555 substorage = msi_split_string( package->patch->transforms, ';' );
556 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
557 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
559 msi_free( substorage );
560 msi_set_media_source_prop( package );
563 * There might be a CAB file in the patch package,
564 * so append it to the list of storage to search for streams.
566 append_storage_to_db( package->db, patch_db->storage );
568 msiobj_release( &patch_db->hdr );
570 return ERROR_SUCCESS;
573 /* get the PATCH property, and apply all the patches it specifies */
574 static UINT msi_apply_patches( MSIPACKAGE *package )
576 LPWSTR patch_list, *patches;
577 UINT i, r = ERROR_SUCCESS;
579 patch_list = msi_dup_property( package->db, szPatch );
581 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
583 patches = msi_split_string( patch_list, ';' );
584 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
585 r = msi_apply_patch_package( package, patches[i] );
588 msi_free( patch_list );
593 static UINT msi_apply_transforms( MSIPACKAGE *package )
595 static const WCHAR szTransforms[] = {
596 'T','R','A','N','S','F','O','R','M','S',0 };
597 LPWSTR xform_list, *xforms;
598 UINT i, r = ERROR_SUCCESS;
600 xform_list = msi_dup_property( package->db, szTransforms );
601 xforms = msi_split_string( xform_list, ';' );
603 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
605 if (xforms[i][0] == ':')
606 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
608 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
612 msi_free( xform_list );
617 static BOOL ui_sequence_exists( MSIPACKAGE *package )
622 static const WCHAR ExecSeqQuery [] =
623 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
624 '`','I','n','s','t','a','l','l',
625 'U','I','S','e','q','u','e','n','c','e','`',
626 ' ','W','H','E','R','E',' ',
627 '`','S','e','q','u','e','n','c','e','`',' ',
628 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
629 '`','S','e','q','u','e','n','c','e','`',0};
631 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
632 if (rc == ERROR_SUCCESS)
634 msiobj_release(&view->hdr);
641 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
644 LPWSTR source, check;
647 static const WCHAR szOriginalDatabase[] =
648 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
650 db = msi_dup_property( package->db, szOriginalDatabase );
652 return ERROR_OUTOFMEMORY;
654 p = strrchrW( db, '\\' );
657 p = strrchrW( db, '/' );
661 return ERROR_SUCCESS;
666 source = msi_alloc( len * sizeof(WCHAR) );
667 lstrcpynW( source, db, len );
669 check = msi_dup_property( package->db, cszSourceDir );
670 if (!check || replace)
671 MSI_SetPropertyW( package, cszSourceDir, source );
675 check = msi_dup_property( package->db, cszSOURCEDIR );
676 if (!check || replace)
677 MSI_SetPropertyW( package, cszSOURCEDIR, source );
683 return ERROR_SUCCESS;
686 static BOOL needs_ui_sequence(MSIPACKAGE *package)
688 INT level = msi_get_property_int(package->db, szUILevel, 0);
689 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
692 static UINT msi_set_context(MSIPACKAGE *package)
699 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
701 r = MSI_GetPropertyW(package->db, szAllUsers, val, &sz);
702 if (r == ERROR_SUCCESS)
705 if (num == 1 || num == 2)
706 package->Context = MSIINSTALLCONTEXT_MACHINE;
709 return ERROR_SUCCESS;
712 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
715 LPCWSTR cond, action;
716 MSIPACKAGE *package = param;
718 action = MSI_RecordGetString(row,1);
721 ERR("Error is retrieving action name\n");
722 return ERROR_FUNCTION_FAILED;
725 /* check conditions */
726 cond = MSI_RecordGetString(row,2);
728 /* this is a hack to skip errors in the condition code */
729 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
731 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
732 return ERROR_SUCCESS;
735 if (needs_ui_sequence(package))
736 rc = ACTION_PerformUIAction(package, action, -1);
738 rc = ACTION_PerformAction(package, action, -1, FALSE);
740 msi_dialog_check_messages( NULL );
742 if (package->CurrentInstallState != ERROR_SUCCESS)
743 rc = package->CurrentInstallState;
745 if (rc == ERROR_FUNCTION_NOT_CALLED)
748 if (rc != ERROR_SUCCESS)
749 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
754 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
758 static const WCHAR query[] =
759 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
761 ' ','W','H','E','R','E',' ',
762 '`','S','e','q','u','e','n','c','e','`',' ',
763 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
764 '`','S','e','q','u','e','n','c','e','`',0};
766 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
768 r = MSI_OpenQuery( package->db, &view, query, szTable );
769 if (r == ERROR_SUCCESS)
771 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
772 msiobj_release(&view->hdr);
778 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
782 static const WCHAR ExecSeqQuery[] =
783 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
784 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
785 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
786 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
787 'O','R','D','E','R',' ', 'B','Y',' ',
788 '`','S','e','q','u','e','n','c','e','`',0 };
789 static const WCHAR IVQuery[] =
790 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
791 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
792 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
793 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
794 ' ','\'', 'I','n','s','t','a','l','l',
795 'V','a','l','i','d','a','t','e','\'', 0};
798 if (package->script->ExecuteSequenceRun)
800 TRACE("Execute Sequence already Run\n");
801 return ERROR_SUCCESS;
804 package->script->ExecuteSequenceRun = TRUE;
806 /* get the sequence number */
809 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
811 return ERROR_FUNCTION_FAILED;
812 seq = MSI_RecordGetInteger(row,1);
813 msiobj_release(&row->hdr);
816 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
817 if (rc == ERROR_SUCCESS)
819 TRACE("Running the actions\n");
821 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
822 msiobj_release(&view->hdr);
828 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
832 static const WCHAR ExecSeqQuery [] =
833 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
834 '`','I','n','s','t','a','l','l',
835 'U','I','S','e','q','u','e','n','c','e','`',
836 ' ','W','H','E','R','E',' ',
837 '`','S','e','q','u','e','n','c','e','`',' ',
838 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
839 '`','S','e','q','u','e','n','c','e','`',0};
841 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
842 if (rc == ERROR_SUCCESS)
844 TRACE("Running the actions\n");
846 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
847 msiobj_release(&view->hdr);
853 /********************************************************
854 * ACTION helper functions and functions that perform the actions
855 *******************************************************/
856 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
857 UINT* rc, UINT script, BOOL force )
862 arc = ACTION_CustomAction(package, action, script, force);
864 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
873 * Actual Action Handlers
876 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
878 MSIPACKAGE *package = param;
879 LPCWSTR dir, component;
885 component = MSI_RecordGetString(row, 2);
886 comp = get_loaded_component(package, component);
888 return ERROR_SUCCESS;
890 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
892 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
893 comp->Action = comp->Installed;
894 return ERROR_SUCCESS;
896 comp->Action = INSTALLSTATE_LOCAL;
898 dir = MSI_RecordGetString(row,1);
901 ERR("Unable to get folder id\n");
902 return ERROR_SUCCESS;
905 uirow = MSI_CreateRecord(1);
906 MSI_RecordSetStringW(uirow, 1, dir);
907 ui_actiondata(package, szCreateFolders, uirow);
908 msiobj_release(&uirow->hdr);
910 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
913 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
914 return ERROR_SUCCESS;
917 TRACE("Folder is %s\n",debugstr_w(full_path));
919 if (folder->State == 0)
920 create_full_pathW(full_path);
925 return ERROR_SUCCESS;
928 /* FIXME: probably should merge this with the above function */
929 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
931 UINT rc = ERROR_SUCCESS;
935 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
937 return ERROR_FUNCTION_FAILED;
939 /* create the path */
940 if (folder->State == 0)
942 create_full_pathW(install_path);
945 msi_free(install_path);
950 UINT msi_create_component_directories( MSIPACKAGE *package )
954 /* create all the folders required by the components are going to install */
955 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
957 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
959 msi_create_directory( package, comp->Directory );
962 return ERROR_SUCCESS;
965 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
967 static const WCHAR ExecSeqQuery[] =
968 {'S','E','L','E','C','T',' ',
969 '`','D','i','r','e','c','t','o','r','y','_','`',
970 ' ','F','R','O','M',' ',
971 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
975 /* create all the empty folders specified in the CreateFolder table */
976 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
977 if (rc != ERROR_SUCCESS)
978 return ERROR_SUCCESS;
980 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
981 msiobj_release(&view->hdr);
986 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
988 MSIPACKAGE *package = param;
989 LPCWSTR dir, component;
995 component = MSI_RecordGetString(row, 2);
996 comp = get_loaded_component(package, component);
998 return ERROR_SUCCESS;
1000 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1002 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1003 comp->Action = comp->Installed;
1004 return ERROR_SUCCESS;
1006 comp->Action = INSTALLSTATE_ABSENT;
1008 dir = MSI_RecordGetString( row, 1 );
1011 ERR("Unable to get folder id\n");
1012 return ERROR_SUCCESS;
1015 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1018 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1019 return ERROR_SUCCESS;
1022 TRACE("folder is %s\n", debugstr_w(full_path));
1024 uirow = MSI_CreateRecord( 1 );
1025 MSI_RecordSetStringW( uirow, 1, full_path );
1026 ui_actiondata( package, szRemoveFolders, uirow );
1027 msiobj_release( &uirow->hdr );
1029 RemoveDirectoryW( full_path );
1032 msi_free( full_path );
1033 return ERROR_SUCCESS;
1036 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1038 static const WCHAR query[] =
1039 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1040 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1045 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1046 if (rc != ERROR_SUCCESS)
1047 return ERROR_SUCCESS;
1049 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1050 msiobj_release( &view->hdr );
1055 static UINT load_component( MSIRECORD *row, LPVOID param )
1057 MSIPACKAGE *package = param;
1060 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1062 return ERROR_FUNCTION_FAILED;
1064 list_add_tail( &package->components, &comp->entry );
1066 /* fill in the data */
1067 comp->Component = msi_dup_record_field( row, 1 );
1069 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1071 comp->ComponentId = msi_dup_record_field( row, 2 );
1072 comp->Directory = msi_dup_record_field( row, 3 );
1073 comp->Attributes = MSI_RecordGetInteger(row,4);
1074 comp->Condition = msi_dup_record_field( row, 5 );
1075 comp->KeyPath = msi_dup_record_field( row, 6 );
1077 comp->Installed = INSTALLSTATE_UNKNOWN;
1078 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1080 return ERROR_SUCCESS;
1083 static UINT load_all_components( MSIPACKAGE *package )
1085 static const WCHAR query[] = {
1086 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1087 '`','C','o','m','p','o','n','e','n','t','`',0 };
1091 if (!list_empty(&package->components))
1092 return ERROR_SUCCESS;
1094 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1095 if (r != ERROR_SUCCESS)
1098 r = MSI_IterateRecords(view, NULL, load_component, package);
1099 msiobj_release(&view->hdr);
1104 MSIPACKAGE *package;
1105 MSIFEATURE *feature;
1108 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1112 cl = msi_alloc( sizeof (*cl) );
1114 return ERROR_NOT_ENOUGH_MEMORY;
1115 cl->component = comp;
1116 list_add_tail( &feature->Components, &cl->entry );
1118 return ERROR_SUCCESS;
1121 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1125 fl = msi_alloc( sizeof(*fl) );
1127 return ERROR_NOT_ENOUGH_MEMORY;
1128 fl->feature = child;
1129 list_add_tail( &parent->Children, &fl->entry );
1131 return ERROR_SUCCESS;
1134 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1136 _ilfs* ilfs = param;
1140 component = MSI_RecordGetString(row,1);
1142 /* check to see if the component is already loaded */
1143 comp = get_loaded_component( ilfs->package, component );
1146 ERR("unknown component %s\n", debugstr_w(component));
1147 return ERROR_FUNCTION_FAILED;
1150 add_feature_component( ilfs->feature, comp );
1151 comp->Enabled = TRUE;
1153 return ERROR_SUCCESS;
1156 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1158 MSIFEATURE *feature;
1163 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1165 if ( !lstrcmpW( feature->Feature, name ) )
1172 static UINT load_feature(MSIRECORD * row, LPVOID param)
1174 MSIPACKAGE* package = param;
1175 MSIFEATURE* feature;
1176 static const WCHAR Query1[] =
1177 {'S','E','L','E','C','T',' ',
1178 '`','C','o','m','p','o','n','e','n','t','_','`',
1179 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1180 'C','o','m','p','o','n','e','n','t','s','`',' ',
1181 'W','H','E','R','E',' ',
1182 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1187 /* fill in the data */
1189 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1191 return ERROR_NOT_ENOUGH_MEMORY;
1193 list_init( &feature->Children );
1194 list_init( &feature->Components );
1196 feature->Feature = msi_dup_record_field( row, 1 );
1198 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1200 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1201 feature->Title = msi_dup_record_field( row, 3 );
1202 feature->Description = msi_dup_record_field( row, 4 );
1204 if (!MSI_RecordIsNull(row,5))
1205 feature->Display = MSI_RecordGetInteger(row,5);
1207 feature->Level= MSI_RecordGetInteger(row,6);
1208 feature->Directory = msi_dup_record_field( row, 7 );
1209 feature->Attributes = MSI_RecordGetInteger(row,8);
1211 feature->Installed = INSTALLSTATE_UNKNOWN;
1212 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1214 list_add_tail( &package->features, &feature->entry );
1216 /* load feature components */
1218 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1219 if (rc != ERROR_SUCCESS)
1220 return ERROR_SUCCESS;
1222 ilfs.package = package;
1223 ilfs.feature = feature;
1225 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1226 msiobj_release(&view->hdr);
1228 return ERROR_SUCCESS;
1231 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1233 MSIPACKAGE* package = param;
1234 MSIFEATURE *parent, *child;
1236 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1238 return ERROR_FUNCTION_FAILED;
1240 if (!child->Feature_Parent)
1241 return ERROR_SUCCESS;
1243 parent = find_feature_by_name( package, child->Feature_Parent );
1245 return ERROR_FUNCTION_FAILED;
1247 add_feature_child( parent, child );
1248 return ERROR_SUCCESS;
1251 static UINT load_all_features( MSIPACKAGE *package )
1253 static const WCHAR query[] = {
1254 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1255 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1256 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1260 if (!list_empty(&package->features))
1261 return ERROR_SUCCESS;
1263 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1264 if (r != ERROR_SUCCESS)
1267 r = MSI_IterateRecords( view, NULL, load_feature, package );
1268 if (r != ERROR_SUCCESS)
1271 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1272 msiobj_release( &view->hdr );
1277 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1288 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1290 static const WCHAR query[] = {
1291 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1292 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1293 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1294 MSIQUERY *view = NULL;
1295 MSIRECORD *row = NULL;
1298 TRACE("%s\n", debugstr_w(file->File));
1300 r = MSI_OpenQuery(package->db, &view, query, file->File);
1301 if (r != ERROR_SUCCESS)
1304 r = MSI_ViewExecute(view, NULL);
1305 if (r != ERROR_SUCCESS)
1308 r = MSI_ViewFetch(view, &row);
1309 if (r != ERROR_SUCCESS)
1312 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1313 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1314 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1315 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1316 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1319 if (view) msiobj_release(&view->hdr);
1320 if (row) msiobj_release(&row->hdr);
1324 static UINT load_file(MSIRECORD *row, LPVOID param)
1326 MSIPACKAGE* package = param;
1330 /* fill in the data */
1332 file = msi_alloc_zero( sizeof (MSIFILE) );
1334 return ERROR_NOT_ENOUGH_MEMORY;
1336 file->File = msi_dup_record_field( row, 1 );
1338 component = MSI_RecordGetString( row, 2 );
1339 file->Component = get_loaded_component( package, component );
1341 if (!file->Component)
1343 WARN("Component not found: %s\n", debugstr_w(component));
1344 msi_free(file->File);
1346 return ERROR_SUCCESS;
1349 file->FileName = msi_dup_record_field( row, 3 );
1350 reduce_to_longfilename( file->FileName );
1352 file->ShortName = msi_dup_record_field( row, 3 );
1353 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1355 file->FileSize = MSI_RecordGetInteger( row, 4 );
1356 file->Version = msi_dup_record_field( row, 5 );
1357 file->Language = msi_dup_record_field( row, 6 );
1358 file->Attributes = MSI_RecordGetInteger( row, 7 );
1359 file->Sequence = MSI_RecordGetInteger( row, 8 );
1361 file->state = msifs_invalid;
1363 /* if the compressed bits are not set in the file attributes,
1364 * then read the information from the package word count property
1366 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1368 file->IsCompressed = FALSE;
1370 else if (file->Attributes &
1371 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1373 file->IsCompressed = TRUE;
1375 else if (file->Attributes & msidbFileAttributesNoncompressed)
1377 file->IsCompressed = FALSE;
1381 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1384 load_file_hash(package, file);
1386 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1388 list_add_tail( &package->files, &file->entry );
1390 return ERROR_SUCCESS;
1393 static UINT load_all_files(MSIPACKAGE *package)
1397 static const WCHAR Query[] =
1398 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1399 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1400 '`','S','e','q','u','e','n','c','e','`', 0};
1402 if (!list_empty(&package->files))
1403 return ERROR_SUCCESS;
1405 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1406 if (rc != ERROR_SUCCESS)
1407 return ERROR_SUCCESS;
1409 rc = MSI_IterateRecords(view, NULL, load_file, package);
1410 msiobj_release(&view->hdr);
1412 return ERROR_SUCCESS;
1415 static UINT load_folder( MSIRECORD *row, LPVOID param )
1417 MSIPACKAGE *package = param;
1418 static WCHAR szEmpty[] = { 0 };
1419 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1422 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1424 return ERROR_NOT_ENOUGH_MEMORY;
1426 folder->Directory = msi_dup_record_field( row, 1 );
1428 TRACE("%s\n", debugstr_w(folder->Directory));
1430 p = msi_dup_record_field(row, 3);
1432 /* split src and target dir */
1434 src_short = folder_split_path( p, ':' );
1436 /* split the long and short paths */
1437 tgt_long = folder_split_path( tgt_short, '|' );
1438 src_long = folder_split_path( src_short, '|' );
1440 /* check for no-op dirs */
1441 if (!lstrcmpW(szDot, tgt_short))
1442 tgt_short = szEmpty;
1443 if (!lstrcmpW(szDot, src_short))
1444 src_short = szEmpty;
1447 tgt_long = tgt_short;
1450 src_short = tgt_short;
1451 src_long = tgt_long;
1455 src_long = src_short;
1457 /* FIXME: use the target short path too */
1458 folder->TargetDefault = strdupW(tgt_long);
1459 folder->SourceShortPath = strdupW(src_short);
1460 folder->SourceLongPath = strdupW(src_long);
1463 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1464 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1465 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1467 folder->Parent = msi_dup_record_field( row, 2 );
1469 folder->Property = msi_dup_property( package->db, folder->Directory );
1471 list_add_tail( &package->folders, &folder->entry );
1473 TRACE("returning %p\n", folder);
1475 return ERROR_SUCCESS;
1478 static UINT load_all_folders( MSIPACKAGE *package )
1480 static const WCHAR query[] = {
1481 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1482 '`','D','i','r','e','c','t','o','r','y','`',0 };
1486 if (!list_empty(&package->folders))
1487 return ERROR_SUCCESS;
1489 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1490 if (r != ERROR_SUCCESS)
1493 r = MSI_IterateRecords(view, NULL, load_folder, package);
1494 msiobj_release(&view->hdr);
1499 * I am not doing any of the costing functionality yet.
1500 * Mostly looking at doing the Component and Feature loading
1502 * The native MSI does A LOT of modification to tables here. Mostly adding
1503 * a lot of temporary columns to the Feature and Component tables.
1505 * note: Native msi also tracks the short filename. But I am only going to
1506 * track the long ones. Also looking at this directory table
1507 * it appears that the directory table does not get the parents
1508 * resolved base on property only based on their entries in the
1511 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1513 static const WCHAR szCosting[] =
1514 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1516 MSI_SetPropertyW(package, szCosting, szZero);
1517 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1519 load_all_folders( package );
1520 load_all_components( package );
1521 load_all_features( package );
1522 load_all_files( package );
1524 return ERROR_SUCCESS;
1527 static UINT execute_script(MSIPACKAGE *package, UINT script )
1530 UINT rc = ERROR_SUCCESS;
1532 TRACE("Executing Script %i\n",script);
1534 if (!package->script)
1536 ERR("no script!\n");
1537 return ERROR_FUNCTION_FAILED;
1540 for (i = 0; i < package->script->ActionCount[script]; i++)
1543 action = package->script->Actions[script][i];
1544 ui_actionstart(package, action);
1545 TRACE("Executing Action (%s)\n",debugstr_w(action));
1546 rc = ACTION_PerformAction(package, action, script, TRUE);
1547 if (rc != ERROR_SUCCESS)
1550 msi_free_action_script(package, script);
1554 static UINT ACTION_FileCost(MSIPACKAGE *package)
1556 return ERROR_SUCCESS;
1559 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1565 state = MsiQueryProductStateW(package->ProductCode);
1567 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1569 if (!comp->ComponentId)
1572 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1573 comp->Installed = INSTALLSTATE_ABSENT;
1576 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1577 package->Context, comp->ComponentId,
1579 if (r != ERROR_SUCCESS)
1580 comp->Installed = INSTALLSTATE_ABSENT;
1585 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1587 MSIFEATURE *feature;
1590 state = MsiQueryProductStateW(package->ProductCode);
1592 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1594 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1595 feature->Installed = INSTALLSTATE_ABSENT;
1598 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1604 static BOOL process_state_property(MSIPACKAGE* package, int level,
1605 LPCWSTR property, INSTALLSTATE state)
1608 MSIFEATURE *feature;
1610 override = msi_dup_property( package->db, property );
1614 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1616 if (lstrcmpW(property, szRemove) &&
1617 (feature->Level <= 0 || feature->Level > level))
1620 if (!strcmpW(property, szReinstall)) state = feature->Installed;
1622 if (strcmpiW(override, szAll)==0)
1623 msi_feature_set_state(package, feature, state);
1626 LPWSTR ptr = override;
1627 LPWSTR ptr2 = strchrW(override,',');
1631 int len = ptr2 - ptr;
1633 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1634 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
1636 msi_feature_set_state(package, feature, state);
1642 ptr2 = strchrW(ptr,',');
1654 static BOOL process_overrides( MSIPACKAGE *package, int level )
1656 static const WCHAR szAddLocal[] =
1657 {'A','D','D','L','O','C','A','L',0};
1658 static const WCHAR szAddSource[] =
1659 {'A','D','D','S','O','U','R','C','E',0};
1660 static const WCHAR szAdvertise[] =
1661 {'A','D','V','E','R','T','I','S','E',0};
1664 /* all these activation/deactivation things happen in order and things
1665 * later on the list override things earlier on the list.
1667 * 0 INSTALLLEVEL processing
1680 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1681 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1682 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1683 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1684 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1687 MSI_SetPropertyW( package, szPreselected, szOne );
1692 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1695 static const WCHAR szlevel[] =
1696 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1697 MSICOMPONENT* component;
1698 MSIFEATURE *feature;
1700 TRACE("Checking Install Level\n");
1702 level = msi_get_property_int(package->db, szlevel, 1);
1704 if (!msi_get_property_int( package->db, szPreselected, 0 ))
1706 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1708 BOOL feature_state = ((feature->Level > 0) &&
1709 (feature->Level <= level));
1711 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1713 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1714 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1715 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1716 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1718 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1722 /* disable child features of unselected parent features */
1723 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1727 if (feature->Level > 0 && feature->Level <= level)
1730 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1731 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1736 * now we want to enable or disable components base on feature
1739 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1743 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1744 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1746 if (!feature->Level)
1749 /* features with components that have compressed files are made local */
1750 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1752 if (cl->component->Enabled &&
1753 cl->component->ForceLocalState &&
1754 feature->Action == INSTALLSTATE_SOURCE)
1756 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1761 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1763 component = cl->component;
1765 if (!component->Enabled)
1768 switch (feature->Action)
1770 case INSTALLSTATE_ABSENT:
1771 component->anyAbsent = 1;
1773 case INSTALLSTATE_ADVERTISED:
1774 component->hasAdvertiseFeature = 1;
1776 case INSTALLSTATE_SOURCE:
1777 component->hasSourceFeature = 1;
1779 case INSTALLSTATE_LOCAL:
1780 component->hasLocalFeature = 1;
1782 case INSTALLSTATE_DEFAULT:
1783 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1784 component->hasAdvertiseFeature = 1;
1785 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1786 component->hasSourceFeature = 1;
1788 component->hasLocalFeature = 1;
1796 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1798 /* if the component isn't enabled, leave it alone */
1799 if (!component->Enabled)
1802 /* check if it's local or source */
1803 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1804 (component->hasLocalFeature || component->hasSourceFeature))
1806 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1807 !component->ForceLocalState)
1808 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1810 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1814 /* if any feature is local, the component must be local too */
1815 if (component->hasLocalFeature)
1817 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1821 if (component->hasSourceFeature)
1823 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1827 if (component->hasAdvertiseFeature)
1829 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1833 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1834 if (component->anyAbsent)
1835 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1838 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1840 if (component->Action == INSTALLSTATE_DEFAULT)
1842 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1843 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1846 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1847 debugstr_w(component->Component), component->Installed, component->Action);
1851 return ERROR_SUCCESS;
1854 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1856 MSIPACKAGE *package = param;
1861 name = MSI_RecordGetString(row,1);
1863 f = get_loaded_folder(package, name);
1864 if (!f) return ERROR_SUCCESS;
1866 /* reset the ResolvedTarget */
1867 msi_free(f->ResolvedTarget);
1868 f->ResolvedTarget = NULL;
1870 /* This helper function now does ALL the work */
1871 TRACE("Dir %s ...\n",debugstr_w(name));
1872 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1873 TRACE("resolves to %s\n",debugstr_w(path));
1876 return ERROR_SUCCESS;
1879 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1881 MSIPACKAGE *package = param;
1883 MSIFEATURE *feature;
1885 name = MSI_RecordGetString( row, 1 );
1887 feature = get_loaded_feature( package, name );
1889 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1893 Condition = MSI_RecordGetString(row,3);
1895 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1897 int level = MSI_RecordGetInteger(row,2);
1898 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1899 feature->Level = level;
1902 return ERROR_SUCCESS;
1905 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1907 static const WCHAR name_fmt[] =
1908 {'%','u','.','%','u','.','%','u','.','%','u',0};
1909 static const WCHAR name[] = {'\\',0};
1910 VS_FIXEDFILEINFO *lpVer;
1911 WCHAR filever[0x100];
1917 TRACE("%s\n", debugstr_w(filename));
1919 versize = GetFileVersionInfoSizeW( filename, &handle );
1923 version = msi_alloc( versize );
1924 GetFileVersionInfoW( filename, 0, versize, version );
1926 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1928 msi_free( version );
1932 sprintfW( filever, name_fmt,
1933 HIWORD(lpVer->dwFileVersionMS),
1934 LOWORD(lpVer->dwFileVersionMS),
1935 HIWORD(lpVer->dwFileVersionLS),
1936 LOWORD(lpVer->dwFileVersionLS));
1938 msi_free( version );
1940 return strdupW( filever );
1943 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1945 LPWSTR file_version;
1948 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1950 MSICOMPONENT* comp = file->Component;
1956 if (file->IsCompressed)
1957 comp->ForceLocalState = TRUE;
1959 /* calculate target */
1960 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1962 msi_free(file->TargetPath);
1964 TRACE("file %s is named %s\n",
1965 debugstr_w(file->File), debugstr_w(file->FileName));
1967 file->TargetPath = build_directory_name(2, p, file->FileName);
1971 TRACE("file %s resolves to %s\n",
1972 debugstr_w(file->File), debugstr_w(file->TargetPath));
1974 /* don't check files of components that aren't installed */
1975 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1976 comp->Installed == INSTALLSTATE_ABSENT)
1978 file->state = msifs_missing; /* assume files are missing */
1982 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1984 file->state = msifs_missing;
1985 comp->Cost += file->FileSize;
1989 if (file->Version &&
1990 (file_version = msi_get_disk_file_version( file->TargetPath )))
1992 TRACE("new %s old %s\n", debugstr_w(file->Version),
1993 debugstr_w(file_version));
1994 /* FIXME: seems like a bad way to compare version numbers */
1995 if (lstrcmpiW(file_version, file->Version)<0)
1997 file->state = msifs_overwrite;
1998 comp->Cost += file->FileSize;
2001 file->state = msifs_present;
2002 msi_free( file_version );
2006 file->state = msifs_overwrite;
2007 comp->Cost += file->FileSize;
2011 return ERROR_SUCCESS;
2015 * A lot is done in this function aside from just the costing.
2016 * The costing needs to be implemented at some point but for now I am going
2017 * to focus on the directory building
2020 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2022 static const WCHAR ExecSeqQuery[] =
2023 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2024 '`','D','i','r','e','c','t','o','r','y','`',0};
2025 static const WCHAR ConditionQuery[] =
2026 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2027 '`','C','o','n','d','i','t','i','o','n','`',0};
2028 static const WCHAR szCosting[] =
2029 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2030 static const WCHAR szlevel[] =
2031 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2032 static const WCHAR szOutOfDiskSpace[] =
2033 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2035 UINT rc = ERROR_SUCCESS;
2039 TRACE("Building Directory properties\n");
2041 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2042 if (rc == ERROR_SUCCESS)
2044 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2046 msiobj_release(&view->hdr);
2049 /* read components states from the registry */
2050 ACTION_GetComponentInstallStates(package);
2051 ACTION_GetFeatureInstallStates(package);
2053 TRACE("File calculations\n");
2054 msi_check_file_install_states( package );
2056 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
2058 TRACE("Evaluating Condition Table\n");
2060 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2061 if (rc == ERROR_SUCCESS)
2063 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2064 msiobj_release( &view->hdr );
2067 TRACE("Enabling or Disabling Components\n");
2068 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2070 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2072 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2073 comp->Enabled = FALSE;
2076 comp->Enabled = TRUE;
2080 MSI_SetPropertyW(package,szCosting,szOne);
2081 /* set default run level if not set */
2082 level = msi_dup_property( package->db, szlevel );
2084 MSI_SetPropertyW(package,szlevel, szOne);
2087 /* FIXME: check volume disk space */
2088 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2090 return MSI_SetFeatureStates(package);
2093 /* OK this value is "interpreted" and then formatted based on the
2094 first few characters */
2095 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2100 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2106 LPWSTR deformated = NULL;
2109 deformat_string(package, &value[2], &deformated);
2111 /* binary value type */
2115 *size = (strlenW(ptr)/2)+1;
2117 *size = strlenW(ptr)/2;
2119 data = msi_alloc(*size);
2125 /* if uneven pad with a zero in front */
2131 data[count] = (BYTE)strtol(byte,NULL,0);
2133 TRACE("Uneven byte count\n");
2141 data[count] = (BYTE)strtol(byte,NULL,0);
2144 msi_free(deformated);
2146 TRACE("Data %i bytes(%i)\n",*size,count);
2153 deformat_string(package, &value[1], &deformated);
2156 *size = sizeof(DWORD);
2157 data = msi_alloc(*size);
2163 if ( (*p < '0') || (*p > '9') )
2169 if (deformated[0] == '-')
2172 TRACE("DWORD %i\n",*(LPDWORD)data);
2174 msi_free(deformated);
2179 static const WCHAR szMulti[] = {'[','~',']',0};
2188 *type=REG_EXPAND_SZ;
2196 if (strstrW(value,szMulti))
2197 *type = REG_MULTI_SZ;
2199 /* remove initial delimiter */
2200 if (!strncmpW(value, szMulti, 3))
2203 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2205 /* add double NULL terminator */
2206 if (*type == REG_MULTI_SZ)
2208 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2209 data = msi_realloc_zero(data, *size);
2215 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2222 if (msi_get_property_int( package->db, szAllUsers, 0 ))
2224 *root_key = HKEY_LOCAL_MACHINE;
2229 *root_key = HKEY_CURRENT_USER;
2234 *root_key = HKEY_CLASSES_ROOT;
2238 *root_key = HKEY_CURRENT_USER;
2242 *root_key = HKEY_LOCAL_MACHINE;
2246 *root_key = HKEY_USERS;
2250 ERR("Unknown root %i\n", root);
2257 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2259 MSIPACKAGE *package = param;
2260 LPSTR value_data = NULL;
2261 HKEY root_key, hkey;
2264 LPCWSTR szRoot, component, name, key, value;
2269 BOOL check_first = FALSE;
2272 ui_progress(package,2,0,0,0);
2279 component = MSI_RecordGetString(row, 6);
2280 comp = get_loaded_component(package,component);
2282 return ERROR_SUCCESS;
2284 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2286 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2287 comp->Action = comp->Installed;
2288 return ERROR_SUCCESS;
2290 comp->Action = INSTALLSTATE_LOCAL;
2292 name = MSI_RecordGetString(row, 4);
2293 if( MSI_RecordIsNull(row,5) && name )
2295 /* null values can have special meanings */
2296 if (name[0]=='-' && name[1] == 0)
2297 return ERROR_SUCCESS;
2298 else if ((name[0]=='+' && name[1] == 0) ||
2299 (name[0] == '*' && name[1] == 0))
2304 root = MSI_RecordGetInteger(row,2);
2305 key = MSI_RecordGetString(row, 3);
2307 szRoot = get_root_key( package, root, &root_key );
2309 return ERROR_SUCCESS;
2311 deformat_string(package, key , &deformated);
2312 size = strlenW(deformated) + strlenW(szRoot) + 1;
2313 uikey = msi_alloc(size*sizeof(WCHAR));
2314 strcpyW(uikey,szRoot);
2315 strcatW(uikey,deformated);
2317 if (RegCreateKeyW( root_key, deformated, &hkey))
2319 ERR("Could not create key %s\n",debugstr_w(deformated));
2320 msi_free(deformated);
2322 return ERROR_SUCCESS;
2324 msi_free(deformated);
2326 value = MSI_RecordGetString(row,5);
2328 value_data = parse_value(package, value, &type, &size);
2331 value_data = (LPSTR)strdupW(szEmpty);
2332 size = sizeof(szEmpty);
2336 deformat_string(package, name, &deformated);
2340 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2342 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2347 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2348 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2350 TRACE("value %s of %s checked already exists\n",
2351 debugstr_w(deformated), debugstr_w(uikey));
2355 TRACE("Checked and setting value %s of %s\n",
2356 debugstr_w(deformated), debugstr_w(uikey));
2357 if (deformated || size)
2358 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2363 uirow = MSI_CreateRecord(3);
2364 MSI_RecordSetStringW(uirow,2,deformated);
2365 MSI_RecordSetStringW(uirow,1,uikey);
2366 if (type == REG_SZ || type == REG_EXPAND_SZ)
2367 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2368 ui_actiondata(package,szWriteRegistryValues,uirow);
2369 msiobj_release( &uirow->hdr );
2371 msi_free(value_data);
2372 msi_free(deformated);
2375 return ERROR_SUCCESS;
2378 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2382 static const WCHAR ExecSeqQuery[] =
2383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2384 '`','R','e','g','i','s','t','r','y','`',0 };
2386 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2387 if (rc != ERROR_SUCCESS)
2388 return ERROR_SUCCESS;
2390 /* increment progress bar each time action data is sent */
2391 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2393 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2395 msiobj_release(&view->hdr);
2399 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2403 DWORD num_subkeys, num_values;
2407 if ((res = RegDeleteTreeW( hkey_root, key )))
2409 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2414 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2416 if ((res = RegDeleteValueW( hkey, value )))
2418 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2420 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2421 NULL, NULL, NULL, NULL );
2422 RegCloseKey( hkey );
2424 if (!res && !num_subkeys && !num_values)
2426 TRACE("Removing empty key %s\n", debugstr_w(key));
2427 RegDeleteKeyW( hkey_root, key );
2431 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2435 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2437 MSIPACKAGE *package = param;
2438 LPCWSTR component, name, key_str, root_key_str;
2439 LPWSTR deformated_key, deformated_name, ui_key_str;
2442 BOOL delete_key = FALSE;
2447 ui_progress( package, 2, 0, 0, 0 );
2449 component = MSI_RecordGetString( row, 6 );
2450 comp = get_loaded_component( package, component );
2452 return ERROR_SUCCESS;
2454 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2456 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2457 comp->Action = comp->Installed;
2458 return ERROR_SUCCESS;
2460 comp->Action = INSTALLSTATE_ABSENT;
2462 name = MSI_RecordGetString( row, 4 );
2463 if (MSI_RecordIsNull( row, 5 ) && name )
2465 if (name[0] == '+' && !name[1])
2466 return ERROR_SUCCESS;
2467 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2474 root = MSI_RecordGetInteger( row, 2 );
2475 key_str = MSI_RecordGetString( row, 3 );
2477 root_key_str = get_root_key( package, root, &hkey_root );
2479 return ERROR_SUCCESS;
2481 deformat_string( package, key_str, &deformated_key );
2482 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2483 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2484 strcpyW( ui_key_str, root_key_str );
2485 strcatW( ui_key_str, deformated_key );
2487 deformat_string( package, name, &deformated_name );
2489 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2490 msi_free( deformated_key );
2492 uirow = MSI_CreateRecord( 2 );
2493 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2494 MSI_RecordSetStringW( uirow, 2, deformated_name );
2496 ui_actiondata( package, szRemoveRegistryValues, uirow );
2497 msiobj_release( &uirow->hdr );
2499 msi_free( ui_key_str );
2500 msi_free( deformated_name );
2501 return ERROR_SUCCESS;
2504 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2506 MSIPACKAGE *package = param;
2507 LPCWSTR component, name, key_str, root_key_str;
2508 LPWSTR deformated_key, deformated_name, ui_key_str;
2511 BOOL delete_key = FALSE;
2516 ui_progress( package, 2, 0, 0, 0 );
2518 component = MSI_RecordGetString( row, 5 );
2519 comp = get_loaded_component( package, component );
2521 return ERROR_SUCCESS;
2523 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2525 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2526 comp->Action = comp->Installed;
2527 return ERROR_SUCCESS;
2529 comp->Action = INSTALLSTATE_LOCAL;
2531 if ((name = MSI_RecordGetString( row, 4 )))
2533 if (name[0] == '-' && !name[1])
2540 root = MSI_RecordGetInteger( row, 2 );
2541 key_str = MSI_RecordGetString( row, 3 );
2543 root_key_str = get_root_key( package, root, &hkey_root );
2545 return ERROR_SUCCESS;
2547 deformat_string( package, key_str, &deformated_key );
2548 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2549 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2550 strcpyW( ui_key_str, root_key_str );
2551 strcatW( ui_key_str, deformated_key );
2553 deformat_string( package, name, &deformated_name );
2555 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2556 msi_free( deformated_key );
2558 uirow = MSI_CreateRecord( 2 );
2559 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2560 MSI_RecordSetStringW( uirow, 2, deformated_name );
2562 ui_actiondata( package, szRemoveRegistryValues, uirow );
2563 msiobj_release( &uirow->hdr );
2565 msi_free( ui_key_str );
2566 msi_free( deformated_name );
2567 return ERROR_SUCCESS;
2570 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2574 static const WCHAR registry_query[] =
2575 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2576 '`','R','e','g','i','s','t','r','y','`',0 };
2577 static const WCHAR remove_registry_query[] =
2578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2579 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2581 /* increment progress bar each time action data is sent */
2582 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2584 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2585 if (rc == ERROR_SUCCESS)
2587 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2588 msiobj_release( &view->hdr );
2589 if (rc != ERROR_SUCCESS)
2593 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2594 if (rc == ERROR_SUCCESS)
2596 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2597 msiobj_release( &view->hdr );
2598 if (rc != ERROR_SUCCESS)
2602 return ERROR_SUCCESS;
2605 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2607 package->script->CurrentlyScripting = TRUE;
2609 return ERROR_SUCCESS;
2613 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2618 static const WCHAR q1[]=
2619 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2620 '`','R','e','g','i','s','t','r','y','`',0};
2623 MSIFEATURE *feature;
2626 TRACE("InstallValidate\n");
2628 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2629 if (rc == ERROR_SUCCESS)
2631 MSI_IterateRecords( view, &progress, NULL, package );
2632 msiobj_release( &view->hdr );
2633 total += progress * REG_PROGRESS_VALUE;
2636 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2637 total += COMPONENT_PROGRESS_VALUE;
2639 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2640 total += file->FileSize;
2642 ui_progress(package,0,total,0,0);
2644 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2646 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2647 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2648 feature->ActionRequest);
2651 return ERROR_SUCCESS;
2654 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2656 MSIPACKAGE* package = param;
2657 LPCWSTR cond = NULL;
2658 LPCWSTR message = NULL;
2661 static const WCHAR title[]=
2662 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2664 cond = MSI_RecordGetString(row,1);
2666 r = MSI_EvaluateConditionW(package,cond);
2667 if (r == MSICONDITION_FALSE)
2669 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2672 message = MSI_RecordGetString(row,2);
2673 deformat_string(package,message,&deformated);
2674 MessageBoxW(NULL,deformated,title,MB_OK);
2675 msi_free(deformated);
2678 return ERROR_INSTALL_FAILURE;
2681 return ERROR_SUCCESS;
2684 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2687 MSIQUERY * view = NULL;
2688 static const WCHAR ExecSeqQuery[] =
2689 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2690 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2692 TRACE("Checking launch conditions\n");
2694 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2695 if (rc != ERROR_SUCCESS)
2696 return ERROR_SUCCESS;
2698 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2699 msiobj_release(&view->hdr);
2704 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2708 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2710 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2712 MSIRECORD * row = 0;
2714 LPWSTR deformated,buffer,deformated_name;
2716 static const WCHAR ExecSeqQuery[] =
2717 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2718 '`','R','e','g','i','s','t','r','y','`',' ',
2719 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2720 ' ','=',' ' ,'\'','%','s','\'',0 };
2721 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2722 static const WCHAR fmt2[]=
2723 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2725 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2729 root = MSI_RecordGetInteger(row,2);
2730 key = MSI_RecordGetString(row, 3);
2731 name = MSI_RecordGetString(row, 4);
2732 deformat_string(package, key , &deformated);
2733 deformat_string(package, name, &deformated_name);
2735 len = strlenW(deformated) + 6;
2736 if (deformated_name)
2737 len+=strlenW(deformated_name);
2739 buffer = msi_alloc( len *sizeof(WCHAR));
2741 if (deformated_name)
2742 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2744 sprintfW(buffer,fmt,root,deformated);
2746 msi_free(deformated);
2747 msi_free(deformated_name);
2748 msiobj_release(&row->hdr);
2752 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2754 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2759 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2762 return strdupW( file->TargetPath );
2767 static HKEY openSharedDLLsKey(void)
2770 static const WCHAR path[] =
2771 {'S','o','f','t','w','a','r','e','\\',
2772 'M','i','c','r','o','s','o','f','t','\\',
2773 'W','i','n','d','o','w','s','\\',
2774 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2775 'S','h','a','r','e','d','D','L','L','s',0};
2777 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2781 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2786 DWORD sz = sizeof(count);
2789 hkey = openSharedDLLsKey();
2790 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2791 if (rc != ERROR_SUCCESS)
2797 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2801 hkey = openSharedDLLsKey();
2803 msi_reg_set_val_dword( hkey, path, count );
2805 RegDeleteValueW(hkey,path);
2811 * Return TRUE if the count should be written out and FALSE if not
2813 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2815 MSIFEATURE *feature;
2819 /* only refcount DLLs */
2820 if (comp->KeyPath == NULL ||
2821 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2822 comp->Attributes & msidbComponentAttributesODBCDataSource)
2826 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2827 write = (count > 0);
2829 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2833 /* increment counts */
2834 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2838 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2841 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2843 if ( cl->component == comp )
2848 /* decrement counts */
2849 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2853 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2856 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2858 if ( cl->component == comp )
2863 /* ref count all the files in the component */
2868 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2870 if (file->Component == comp)
2871 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2875 /* add a count for permanent */
2876 if (comp->Attributes & msidbComponentAttributesPermanent)
2879 comp->RefCount = count;
2882 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2885 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2887 WCHAR squished_pc[GUID_SIZE];
2888 WCHAR squished_cc[GUID_SIZE];
2895 squash_guid(package->ProductCode,squished_pc);
2896 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2898 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2902 ui_progress(package,2,0,0,0);
2903 if (!comp->ComponentId)
2906 squash_guid(comp->ComponentId,squished_cc);
2908 msi_free(comp->FullKeypath);
2909 comp->FullKeypath = resolve_keypath( package, comp );
2911 ACTION_RefCountComponent( package, comp );
2913 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2914 debugstr_w(comp->Component),
2915 debugstr_w(squished_cc),
2916 debugstr_w(comp->FullKeypath),
2919 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2920 comp->ActionRequest == INSTALLSTATE_SOURCE)
2922 if (!comp->FullKeypath)
2925 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2926 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2929 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2932 if (rc != ERROR_SUCCESS)
2935 if (comp->Attributes & msidbComponentAttributesPermanent)
2937 static const WCHAR szPermKey[] =
2938 { '0','0','0','0','0','0','0','0','0','0','0','0',
2939 '0','0','0','0','0','0','0','0','0','0','0','0',
2940 '0','0','0','0','0','0','0','0',0 };
2942 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2945 if (comp->Action == INSTALLSTATE_LOCAL)
2946 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2952 WCHAR source[MAX_PATH];
2953 WCHAR base[MAX_PATH];
2956 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2957 static const WCHAR query[] = {
2958 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2959 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2960 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2961 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2962 '`','D','i','s','k','I','d','`',0};
2964 file = get_loaded_file(package, comp->KeyPath);
2968 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2969 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2970 ptr2 = strrchrW(source, '\\') + 1;
2971 msiobj_release(&row->hdr);
2973 lstrcpyW(base, package->PackagePath);
2974 ptr = strrchrW(base, '\\');
2977 sourcepath = resolve_file_source(package, file);
2978 ptr = sourcepath + lstrlenW(base);
2979 lstrcpyW(ptr2, ptr);
2980 msi_free(sourcepath);
2982 msi_reg_set_val_str(hkey, squished_pc, source);
2986 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2988 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2989 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2991 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2993 comp->Action = comp->ActionRequest;
2996 uirow = MSI_CreateRecord(3);
2997 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2998 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2999 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3000 ui_actiondata(package,szProcessComponents,uirow);
3001 msiobj_release( &uirow->hdr );
3004 return ERROR_SUCCESS;
3015 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3016 LPWSTR lpszName, LONG_PTR lParam)
3019 typelib_struct *tl_struct = (typelib_struct*) lParam;
3020 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3024 if (!IS_INTRESOURCE(lpszName))
3026 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3030 sz = strlenW(tl_struct->source)+4;
3031 sz *= sizeof(WCHAR);
3033 if ((INT_PTR)lpszName == 1)
3034 tl_struct->path = strdupW(tl_struct->source);
3037 tl_struct->path = msi_alloc(sz);
3038 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3041 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3042 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3045 msi_free(tl_struct->path);
3046 tl_struct->path = NULL;
3051 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3052 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3054 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3058 msi_free(tl_struct->path);
3059 tl_struct->path = NULL;
3061 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3062 ITypeLib_Release(tl_struct->ptLib);
3067 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3069 MSIPACKAGE* package = param;
3073 typelib_struct tl_struct;
3078 component = MSI_RecordGetString(row,3);
3079 comp = get_loaded_component(package,component);
3081 return ERROR_SUCCESS;
3083 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3085 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3086 comp->Action = comp->Installed;
3087 return ERROR_SUCCESS;
3089 comp->Action = INSTALLSTATE_LOCAL;
3091 file = get_loaded_file( package, comp->KeyPath );
3093 return ERROR_SUCCESS;
3095 ui_actiondata( package, szRegisterTypeLibraries, row );
3097 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3101 guid = MSI_RecordGetString(row,1);
3102 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3103 tl_struct.source = strdupW( file->TargetPath );
3104 tl_struct.path = NULL;
3106 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3107 (LONG_PTR)&tl_struct);
3115 helpid = MSI_RecordGetString(row,6);
3118 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3119 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3123 ERR("Failed to register type library %s\n",
3124 debugstr_w(tl_struct.path));
3126 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3128 ITypeLib_Release(tl_struct.ptLib);
3129 msi_free(tl_struct.path);
3132 ERR("Failed to load type library %s\n",
3133 debugstr_w(tl_struct.source));
3135 FreeLibrary(module);
3136 msi_free(tl_struct.source);
3140 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3143 ERR("Failed to load type library: %08x\n", hr);
3144 return ERROR_INSTALL_FAILURE;
3147 ITypeLib_Release(tlib);
3150 return ERROR_SUCCESS;
3153 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3156 * OK this is a bit confusing.. I am given a _Component key and I believe
3157 * that the file that is being registered as a type library is the "key file
3158 * of that component" which I interpret to mean "The file in the KeyPath of
3163 static const WCHAR Query[] =
3164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3165 '`','T','y','p','e','L','i','b','`',0};
3167 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3168 if (rc != ERROR_SUCCESS)
3169 return ERROR_SUCCESS;
3171 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3172 msiobj_release(&view->hdr);
3176 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3178 MSIPACKAGE *package = param;
3179 LPCWSTR component, guid;
3187 component = MSI_RecordGetString( row, 3 );
3188 comp = get_loaded_component( package, component );
3190 return ERROR_SUCCESS;
3192 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3194 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3195 comp->Action = comp->Installed;
3196 return ERROR_SUCCESS;
3198 comp->Action = INSTALLSTATE_ABSENT;
3200 ui_actiondata( package, szUnregisterTypeLibraries, row );
3202 guid = MSI_RecordGetString( row, 1 );
3203 CLSIDFromString( (LPCWSTR)guid, &libid );
3204 version = MSI_RecordGetInteger( row, 4 );
3205 language = MSI_RecordGetInteger( row, 2 );
3208 syskind = SYS_WIN64;
3210 syskind = SYS_WIN32;
3213 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3216 WARN("Failed to unregister typelib: %08x\n", hr);
3219 return ERROR_SUCCESS;
3222 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3226 static const WCHAR query[] =
3227 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3228 '`','T','y','p','e','L','i','b','`',0};
3230 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3231 if (rc != ERROR_SUCCESS)
3232 return ERROR_SUCCESS;
3234 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3235 msiobj_release( &view->hdr );
3239 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3241 static const WCHAR szlnk[] = {'.','l','n','k',0};
3242 LPCWSTR directory, extension;
3243 LPWSTR link_folder, link_file, filename;
3245 directory = MSI_RecordGetString( row, 2 );
3246 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3248 /* may be needed because of a bug somewhere else */
3249 create_full_pathW( link_folder );
3251 filename = msi_dup_record_field( row, 3 );
3252 reduce_to_longfilename( filename );
3254 extension = strchrW( filename, '.' );
3255 if (!extension || strcmpiW( extension, szlnk ))
3257 int len = strlenW( filename );
3258 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3259 memcpy( filename + len, szlnk, sizeof(szlnk) );
3261 link_file = build_directory_name( 2, link_folder, filename );
3262 msi_free( link_folder );
3263 msi_free( filename );
3268 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3270 MSIPACKAGE *package = param;
3271 LPWSTR link_file, deformated, path;
3272 LPCWSTR component, target;
3274 IShellLinkW *sl = NULL;
3275 IPersistFile *pf = NULL;
3278 component = MSI_RecordGetString(row, 4);
3279 comp = get_loaded_component(package, component);
3281 return ERROR_SUCCESS;
3283 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3285 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3286 comp->Action = comp->Installed;
3287 return ERROR_SUCCESS;
3289 comp->Action = INSTALLSTATE_LOCAL;
3291 ui_actiondata(package,szCreateShortcuts,row);
3293 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3294 &IID_IShellLinkW, (LPVOID *) &sl );
3298 ERR("CLSID_ShellLink not available\n");
3302 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3305 ERR("QueryInterface(IID_IPersistFile) failed\n");
3309 target = MSI_RecordGetString(row, 5);
3310 if (strchrW(target, '['))
3312 deformat_string(package, target, &deformated);
3313 IShellLinkW_SetPath(sl,deformated);
3314 msi_free(deformated);
3318 FIXME("poorly handled shortcut format, advertised shortcut\n");
3319 IShellLinkW_SetPath(sl,comp->FullKeypath);
3322 if (!MSI_RecordIsNull(row,6))
3324 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3325 deformat_string(package, arguments, &deformated);
3326 IShellLinkW_SetArguments(sl,deformated);
3327 msi_free(deformated);
3330 if (!MSI_RecordIsNull(row,7))
3332 LPCWSTR description = MSI_RecordGetString(row, 7);
3333 IShellLinkW_SetDescription(sl, description);
3336 if (!MSI_RecordIsNull(row,8))
3337 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3339 if (!MSI_RecordIsNull(row,9))
3342 LPCWSTR icon = MSI_RecordGetString(row, 9);
3344 path = build_icon_path(package, icon);
3345 index = MSI_RecordGetInteger(row,10);
3347 /* no value means 0 */
3348 if (index == MSI_NULL_INTEGER)
3351 IShellLinkW_SetIconLocation(sl, path, index);
3355 if (!MSI_RecordIsNull(row,11))
3356 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3358 if (!MSI_RecordIsNull(row,12))
3360 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3361 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3363 IShellLinkW_SetWorkingDirectory(sl, path);
3367 link_file = get_link_file(package, row);
3369 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3370 IPersistFile_Save(pf, link_file, FALSE);
3372 msi_free(link_file);
3376 IPersistFile_Release( pf );
3378 IShellLinkW_Release( sl );
3380 return ERROR_SUCCESS;
3383 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3388 static const WCHAR Query[] =
3389 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3390 '`','S','h','o','r','t','c','u','t','`',0};
3392 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3393 if (rc != ERROR_SUCCESS)
3394 return ERROR_SUCCESS;
3396 res = CoInitialize( NULL );
3398 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3399 msiobj_release(&view->hdr);
3407 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3409 MSIPACKAGE *package = param;
3414 component = MSI_RecordGetString( row, 4 );
3415 comp = get_loaded_component( package, component );
3417 return ERROR_SUCCESS;
3419 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3421 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3422 comp->Action = comp->Installed;
3423 return ERROR_SUCCESS;
3425 comp->Action = INSTALLSTATE_ABSENT;
3427 ui_actiondata( package, szRemoveShortcuts, row );
3429 link_file = get_link_file( package, row );
3431 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3432 if (!DeleteFileW( link_file ))
3434 WARN("Failed to remove shortcut file %u\n", GetLastError());
3436 msi_free( link_file );
3438 return ERROR_SUCCESS;
3441 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3445 static const WCHAR query[] =
3446 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3447 '`','S','h','o','r','t','c','u','t','`',0};
3449 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3450 if (rc != ERROR_SUCCESS)
3451 return ERROR_SUCCESS;
3453 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3454 msiobj_release( &view->hdr );
3459 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3461 MSIPACKAGE* package = param;
3469 FileName = MSI_RecordGetString(row,1);
3472 ERR("Unable to get FileName\n");
3473 return ERROR_SUCCESS;
3476 FilePath = build_icon_path(package,FileName);
3478 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3480 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3481 FILE_ATTRIBUTE_NORMAL, NULL);
3483 if (the_file == INVALID_HANDLE_VALUE)
3485 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3487 return ERROR_SUCCESS;
3494 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3495 if (rc != ERROR_SUCCESS)
3497 ERR("Failed to get stream\n");
3498 CloseHandle(the_file);
3499 DeleteFileW(FilePath);
3502 WriteFile(the_file,buffer,sz,&write,NULL);
3503 } while (sz == 1024);
3506 CloseHandle(the_file);
3508 return ERROR_SUCCESS;
3511 static UINT msi_publish_icons(MSIPACKAGE *package)
3516 static const WCHAR query[]= {
3517 'S','E','L','E','C','T',' ','*',' ',
3518 'F','R','O','M',' ','`','I','c','o','n','`',0};
3520 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3521 if (r == ERROR_SUCCESS)
3523 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3524 msiobj_release(&view->hdr);
3527 return ERROR_SUCCESS;
3530 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3536 MSISOURCELISTINFO *info;
3538 r = RegCreateKeyW(hkey, szSourceList, &source);
3539 if (r != ERROR_SUCCESS)
3542 RegCloseKey(source);
3544 buffer = strrchrW(package->PackagePath, '\\') + 1;
3545 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3546 package->Context, MSICODE_PRODUCT,
3547 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3548 if (r != ERROR_SUCCESS)
3551 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3552 package->Context, MSICODE_PRODUCT,
3553 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3554 if (r != ERROR_SUCCESS)
3557 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3558 package->Context, MSICODE_PRODUCT,
3559 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3560 if (r != ERROR_SUCCESS)
3563 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3565 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3566 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3567 info->options, info->value);
3569 MsiSourceListSetInfoW(package->ProductCode, NULL,
3570 info->context, info->options,
3571 info->property, info->value);
3574 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3576 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3577 disk->context, disk->options,
3578 disk->disk_id, disk->volume_label, disk->disk_prompt);
3581 return ERROR_SUCCESS;
3584 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3586 MSIHANDLE hdb, suminfo;
3587 WCHAR guids[MAX_PATH];
3588 WCHAR packcode[SQUISH_GUID_SIZE];
3595 static const WCHAR szProductLanguage[] =
3596 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3597 static const WCHAR szARPProductIcon[] =
3598 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3599 static const WCHAR szProductVersion[] =
3600 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3601 static const WCHAR szAssignment[] =
3602 {'A','s','s','i','g','n','m','e','n','t',0};
3603 static const WCHAR szAdvertiseFlags[] =
3604 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3605 static const WCHAR szClients[] =
3606 {'C','l','i','e','n','t','s',0};
3607 static const WCHAR szColon[] = {':',0};
3609 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3610 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3613 langid = msi_get_property_int(package->db, szProductLanguage, 0);
3614 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3617 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3619 buffer = msi_dup_property(package->db, szARPProductIcon);
3622 LPWSTR path = build_icon_path(package,buffer);
3623 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3628 buffer = msi_dup_property(package->db, szProductVersion);
3631 DWORD verdword = msi_version_str_to_dword(buffer);
3632 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3636 msi_reg_set_val_dword(hkey, szAssignment, 0);
3637 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3638 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3639 msi_reg_set_val_str(hkey, szClients, szColon);
3641 hdb = alloc_msihandle(&package->db->hdr);
3643 return ERROR_NOT_ENOUGH_MEMORY;
3645 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3646 MsiCloseHandle(hdb);
3647 if (r != ERROR_SUCCESS)
3651 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3652 NULL, guids, &size);
3653 if (r != ERROR_SUCCESS)
3656 ptr = strchrW(guids, ';');
3658 squash_guid(guids, packcode);
3659 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3662 MsiCloseHandle(suminfo);
3663 return ERROR_SUCCESS;
3666 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3671 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3673 static const WCHAR szUpgradeCode[] =
3674 {'U','p','g','r','a','d','e','C','o','d','e',0};
3676 upgrade = msi_dup_property(package->db, szUpgradeCode);
3678 return ERROR_SUCCESS;
3680 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3682 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3683 if (r != ERROR_SUCCESS)
3688 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3689 if (r != ERROR_SUCCESS)
3693 squash_guid(package->ProductCode, squashed_pc);
3694 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3703 static BOOL msi_check_publish(MSIPACKAGE *package)
3705 MSIFEATURE *feature;
3707 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3709 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3716 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3718 MSIFEATURE *feature;
3720 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3722 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3729 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3731 WCHAR patch_squashed[GUID_SIZE];
3734 UINT r = ERROR_FUNCTION_FAILED;
3736 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3738 if (res != ERROR_SUCCESS)
3739 return ERROR_FUNCTION_FAILED;
3741 squash_guid(package->patch->patchcode, patch_squashed);
3743 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3744 (const BYTE *)patch_squashed,
3745 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3746 if (res != ERROR_SUCCESS)
3749 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3750 (const BYTE *)package->patch->transforms,
3751 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3752 if (res == ERROR_SUCCESS)
3756 RegCloseKey(patches);
3761 * 99% of the work done here is only done for
3762 * advertised installs. However this is where the
3763 * Icon table is processed and written out
3764 * so that is what I am going to do here.
3766 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3769 HKEY hukey = NULL, hudkey = NULL;
3772 /* FIXME: also need to publish if the product is in advertise mode */
3773 if (!msi_check_publish(package))
3774 return ERROR_SUCCESS;
3776 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3778 if (rc != ERROR_SUCCESS)
3781 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3782 NULL, &hudkey, TRUE);
3783 if (rc != ERROR_SUCCESS)
3786 rc = msi_publish_upgrade_code(package);
3787 if (rc != ERROR_SUCCESS)
3792 rc = msi_publish_patch(package, hukey, hudkey);
3793 if (rc != ERROR_SUCCESS)
3797 rc = msi_publish_product_properties(package, hukey);
3798 if (rc != ERROR_SUCCESS)
3801 rc = msi_publish_sourcelist(package, hukey);
3802 if (rc != ERROR_SUCCESS)
3805 rc = msi_publish_icons(package);
3808 uirow = MSI_CreateRecord( 1 );
3809 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3810 ui_actiondata( package, szPublishProduct, uirow );
3811 msiobj_release( &uirow->hdr );
3814 RegCloseKey(hudkey);
3819 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3821 WCHAR *filename, *ptr, *folder, *ret;
3822 const WCHAR *dirprop;
3824 filename = msi_dup_record_field( row, 2 );
3825 if (filename && (ptr = strchrW( filename, '|' )))
3830 dirprop = MSI_RecordGetString( row, 3 );
3833 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3835 folder = msi_dup_property( package->db, dirprop );
3838 folder = msi_dup_property( package->db, szWindowsFolder );
3842 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3843 msi_free( filename );
3847 ret = build_directory_name( 2, folder, ptr );
3849 msi_free( filename );
3854 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3856 MSIPACKAGE *package = param;
3857 LPCWSTR component, section, key, value, identifier;
3858 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3863 component = MSI_RecordGetString(row, 8);
3864 comp = get_loaded_component(package,component);
3866 return ERROR_SUCCESS;
3868 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3870 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3871 comp->Action = comp->Installed;
3872 return ERROR_SUCCESS;
3874 comp->Action = INSTALLSTATE_LOCAL;
3876 identifier = MSI_RecordGetString(row,1);
3877 section = MSI_RecordGetString(row,4);
3878 key = MSI_RecordGetString(row,5);
3879 value = MSI_RecordGetString(row,6);
3880 action = MSI_RecordGetInteger(row,7);
3882 deformat_string(package,section,&deformated_section);
3883 deformat_string(package,key,&deformated_key);
3884 deformat_string(package,value,&deformated_value);
3886 fullname = get_ini_file_name(package, row);
3890 TRACE("Adding value %s to section %s in %s\n",
3891 debugstr_w(deformated_key), debugstr_w(deformated_section),
3892 debugstr_w(fullname));
3893 WritePrivateProfileStringW(deformated_section, deformated_key,
3894 deformated_value, fullname);
3896 else if (action == 1)
3899 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3900 returned, 10, fullname);
3901 if (returned[0] == 0)
3903 TRACE("Adding value %s to section %s in %s\n",
3904 debugstr_w(deformated_key), debugstr_w(deformated_section),
3905 debugstr_w(fullname));
3907 WritePrivateProfileStringW(deformated_section, deformated_key,
3908 deformated_value, fullname);
3911 else if (action == 3)
3912 FIXME("Append to existing section not yet implemented\n");
3914 uirow = MSI_CreateRecord(4);
3915 MSI_RecordSetStringW(uirow,1,identifier);
3916 MSI_RecordSetStringW(uirow,2,deformated_section);
3917 MSI_RecordSetStringW(uirow,3,deformated_key);
3918 MSI_RecordSetStringW(uirow,4,deformated_value);
3919 ui_actiondata(package,szWriteIniValues,uirow);
3920 msiobj_release( &uirow->hdr );
3923 msi_free(deformated_key);
3924 msi_free(deformated_value);
3925 msi_free(deformated_section);
3926 return ERROR_SUCCESS;
3929 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3933 static const WCHAR ExecSeqQuery[] =
3934 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3935 '`','I','n','i','F','i','l','e','`',0};
3937 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3938 if (rc != ERROR_SUCCESS)
3940 TRACE("no IniFile table\n");
3941 return ERROR_SUCCESS;
3944 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3945 msiobj_release(&view->hdr);
3949 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3951 MSIPACKAGE *package = param;
3952 LPCWSTR component, section, key, value, identifier;
3953 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3958 component = MSI_RecordGetString( row, 8 );
3959 comp = get_loaded_component( package, component );
3961 return ERROR_SUCCESS;
3963 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3965 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3966 comp->Action = comp->Installed;
3967 return ERROR_SUCCESS;
3969 comp->Action = INSTALLSTATE_ABSENT;
3971 identifier = MSI_RecordGetString( row, 1 );
3972 section = MSI_RecordGetString( row, 4 );
3973 key = MSI_RecordGetString( row, 5 );
3974 value = MSI_RecordGetString( row, 6 );
3975 action = MSI_RecordGetInteger( row, 7 );
3977 deformat_string( package, section, &deformated_section );
3978 deformat_string( package, key, &deformated_key );
3979 deformat_string( package, value, &deformated_value );
3981 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3983 filename = get_ini_file_name( package, row );
3985 TRACE("Removing key %s from section %s in %s\n",
3986 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3988 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3990 WARN("Unable to remove key %u\n", GetLastError());
3992 msi_free( filename );
3995 FIXME("Unsupported action %d\n", action);
3998 uirow = MSI_CreateRecord( 4 );
3999 MSI_RecordSetStringW( uirow, 1, identifier );
4000 MSI_RecordSetStringW( uirow, 2, deformated_section );
4001 MSI_RecordSetStringW( uirow, 3, deformated_key );
4002 MSI_RecordSetStringW( uirow, 4, deformated_value );
4003 ui_actiondata( package, szRemoveIniValues, uirow );
4004 msiobj_release( &uirow->hdr );
4006 msi_free( deformated_key );
4007 msi_free( deformated_value );
4008 msi_free( deformated_section );
4009 return ERROR_SUCCESS;
4012 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4014 MSIPACKAGE *package = param;
4015 LPCWSTR component, section, key, value, identifier;
4016 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4021 component = MSI_RecordGetString( row, 8 );
4022 comp = get_loaded_component( package, component );
4024 return ERROR_SUCCESS;
4026 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4028 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4029 comp->Action = comp->Installed;
4030 return ERROR_SUCCESS;
4032 comp->Action = INSTALLSTATE_LOCAL;
4034 identifier = MSI_RecordGetString( row, 1 );
4035 section = MSI_RecordGetString( row, 4 );
4036 key = MSI_RecordGetString( row, 5 );
4037 value = MSI_RecordGetString( row, 6 );
4038 action = MSI_RecordGetInteger( row, 7 );
4040 deformat_string( package, section, &deformated_section );
4041 deformat_string( package, key, &deformated_key );
4042 deformat_string( package, value, &deformated_value );
4044 if (action == msidbIniFileActionRemoveLine)
4046 filename = get_ini_file_name( package, row );
4048 TRACE("Removing key %s from section %s in %s\n",
4049 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4051 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4053 WARN("Unable to remove key %u\n", GetLastError());
4055 msi_free( filename );
4058 FIXME("Unsupported action %d\n", action);
4060 uirow = MSI_CreateRecord( 4 );
4061 MSI_RecordSetStringW( uirow, 1, identifier );
4062 MSI_RecordSetStringW( uirow, 2, deformated_section );
4063 MSI_RecordSetStringW( uirow, 3, deformated_key );
4064 MSI_RecordSetStringW( uirow, 4, deformated_value );
4065 ui_actiondata( package, szRemoveIniValues, uirow );
4066 msiobj_release( &uirow->hdr );
4068 msi_free( deformated_key );
4069 msi_free( deformated_value );
4070 msi_free( deformated_section );
4071 return ERROR_SUCCESS;
4074 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4078 static const WCHAR query[] =
4079 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4080 '`','I','n','i','F','i','l','e','`',0};
4081 static const WCHAR remove_query[] =
4082 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4083 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4085 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4086 if (rc == ERROR_SUCCESS)
4088 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4089 msiobj_release( &view->hdr );
4090 if (rc != ERROR_SUCCESS)
4094 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4095 if (rc == ERROR_SUCCESS)
4097 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4098 msiobj_release( &view->hdr );
4099 if (rc != ERROR_SUCCESS)
4103 return ERROR_SUCCESS;
4106 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4108 MSIPACKAGE *package = param;
4113 static const WCHAR ExeStr[] =
4114 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4115 static const WCHAR close[] = {'\"',0};
4117 PROCESS_INFORMATION info;
4122 memset(&si,0,sizeof(STARTUPINFOW));
4124 filename = MSI_RecordGetString(row,1);
4125 file = get_loaded_file( package, filename );
4129 ERR("Unable to find file id %s\n",debugstr_w(filename));
4130 return ERROR_SUCCESS;
4133 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4135 FullName = msi_alloc(len*sizeof(WCHAR));
4136 strcpyW(FullName,ExeStr);
4137 strcatW( FullName, file->TargetPath );
4138 strcatW(FullName,close);
4140 TRACE("Registering %s\n",debugstr_w(FullName));
4141 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4146 CloseHandle(info.hThread);
4147 msi_dialog_check_messages(info.hProcess);
4148 CloseHandle(info.hProcess);
4151 uirow = MSI_CreateRecord( 2 );
4152 MSI_RecordSetStringW( uirow, 1, filename );
4153 uipath = strdupW( file->TargetPath );
4154 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4155 MSI_RecordSetStringW( uirow, 2, uipath );
4156 ui_actiondata( package, szSelfRegModules, uirow );
4157 msiobj_release( &uirow->hdr );
4159 msi_free( FullName );
4161 return ERROR_SUCCESS;
4164 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4168 static const WCHAR ExecSeqQuery[] =
4169 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4170 '`','S','e','l','f','R','e','g','`',0};
4172 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4173 if (rc != ERROR_SUCCESS)
4175 TRACE("no SelfReg table\n");
4176 return ERROR_SUCCESS;
4179 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4180 msiobj_release(&view->hdr);
4182 return ERROR_SUCCESS;
4185 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4187 static const WCHAR regsvr32[] =
4188 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4189 static const WCHAR close[] = {'\"',0};
4190 MSIPACKAGE *package = param;
4196 PROCESS_INFORMATION pi;
4201 memset( &si, 0, sizeof(STARTUPINFOW) );
4203 filename = MSI_RecordGetString( row, 1 );
4204 file = get_loaded_file( package, filename );
4208 ERR("Unable to find file id %s\n", debugstr_w(filename));
4209 return ERROR_SUCCESS;
4212 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4214 cmdline = msi_alloc( len * sizeof(WCHAR) );
4215 strcpyW( cmdline, regsvr32 );
4216 strcatW( cmdline, file->TargetPath );
4217 strcatW( cmdline, close );
4219 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4221 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4224 CloseHandle( pi.hThread );
4225 msi_dialog_check_messages( pi.hProcess );
4226 CloseHandle( pi.hProcess );
4229 uirow = MSI_CreateRecord( 2 );
4230 MSI_RecordSetStringW( uirow, 1, filename );
4231 uipath = strdupW( file->TargetPath );
4232 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4233 MSI_RecordSetStringW( uirow, 2, uipath );
4234 ui_actiondata( package, szSelfUnregModules, uirow );
4235 msiobj_release( &uirow->hdr );
4237 msi_free( cmdline );
4239 return ERROR_SUCCESS;
4242 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4246 static const WCHAR query[] =
4247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4248 '`','S','e','l','f','R','e','g','`',0};
4250 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4251 if (rc != ERROR_SUCCESS)
4253 TRACE("no SelfReg table\n");
4254 return ERROR_SUCCESS;
4257 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4258 msiobj_release( &view->hdr );
4260 return ERROR_SUCCESS;
4263 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4265 MSIFEATURE *feature;
4267 HKEY hkey = NULL, userdata = NULL;
4269 if (!msi_check_publish(package))
4270 return ERROR_SUCCESS;
4272 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4274 if (rc != ERROR_SUCCESS)
4277 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4279 if (rc != ERROR_SUCCESS)
4282 /* here the guids are base 85 encoded */
4283 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4289 BOOL absent = FALSE;
4292 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4293 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4294 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4297 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4301 if (feature->Feature_Parent)
4302 size += strlenW( feature->Feature_Parent )+2;
4304 data = msi_alloc(size * sizeof(WCHAR));
4307 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4309 MSICOMPONENT* component = cl->component;
4313 if (component->ComponentId)
4315 TRACE("From %s\n",debugstr_w(component->ComponentId));
4316 CLSIDFromString(component->ComponentId, &clsid);
4317 encode_base85_guid(&clsid,buf);
4318 TRACE("to %s\n",debugstr_w(buf));
4323 if (feature->Feature_Parent)
4325 static const WCHAR sep[] = {'\2',0};
4327 strcatW(data,feature->Feature_Parent);
4330 msi_reg_set_val_str( userdata, feature->Feature, data );
4334 if (feature->Feature_Parent)
4335 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4338 size += sizeof(WCHAR);
4339 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4340 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4344 size += 2*sizeof(WCHAR);
4345 data = msi_alloc(size);
4348 if (feature->Feature_Parent)
4349 strcpyW( &data[1], feature->Feature_Parent );
4350 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4356 uirow = MSI_CreateRecord( 1 );
4357 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4358 ui_actiondata( package, szPublishFeatures, uirow);
4359 msiobj_release( &uirow->hdr );
4360 /* FIXME: call ui_progress? */
4365 RegCloseKey(userdata);
4369 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4375 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4377 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4379 if (r == ERROR_SUCCESS)
4381 RegDeleteValueW(hkey, feature->Feature);
4385 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4387 if (r == ERROR_SUCCESS)
4389 RegDeleteValueW(hkey, feature->Feature);
4393 uirow = MSI_CreateRecord( 1 );
4394 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4395 ui_actiondata( package, szUnpublishFeatures, uirow );
4396 msiobj_release( &uirow->hdr );
4398 return ERROR_SUCCESS;
4401 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4403 MSIFEATURE *feature;
4405 if (!msi_check_unpublish(package))
4406 return ERROR_SUCCESS;
4408 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4410 msi_unpublish_feature(package, feature);
4413 return ERROR_SUCCESS;
4416 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4418 LPWSTR prop, val, key;
4424 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4425 static const WCHAR szWindowsInstaller[] =
4426 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4427 static const WCHAR modpath_fmt[] =
4428 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4429 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4430 static const WCHAR szModifyPath[] =
4431 {'M','o','d','i','f','y','P','a','t','h',0};
4432 static const WCHAR szUninstallString[] =
4433 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4434 static const WCHAR szEstimatedSize[] =
4435 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4436 static const WCHAR szProductLanguage[] =
4437 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4438 static const WCHAR szProductVersion[] =
4439 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4440 static const WCHAR szProductName[] =
4441 {'P','r','o','d','u','c','t','N','a','m','e',0};
4442 static const WCHAR szDisplayName[] =
4443 {'D','i','s','p','l','a','y','N','a','m','e',0};
4444 static const WCHAR szDisplayVersion[] =
4445 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4446 static const WCHAR szManufacturer[] =
4447 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4449 static const LPCSTR propval[] = {
4450 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4451 "ARPCONTACT", "Contact",
4452 "ARPCOMMENTS", "Comments",
4453 "ProductName", "DisplayName",
4454 "ProductVersion", "DisplayVersion",
4455 "ARPHELPLINK", "HelpLink",
4456 "ARPHELPTELEPHONE", "HelpTelephone",
4457 "ARPINSTALLLOCATION", "InstallLocation",
4458 "SourceDir", "InstallSource",
4459 "Manufacturer", "Publisher",
4460 "ARPREADME", "Readme",
4462 "ARPURLINFOABOUT", "URLInfoAbout",
4463 "ARPURLUPDATEINFO", "URLUpdateInfo",
4466 const LPCSTR *p = propval;
4470 prop = strdupAtoW(*p++);
4471 key = strdupAtoW(*p++);
4472 val = msi_dup_property(package->db, prop);
4473 msi_reg_set_val_str(hkey, key, val);
4479 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4481 size = deformat_string(package, modpath_fmt, &buffer);
4482 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4483 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4486 /* FIXME: Write real Estimated Size when we have it */
4487 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4489 buffer = msi_dup_property(package->db, szProductName);
4490 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4493 buffer = msi_dup_property(package->db, cszSourceDir);
4494 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4497 buffer = msi_dup_property(package->db, szManufacturer);
4498 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4501 GetLocalTime(&systime);
4502 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4503 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4505 langid = msi_get_property_int(package->db, szProductLanguage, 0);
4506 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4508 buffer = msi_dup_property(package->db, szProductVersion);
4509 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4512 DWORD verdword = msi_version_str_to_dword(buffer);
4514 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4515 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4516 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4520 return ERROR_SUCCESS;
4523 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4525 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4527 LPWSTR upgrade_code;
4532 static const WCHAR szUpgradeCode[] = {
4533 'U','p','g','r','a','d','e','C','o','d','e',0};
4535 /* FIXME: also need to publish if the product is in advertise mode */
4536 if (!msi_check_publish(package))
4537 return ERROR_SUCCESS;
4539 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4540 if (rc != ERROR_SUCCESS)
4543 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4544 NULL, &props, TRUE);
4545 if (rc != ERROR_SUCCESS)
4548 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4549 msi_free( package->db->localfile );
4550 package->db->localfile = NULL;
4552 rc = msi_publish_install_properties(package, hkey);
4553 if (rc != ERROR_SUCCESS)
4556 rc = msi_publish_install_properties(package, props);
4557 if (rc != ERROR_SUCCESS)
4560 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4563 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4564 squash_guid(package->ProductCode, squashed_pc);
4565 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4566 RegCloseKey(upgrade);
4567 msi_free(upgrade_code);
4571 uirow = MSI_CreateRecord( 1 );
4572 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4573 ui_actiondata( package, szRegisterProduct, uirow );
4574 msiobj_release( &uirow->hdr );
4577 return ERROR_SUCCESS;
4580 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4582 return execute_script(package,INSTALL_SCRIPT);
4585 static UINT msi_unpublish_product(MSIPACKAGE *package)
4588 LPWSTR remove = NULL;
4589 LPWSTR *features = NULL;
4590 BOOL full_uninstall = TRUE;
4591 MSIFEATURE *feature;
4593 static const WCHAR szUpgradeCode[] =
4594 {'U','p','g','r','a','d','e','C','o','d','e',0};
4596 remove = msi_dup_property(package->db, szRemove);
4598 return ERROR_SUCCESS;
4600 features = msi_split_string(remove, ',');
4604 ERR("REMOVE feature list is empty!\n");
4605 return ERROR_FUNCTION_FAILED;
4608 if (!lstrcmpW(features[0], szAll))
4609 full_uninstall = TRUE;
4612 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4614 if (feature->Action != INSTALLSTATE_ABSENT)
4615 full_uninstall = FALSE;
4619 if (!full_uninstall)
4622 MSIREG_DeleteProductKey(package->ProductCode);
4623 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4624 MSIREG_DeleteUninstallKey(package->ProductCode);
4626 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4628 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4629 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4633 MSIREG_DeleteUserProductKey(package->ProductCode);
4634 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4637 upgrade = msi_dup_property(package->db, szUpgradeCode);
4640 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4647 return ERROR_SUCCESS;
4650 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4654 rc = msi_unpublish_product(package);
4655 if (rc != ERROR_SUCCESS)
4658 /* turn off scheduling */
4659 package->script->CurrentlyScripting= FALSE;
4661 /* first do the same as an InstallExecute */
4662 rc = ACTION_InstallExecute(package);
4663 if (rc != ERROR_SUCCESS)
4666 /* then handle Commit Actions */
4667 rc = execute_script(package,COMMIT_SCRIPT);
4672 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4674 static const WCHAR RunOnce[] = {
4675 'S','o','f','t','w','a','r','e','\\',
4676 'M','i','c','r','o','s','o','f','t','\\',
4677 'W','i','n','d','o','w','s','\\',
4678 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4679 'R','u','n','O','n','c','e',0};
4680 static const WCHAR InstallRunOnce[] = {
4681 'S','o','f','t','w','a','r','e','\\',
4682 'M','i','c','r','o','s','o','f','t','\\',
4683 'W','i','n','d','o','w','s','\\',
4684 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4685 'I','n','s','t','a','l','l','e','r','\\',
4686 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4688 static const WCHAR msiexec_fmt[] = {
4690 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4691 '\"','%','s','\"',0};
4692 static const WCHAR install_fmt[] = {
4693 '/','I',' ','\"','%','s','\"',' ',
4694 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4695 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4696 WCHAR buffer[256], sysdir[MAX_PATH];
4698 WCHAR squished_pc[100];
4700 squash_guid(package->ProductCode,squished_pc);
4702 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4703 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4704 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4707 msi_reg_set_val_str( hkey, squished_pc, buffer );
4710 TRACE("Reboot command %s\n",debugstr_w(buffer));
4712 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4713 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4715 msi_reg_set_val_str( hkey, squished_pc, buffer );
4718 return ERROR_INSTALL_SUSPEND;
4721 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4727 * We are currently doing what should be done here in the top level Install
4728 * however for Administrative and uninstalls this step will be needed
4730 if (!package->PackagePath)
4731 return ERROR_SUCCESS;
4733 msi_set_sourcedir_props(package, TRUE);
4735 attrib = GetFileAttributesW(package->db->path);
4736 if (attrib == INVALID_FILE_ATTRIBUTES)
4742 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4743 package->Context, MSICODE_PRODUCT,
4744 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4745 if (rc == ERROR_MORE_DATA)
4747 prompt = msi_alloc(size * sizeof(WCHAR));
4748 MsiSourceListGetInfoW(package->ProductCode, NULL,
4749 package->Context, MSICODE_PRODUCT,
4750 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4753 prompt = strdupW(package->db->path);
4755 msg = generate_error_string(package,1302,1,prompt);
4756 while(attrib == INVALID_FILE_ATTRIBUTES)
4758 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4761 rc = ERROR_INSTALL_USEREXIT;
4764 attrib = GetFileAttributesW(package->db->path);
4770 return ERROR_SUCCESS;
4775 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4778 LPWSTR buffer, productid = NULL;
4779 UINT i, rc = ERROR_SUCCESS;
4782 static const WCHAR szPropKeys[][80] =
4784 {'P','r','o','d','u','c','t','I','D',0},
4785 {'U','S','E','R','N','A','M','E',0},
4786 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4790 static const WCHAR szRegKeys[][80] =
4792 {'P','r','o','d','u','c','t','I','D',0},
4793 {'R','e','g','O','w','n','e','r',0},
4794 {'R','e','g','C','o','m','p','a','n','y',0},
4798 if (msi_check_unpublish(package))
4800 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4804 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
4808 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4810 if (rc != ERROR_SUCCESS)
4813 for( i = 0; szPropKeys[i][0]; i++ )
4815 buffer = msi_dup_property( package->db, szPropKeys[i] );
4816 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4821 uirow = MSI_CreateRecord( 1 );
4822 MSI_RecordSetStringW( uirow, 1, productid );
4823 ui_actiondata( package, szRegisterUser, uirow );
4824 msiobj_release( &uirow->hdr );
4826 msi_free(productid);
4832 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4836 package->script->InWhatSequence |= SEQUENCE_EXEC;
4837 rc = ACTION_ProcessExecSequence(package,FALSE);
4842 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4844 MSIPACKAGE *package = param;
4845 LPCWSTR compgroupid, component, feature, qualifier, text;
4846 LPWSTR advertise = NULL, output = NULL;
4854 feature = MSI_RecordGetString(rec, 5);
4855 feat = get_loaded_feature(package, feature);
4857 return ERROR_SUCCESS;
4859 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4860 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4861 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4863 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4864 feat->Action = feat->Installed;
4865 return ERROR_SUCCESS;
4868 component = MSI_RecordGetString(rec, 3);
4869 comp = get_loaded_component(package, component);
4871 return ERROR_SUCCESS;
4873 compgroupid = MSI_RecordGetString(rec,1);
4874 qualifier = MSI_RecordGetString(rec,2);
4876 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4877 if (rc != ERROR_SUCCESS)
4880 text = MSI_RecordGetString(rec,4);
4881 advertise = create_component_advertise_string(package, comp, feature);
4883 sz = strlenW(advertise);
4886 sz += lstrlenW(text);
4889 sz *= sizeof(WCHAR);
4891 output = msi_alloc_zero(sz);
4892 strcpyW(output,advertise);
4893 msi_free(advertise);
4896 strcatW(output,text);
4898 msi_reg_set_val_multi_str( hkey, qualifier, output );
4905 uirow = MSI_CreateRecord( 2 );
4906 MSI_RecordSetStringW( uirow, 1, compgroupid );
4907 MSI_RecordSetStringW( uirow, 2, qualifier);
4908 ui_actiondata( package, szPublishComponents, uirow);
4909 msiobj_release( &uirow->hdr );
4910 /* FIXME: call ui_progress? */
4916 * At present I am ignorning the advertised components part of this and only
4917 * focusing on the qualified component sets
4919 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4923 static const WCHAR ExecSeqQuery[] =
4924 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4925 '`','P','u','b','l','i','s','h',
4926 'C','o','m','p','o','n','e','n','t','`',0};
4928 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4929 if (rc != ERROR_SUCCESS)
4930 return ERROR_SUCCESS;
4932 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4933 msiobj_release(&view->hdr);
4938 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4940 static const WCHAR szInstallerComponents[] = {
4941 'S','o','f','t','w','a','r','e','\\',
4942 'M','i','c','r','o','s','o','f','t','\\',
4943 'I','n','s','t','a','l','l','e','r','\\',
4944 'C','o','m','p','o','n','e','n','t','s','\\',0};
4946 MSIPACKAGE *package = param;
4947 LPCWSTR compgroupid, component, feature, qualifier;
4951 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4954 feature = MSI_RecordGetString( rec, 5 );
4955 feat = get_loaded_feature( package, feature );
4957 return ERROR_SUCCESS;
4959 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4961 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4962 feat->Action = feat->Installed;
4963 return ERROR_SUCCESS;
4966 component = MSI_RecordGetString( rec, 3 );
4967 comp = get_loaded_component( package, component );
4969 return ERROR_SUCCESS;
4971 compgroupid = MSI_RecordGetString( rec, 1 );
4972 qualifier = MSI_RecordGetString( rec, 2 );
4974 squash_guid( compgroupid, squashed );
4975 strcpyW( keypath, szInstallerComponents );
4976 strcatW( keypath, squashed );
4978 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4979 if (res != ERROR_SUCCESS)
4981 WARN("Unable to delete component key %d\n", res);
4984 uirow = MSI_CreateRecord( 2 );
4985 MSI_RecordSetStringW( uirow, 1, compgroupid );
4986 MSI_RecordSetStringW( uirow, 2, qualifier );
4987 ui_actiondata( package, szUnpublishComponents, uirow );
4988 msiobj_release( &uirow->hdr );
4990 return ERROR_SUCCESS;
4993 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4997 static const WCHAR query[] =
4998 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4999 '`','P','u','b','l','i','s','h',
5000 'C','o','m','p','o','n','e','n','t','`',0};
5002 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5003 if (rc != ERROR_SUCCESS)
5004 return ERROR_SUCCESS;
5006 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5007 msiobj_release( &view->hdr );
5012 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5014 MSIPACKAGE *package = param;
5017 SC_HANDLE hscm, service = NULL;
5018 LPCWSTR comp, depends, pass;
5019 LPWSTR name = NULL, disp = NULL;
5020 LPCWSTR load_order, serv_name, key;
5021 DWORD serv_type, start_type;
5024 static const WCHAR query[] =
5025 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5026 '`','C','o','m','p','o','n','e','n','t','`',' ',
5027 'W','H','E','R','E',' ',
5028 '`','C','o','m','p','o','n','e','n','t','`',' ',
5029 '=','\'','%','s','\'',0};
5031 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5034 ERR("Failed to open the SC Manager!\n");
5038 start_type = MSI_RecordGetInteger(rec, 5);
5039 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5042 depends = MSI_RecordGetString(rec, 8);
5043 if (depends && *depends)
5044 FIXME("Dependency list unhandled!\n");
5046 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5047 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5048 serv_type = MSI_RecordGetInteger(rec, 4);
5049 err_control = MSI_RecordGetInteger(rec, 6);
5050 load_order = MSI_RecordGetString(rec, 7);
5051 serv_name = MSI_RecordGetString(rec, 9);
5052 pass = MSI_RecordGetString(rec, 10);
5053 comp = MSI_RecordGetString(rec, 12);
5055 /* fetch the service path */
5056 row = MSI_QueryGetRecord(package->db, query, comp);
5059 ERR("Control query failed!\n");
5063 key = MSI_RecordGetString(row, 6);
5065 file = get_loaded_file(package, key);
5066 msiobj_release(&row->hdr);
5069 ERR("Failed to load the service file\n");
5073 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5074 start_type, err_control, file->TargetPath,
5075 load_order, NULL, NULL, serv_name, pass);
5078 if (GetLastError() != ERROR_SERVICE_EXISTS)
5079 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5083 CloseServiceHandle(service);
5084 CloseServiceHandle(hscm);
5088 return ERROR_SUCCESS;
5091 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5095 static const WCHAR ExecSeqQuery[] =
5096 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5097 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5099 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5100 if (rc != ERROR_SUCCESS)
5101 return ERROR_SUCCESS;
5103 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5104 msiobj_release(&view->hdr);
5109 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5110 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5112 LPCWSTR *vector, *temp_vector;
5116 static const WCHAR separator[] = {'[','~',']',0};
5119 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5124 vector = msi_alloc(sizeof(LPWSTR));
5132 vector[*numargs - 1] = p;
5134 if ((q = strstrW(p, separator)))
5138 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5144 vector = temp_vector;
5153 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5155 MSIPACKAGE *package = param;
5158 SC_HANDLE scm = NULL, service = NULL;
5159 LPCWSTR component, *vector = NULL;
5160 LPWSTR name, args, display_name = NULL;
5161 DWORD event, numargs, len;
5162 UINT r = ERROR_FUNCTION_FAILED;
5164 component = MSI_RecordGetString(rec, 6);
5165 comp = get_loaded_component(package, component);
5167 return ERROR_SUCCESS;
5169 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5171 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5172 comp->Action = comp->Installed;
5173 return ERROR_SUCCESS;
5175 comp->Action = INSTALLSTATE_LOCAL;
5177 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5178 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5179 event = MSI_RecordGetInteger(rec, 3);
5181 if (!(event & msidbServiceControlEventStart))
5187 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5190 ERR("Failed to open the service control manager\n");
5195 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5196 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5198 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5199 GetServiceDisplayNameW( scm, name, display_name, &len );
5202 service = OpenServiceW(scm, name, SERVICE_START);
5205 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5209 vector = msi_service_args_to_vector(args, &numargs);
5211 if (!StartServiceW(service, numargs, vector) &&
5212 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5214 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5221 uirow = MSI_CreateRecord( 2 );
5222 MSI_RecordSetStringW( uirow, 1, display_name );
5223 MSI_RecordSetStringW( uirow, 2, name );
5224 ui_actiondata( package, szStartServices, uirow );
5225 msiobj_release( &uirow->hdr );
5227 CloseServiceHandle(service);
5228 CloseServiceHandle(scm);
5233 msi_free(display_name);
5237 static UINT ACTION_StartServices( MSIPACKAGE *package )
5242 static const WCHAR query[] = {
5243 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5244 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5246 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5247 if (rc != ERROR_SUCCESS)
5248 return ERROR_SUCCESS;
5250 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5251 msiobj_release(&view->hdr);
5256 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5258 DWORD i, needed, count;
5259 ENUM_SERVICE_STATUSW *dependencies;
5263 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5264 0, &needed, &count))
5267 if (GetLastError() != ERROR_MORE_DATA)
5270 dependencies = msi_alloc(needed);
5274 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5275 needed, &needed, &count))
5278 for (i = 0; i < count; i++)
5280 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5281 SERVICE_STOP | SERVICE_QUERY_STATUS);
5285 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5292 msi_free(dependencies);
5296 static UINT stop_service( LPCWSTR name )
5298 SC_HANDLE scm = NULL, service = NULL;
5299 SERVICE_STATUS status;
5300 SERVICE_STATUS_PROCESS ssp;
5303 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5306 WARN("Failed to open the SCM: %d\n", GetLastError());
5310 service = OpenServiceW(scm, name,
5312 SERVICE_QUERY_STATUS |
5313 SERVICE_ENUMERATE_DEPENDENTS);
5316 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5320 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5321 sizeof(SERVICE_STATUS_PROCESS), &needed))
5323 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5327 if (ssp.dwCurrentState == SERVICE_STOPPED)
5330 stop_service_dependents(scm, service);
5332 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5333 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5336 CloseServiceHandle(service);
5337 CloseServiceHandle(scm);
5339 return ERROR_SUCCESS;
5342 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5344 MSIPACKAGE *package = param;
5348 LPWSTR name = NULL, display_name = NULL;
5352 event = MSI_RecordGetInteger( rec, 3 );
5353 if (!(event & msidbServiceControlEventStop))
5354 return ERROR_SUCCESS;
5356 component = MSI_RecordGetString( rec, 6 );
5357 comp = get_loaded_component( package, component );
5359 return ERROR_SUCCESS;
5361 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5363 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5364 comp->Action = comp->Installed;
5365 return ERROR_SUCCESS;
5367 comp->Action = INSTALLSTATE_ABSENT;
5369 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5372 ERR("Failed to open the service control manager\n");
5377 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5378 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5380 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5381 GetServiceDisplayNameW( scm, name, display_name, &len );
5383 CloseServiceHandle( scm );
5385 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5386 stop_service( name );
5389 uirow = MSI_CreateRecord( 2 );
5390 MSI_RecordSetStringW( uirow, 1, display_name );
5391 MSI_RecordSetStringW( uirow, 2, name );
5392 ui_actiondata( package, szStopServices, uirow );
5393 msiobj_release( &uirow->hdr );
5396 msi_free( display_name );
5397 return ERROR_SUCCESS;
5400 static UINT ACTION_StopServices( MSIPACKAGE *package )
5405 static const WCHAR query[] = {
5406 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5407 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5409 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5410 if (rc != ERROR_SUCCESS)
5411 return ERROR_SUCCESS;
5413 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5414 msiobj_release(&view->hdr);
5419 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5421 MSIPACKAGE *package = param;
5425 LPWSTR name = NULL, display_name = NULL;
5427 SC_HANDLE scm = NULL, service = NULL;
5429 event = MSI_RecordGetInteger( rec, 3 );
5430 if (!(event & msidbServiceControlEventDelete))
5431 return ERROR_SUCCESS;
5433 component = MSI_RecordGetString(rec, 6);
5434 comp = get_loaded_component(package, component);
5436 return ERROR_SUCCESS;
5438 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5440 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5441 comp->Action = comp->Installed;
5442 return ERROR_SUCCESS;
5444 comp->Action = INSTALLSTATE_ABSENT;
5446 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5447 stop_service( name );
5449 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5452 WARN("Failed to open the SCM: %d\n", GetLastError());
5457 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5458 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5460 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5461 GetServiceDisplayNameW( scm, name, display_name, &len );
5464 service = OpenServiceW( scm, name, DELETE );
5467 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5471 if (!DeleteService( service ))
5472 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5475 uirow = MSI_CreateRecord( 2 );
5476 MSI_RecordSetStringW( uirow, 1, display_name );
5477 MSI_RecordSetStringW( uirow, 2, name );
5478 ui_actiondata( package, szDeleteServices, uirow );
5479 msiobj_release( &uirow->hdr );
5481 CloseServiceHandle( service );
5482 CloseServiceHandle( scm );
5484 msi_free( display_name );
5486 return ERROR_SUCCESS;
5489 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5494 static const WCHAR query[] = {
5495 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5496 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5498 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5499 if (rc != ERROR_SUCCESS)
5500 return ERROR_SUCCESS;
5502 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5503 msiobj_release( &view->hdr );
5508 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5512 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5514 if (!lstrcmpW(file->File, filename))
5521 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5523 MSIPACKAGE *package = param;
5524 LPWSTR driver, driver_path, ptr;
5525 WCHAR outpath[MAX_PATH];
5526 MSIFILE *driver_file, *setup_file;
5530 UINT r = ERROR_SUCCESS;
5532 static const WCHAR driver_fmt[] = {
5533 'D','r','i','v','e','r','=','%','s',0};
5534 static const WCHAR setup_fmt[] = {
5535 'S','e','t','u','p','=','%','s',0};
5536 static const WCHAR usage_fmt[] = {
5537 'F','i','l','e','U','s','a','g','e','=','1',0};
5539 desc = MSI_RecordGetString(rec, 3);
5541 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5542 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5546 ERR("ODBC Driver entry not found!\n");
5547 return ERROR_FUNCTION_FAILED;
5550 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5552 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5553 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5555 driver = msi_alloc(len * sizeof(WCHAR));
5557 return ERROR_OUTOFMEMORY;
5560 lstrcpyW(ptr, desc);
5561 ptr += lstrlenW(ptr) + 1;
5563 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5568 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5572 lstrcpyW(ptr, usage_fmt);
5573 ptr += lstrlenW(ptr) + 1;
5576 driver_path = strdupW(driver_file->TargetPath);
5577 ptr = strrchrW(driver_path, '\\');
5578 if (ptr) *ptr = '\0';
5580 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5581 NULL, ODBC_INSTALL_COMPLETE, &usage))
5583 ERR("Failed to install SQL driver!\n");
5584 r = ERROR_FUNCTION_FAILED;
5587 uirow = MSI_CreateRecord( 5 );
5588 MSI_RecordSetStringW( uirow, 1, desc );
5589 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5590 MSI_RecordSetStringW( uirow, 3, driver_path );
5591 ui_actiondata( package, szInstallODBC, uirow );
5592 msiobj_release( &uirow->hdr );
5595 msi_free(driver_path);
5600 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5602 MSIPACKAGE *package = param;
5603 LPWSTR translator, translator_path, ptr;
5604 WCHAR outpath[MAX_PATH];
5605 MSIFILE *translator_file, *setup_file;
5609 UINT r = ERROR_SUCCESS;
5611 static const WCHAR translator_fmt[] = {
5612 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5613 static const WCHAR setup_fmt[] = {
5614 'S','e','t','u','p','=','%','s',0};
5616 desc = MSI_RecordGetString(rec, 3);
5618 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5619 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5621 if (!translator_file)
5623 ERR("ODBC Translator entry not found!\n");
5624 return ERROR_FUNCTION_FAILED;
5627 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5629 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5631 translator = msi_alloc(len * sizeof(WCHAR));
5633 return ERROR_OUTOFMEMORY;
5636 lstrcpyW(ptr, desc);
5637 ptr += lstrlenW(ptr) + 1;
5639 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5644 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5649 translator_path = strdupW(translator_file->TargetPath);
5650 ptr = strrchrW(translator_path, '\\');
5651 if (ptr) *ptr = '\0';
5653 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5654 NULL, ODBC_INSTALL_COMPLETE, &usage))
5656 ERR("Failed to install SQL translator!\n");
5657 r = ERROR_FUNCTION_FAILED;
5660 uirow = MSI_CreateRecord( 5 );
5661 MSI_RecordSetStringW( uirow, 1, desc );
5662 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5663 MSI_RecordSetStringW( uirow, 3, translator_path );
5664 ui_actiondata( package, szInstallODBC, uirow );
5665 msiobj_release( &uirow->hdr );
5667 msi_free(translator);
5668 msi_free(translator_path);
5673 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5675 MSIPACKAGE *package = param;
5677 LPCWSTR desc, driver;
5678 WORD request = ODBC_ADD_SYS_DSN;
5681 UINT r = ERROR_SUCCESS;
5684 static const WCHAR attrs_fmt[] = {
5685 'D','S','N','=','%','s',0 };
5687 desc = MSI_RecordGetString(rec, 3);
5688 driver = MSI_RecordGetString(rec, 4);
5689 registration = MSI_RecordGetInteger(rec, 5);
5691 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5692 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5694 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5695 attrs = msi_alloc(len * sizeof(WCHAR));
5697 return ERROR_OUTOFMEMORY;
5699 len = sprintfW(attrs, attrs_fmt, desc);
5702 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5704 ERR("Failed to install SQL data source!\n");
5705 r = ERROR_FUNCTION_FAILED;
5708 uirow = MSI_CreateRecord( 5 );
5709 MSI_RecordSetStringW( uirow, 1, desc );
5710 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5711 MSI_RecordSetInteger( uirow, 3, request );
5712 ui_actiondata( package, szInstallODBC, uirow );
5713 msiobj_release( &uirow->hdr );
5720 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5725 static const WCHAR driver_query[] = {
5726 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5727 'O','D','B','C','D','r','i','v','e','r',0 };
5729 static const WCHAR translator_query[] = {
5730 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5731 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5733 static const WCHAR source_query[] = {
5734 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5735 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5737 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5738 if (rc != ERROR_SUCCESS)
5739 return ERROR_SUCCESS;
5741 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5742 msiobj_release(&view->hdr);
5744 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5745 if (rc != ERROR_SUCCESS)
5746 return ERROR_SUCCESS;
5748 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5749 msiobj_release(&view->hdr);
5751 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5752 if (rc != ERROR_SUCCESS)
5753 return ERROR_SUCCESS;
5755 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5756 msiobj_release(&view->hdr);
5761 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5763 MSIPACKAGE *package = param;
5768 desc = MSI_RecordGetString( rec, 3 );
5769 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5771 WARN("Failed to remove ODBC driver\n");
5775 FIXME("Usage count reached 0\n");
5778 uirow = MSI_CreateRecord( 2 );
5779 MSI_RecordSetStringW( uirow, 1, desc );
5780 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5781 ui_actiondata( package, szRemoveODBC, uirow );
5782 msiobj_release( &uirow->hdr );
5784 return ERROR_SUCCESS;
5787 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5789 MSIPACKAGE *package = param;
5794 desc = MSI_RecordGetString( rec, 3 );
5795 if (!SQLRemoveTranslatorW( desc, &usage ))
5797 WARN("Failed to remove ODBC translator\n");
5801 FIXME("Usage count reached 0\n");
5804 uirow = MSI_CreateRecord( 2 );
5805 MSI_RecordSetStringW( uirow, 1, desc );
5806 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5807 ui_actiondata( package, szRemoveODBC, uirow );
5808 msiobj_release( &uirow->hdr );
5810 return ERROR_SUCCESS;
5813 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5815 MSIPACKAGE *package = param;
5818 LPCWSTR desc, driver;
5819 WORD request = ODBC_REMOVE_SYS_DSN;
5823 static const WCHAR attrs_fmt[] = {
5824 'D','S','N','=','%','s',0 };
5826 desc = MSI_RecordGetString( rec, 3 );
5827 driver = MSI_RecordGetString( rec, 4 );
5828 registration = MSI_RecordGetInteger( rec, 5 );
5830 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5831 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5833 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5834 attrs = msi_alloc( len * sizeof(WCHAR) );
5836 return ERROR_OUTOFMEMORY;
5838 FIXME("Use ODBCSourceAttribute table\n");
5840 len = sprintfW( attrs, attrs_fmt, desc );
5843 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5845 WARN("Failed to remove ODBC data source\n");
5849 uirow = MSI_CreateRecord( 3 );
5850 MSI_RecordSetStringW( uirow, 1, desc );
5851 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5852 MSI_RecordSetInteger( uirow, 3, request );
5853 ui_actiondata( package, szRemoveODBC, uirow );
5854 msiobj_release( &uirow->hdr );
5856 return ERROR_SUCCESS;
5859 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5864 static const WCHAR driver_query[] = {
5865 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5866 'O','D','B','C','D','r','i','v','e','r',0 };
5868 static const WCHAR translator_query[] = {
5869 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5870 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5872 static const WCHAR source_query[] = {
5873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5874 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5876 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5877 if (rc != ERROR_SUCCESS)
5878 return ERROR_SUCCESS;
5880 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5881 msiobj_release( &view->hdr );
5883 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5884 if (rc != ERROR_SUCCESS)
5885 return ERROR_SUCCESS;
5887 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5888 msiobj_release( &view->hdr );
5890 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5891 if (rc != ERROR_SUCCESS)
5892 return ERROR_SUCCESS;
5894 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5895 msiobj_release( &view->hdr );
5900 #define ENV_ACT_SETALWAYS 0x1
5901 #define ENV_ACT_SETABSENT 0x2
5902 #define ENV_ACT_REMOVE 0x4
5903 #define ENV_ACT_REMOVEMATCH 0x8
5905 #define ENV_MOD_MACHINE 0x20000000
5906 #define ENV_MOD_APPEND 0x40000000
5907 #define ENV_MOD_PREFIX 0x80000000
5908 #define ENV_MOD_MASK 0xC0000000
5910 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5912 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5914 LPCWSTR cptr = *name;
5916 static const WCHAR prefix[] = {'[','~',']',0};
5917 static const int prefix_len = 3;
5923 *flags |= ENV_ACT_SETALWAYS;
5924 else if (*cptr == '+')
5925 *flags |= ENV_ACT_SETABSENT;
5926 else if (*cptr == '-')
5927 *flags |= ENV_ACT_REMOVE;
5928 else if (*cptr == '!')
5929 *flags |= ENV_ACT_REMOVEMATCH;
5930 else if (*cptr == '*')
5931 *flags |= ENV_MOD_MACHINE;
5941 ERR("Missing environment variable\n");
5942 return ERROR_FUNCTION_FAILED;
5947 LPCWSTR ptr = *value;
5948 if (!strncmpW(ptr, prefix, prefix_len))
5950 if (ptr[prefix_len] == szSemiColon[0])
5952 *flags |= ENV_MOD_APPEND;
5953 *value += lstrlenW(prefix);
5960 else if (lstrlenW(*value) >= prefix_len)
5962 ptr += lstrlenW(ptr) - prefix_len;
5963 if (!lstrcmpW(ptr, prefix))
5965 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5967 *flags |= ENV_MOD_PREFIX;
5968 /* the "[~]" will be removed by deformat_string */;
5978 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5979 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5980 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5981 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5983 ERR("Invalid flags: %08x\n", *flags);
5984 return ERROR_FUNCTION_FAILED;
5988 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5990 return ERROR_SUCCESS;
5993 static UINT open_env_key( DWORD flags, HKEY *key )
5995 static const WCHAR user_env[] =
5996 {'E','n','v','i','r','o','n','m','e','n','t',0};
5997 static const WCHAR machine_env[] =
5998 {'S','y','s','t','e','m','\\',
5999 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6000 'C','o','n','t','r','o','l','\\',
6001 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6002 'E','n','v','i','r','o','n','m','e','n','t',0};
6007 if (flags & ENV_MOD_MACHINE)
6010 root = HKEY_LOCAL_MACHINE;
6015 root = HKEY_CURRENT_USER;
6018 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6019 if (res != ERROR_SUCCESS)
6021 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6022 return ERROR_FUNCTION_FAILED;
6025 return ERROR_SUCCESS;
6028 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6030 MSIPACKAGE *package = param;
6031 LPCWSTR name, value, component;
6032 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6033 DWORD flags, type, size;
6040 component = MSI_RecordGetString(rec, 4);
6041 comp = get_loaded_component(package, component);
6043 return ERROR_SUCCESS;
6045 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6047 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6048 comp->Action = comp->Installed;
6049 return ERROR_SUCCESS;
6051 comp->Action = INSTALLSTATE_LOCAL;
6053 name = MSI_RecordGetString(rec, 2);
6054 value = MSI_RecordGetString(rec, 3);
6056 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6058 res = env_parse_flags(&name, &value, &flags);
6059 if (res != ERROR_SUCCESS || !value)
6062 if (value && !deformat_string(package, value, &deformatted))
6064 res = ERROR_OUTOFMEMORY;
6068 value = deformatted;
6070 res = open_env_key( flags, &env );
6071 if (res != ERROR_SUCCESS)
6074 if (flags & ENV_MOD_MACHINE)
6075 action |= 0x20000000;
6079 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6080 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6081 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6084 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6088 /* Nothing to do. */
6091 res = ERROR_SUCCESS;
6095 /* If we are appending but the string was empty, strip ; */
6096 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6098 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6099 newval = strdupW(value);
6102 res = ERROR_OUTOFMEMORY;
6110 /* Contrary to MSDN, +-variable to [~];path works */
6111 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6113 res = ERROR_SUCCESS;
6117 data = msi_alloc(size);
6121 return ERROR_OUTOFMEMORY;
6124 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6125 if (res != ERROR_SUCCESS)
6128 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6131 res = RegDeleteValueW(env, name);
6132 if (res != ERROR_SUCCESS)
6133 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6137 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6138 if (flags & ENV_MOD_MASK)
6142 if (flags & ENV_MOD_APPEND) multiplier++;
6143 if (flags & ENV_MOD_PREFIX) multiplier++;
6144 mod_size = lstrlenW(value) * multiplier;
6145 size += mod_size * sizeof(WCHAR);
6148 newval = msi_alloc(size);
6152 res = ERROR_OUTOFMEMORY;
6156 if (flags & ENV_MOD_PREFIX)
6158 lstrcpyW(newval, value);
6159 ptr = newval + lstrlenW(value);
6160 action |= 0x80000000;
6163 lstrcpyW(ptr, data);
6165 if (flags & ENV_MOD_APPEND)
6167 lstrcatW(newval, value);
6168 action |= 0x40000000;
6171 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6172 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6175 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6179 uirow = MSI_CreateRecord( 3 );
6180 MSI_RecordSetStringW( uirow, 1, name );
6181 MSI_RecordSetStringW( uirow, 2, newval );
6182 MSI_RecordSetInteger( uirow, 3, action );
6183 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6184 msiobj_release( &uirow->hdr );
6186 if (env) RegCloseKey(env);
6187 msi_free(deformatted);
6193 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6197 static const WCHAR ExecSeqQuery[] =
6198 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6199 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6200 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6201 if (rc != ERROR_SUCCESS)
6202 return ERROR_SUCCESS;
6204 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6205 msiobj_release(&view->hdr);
6210 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6212 MSIPACKAGE *package = param;
6213 LPCWSTR name, value, component;
6214 LPWSTR deformatted = NULL;
6223 component = MSI_RecordGetString( rec, 4 );
6224 comp = get_loaded_component( package, component );
6226 return ERROR_SUCCESS;
6228 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6230 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6231 comp->Action = comp->Installed;
6232 return ERROR_SUCCESS;
6234 comp->Action = INSTALLSTATE_ABSENT;
6236 name = MSI_RecordGetString( rec, 2 );
6237 value = MSI_RecordGetString( rec, 3 );
6239 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6241 r = env_parse_flags( &name, &value, &flags );
6242 if (r != ERROR_SUCCESS)
6245 if (!(flags & ENV_ACT_REMOVE))
6247 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6248 return ERROR_SUCCESS;
6251 if (value && !deformat_string( package, value, &deformatted ))
6252 return ERROR_OUTOFMEMORY;
6254 value = deformatted;
6256 r = open_env_key( flags, &env );
6257 if (r != ERROR_SUCCESS)
6263 if (flags & ENV_MOD_MACHINE)
6264 action |= 0x20000000;
6266 TRACE("Removing %s\n", debugstr_w(name));
6268 res = RegDeleteValueW( env, name );
6269 if (res != ERROR_SUCCESS)
6271 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6276 uirow = MSI_CreateRecord( 3 );
6277 MSI_RecordSetStringW( uirow, 1, name );
6278 MSI_RecordSetStringW( uirow, 2, value );
6279 MSI_RecordSetInteger( uirow, 3, action );
6280 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6281 msiobj_release( &uirow->hdr );
6283 if (env) RegCloseKey( env );
6284 msi_free( deformatted );
6288 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6292 static const WCHAR query[] =
6293 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6294 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6296 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6297 if (rc != ERROR_SUCCESS)
6298 return ERROR_SUCCESS;
6300 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6301 msiobj_release( &view->hdr );
6306 typedef struct tagMSIASSEMBLY
6309 MSICOMPONENT *component;
6310 MSIFEATURE *feature;
6314 LPWSTR display_name;
6319 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6321 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6322 LPVOID pvReserved, HMODULE *phModDll);
6324 static BOOL init_functionpointers(void)
6330 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6332 hmscoree = LoadLibraryA("mscoree.dll");
6335 WARN("mscoree.dll not available\n");
6339 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6340 if (!pLoadLibraryShim)
6342 WARN("LoadLibraryShim not available\n");
6343 FreeLibrary(hmscoree);
6347 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6350 WARN("fusion.dll not available\n");
6351 FreeLibrary(hmscoree);
6355 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6357 FreeLibrary(hmscoree);
6361 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6364 IAssemblyCache *cache;
6367 UINT r = ERROR_FUNCTION_FAILED;
6369 TRACE("installing assembly: %s\n", debugstr_w(path));
6371 uirow = MSI_CreateRecord( 2 );
6372 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6373 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6374 msiobj_release( &uirow->hdr );
6376 if (assembly->feature)
6377 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6379 if (assembly->manifest)
6380 FIXME("Manifest unhandled\n");
6382 if (assembly->application)
6384 FIXME("Assembly should be privately installed\n");
6385 return ERROR_SUCCESS;
6388 if (assembly->attributes == msidbAssemblyAttributesWin32)
6390 FIXME("Win32 assemblies not handled\n");
6391 return ERROR_SUCCESS;
6394 hr = pCreateAssemblyCache(&cache, 0);
6398 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6400 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6405 IAssemblyCache_Release(cache);
6409 typedef struct tagASSEMBLY_LIST
6411 MSIPACKAGE *package;
6412 IAssemblyCache *cache;
6413 struct list *assemblies;
6416 typedef struct tagASSEMBLY_NAME
6424 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6426 ASSEMBLY_NAME *asmname = param;
6427 LPCWSTR name = MSI_RecordGetString(rec, 2);
6428 LPWSTR val = msi_dup_record_field(rec, 3);
6430 static const WCHAR Name[] = {'N','a','m','e',0};
6431 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6432 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6433 static const WCHAR PublicKeyToken[] = {
6434 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6436 if (!strcmpiW(name, Name))
6437 asmname->name = val;
6438 else if (!strcmpiW(name, Version))
6439 asmname->version = val;
6440 else if (!strcmpiW(name, Culture))
6441 asmname->culture = val;
6442 else if (!strcmpiW(name, PublicKeyToken))
6443 asmname->pubkeytoken = val;
6447 return ERROR_SUCCESS;
6450 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6454 *size = lstrlenW(append) + 1;
6455 *str = msi_alloc((*size) * sizeof(WCHAR));
6456 lstrcpyW(*str, append);
6460 (*size) += lstrlenW(append);
6461 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6462 lstrcatW(*str, append);
6465 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6467 static const WCHAR separator[] = {',',' ',0};
6468 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6469 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6470 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6471 static const WCHAR query[] = {
6472 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6473 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6474 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6475 '=','\'','%','s','\'',0};
6478 LPWSTR display_name;
6482 display_name = NULL;
6483 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6485 r = MSI_OpenQuery( db, &view, query, comp->Component );
6486 if (r != ERROR_SUCCESS)
6489 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6490 msiobj_release( &view->hdr );
6494 ERR("No assembly name specified!\n");
6498 append_str( &display_name, &size, name.name );
6502 append_str( &display_name, &size, separator );
6503 append_str( &display_name, &size, Version );
6504 append_str( &display_name, &size, name.version );
6508 append_str( &display_name, &size, separator );
6509 append_str( &display_name, &size, Culture );
6510 append_str( &display_name, &size, name.culture );
6512 if (name.pubkeytoken)
6514 append_str( &display_name, &size, separator );
6515 append_str( &display_name, &size, PublicKeyToken );
6516 append_str( &display_name, &size, name.pubkeytoken );
6519 msi_free( name.name );
6520 msi_free( name.version );
6521 msi_free( name.culture );
6522 msi_free( name.pubkeytoken );
6524 return display_name;
6527 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6529 ASSEMBLY_INFO asminfo;
6534 disp = get_assembly_display_name( db, comp );
6538 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6539 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6541 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6543 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6549 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6551 ASSEMBLY_LIST *list = param;
6552 MSIASSEMBLY *assembly;
6555 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6557 return ERROR_OUTOFMEMORY;
6559 component = MSI_RecordGetString(rec, 1);
6560 assembly->component = get_loaded_component(list->package, component);
6561 if (!assembly->component)
6562 return ERROR_SUCCESS;
6564 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6565 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6567 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6568 assembly->component->Action = assembly->component->Installed;
6569 return ERROR_SUCCESS;
6571 assembly->component->Action = assembly->component->ActionRequest;
6573 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6574 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6576 if (!assembly->file)
6578 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6579 return ERROR_FUNCTION_FAILED;
6582 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6583 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6584 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6586 if (assembly->application)
6589 DWORD size = sizeof(version)/sizeof(WCHAR);
6591 /* FIXME: we should probably check the manifest file here */
6593 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6594 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6596 assembly->installed = TRUE;
6600 assembly->installed = check_assembly_installed(list->package->db,
6602 assembly->component);
6604 list_add_head(list->assemblies, &assembly->entry);
6605 return ERROR_SUCCESS;
6608 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6610 IAssemblyCache *cache = NULL;
6616 static const WCHAR query[] =
6617 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6618 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6620 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6621 if (r != ERROR_SUCCESS)
6622 return ERROR_SUCCESS;
6624 hr = pCreateAssemblyCache(&cache, 0);
6626 return ERROR_FUNCTION_FAILED;
6628 list.package = package;
6630 list.assemblies = assemblies;
6632 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6633 msiobj_release(&view->hdr);
6635 IAssemblyCache_Release(cache);
6640 static void free_assemblies(struct list *assemblies)
6642 struct list *item, *cursor;
6644 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6646 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6648 list_remove(&assembly->entry);
6649 msi_free(assembly->application);
6650 msi_free(assembly->manifest);
6651 msi_free(assembly->display_name);
6656 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6658 MSIASSEMBLY *assembly;
6660 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6662 if (!lstrcmpW(assembly->file->File, file))
6672 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6673 LPWSTR *path, DWORD *attrs, PVOID user)
6675 MSIASSEMBLY *assembly;
6676 WCHAR temppath[MAX_PATH];
6677 struct list *assemblies = user;
6680 if (!find_assembly(assemblies, file, &assembly))
6683 GetTempPathW(MAX_PATH, temppath);
6684 PathAddBackslashW(temppath);
6685 lstrcatW(temppath, assembly->file->FileName);
6687 if (action == MSICABEXTRACT_BEGINEXTRACT)
6689 if (assembly->installed)
6692 *path = strdupW(temppath);
6693 *attrs = assembly->file->Attributes;
6695 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6697 assembly->installed = TRUE;
6699 r = install_assembly(package, assembly, temppath);
6700 if (r != ERROR_SUCCESS)
6701 ERR("Failed to install assembly\n");
6707 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6710 struct list assemblies = LIST_INIT(assemblies);
6711 MSIASSEMBLY *assembly;
6714 if (!init_functionpointers() || !pCreateAssemblyCache)
6715 return ERROR_FUNCTION_FAILED;
6717 r = load_assemblies(package, &assemblies);
6718 if (r != ERROR_SUCCESS)
6721 if (list_empty(&assemblies))
6724 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6727 r = ERROR_OUTOFMEMORY;
6731 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6733 if (assembly->installed && !mi->is_continuous)
6736 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6737 (assembly->file->IsCompressed && !mi->is_extracted))
6741 r = ready_media(package, assembly->file, mi);
6742 if (r != ERROR_SUCCESS)
6744 ERR("Failed to ready media\n");
6749 data.package = package;
6750 data.cb = installassembly_cb;
6751 data.user = &assemblies;
6753 if (assembly->file->IsCompressed &&
6754 !msi_cabextract(package, mi, &data))
6756 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6757 r = ERROR_FUNCTION_FAILED;
6762 if (!assembly->file->IsCompressed)
6764 LPWSTR source = resolve_file_source(package, assembly->file);
6766 r = install_assembly(package, assembly, source);
6767 if (r != ERROR_SUCCESS)
6768 ERR("Failed to install assembly\n");
6773 /* FIXME: write Installer assembly reg values */
6777 free_assemblies(&assemblies);
6781 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6783 LPWSTR key, template, id;
6784 UINT r = ERROR_SUCCESS;
6786 id = msi_dup_property( package->db, szProductID );
6790 return ERROR_SUCCESS;
6792 template = msi_dup_property( package->db, szPIDTemplate );
6793 key = msi_dup_property( package->db, szPIDKEY );
6795 if (key && template)
6797 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6798 r = MSI_SetPropertyW( package, szProductID, key );
6800 msi_free( template );
6805 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6808 package->need_reboot = 1;
6809 return ERROR_SUCCESS;
6812 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6814 static const WCHAR szAvailableFreeReg[] =
6815 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6817 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6819 TRACE("%p %d kilobytes\n", package, space);
6821 uirow = MSI_CreateRecord( 1 );
6822 MSI_RecordSetInteger( uirow, 1, space );
6823 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6824 msiobj_release( &uirow->hdr );
6826 return ERROR_SUCCESS;
6829 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6831 FIXME("%p\n", package);
6832 return ERROR_SUCCESS;
6835 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6837 FIXME("%p\n", package);
6838 return ERROR_SUCCESS;
6841 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6846 static const WCHAR driver_query[] = {
6847 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6848 'O','D','B','C','D','r','i','v','e','r',0 };
6850 static const WCHAR translator_query[] = {
6851 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6852 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6854 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6855 if (r == ERROR_SUCCESS)
6858 r = MSI_IterateRecords( view, &count, NULL, package );
6859 msiobj_release( &view->hdr );
6860 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6863 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6864 if (r == ERROR_SUCCESS)
6867 r = MSI_IterateRecords( view, &count, NULL, package );
6868 msiobj_release( &view->hdr );
6869 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6872 return ERROR_SUCCESS;
6875 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6876 LPCSTR action, LPCWSTR table )
6878 static const WCHAR query[] = {
6879 'S','E','L','E','C','T',' ','*',' ',
6880 'F','R','O','M',' ','`','%','s','`',0 };
6881 MSIQUERY *view = NULL;
6885 r = MSI_OpenQuery( package->db, &view, query, table );
6886 if (r == ERROR_SUCCESS)
6888 r = MSI_IterateRecords(view, &count, NULL, package);
6889 msiobj_release(&view->hdr);
6893 FIXME("%s -> %u ignored %s table values\n",
6894 action, count, debugstr_w(table));
6896 return ERROR_SUCCESS;
6899 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6901 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6902 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6905 static UINT ACTION_BindImage( MSIPACKAGE *package )
6907 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6908 return msi_unimplemented_action_stub( package, "BindImage", table );
6911 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6913 static const WCHAR table[] = {
6914 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6915 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6918 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6920 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6921 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6924 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6926 static const WCHAR table[] = {
6927 'M','s','i','A','s','s','e','m','b','l','y',0 };
6928 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6931 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6933 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6934 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6937 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6939 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6940 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6943 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6945 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6946 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6949 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6951 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6952 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6955 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6957 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6958 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6961 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6965 const WCHAR *action;
6966 UINT (*handler)(MSIPACKAGE *);
6970 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6971 { szAppSearch, ACTION_AppSearch },
6972 { szBindImage, ACTION_BindImage },
6973 { szCCPSearch, ACTION_CCPSearch },
6974 { szCostFinalize, ACTION_CostFinalize },
6975 { szCostInitialize, ACTION_CostInitialize },
6976 { szCreateFolders, ACTION_CreateFolders },
6977 { szCreateShortcuts, ACTION_CreateShortcuts },
6978 { szDeleteServices, ACTION_DeleteServices },
6979 { szDisableRollback, ACTION_DisableRollback },
6980 { szDuplicateFiles, ACTION_DuplicateFiles },
6981 { szExecuteAction, ACTION_ExecuteAction },
6982 { szFileCost, ACTION_FileCost },
6983 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6984 { szForceReboot, ACTION_ForceReboot },
6985 { szInstallAdminPackage, ACTION_InstallAdminPackage },
6986 { szInstallExecute, ACTION_InstallExecute },
6987 { szInstallExecuteAgain, ACTION_InstallExecute },
6988 { szInstallFiles, ACTION_InstallFiles},
6989 { szInstallFinalize, ACTION_InstallFinalize },
6990 { szInstallInitialize, ACTION_InstallInitialize },
6991 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6992 { szInstallValidate, ACTION_InstallValidate },
6993 { szIsolateComponents, ACTION_IsolateComponents },
6994 { szLaunchConditions, ACTION_LaunchConditions },
6995 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6996 { szMoveFiles, ACTION_MoveFiles },
6997 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6998 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6999 { szInstallODBC, ACTION_InstallODBC },
7000 { szInstallServices, ACTION_InstallServices },
7001 { szPatchFiles, ACTION_PatchFiles },
7002 { szProcessComponents, ACTION_ProcessComponents },
7003 { szPublishComponents, ACTION_PublishComponents },
7004 { szPublishFeatures, ACTION_PublishFeatures },
7005 { szPublishProduct, ACTION_PublishProduct },
7006 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7007 { szRegisterComPlus, ACTION_RegisterComPlus},
7008 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7009 { szRegisterFonts, ACTION_RegisterFonts },
7010 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7011 { szRegisterProduct, ACTION_RegisterProduct },
7012 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7013 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7014 { szRegisterUser, ACTION_RegisterUser },
7015 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7016 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7017 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7018 { szRemoveFiles, ACTION_RemoveFiles },
7019 { szRemoveFolders, ACTION_RemoveFolders },
7020 { szRemoveIniValues, ACTION_RemoveIniValues },
7021 { szRemoveODBC, ACTION_RemoveODBC },
7022 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7023 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7024 { szResolveSource, ACTION_ResolveSource },
7025 { szRMCCPSearch, ACTION_RMCCPSearch },
7026 { szScheduleReboot, ACTION_ScheduleReboot },
7027 { szSelfRegModules, ACTION_SelfRegModules },
7028 { szSelfUnregModules, ACTION_SelfUnregModules },
7029 { szSetODBCFolders, ACTION_SetODBCFolders },
7030 { szStartServices, ACTION_StartServices },
7031 { szStopServices, ACTION_StopServices },
7032 { szUnpublishComponents, ACTION_UnpublishComponents },
7033 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7034 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7035 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7036 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7037 { szUnregisterFonts, ACTION_UnregisterFonts },
7038 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7039 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7040 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7041 { szValidateProductID, ACTION_ValidateProductID },
7042 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7043 { szWriteIniValues, ACTION_WriteIniValues },
7044 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7048 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7049 UINT* rc, BOOL force )
7055 if (!run && !package->script->CurrentlyScripting)
7060 if (strcmpW(action,szInstallFinalize) == 0 ||
7061 strcmpW(action,szInstallExecute) == 0 ||
7062 strcmpW(action,szInstallExecuteAgain) == 0)
7067 while (StandardActions[i].action != NULL)
7069 if (strcmpW(StandardActions[i].action, action)==0)
7073 ui_actioninfo(package, action, TRUE, 0);
7074 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7075 ui_actioninfo(package, action, FALSE, *rc);
7079 ui_actionstart(package, action);
7080 if (StandardActions[i].handler)
7082 *rc = StandardActions[i].handler(package);
7086 FIXME("unhandled standard action %s\n",debugstr_w(action));
7087 *rc = ERROR_SUCCESS;
7098 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7100 UINT rc = ERROR_SUCCESS;
7103 TRACE("Performing action (%s)\n", debugstr_w(action));
7105 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7108 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7112 WARN("unhandled msi action %s\n", debugstr_w(action));
7113 rc = ERROR_FUNCTION_NOT_CALLED;
7119 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7121 UINT rc = ERROR_SUCCESS;
7122 BOOL handled = FALSE;
7124 TRACE("Performing action (%s)\n", debugstr_w(action));
7126 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7129 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7131 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7136 WARN("unhandled msi action %s\n", debugstr_w(action));
7137 rc = ERROR_FUNCTION_NOT_CALLED;
7143 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7145 UINT rc = ERROR_SUCCESS;
7148 static const WCHAR ExecSeqQuery[] =
7149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7150 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7151 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7152 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7153 static const WCHAR UISeqQuery[] =
7154 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7155 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7156 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7157 ' ', '=',' ','%','i',0};
7159 if (needs_ui_sequence(package))
7160 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7162 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7166 LPCWSTR action, cond;
7168 TRACE("Running the actions\n");
7170 /* check conditions */
7171 cond = MSI_RecordGetString(row, 2);
7173 /* this is a hack to skip errors in the condition code */
7174 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7176 msiobj_release(&row->hdr);
7177 return ERROR_SUCCESS;
7180 action = MSI_RecordGetString(row, 1);
7183 ERR("failed to fetch action\n");
7184 msiobj_release(&row->hdr);
7185 return ERROR_FUNCTION_FAILED;
7188 if (needs_ui_sequence(package))
7189 rc = ACTION_PerformUIAction(package, action, -1);
7191 rc = ACTION_PerformAction(package, action, -1, FALSE);
7193 msiobj_release(&row->hdr);
7199 /****************************************************
7200 * TOP level entry points
7201 *****************************************************/
7203 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7204 LPCWSTR szCommandLine )
7209 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7210 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7212 MSI_SetPropertyW(package, szAction, szInstall);
7214 package->script->InWhatSequence = SEQUENCE_INSTALL;
7221 dir = strdupW(szPackagePath);
7222 p = strrchrW(dir, '\\');
7226 file = szPackagePath + (p - dir);
7231 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7232 GetCurrentDirectoryW(MAX_PATH, dir);
7233 lstrcatW(dir, szBackSlash);
7234 file = szPackagePath;
7237 msi_free( package->PackagePath );
7238 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7239 if (!package->PackagePath)
7242 return ERROR_OUTOFMEMORY;
7245 lstrcpyW(package->PackagePath, dir);
7246 lstrcatW(package->PackagePath, file);
7249 msi_set_sourcedir_props(package, FALSE);
7252 msi_parse_command_line( package, szCommandLine, FALSE );
7254 msi_apply_transforms( package );
7255 msi_apply_patches( package );
7257 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7259 TRACE("setting reinstall property\n");
7260 MSI_SetPropertyW( package, szReinstall, szAll );
7263 /* properties may have been added by a transform */
7264 msi_clone_properties( package );
7265 msi_set_context( package );
7267 if (needs_ui_sequence( package))
7269 package->script->InWhatSequence |= SEQUENCE_UI;
7270 rc = ACTION_ProcessUISequence(package);
7271 ui_exists = ui_sequence_exists(package);
7272 if (rc == ERROR_SUCCESS || !ui_exists)
7274 package->script->InWhatSequence |= SEQUENCE_EXEC;
7275 rc = ACTION_ProcessExecSequence(package, ui_exists);
7279 rc = ACTION_ProcessExecSequence(package, FALSE);
7281 package->script->CurrentlyScripting = FALSE;
7283 /* process the ending type action */
7284 if (rc == ERROR_SUCCESS)
7285 ACTION_PerformActionSequence(package, -1);
7286 else if (rc == ERROR_INSTALL_USEREXIT)
7287 ACTION_PerformActionSequence(package, -2);
7288 else if (rc == ERROR_INSTALL_SUSPEND)
7289 ACTION_PerformActionSequence(package, -4);
7291 ACTION_PerformActionSequence(package, -3);
7293 /* finish up running custom actions */
7294 ACTION_FinishCustomActions(package);
7296 if (rc == ERROR_SUCCESS && package->need_reboot)
7297 return ERROR_SUCCESS_REBOOT_REQUIRED;