2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * consts and values used
51 static const WCHAR c_colon[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAllocateRegistrySpace[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterFonts[] =
128 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
129 static const WCHAR szRegisterUser[] =
130 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
131 static const WCHAR szRemoveEnvironmentStrings[] =
132 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
133 static const WCHAR szRemoveExistingProducts[] =
134 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
135 static const WCHAR szRemoveFolders[] =
136 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
137 static const WCHAR szRemoveIniValues[] =
138 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
139 static const WCHAR szRemoveODBC[] =
140 {'R','e','m','o','v','e','O','D','B','C',0};
141 static const WCHAR szRemoveRegistryValues[] =
142 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
143 static const WCHAR szRemoveShortcuts[] =
144 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
145 static const WCHAR szRMCCPSearch[] =
146 {'R','M','C','C','P','S','e','a','r','c','h',0};
147 static const WCHAR szScheduleReboot[] =
148 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
149 static const WCHAR szSelfUnregModules[] =
150 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
151 static const WCHAR szSetODBCFolders[] =
152 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
153 static const WCHAR szStartServices[] =
154 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szStopServices[] =
156 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szUnpublishComponents[] =
158 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szUnpublishFeatures[] =
160 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
161 static const WCHAR szUnregisterComPlus[] =
162 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 static const WCHAR szUnregisterExtensionInfo[] =
164 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
165 static const WCHAR szUnregisterFonts[] =
166 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
167 static const WCHAR szUnregisterMIMEInfo[] =
168 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
169 static const WCHAR szUnregisterProgIdInfo[] =
170 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
171 static const WCHAR szUnregisterTypeLibraries[] =
172 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
173 static const WCHAR szValidateProductID[] =
174 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
175 static const WCHAR szWriteEnvironmentStrings[] =
176 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
178 /********************************************************
180 ********************************************************/
182 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
184 static const WCHAR Query_t[] =
185 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
186 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
187 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
188 ' ','\'','%','s','\'',0};
191 row = MSI_QueryGetRecord( package->db, Query_t, action );
194 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
195 msiobj_release(&row->hdr);
198 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
202 static const WCHAR template_s[]=
203 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
205 static const WCHAR template_e[]=
206 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
207 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
209 static const WCHAR format[] =
210 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
214 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
216 sprintfW(message,template_s,timet,action);
218 sprintfW(message,template_e,timet,action,rc);
220 row = MSI_CreateRecord(1);
221 MSI_RecordSetStringW(row,1,message);
223 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
224 msiobj_release(&row->hdr);
227 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
233 LPWSTR prop = NULL, val = NULL;
236 return ERROR_SUCCESS;
248 TRACE("Looking at %s\n",debugstr_w(ptr));
250 ptr2 = strchrW(ptr,'=');
253 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
260 prop = msi_alloc((len+1)*sizeof(WCHAR));
261 memcpy(prop,ptr,len*sizeof(WCHAR));
271 while (*ptr && (quote || (!quote && *ptr!=' ')))
284 val = msi_alloc((len+1)*sizeof(WCHAR));
285 memcpy(val,ptr2,len*sizeof(WCHAR));
288 if (lstrlenW(prop) > 0)
290 TRACE("Found commandline property (%s) = (%s)\n",
291 debugstr_w(prop), debugstr_w(val));
292 MSI_SetPropertyW(package,prop,val);
298 return ERROR_SUCCESS;
302 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
305 LPWSTR p, *ret = NULL;
311 /* count the number of substrings */
312 for ( pc = str, count = 0; pc; count++ )
314 pc = strchrW( pc, sep );
319 /* allocate space for an array of substring pointers and the substrings */
320 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
321 (lstrlenW(str)+1) * sizeof(WCHAR) );
325 /* copy the string and set the pointers */
326 p = (LPWSTR) &ret[count+1];
328 for( count = 0; (ret[count] = p); count++ )
330 p = strchrW( p, sep );
338 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
340 static const WCHAR szSystemLanguageID[] =
341 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
343 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
344 UINT ret = ERROR_FUNCTION_FAILED;
346 prod_code = msi_dup_property( package, szProductCode );
347 patch_product = msi_get_suminfo_product( patch );
349 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
351 if ( strstrW( patch_product, prod_code ) )
356 si = MSI_GetSummaryInformationW( patch, 0 );
359 ERR("no summary information!\n");
363 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
366 ERR("no template property!\n");
367 msiobj_release( &si->hdr );
374 msiobj_release( &si->hdr );
378 langid = msi_dup_property( package, szSystemLanguageID );
381 msiobj_release( &si->hdr );
385 p = strchrW( template, ';' );
386 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
388 TRACE("applicable transform\n");
392 /* FIXME: check platform */
394 msiobj_release( &si->hdr );
398 msi_free( patch_product );
399 msi_free( prod_code );
400 msi_free( template );
406 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
407 MSIDATABASE *patch_db, LPCWSTR name )
409 UINT ret = ERROR_FUNCTION_FAILED;
410 IStorage *stg = NULL;
413 TRACE("%p %s\n", package, debugstr_w(name) );
417 ERR("expected a colon in %s\n", debugstr_w(name));
418 return ERROR_FUNCTION_FAILED;
421 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
424 ret = msi_check_transform_applicable( package, stg );
425 if (ret == ERROR_SUCCESS)
426 msi_table_apply_transform( package->db, stg );
428 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
429 IStorage_Release( stg );
432 ERR("failed to open substorage %s\n", debugstr_w(name));
434 return ERROR_SUCCESS;
437 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
439 LPWSTR guid_list, *guids, product_code;
440 UINT i, ret = ERROR_FUNCTION_FAILED;
442 product_code = msi_dup_property( package, szProductCode );
445 /* FIXME: the property ProductCode should be written into the DB somewhere */
446 ERR("no product code to check\n");
447 return ERROR_SUCCESS;
450 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
451 guids = msi_split_string( guid_list, ';' );
452 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
454 if (!lstrcmpW( guids[i], product_code ))
458 msi_free( guid_list );
459 msi_free( product_code );
464 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
467 MSIRECORD *rec = NULL;
472 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
473 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
474 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
475 '`','S','o','u','r','c','e','`',' ','I','S',' ',
476 'N','O','T',' ','N','U','L','L',0};
478 r = MSI_DatabaseOpenViewW(package->db, query, &view);
479 if (r != ERROR_SUCCESS)
482 r = MSI_ViewExecute(view, 0);
483 if (r != ERROR_SUCCESS)
486 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
488 prop = MSI_RecordGetString(rec, 1);
489 patch = msi_dup_property(package, szPatch);
490 MSI_SetPropertyW(package, prop, patch);
495 if (rec) msiobj_release(&rec->hdr);
496 msiobj_release(&view->hdr);
501 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
504 LPWSTR str, *substorage;
505 UINT i, r = ERROR_SUCCESS;
507 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
509 return ERROR_FUNCTION_FAILED;
511 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
513 TRACE("Patch not applicable\n");
514 return ERROR_SUCCESS;
517 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
519 return ERROR_OUTOFMEMORY;
521 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
522 if (!package->patch->patchcode)
523 return ERROR_OUTOFMEMORY;
525 /* enumerate the substorage */
526 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
527 package->patch->transforms = str;
529 substorage = msi_split_string( str, ';' );
530 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
531 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
533 msi_free( substorage );
534 msiobj_release( &si->hdr );
536 msi_set_media_source_prop(package);
541 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
543 MSIDATABASE *patch_db = NULL;
546 TRACE("%p %s\n", package, debugstr_w( file ) );
549 * We probably want to make sure we only open a patch collection here.
550 * Patch collections (.msp) and databases (.msi) have different GUIDs
551 * but currently MSI_OpenDatabaseW will accept both.
553 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
554 if ( r != ERROR_SUCCESS )
556 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
560 msi_parse_patch_summary( package, patch_db );
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, 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, 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, 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, cszSourceDir );
670 if (!check || replace)
671 MSI_SetPropertyW( package, cszSourceDir, source );
675 check = msi_dup_property( package, 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, 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, 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, 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, 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, szlevel, 1);
1704 if (!msi_get_property_int( package, 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 );
2005 file->state = msifs_present;
2008 return ERROR_SUCCESS;
2012 * A lot is done in this function aside from just the costing.
2013 * The costing needs to be implemented at some point but for now I am going
2014 * to focus on the directory building
2017 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2019 static const WCHAR ExecSeqQuery[] =
2020 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2021 '`','D','i','r','e','c','t','o','r','y','`',0};
2022 static const WCHAR ConditionQuery[] =
2023 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2024 '`','C','o','n','d','i','t','i','o','n','`',0};
2025 static const WCHAR szCosting[] =
2026 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2027 static const WCHAR szlevel[] =
2028 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2029 static const WCHAR szOutOfDiskSpace[] =
2030 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2032 UINT rc = ERROR_SUCCESS;
2036 TRACE("Building Directory properties\n");
2038 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2039 if (rc == ERROR_SUCCESS)
2041 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2043 msiobj_release(&view->hdr);
2046 /* read components states from the registry */
2047 ACTION_GetComponentInstallStates(package);
2048 ACTION_GetFeatureInstallStates(package);
2050 TRACE("File calculations\n");
2051 msi_check_file_install_states( package );
2053 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
2055 TRACE("Evaluating Condition Table\n");
2057 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2058 if (rc == ERROR_SUCCESS)
2060 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2061 msiobj_release( &view->hdr );
2064 TRACE("Enabling or Disabling Components\n");
2065 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2067 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2069 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2070 comp->Enabled = FALSE;
2073 comp->Enabled = TRUE;
2077 MSI_SetPropertyW(package,szCosting,szOne);
2078 /* set default run level if not set */
2079 level = msi_dup_property( package, szlevel );
2081 MSI_SetPropertyW(package,szlevel, szOne);
2084 /* FIXME: check volume disk space */
2085 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2087 return MSI_SetFeatureStates(package);
2090 /* OK this value is "interpreted" and then formatted based on the
2091 first few characters */
2092 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2097 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2103 LPWSTR deformated = NULL;
2106 deformat_string(package, &value[2], &deformated);
2108 /* binary value type */
2112 *size = (strlenW(ptr)/2)+1;
2114 *size = strlenW(ptr)/2;
2116 data = msi_alloc(*size);
2122 /* if uneven pad with a zero in front */
2128 data[count] = (BYTE)strtol(byte,NULL,0);
2130 TRACE("Uneven byte count\n");
2138 data[count] = (BYTE)strtol(byte,NULL,0);
2141 msi_free(deformated);
2143 TRACE("Data %i bytes(%i)\n",*size,count);
2150 deformat_string(package, &value[1], &deformated);
2153 *size = sizeof(DWORD);
2154 data = msi_alloc(*size);
2160 if ( (*p < '0') || (*p > '9') )
2166 if (deformated[0] == '-')
2169 TRACE("DWORD %i\n",*(LPDWORD)data);
2171 msi_free(deformated);
2176 static const WCHAR szMulti[] = {'[','~',']',0};
2185 *type=REG_EXPAND_SZ;
2193 if (strstrW(value,szMulti))
2194 *type = REG_MULTI_SZ;
2196 /* remove initial delimiter */
2197 if (!strncmpW(value, szMulti, 3))
2200 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2202 /* add double NULL terminator */
2203 if (*type == REG_MULTI_SZ)
2205 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2206 data = msi_realloc_zero(data, *size);
2212 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2219 if (msi_get_property_int( package, szAllUsers, 0 ))
2221 *root_key = HKEY_LOCAL_MACHINE;
2226 *root_key = HKEY_CURRENT_USER;
2231 *root_key = HKEY_CLASSES_ROOT;
2235 *root_key = HKEY_CURRENT_USER;
2239 *root_key = HKEY_LOCAL_MACHINE;
2243 *root_key = HKEY_USERS;
2247 ERR("Unknown root %i\n", root);
2254 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2256 MSIPACKAGE *package = param;
2257 LPSTR value_data = NULL;
2258 HKEY root_key, hkey;
2261 LPCWSTR szRoot, component, name, key, value;
2266 BOOL check_first = FALSE;
2269 ui_progress(package,2,0,0,0);
2276 component = MSI_RecordGetString(row, 6);
2277 comp = get_loaded_component(package,component);
2279 return ERROR_SUCCESS;
2281 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2283 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2284 comp->Action = comp->Installed;
2285 return ERROR_SUCCESS;
2287 comp->Action = INSTALLSTATE_LOCAL;
2289 name = MSI_RecordGetString(row, 4);
2290 if( MSI_RecordIsNull(row,5) && name )
2292 /* null values can have special meanings */
2293 if (name[0]=='-' && name[1] == 0)
2294 return ERROR_SUCCESS;
2295 else if ((name[0]=='+' && name[1] == 0) ||
2296 (name[0] == '*' && name[1] == 0))
2301 root = MSI_RecordGetInteger(row,2);
2302 key = MSI_RecordGetString(row, 3);
2304 szRoot = get_root_key( package, root, &root_key );
2306 return ERROR_SUCCESS;
2308 deformat_string(package, key , &deformated);
2309 size = strlenW(deformated) + strlenW(szRoot) + 1;
2310 uikey = msi_alloc(size*sizeof(WCHAR));
2311 strcpyW(uikey,szRoot);
2312 strcatW(uikey,deformated);
2314 if (RegCreateKeyW( root_key, deformated, &hkey))
2316 ERR("Could not create key %s\n",debugstr_w(deformated));
2317 msi_free(deformated);
2319 return ERROR_SUCCESS;
2321 msi_free(deformated);
2323 value = MSI_RecordGetString(row,5);
2325 value_data = parse_value(package, value, &type, &size);
2328 value_data = (LPSTR)strdupW(szEmpty);
2329 size = sizeof(szEmpty);
2333 deformat_string(package, name, &deformated);
2337 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2339 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2344 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2345 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2347 TRACE("value %s of %s checked already exists\n",
2348 debugstr_w(deformated), debugstr_w(uikey));
2352 TRACE("Checked and setting value %s of %s\n",
2353 debugstr_w(deformated), debugstr_w(uikey));
2354 if (deformated || size)
2355 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2360 uirow = MSI_CreateRecord(3);
2361 MSI_RecordSetStringW(uirow,2,deformated);
2362 MSI_RecordSetStringW(uirow,1,uikey);
2363 if (type == REG_SZ || type == REG_EXPAND_SZ)
2364 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2365 ui_actiondata(package,szWriteRegistryValues,uirow);
2366 msiobj_release( &uirow->hdr );
2368 msi_free(value_data);
2369 msi_free(deformated);
2372 return ERROR_SUCCESS;
2375 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2379 static const WCHAR ExecSeqQuery[] =
2380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2381 '`','R','e','g','i','s','t','r','y','`',0 };
2383 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2384 if (rc != ERROR_SUCCESS)
2385 return ERROR_SUCCESS;
2387 /* increment progress bar each time action data is sent */
2388 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2390 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2392 msiobj_release(&view->hdr);
2396 static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2400 DWORD num_subkeys, num_values;
2404 if ((res = RegDeleteTreeW( hkey_root, key )))
2406 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2411 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2413 if ((res = RegDeleteValueW( hkey, value )))
2415 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2417 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2418 NULL, NULL, NULL, NULL );
2419 RegCloseKey( hkey );
2421 if (!res && !num_subkeys && !num_values)
2423 TRACE("Removing empty key %s\n", debugstr_w(key));
2424 RegDeleteKeyW( hkey_root, key );
2428 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2432 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2434 MSIPACKAGE *package = param;
2435 LPCWSTR component, name, key_str, root_key_str;
2436 LPWSTR deformated_key, deformated_name, ui_key_str;
2439 BOOL delete_key = FALSE;
2444 ui_progress( package, 2, 0, 0, 0 );
2446 component = MSI_RecordGetString( row, 6 );
2447 comp = get_loaded_component( package, component );
2449 return ERROR_SUCCESS;
2451 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2453 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2454 comp->Action = comp->Installed;
2455 return ERROR_SUCCESS;
2457 comp->Action = INSTALLSTATE_ABSENT;
2459 name = MSI_RecordGetString( row, 4 );
2460 if (MSI_RecordIsNull( row, 5 ) && name )
2462 if (name[0] == '+' && !name[1])
2463 return ERROR_SUCCESS;
2464 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2471 root = MSI_RecordGetInteger( row, 2 );
2472 key_str = MSI_RecordGetString( row, 3 );
2474 root_key_str = get_root_key( package, root, &hkey_root );
2476 return ERROR_SUCCESS;
2478 deformat_string( package, key_str, &deformated_key );
2479 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2480 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2481 strcpyW( ui_key_str, root_key_str );
2482 strcatW( ui_key_str, deformated_key );
2484 deformat_string( package, name, &deformated_name );
2486 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2487 msi_free( deformated_key );
2489 uirow = MSI_CreateRecord( 2 );
2490 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2491 MSI_RecordSetStringW( uirow, 2, deformated_name );
2493 ui_actiondata( package, szRemoveRegistryValues, uirow );
2494 msiobj_release( &uirow->hdr );
2496 msi_free( ui_key_str );
2497 msi_free( deformated_name );
2498 return ERROR_SUCCESS;
2501 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2503 MSIPACKAGE *package = param;
2504 LPCWSTR component, name, key_str, root_key_str;
2505 LPWSTR deformated_key, deformated_name, ui_key_str;
2508 BOOL delete_key = FALSE;
2513 ui_progress( package, 2, 0, 0, 0 );
2515 component = MSI_RecordGetString( row, 5 );
2516 comp = get_loaded_component( package, component );
2518 return ERROR_SUCCESS;
2520 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2522 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2523 comp->Action = comp->Installed;
2524 return ERROR_SUCCESS;
2526 comp->Action = INSTALLSTATE_LOCAL;
2528 if ((name = MSI_RecordGetString( row, 4 )))
2530 if (name[0] == '-' && !name[1])
2537 root = MSI_RecordGetInteger( row, 2 );
2538 key_str = MSI_RecordGetString( row, 3 );
2540 root_key_str = get_root_key( package, root, &hkey_root );
2542 return ERROR_SUCCESS;
2544 deformat_string( package, key_str, &deformated_key );
2545 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2546 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2547 strcpyW( ui_key_str, root_key_str );
2548 strcatW( ui_key_str, deformated_key );
2550 deformat_string( package, name, &deformated_name );
2552 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2553 msi_free( deformated_key );
2555 uirow = MSI_CreateRecord( 2 );
2556 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2557 MSI_RecordSetStringW( uirow, 2, deformated_name );
2559 ui_actiondata( package, szRemoveRegistryValues, uirow );
2560 msiobj_release( &uirow->hdr );
2562 msi_free( ui_key_str );
2563 msi_free( deformated_name );
2564 return ERROR_SUCCESS;
2567 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2571 static const WCHAR registry_query[] =
2572 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2573 '`','R','e','g','i','s','t','r','y','`',0 };
2574 static const WCHAR remove_registry_query[] =
2575 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2576 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2578 /* increment progress bar each time action data is sent */
2579 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2581 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2582 if (rc == ERROR_SUCCESS)
2584 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2585 msiobj_release( &view->hdr );
2586 if (rc != ERROR_SUCCESS)
2590 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2591 if (rc == ERROR_SUCCESS)
2593 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2594 msiobj_release( &view->hdr );
2595 if (rc != ERROR_SUCCESS)
2599 return ERROR_SUCCESS;
2602 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2604 package->script->CurrentlyScripting = TRUE;
2606 return ERROR_SUCCESS;
2610 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2615 static const WCHAR q1[]=
2616 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2617 '`','R','e','g','i','s','t','r','y','`',0};
2620 MSIFEATURE *feature;
2623 TRACE("InstallValidate\n");
2625 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2626 if (rc == ERROR_SUCCESS)
2628 MSI_IterateRecords( view, &progress, NULL, package );
2629 msiobj_release( &view->hdr );
2630 total += progress * REG_PROGRESS_VALUE;
2633 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2634 total += COMPONENT_PROGRESS_VALUE;
2636 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2637 total += file->FileSize;
2639 ui_progress(package,0,total,0,0);
2641 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2643 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2644 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2645 feature->ActionRequest);
2648 return ERROR_SUCCESS;
2651 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2653 MSIPACKAGE* package = param;
2654 LPCWSTR cond = NULL;
2655 LPCWSTR message = NULL;
2658 static const WCHAR title[]=
2659 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2661 cond = MSI_RecordGetString(row,1);
2663 r = MSI_EvaluateConditionW(package,cond);
2664 if (r == MSICONDITION_FALSE)
2666 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2669 message = MSI_RecordGetString(row,2);
2670 deformat_string(package,message,&deformated);
2671 MessageBoxW(NULL,deformated,title,MB_OK);
2672 msi_free(deformated);
2675 return ERROR_INSTALL_FAILURE;
2678 return ERROR_SUCCESS;
2681 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2684 MSIQUERY * view = NULL;
2685 static const WCHAR ExecSeqQuery[] =
2686 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2687 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2689 TRACE("Checking launch conditions\n");
2691 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2692 if (rc != ERROR_SUCCESS)
2693 return ERROR_SUCCESS;
2695 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2696 msiobj_release(&view->hdr);
2701 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2705 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2707 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2709 MSIRECORD * row = 0;
2711 LPWSTR deformated,buffer,deformated_name;
2713 static const WCHAR ExecSeqQuery[] =
2714 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2715 '`','R','e','g','i','s','t','r','y','`',' ',
2716 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2717 ' ','=',' ' ,'\'','%','s','\'',0 };
2718 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2719 static const WCHAR fmt2[]=
2720 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2722 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2726 root = MSI_RecordGetInteger(row,2);
2727 key = MSI_RecordGetString(row, 3);
2728 name = MSI_RecordGetString(row, 4);
2729 deformat_string(package, key , &deformated);
2730 deformat_string(package, name, &deformated_name);
2732 len = strlenW(deformated) + 6;
2733 if (deformated_name)
2734 len+=strlenW(deformated_name);
2736 buffer = msi_alloc( len *sizeof(WCHAR));
2738 if (deformated_name)
2739 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2741 sprintfW(buffer,fmt,root,deformated);
2743 msi_free(deformated);
2744 msi_free(deformated_name);
2745 msiobj_release(&row->hdr);
2749 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2751 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2756 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2759 return strdupW( file->TargetPath );
2764 static HKEY openSharedDLLsKey(void)
2767 static const WCHAR path[] =
2768 {'S','o','f','t','w','a','r','e','\\',
2769 'M','i','c','r','o','s','o','f','t','\\',
2770 'W','i','n','d','o','w','s','\\',
2771 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2772 'S','h','a','r','e','d','D','L','L','s',0};
2774 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2778 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2783 DWORD sz = sizeof(count);
2786 hkey = openSharedDLLsKey();
2787 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2788 if (rc != ERROR_SUCCESS)
2794 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2798 hkey = openSharedDLLsKey();
2800 msi_reg_set_val_dword( hkey, path, count );
2802 RegDeleteValueW(hkey,path);
2808 * Return TRUE if the count should be written out and FALSE if not
2810 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2812 MSIFEATURE *feature;
2816 /* only refcount DLLs */
2817 if (comp->KeyPath == NULL ||
2818 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2819 comp->Attributes & msidbComponentAttributesODBCDataSource)
2823 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2824 write = (count > 0);
2826 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2830 /* increment counts */
2831 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2835 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
2838 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2840 if ( cl->component == comp )
2845 /* decrement counts */
2846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2850 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
2853 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2855 if ( cl->component == comp )
2860 /* ref count all the files in the component */
2865 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2867 if (file->Component == comp)
2868 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2872 /* add a count for permanent */
2873 if (comp->Attributes & msidbComponentAttributesPermanent)
2876 comp->RefCount = count;
2879 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2882 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2884 WCHAR squished_pc[GUID_SIZE];
2885 WCHAR squished_cc[GUID_SIZE];
2892 squash_guid(package->ProductCode,squished_pc);
2893 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2895 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2899 ui_progress(package,2,0,0,0);
2900 if (!comp->ComponentId)
2903 squash_guid(comp->ComponentId,squished_cc);
2905 msi_free(comp->FullKeypath);
2906 comp->FullKeypath = resolve_keypath( package, comp );
2908 ACTION_RefCountComponent( package, comp );
2910 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2911 debugstr_w(comp->Component),
2912 debugstr_w(squished_cc),
2913 debugstr_w(comp->FullKeypath),
2916 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2917 comp->ActionRequest == INSTALLSTATE_SOURCE)
2919 if (!comp->FullKeypath)
2922 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2923 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2926 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2929 if (rc != ERROR_SUCCESS)
2932 if (comp->Attributes & msidbComponentAttributesPermanent)
2934 static const WCHAR szPermKey[] =
2935 { '0','0','0','0','0','0','0','0','0','0','0','0',
2936 '0','0','0','0','0','0','0','0','0','0','0','0',
2937 '0','0','0','0','0','0','0','0',0 };
2939 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2942 if (comp->Action == INSTALLSTATE_LOCAL)
2943 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2949 WCHAR source[MAX_PATH];
2950 WCHAR base[MAX_PATH];
2953 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2954 static const WCHAR query[] = {
2955 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2956 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2957 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2958 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2959 '`','D','i','s','k','I','d','`',0};
2961 file = get_loaded_file(package, comp->KeyPath);
2965 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2966 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2967 ptr2 = strrchrW(source, '\\') + 1;
2968 msiobj_release(&row->hdr);
2970 lstrcpyW(base, package->PackagePath);
2971 ptr = strrchrW(base, '\\');
2974 sourcepath = resolve_file_source(package, file);
2975 ptr = sourcepath + lstrlenW(base);
2976 lstrcpyW(ptr2, ptr);
2977 msi_free(sourcepath);
2979 msi_reg_set_val_str(hkey, squished_pc, source);
2983 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
2985 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2986 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2988 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2990 comp->Action = comp->ActionRequest;
2993 uirow = MSI_CreateRecord(3);
2994 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2995 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2996 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2997 ui_actiondata(package,szProcessComponents,uirow);
2998 msiobj_release( &uirow->hdr );
3001 return ERROR_SUCCESS;
3012 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3013 LPWSTR lpszName, LONG_PTR lParam)
3016 typelib_struct *tl_struct = (typelib_struct*) lParam;
3017 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3021 if (!IS_INTRESOURCE(lpszName))
3023 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3027 sz = strlenW(tl_struct->source)+4;
3028 sz *= sizeof(WCHAR);
3030 if ((INT_PTR)lpszName == 1)
3031 tl_struct->path = strdupW(tl_struct->source);
3034 tl_struct->path = msi_alloc(sz);
3035 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3038 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3039 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3042 msi_free(tl_struct->path);
3043 tl_struct->path = NULL;
3048 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3049 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3051 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3055 msi_free(tl_struct->path);
3056 tl_struct->path = NULL;
3058 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3059 ITypeLib_Release(tl_struct->ptLib);
3064 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3066 MSIPACKAGE* package = param;
3070 typelib_struct tl_struct;
3075 component = MSI_RecordGetString(row,3);
3076 comp = get_loaded_component(package,component);
3078 return ERROR_SUCCESS;
3080 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3082 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3083 comp->Action = comp->Installed;
3084 return ERROR_SUCCESS;
3086 comp->Action = INSTALLSTATE_LOCAL;
3088 file = get_loaded_file( package, comp->KeyPath );
3090 return ERROR_SUCCESS;
3092 ui_actiondata( package, szRegisterTypeLibraries, row );
3094 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3098 guid = MSI_RecordGetString(row,1);
3099 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3100 tl_struct.source = strdupW( file->TargetPath );
3101 tl_struct.path = NULL;
3103 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3104 (LONG_PTR)&tl_struct);
3112 helpid = MSI_RecordGetString(row,6);
3115 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3116 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3120 ERR("Failed to register type library %s\n",
3121 debugstr_w(tl_struct.path));
3123 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3125 ITypeLib_Release(tl_struct.ptLib);
3126 msi_free(tl_struct.path);
3129 ERR("Failed to load type library %s\n",
3130 debugstr_w(tl_struct.source));
3132 FreeLibrary(module);
3133 msi_free(tl_struct.source);
3137 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3140 ERR("Failed to load type library: %08x\n", hr);
3141 return ERROR_INSTALL_FAILURE;
3144 ITypeLib_Release(tlib);
3147 return ERROR_SUCCESS;
3150 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3153 * OK this is a bit confusing.. I am given a _Component key and I believe
3154 * that the file that is being registered as a type library is the "key file
3155 * of that component" which I interpret to mean "The file in the KeyPath of
3160 static const WCHAR Query[] =
3161 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3162 '`','T','y','p','e','L','i','b','`',0};
3164 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3165 if (rc != ERROR_SUCCESS)
3166 return ERROR_SUCCESS;
3168 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3169 msiobj_release(&view->hdr);
3173 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3175 MSIPACKAGE *package = param;
3176 LPCWSTR component, guid;
3184 component = MSI_RecordGetString( row, 3 );
3185 comp = get_loaded_component( package, component );
3187 return ERROR_SUCCESS;
3189 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3191 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3192 comp->Action = comp->Installed;
3193 return ERROR_SUCCESS;
3195 comp->Action = INSTALLSTATE_ABSENT;
3197 ui_actiondata( package, szUnregisterTypeLibraries, row );
3199 guid = MSI_RecordGetString( row, 1 );
3200 CLSIDFromString( (LPCWSTR)guid, &libid );
3201 version = MSI_RecordGetInteger( row, 4 );
3202 language = MSI_RecordGetInteger( row, 2 );
3205 syskind = SYS_WIN64;
3207 syskind = SYS_WIN32;
3210 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3213 WARN("Failed to unregister typelib: %08x\n", hr);
3216 return ERROR_SUCCESS;
3219 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3223 static const WCHAR query[] =
3224 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3225 '`','T','y','p','e','L','i','b','`',0};
3227 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3228 if (rc != ERROR_SUCCESS)
3229 return ERROR_SUCCESS;
3231 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3232 msiobj_release( &view->hdr );
3236 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3238 static const WCHAR szlnk[] = {'.','l','n','k',0};
3239 LPCWSTR directory, extension;
3240 LPWSTR link_folder, link_file, filename;
3242 directory = MSI_RecordGetString( row, 2 );
3243 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3245 /* may be needed because of a bug somewhere else */
3246 create_full_pathW( link_folder );
3248 filename = msi_dup_record_field( row, 3 );
3249 reduce_to_longfilename( filename );
3251 extension = strchrW( filename, '.' );
3252 if (!extension || strcmpiW( extension, szlnk ))
3254 int len = strlenW( filename );
3255 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3256 memcpy( filename + len, szlnk, sizeof(szlnk) );
3258 link_file = build_directory_name( 2, link_folder, filename );
3259 msi_free( link_folder );
3260 msi_free( filename );
3265 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3267 MSIPACKAGE *package = param;
3268 LPWSTR link_file, deformated, path;
3269 LPCWSTR component, target;
3271 IShellLinkW *sl = NULL;
3272 IPersistFile *pf = NULL;
3275 component = MSI_RecordGetString(row, 4);
3276 comp = get_loaded_component(package, component);
3278 return ERROR_SUCCESS;
3280 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3282 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3283 comp->Action = comp->Installed;
3284 return ERROR_SUCCESS;
3286 comp->Action = INSTALLSTATE_LOCAL;
3288 ui_actiondata(package,szCreateShortcuts,row);
3290 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3291 &IID_IShellLinkW, (LPVOID *) &sl );
3295 ERR("CLSID_ShellLink not available\n");
3299 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3302 ERR("QueryInterface(IID_IPersistFile) failed\n");
3306 target = MSI_RecordGetString(row, 5);
3307 if (strchrW(target, '['))
3309 deformat_string(package, target, &deformated);
3310 IShellLinkW_SetPath(sl,deformated);
3311 msi_free(deformated);
3315 FIXME("poorly handled shortcut format, advertised shortcut\n");
3316 IShellLinkW_SetPath(sl,comp->FullKeypath);
3319 if (!MSI_RecordIsNull(row,6))
3321 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3322 deformat_string(package, arguments, &deformated);
3323 IShellLinkW_SetArguments(sl,deformated);
3324 msi_free(deformated);
3327 if (!MSI_RecordIsNull(row,7))
3329 LPCWSTR description = MSI_RecordGetString(row, 7);
3330 IShellLinkW_SetDescription(sl, description);
3333 if (!MSI_RecordIsNull(row,8))
3334 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3336 if (!MSI_RecordIsNull(row,9))
3339 LPCWSTR icon = MSI_RecordGetString(row, 9);
3341 path = build_icon_path(package, icon);
3342 index = MSI_RecordGetInteger(row,10);
3344 /* no value means 0 */
3345 if (index == MSI_NULL_INTEGER)
3348 IShellLinkW_SetIconLocation(sl, path, index);
3352 if (!MSI_RecordIsNull(row,11))
3353 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3355 if (!MSI_RecordIsNull(row,12))
3357 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3358 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3360 IShellLinkW_SetWorkingDirectory(sl, path);
3364 link_file = get_link_file(package, row);
3366 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3367 IPersistFile_Save(pf, link_file, FALSE);
3369 msi_free(link_file);
3373 IPersistFile_Release( pf );
3375 IShellLinkW_Release( sl );
3377 return ERROR_SUCCESS;
3380 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3385 static const WCHAR Query[] =
3386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3387 '`','S','h','o','r','t','c','u','t','`',0};
3389 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3390 if (rc != ERROR_SUCCESS)
3391 return ERROR_SUCCESS;
3393 res = CoInitialize( NULL );
3395 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3396 msiobj_release(&view->hdr);
3404 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3406 MSIPACKAGE *package = param;
3411 component = MSI_RecordGetString( row, 4 );
3412 comp = get_loaded_component( package, component );
3414 return ERROR_SUCCESS;
3416 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3418 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3419 comp->Action = comp->Installed;
3420 return ERROR_SUCCESS;
3422 comp->Action = INSTALLSTATE_ABSENT;
3424 ui_actiondata( package, szRemoveShortcuts, row );
3426 link_file = get_link_file( package, row );
3428 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3429 if (!DeleteFileW( link_file ))
3431 WARN("Failed to remove shortcut file %u\n", GetLastError());
3433 msi_free( link_file );
3435 return ERROR_SUCCESS;
3438 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3442 static const WCHAR query[] =
3443 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3444 '`','S','h','o','r','t','c','u','t','`',0};
3446 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3447 if (rc != ERROR_SUCCESS)
3448 return ERROR_SUCCESS;
3450 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3451 msiobj_release( &view->hdr );
3456 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3458 MSIPACKAGE* package = param;
3466 FileName = MSI_RecordGetString(row,1);
3469 ERR("Unable to get FileName\n");
3470 return ERROR_SUCCESS;
3473 FilePath = build_icon_path(package,FileName);
3475 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3477 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3478 FILE_ATTRIBUTE_NORMAL, NULL);
3480 if (the_file == INVALID_HANDLE_VALUE)
3482 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3484 return ERROR_SUCCESS;
3491 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3492 if (rc != ERROR_SUCCESS)
3494 ERR("Failed to get stream\n");
3495 CloseHandle(the_file);
3496 DeleteFileW(FilePath);
3499 WriteFile(the_file,buffer,sz,&write,NULL);
3500 } while (sz == 1024);
3503 CloseHandle(the_file);
3505 return ERROR_SUCCESS;
3508 static UINT msi_publish_icons(MSIPACKAGE *package)
3513 static const WCHAR query[]= {
3514 'S','E','L','E','C','T',' ','*',' ',
3515 'F','R','O','M',' ','`','I','c','o','n','`',0};
3517 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3518 if (r == ERROR_SUCCESS)
3520 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3521 msiobj_release(&view->hdr);
3524 return ERROR_SUCCESS;
3527 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3533 MSISOURCELISTINFO *info;
3535 r = RegCreateKeyW(hkey, szSourceList, &source);
3536 if (r != ERROR_SUCCESS)
3539 RegCloseKey(source);
3541 buffer = strrchrW(package->PackagePath, '\\') + 1;
3542 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3543 package->Context, MSICODE_PRODUCT,
3544 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3545 if (r != ERROR_SUCCESS)
3548 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3549 package->Context, MSICODE_PRODUCT,
3550 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3551 if (r != ERROR_SUCCESS)
3554 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3555 package->Context, MSICODE_PRODUCT,
3556 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3557 if (r != ERROR_SUCCESS)
3560 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3562 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3563 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3564 info->options, info->value);
3566 MsiSourceListSetInfoW(package->ProductCode, NULL,
3567 info->context, info->options,
3568 info->property, info->value);
3571 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3573 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3574 disk->context, disk->options,
3575 disk->disk_id, disk->volume_label, disk->disk_prompt);
3578 return ERROR_SUCCESS;
3581 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3583 MSIHANDLE hdb, suminfo;
3584 WCHAR guids[MAX_PATH];
3585 WCHAR packcode[SQUISH_GUID_SIZE];
3592 static const WCHAR szProductLanguage[] =
3593 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3594 static const WCHAR szARPProductIcon[] =
3595 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3596 static const WCHAR szProductVersion[] =
3597 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3598 static const WCHAR szAssignment[] =
3599 {'A','s','s','i','g','n','m','e','n','t',0};
3600 static const WCHAR szAdvertiseFlags[] =
3601 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3602 static const WCHAR szClients[] =
3603 {'C','l','i','e','n','t','s',0};
3604 static const WCHAR szColon[] = {':',0};
3606 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3607 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3610 langid = msi_get_property_int(package, szProductLanguage, 0);
3611 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3614 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3616 buffer = msi_dup_property(package, szARPProductIcon);
3619 LPWSTR path = build_icon_path(package,buffer);
3620 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3625 buffer = msi_dup_property(package, szProductVersion);
3628 DWORD verdword = msi_version_str_to_dword(buffer);
3629 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3633 msi_reg_set_val_dword(hkey, szAssignment, 0);
3634 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3635 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3636 msi_reg_set_val_str(hkey, szClients, szColon);
3638 hdb = alloc_msihandle(&package->db->hdr);
3640 return ERROR_NOT_ENOUGH_MEMORY;
3642 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3643 MsiCloseHandle(hdb);
3644 if (r != ERROR_SUCCESS)
3648 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3649 NULL, guids, &size);
3650 if (r != ERROR_SUCCESS)
3653 ptr = strchrW(guids, ';');
3655 squash_guid(guids, packcode);
3656 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3659 MsiCloseHandle(suminfo);
3660 return ERROR_SUCCESS;
3663 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3668 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3670 static const WCHAR szUpgradeCode[] =
3671 {'U','p','g','r','a','d','e','C','o','d','e',0};
3673 upgrade = msi_dup_property(package, szUpgradeCode);
3675 return ERROR_SUCCESS;
3677 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3679 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3680 if (r != ERROR_SUCCESS)
3685 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3686 if (r != ERROR_SUCCESS)
3690 squash_guid(package->ProductCode, squashed_pc);
3691 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3700 static BOOL msi_check_publish(MSIPACKAGE *package)
3702 MSIFEATURE *feature;
3704 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3706 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3713 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3715 MSIFEATURE *feature;
3717 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3719 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3726 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3728 WCHAR patch_squashed[GUID_SIZE];
3731 UINT r = ERROR_FUNCTION_FAILED;
3733 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3735 if (res != ERROR_SUCCESS)
3736 return ERROR_FUNCTION_FAILED;
3738 squash_guid(package->patch->patchcode, patch_squashed);
3740 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3741 (const BYTE *)patch_squashed,
3742 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3743 if (res != ERROR_SUCCESS)
3746 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3747 (const BYTE *)package->patch->transforms,
3748 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3749 if (res == ERROR_SUCCESS)
3753 RegCloseKey(patches);
3758 * 99% of the work done here is only done for
3759 * advertised installs. However this is where the
3760 * Icon table is processed and written out
3761 * so that is what I am going to do here.
3763 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3766 HKEY hukey = NULL, hudkey = NULL;
3769 /* FIXME: also need to publish if the product is in advertise mode */
3770 if (!msi_check_publish(package))
3771 return ERROR_SUCCESS;
3773 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3775 if (rc != ERROR_SUCCESS)
3778 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3779 NULL, &hudkey, TRUE);
3780 if (rc != ERROR_SUCCESS)
3783 rc = msi_publish_upgrade_code(package);
3784 if (rc != ERROR_SUCCESS)
3789 rc = msi_publish_patch(package, hukey, hudkey);
3790 if (rc != ERROR_SUCCESS)
3794 rc = msi_publish_product_properties(package, hukey);
3795 if (rc != ERROR_SUCCESS)
3798 rc = msi_publish_sourcelist(package, hukey);
3799 if (rc != ERROR_SUCCESS)
3802 rc = msi_publish_icons(package);
3805 uirow = MSI_CreateRecord( 1 );
3806 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3807 ui_actiondata( package, szPublishProduct, uirow );
3808 msiobj_release( &uirow->hdr );
3811 RegCloseKey(hudkey);
3816 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3818 WCHAR *filename, *ptr, *folder, *ret;
3819 const WCHAR *dirprop;
3821 filename = msi_dup_record_field( row, 2 );
3822 if (filename && (ptr = strchrW( filename, '|' )))
3827 dirprop = MSI_RecordGetString( row, 3 );
3830 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3832 folder = msi_dup_property( package, dirprop );
3835 folder = msi_dup_property( package, szWindowsFolder );
3839 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3840 msi_free( filename );
3844 ret = build_directory_name( 2, folder, ptr );
3846 msi_free( filename );
3851 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3853 MSIPACKAGE *package = param;
3854 LPCWSTR component, section, key, value, identifier;
3855 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
3860 component = MSI_RecordGetString(row, 8);
3861 comp = get_loaded_component(package,component);
3863 return ERROR_SUCCESS;
3865 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3867 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3868 comp->Action = comp->Installed;
3869 return ERROR_SUCCESS;
3871 comp->Action = INSTALLSTATE_LOCAL;
3873 identifier = MSI_RecordGetString(row,1);
3874 section = MSI_RecordGetString(row,4);
3875 key = MSI_RecordGetString(row,5);
3876 value = MSI_RecordGetString(row,6);
3877 action = MSI_RecordGetInteger(row,7);
3879 deformat_string(package,section,&deformated_section);
3880 deformat_string(package,key,&deformated_key);
3881 deformat_string(package,value,&deformated_value);
3883 fullname = get_ini_file_name(package, row);
3887 TRACE("Adding value %s to section %s in %s\n",
3888 debugstr_w(deformated_key), debugstr_w(deformated_section),
3889 debugstr_w(fullname));
3890 WritePrivateProfileStringW(deformated_section, deformated_key,
3891 deformated_value, fullname);
3893 else if (action == 1)
3896 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3897 returned, 10, fullname);
3898 if (returned[0] == 0)
3900 TRACE("Adding value %s to section %s in %s\n",
3901 debugstr_w(deformated_key), debugstr_w(deformated_section),
3902 debugstr_w(fullname));
3904 WritePrivateProfileStringW(deformated_section, deformated_key,
3905 deformated_value, fullname);
3908 else if (action == 3)
3909 FIXME("Append to existing section not yet implemented\n");
3911 uirow = MSI_CreateRecord(4);
3912 MSI_RecordSetStringW(uirow,1,identifier);
3913 MSI_RecordSetStringW(uirow,2,deformated_section);
3914 MSI_RecordSetStringW(uirow,3,deformated_key);
3915 MSI_RecordSetStringW(uirow,4,deformated_value);
3916 ui_actiondata(package,szWriteIniValues,uirow);
3917 msiobj_release( &uirow->hdr );
3920 msi_free(deformated_key);
3921 msi_free(deformated_value);
3922 msi_free(deformated_section);
3923 return ERROR_SUCCESS;
3926 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3930 static const WCHAR ExecSeqQuery[] =
3931 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3932 '`','I','n','i','F','i','l','e','`',0};
3934 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3935 if (rc != ERROR_SUCCESS)
3937 TRACE("no IniFile table\n");
3938 return ERROR_SUCCESS;
3941 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3942 msiobj_release(&view->hdr);
3946 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3948 MSIPACKAGE *package = param;
3949 LPCWSTR component, section, key, value, identifier;
3950 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3955 component = MSI_RecordGetString( row, 8 );
3956 comp = get_loaded_component( package, component );
3958 return ERROR_SUCCESS;
3960 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3962 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3963 comp->Action = comp->Installed;
3964 return ERROR_SUCCESS;
3966 comp->Action = INSTALLSTATE_ABSENT;
3968 identifier = MSI_RecordGetString( row, 1 );
3969 section = MSI_RecordGetString( row, 4 );
3970 key = MSI_RecordGetString( row, 5 );
3971 value = MSI_RecordGetString( row, 6 );
3972 action = MSI_RecordGetInteger( row, 7 );
3974 deformat_string( package, section, &deformated_section );
3975 deformat_string( package, key, &deformated_key );
3976 deformat_string( package, value, &deformated_value );
3978 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3980 filename = get_ini_file_name( package, row );
3982 TRACE("Removing key %s from section %s in %s\n",
3983 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3985 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3987 WARN("Unable to remove key %u\n", GetLastError());
3989 msi_free( filename );
3992 FIXME("Unsupported action %d\n", action);
3995 uirow = MSI_CreateRecord( 4 );
3996 MSI_RecordSetStringW( uirow, 1, identifier );
3997 MSI_RecordSetStringW( uirow, 2, deformated_section );
3998 MSI_RecordSetStringW( uirow, 3, deformated_key );
3999 MSI_RecordSetStringW( uirow, 4, deformated_value );
4000 ui_actiondata( package, szRemoveIniValues, uirow );
4001 msiobj_release( &uirow->hdr );
4003 msi_free( deformated_key );
4004 msi_free( deformated_value );
4005 msi_free( deformated_section );
4006 return ERROR_SUCCESS;
4009 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4011 MSIPACKAGE *package = param;
4012 LPCWSTR component, section, key, value, identifier;
4013 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4018 component = MSI_RecordGetString( row, 8 );
4019 comp = get_loaded_component( package, component );
4021 return ERROR_SUCCESS;
4023 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4025 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4026 comp->Action = comp->Installed;
4027 return ERROR_SUCCESS;
4029 comp->Action = INSTALLSTATE_LOCAL;
4031 identifier = MSI_RecordGetString( row, 1 );
4032 section = MSI_RecordGetString( row, 4 );
4033 key = MSI_RecordGetString( row, 5 );
4034 value = MSI_RecordGetString( row, 6 );
4035 action = MSI_RecordGetInteger( row, 7 );
4037 deformat_string( package, section, &deformated_section );
4038 deformat_string( package, key, &deformated_key );
4039 deformat_string( package, value, &deformated_value );
4041 if (action == msidbIniFileActionRemoveLine)
4043 filename = get_ini_file_name( package, row );
4045 TRACE("Removing key %s from section %s in %s\n",
4046 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4048 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4050 WARN("Unable to remove key %u\n", GetLastError());
4052 msi_free( filename );
4055 FIXME("Unsupported action %d\n", action);
4057 uirow = MSI_CreateRecord( 4 );
4058 MSI_RecordSetStringW( uirow, 1, identifier );
4059 MSI_RecordSetStringW( uirow, 2, deformated_section );
4060 MSI_RecordSetStringW( uirow, 3, deformated_key );
4061 MSI_RecordSetStringW( uirow, 4, deformated_value );
4062 ui_actiondata( package, szRemoveIniValues, uirow );
4063 msiobj_release( &uirow->hdr );
4065 msi_free( deformated_key );
4066 msi_free( deformated_value );
4067 msi_free( deformated_section );
4068 return ERROR_SUCCESS;
4071 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4075 static const WCHAR query[] =
4076 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4077 '`','I','n','i','F','i','l','e','`',0};
4078 static const WCHAR remove_query[] =
4079 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4080 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4082 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4083 if (rc == ERROR_SUCCESS)
4085 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4086 msiobj_release( &view->hdr );
4087 if (rc != ERROR_SUCCESS)
4091 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4092 if (rc == ERROR_SUCCESS)
4094 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4095 msiobj_release( &view->hdr );
4096 if (rc != ERROR_SUCCESS)
4100 return ERROR_SUCCESS;
4103 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4105 MSIPACKAGE *package = param;
4110 static const WCHAR ExeStr[] =
4111 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4112 static const WCHAR close[] = {'\"',0};
4114 PROCESS_INFORMATION info;
4119 memset(&si,0,sizeof(STARTUPINFOW));
4121 filename = MSI_RecordGetString(row,1);
4122 file = get_loaded_file( package, filename );
4126 ERR("Unable to find file id %s\n",debugstr_w(filename));
4127 return ERROR_SUCCESS;
4130 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
4132 FullName = msi_alloc(len*sizeof(WCHAR));
4133 strcpyW(FullName,ExeStr);
4134 strcatW( FullName, file->TargetPath );
4135 strcatW(FullName,close);
4137 TRACE("Registering %s\n",debugstr_w(FullName));
4138 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4143 CloseHandle(info.hThread);
4144 msi_dialog_check_messages(info.hProcess);
4145 CloseHandle(info.hProcess);
4148 uirow = MSI_CreateRecord( 2 );
4149 MSI_RecordSetStringW( uirow, 1, filename );
4150 uipath = strdupW( file->TargetPath );
4151 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4152 MSI_RecordSetStringW( uirow, 2, uipath );
4153 ui_actiondata( package, szSelfRegModules, uirow );
4154 msiobj_release( &uirow->hdr );
4156 msi_free( FullName );
4158 return ERROR_SUCCESS;
4161 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4165 static const WCHAR ExecSeqQuery[] =
4166 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4167 '`','S','e','l','f','R','e','g','`',0};
4169 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4170 if (rc != ERROR_SUCCESS)
4172 TRACE("no SelfReg table\n");
4173 return ERROR_SUCCESS;
4176 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4177 msiobj_release(&view->hdr);
4179 return ERROR_SUCCESS;
4182 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4184 static const WCHAR regsvr32[] =
4185 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4186 static const WCHAR close[] = {'\"',0};
4187 MSIPACKAGE *package = param;
4193 PROCESS_INFORMATION pi;
4198 memset( &si, 0, sizeof(STARTUPINFOW) );
4200 filename = MSI_RecordGetString( row, 1 );
4201 file = get_loaded_file( package, filename );
4205 ERR("Unable to find file id %s\n", debugstr_w(filename));
4206 return ERROR_SUCCESS;
4209 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4211 cmdline = msi_alloc( len * sizeof(WCHAR) );
4212 strcpyW( cmdline, regsvr32 );
4213 strcatW( cmdline, file->TargetPath );
4214 strcatW( cmdline, close );
4216 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4218 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4221 CloseHandle( pi.hThread );
4222 msi_dialog_check_messages( pi.hProcess );
4223 CloseHandle( pi.hProcess );
4226 uirow = MSI_CreateRecord( 2 );
4227 MSI_RecordSetStringW( uirow, 1, filename );
4228 uipath = strdupW( file->TargetPath );
4229 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4230 MSI_RecordSetStringW( uirow, 2, uipath );
4231 ui_actiondata( package, szSelfUnregModules, uirow );
4232 msiobj_release( &uirow->hdr );
4234 msi_free( cmdline );
4236 return ERROR_SUCCESS;
4239 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4243 static const WCHAR query[] =
4244 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4245 '`','S','e','l','f','R','e','g','`',0};
4247 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4248 if (rc != ERROR_SUCCESS)
4250 TRACE("no SelfReg table\n");
4251 return ERROR_SUCCESS;
4254 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4255 msiobj_release( &view->hdr );
4257 return ERROR_SUCCESS;
4260 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4262 MSIFEATURE *feature;
4264 HKEY hkey = NULL, userdata = NULL;
4266 if (!msi_check_publish(package))
4267 return ERROR_SUCCESS;
4269 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4271 if (rc != ERROR_SUCCESS)
4274 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4276 if (rc != ERROR_SUCCESS)
4279 /* here the guids are base 85 encoded */
4280 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4286 BOOL absent = FALSE;
4289 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4290 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4291 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4294 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4298 if (feature->Feature_Parent)
4299 size += strlenW( feature->Feature_Parent )+2;
4301 data = msi_alloc(size * sizeof(WCHAR));
4304 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4306 MSICOMPONENT* component = cl->component;
4310 if (component->ComponentId)
4312 TRACE("From %s\n",debugstr_w(component->ComponentId));
4313 CLSIDFromString(component->ComponentId, &clsid);
4314 encode_base85_guid(&clsid,buf);
4315 TRACE("to %s\n",debugstr_w(buf));
4320 if (feature->Feature_Parent)
4322 static const WCHAR sep[] = {'\2',0};
4324 strcatW(data,feature->Feature_Parent);
4327 msi_reg_set_val_str( userdata, feature->Feature, data );
4331 if (feature->Feature_Parent)
4332 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4335 size += sizeof(WCHAR);
4336 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4337 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4341 size += 2*sizeof(WCHAR);
4342 data = msi_alloc(size);
4345 if (feature->Feature_Parent)
4346 strcpyW( &data[1], feature->Feature_Parent );
4347 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4353 uirow = MSI_CreateRecord( 1 );
4354 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4355 ui_actiondata( package, szPublishFeatures, uirow);
4356 msiobj_release( &uirow->hdr );
4357 /* FIXME: call ui_progress? */
4362 RegCloseKey(userdata);
4366 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4372 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4374 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4376 if (r == ERROR_SUCCESS)
4378 RegDeleteValueW(hkey, feature->Feature);
4382 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4384 if (r == ERROR_SUCCESS)
4386 RegDeleteValueW(hkey, feature->Feature);
4390 uirow = MSI_CreateRecord( 1 );
4391 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4392 ui_actiondata( package, szUnpublishFeatures, uirow );
4393 msiobj_release( &uirow->hdr );
4395 return ERROR_SUCCESS;
4398 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4400 MSIFEATURE *feature;
4402 if (!msi_check_unpublish(package))
4403 return ERROR_SUCCESS;
4405 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4407 msi_unpublish_feature(package, feature);
4410 return ERROR_SUCCESS;
4413 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4415 LPWSTR prop, val, key;
4421 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4422 static const WCHAR szWindowsInstaller[] =
4423 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4424 static const WCHAR modpath_fmt[] =
4425 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4426 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4427 static const WCHAR szModifyPath[] =
4428 {'M','o','d','i','f','y','P','a','t','h',0};
4429 static const WCHAR szUninstallString[] =
4430 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4431 static const WCHAR szEstimatedSize[] =
4432 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4433 static const WCHAR szProductLanguage[] =
4434 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4435 static const WCHAR szProductVersion[] =
4436 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4437 static const WCHAR szProductName[] =
4438 {'P','r','o','d','u','c','t','N','a','m','e',0};
4439 static const WCHAR szDisplayName[] =
4440 {'D','i','s','p','l','a','y','N','a','m','e',0};
4441 static const WCHAR szDisplayVersion[] =
4442 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4443 static const WCHAR szManufacturer[] =
4444 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4446 static const LPCSTR propval[] = {
4447 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4448 "ARPCONTACT", "Contact",
4449 "ARPCOMMENTS", "Comments",
4450 "ProductName", "DisplayName",
4451 "ProductVersion", "DisplayVersion",
4452 "ARPHELPLINK", "HelpLink",
4453 "ARPHELPTELEPHONE", "HelpTelephone",
4454 "ARPINSTALLLOCATION", "InstallLocation",
4455 "SourceDir", "InstallSource",
4456 "Manufacturer", "Publisher",
4457 "ARPREADME", "Readme",
4459 "ARPURLINFOABOUT", "URLInfoAbout",
4460 "ARPURLUPDATEINFO", "URLUpdateInfo",
4463 const LPCSTR *p = propval;
4467 prop = strdupAtoW(*p++);
4468 key = strdupAtoW(*p++);
4469 val = msi_dup_property(package, prop);
4470 msi_reg_set_val_str(hkey, key, val);
4476 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4478 size = deformat_string(package, modpath_fmt, &buffer);
4479 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4480 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4483 /* FIXME: Write real Estimated Size when we have it */
4484 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4486 buffer = msi_dup_property(package, szProductName);
4487 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4490 buffer = msi_dup_property(package, cszSourceDir);
4491 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4494 buffer = msi_dup_property(package, szManufacturer);
4495 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4498 GetLocalTime(&systime);
4499 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4500 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4502 langid = msi_get_property_int(package, szProductLanguage, 0);
4503 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4505 buffer = msi_dup_property(package, szProductVersion);
4506 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4509 DWORD verdword = msi_version_str_to_dword(buffer);
4511 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4512 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4517 return ERROR_SUCCESS;
4520 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4522 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4524 LPWSTR upgrade_code;
4529 static const WCHAR szUpgradeCode[] = {
4530 'U','p','g','r','a','d','e','C','o','d','e',0};
4532 /* FIXME: also need to publish if the product is in advertise mode */
4533 if (!msi_check_publish(package))
4534 return ERROR_SUCCESS;
4536 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4537 if (rc != ERROR_SUCCESS)
4540 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4541 NULL, &props, TRUE);
4542 if (rc != ERROR_SUCCESS)
4545 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4546 msi_free( package->db->localfile );
4547 package->db->localfile = NULL;
4549 rc = msi_publish_install_properties(package, hkey);
4550 if (rc != ERROR_SUCCESS)
4553 rc = msi_publish_install_properties(package, props);
4554 if (rc != ERROR_SUCCESS)
4557 upgrade_code = msi_dup_property(package, szUpgradeCode);
4560 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4561 squash_guid(package->ProductCode, squashed_pc);
4562 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4563 RegCloseKey(upgrade);
4564 msi_free(upgrade_code);
4568 uirow = MSI_CreateRecord( 1 );
4569 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4570 ui_actiondata( package, szRegisterProduct, uirow );
4571 msiobj_release( &uirow->hdr );
4574 return ERROR_SUCCESS;
4577 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4579 return execute_script(package,INSTALL_SCRIPT);
4582 static UINT msi_unpublish_product(MSIPACKAGE *package)
4585 LPWSTR remove = NULL;
4586 LPWSTR *features = NULL;
4587 BOOL full_uninstall = TRUE;
4588 MSIFEATURE *feature;
4590 static const WCHAR szUpgradeCode[] =
4591 {'U','p','g','r','a','d','e','C','o','d','e',0};
4593 remove = msi_dup_property(package, szRemove);
4595 return ERROR_SUCCESS;
4597 features = msi_split_string(remove, ',');
4601 ERR("REMOVE feature list is empty!\n");
4602 return ERROR_FUNCTION_FAILED;
4605 if (!lstrcmpW(features[0], szAll))
4606 full_uninstall = TRUE;
4609 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4611 if (feature->Action != INSTALLSTATE_ABSENT)
4612 full_uninstall = FALSE;
4616 if (!full_uninstall)
4619 MSIREG_DeleteProductKey(package->ProductCode);
4620 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4621 MSIREG_DeleteUninstallKey(package->ProductCode);
4623 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4625 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4626 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4630 MSIREG_DeleteUserProductKey(package->ProductCode);
4631 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4634 upgrade = msi_dup_property(package, szUpgradeCode);
4637 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4644 return ERROR_SUCCESS;
4647 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4651 rc = msi_unpublish_product(package);
4652 if (rc != ERROR_SUCCESS)
4655 /* turn off scheduling */
4656 package->script->CurrentlyScripting= FALSE;
4658 /* first do the same as an InstallExecute */
4659 rc = ACTION_InstallExecute(package);
4660 if (rc != ERROR_SUCCESS)
4663 /* then handle Commit Actions */
4664 rc = execute_script(package,COMMIT_SCRIPT);
4669 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4671 static const WCHAR RunOnce[] = {
4672 'S','o','f','t','w','a','r','e','\\',
4673 'M','i','c','r','o','s','o','f','t','\\',
4674 'W','i','n','d','o','w','s','\\',
4675 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4676 'R','u','n','O','n','c','e',0};
4677 static const WCHAR InstallRunOnce[] = {
4678 'S','o','f','t','w','a','r','e','\\',
4679 'M','i','c','r','o','s','o','f','t','\\',
4680 'W','i','n','d','o','w','s','\\',
4681 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4682 'I','n','s','t','a','l','l','e','r','\\',
4683 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4685 static const WCHAR msiexec_fmt[] = {
4687 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4688 '\"','%','s','\"',0};
4689 static const WCHAR install_fmt[] = {
4690 '/','I',' ','\"','%','s','\"',' ',
4691 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4692 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4693 WCHAR buffer[256], sysdir[MAX_PATH];
4695 WCHAR squished_pc[100];
4697 squash_guid(package->ProductCode,squished_pc);
4699 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4700 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4701 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4704 msi_reg_set_val_str( hkey, squished_pc, buffer );
4707 TRACE("Reboot command %s\n",debugstr_w(buffer));
4709 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4710 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4712 msi_reg_set_val_str( hkey, squished_pc, buffer );
4715 return ERROR_INSTALL_SUSPEND;
4718 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4724 * We are currently doing what should be done here in the top level Install
4725 * however for Administrative and uninstalls this step will be needed
4727 if (!package->PackagePath)
4728 return ERROR_SUCCESS;
4730 msi_set_sourcedir_props(package, TRUE);
4732 attrib = GetFileAttributesW(package->db->path);
4733 if (attrib == INVALID_FILE_ATTRIBUTES)
4739 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4740 package->Context, MSICODE_PRODUCT,
4741 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4742 if (rc == ERROR_MORE_DATA)
4744 prompt = msi_alloc(size * sizeof(WCHAR));
4745 MsiSourceListGetInfoW(package->ProductCode, NULL,
4746 package->Context, MSICODE_PRODUCT,
4747 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4750 prompt = strdupW(package->db->path);
4752 msg = generate_error_string(package,1302,1,prompt);
4753 while(attrib == INVALID_FILE_ATTRIBUTES)
4755 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4758 rc = ERROR_INSTALL_USEREXIT;
4761 attrib = GetFileAttributesW(package->db->path);
4767 return ERROR_SUCCESS;
4772 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4775 LPWSTR buffer, productid = NULL;
4776 UINT i, rc = ERROR_SUCCESS;
4779 static const WCHAR szPropKeys[][80] =
4781 {'P','r','o','d','u','c','t','I','D',0},
4782 {'U','S','E','R','N','A','M','E',0},
4783 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4787 static const WCHAR szRegKeys[][80] =
4789 {'P','r','o','d','u','c','t','I','D',0},
4790 {'R','e','g','O','w','n','e','r',0},
4791 {'R','e','g','C','o','m','p','a','n','y',0},
4795 if (msi_check_unpublish(package))
4797 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4801 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4805 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4807 if (rc != ERROR_SUCCESS)
4810 for( i = 0; szPropKeys[i][0]; i++ )
4812 buffer = msi_dup_property( package, szPropKeys[i] );
4813 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4818 uirow = MSI_CreateRecord( 1 );
4819 MSI_RecordSetStringW( uirow, 1, productid );
4820 ui_actiondata( package, szRegisterUser, uirow );
4821 msiobj_release( &uirow->hdr );
4823 msi_free(productid);
4829 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4833 package->script->InWhatSequence |= SEQUENCE_EXEC;
4834 rc = ACTION_ProcessExecSequence(package,FALSE);
4839 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4841 MSIPACKAGE *package = param;
4842 LPCWSTR compgroupid, component, feature, qualifier, text;
4843 LPWSTR advertise = NULL, output = NULL;
4851 feature = MSI_RecordGetString(rec, 5);
4852 feat = get_loaded_feature(package, feature);
4854 return ERROR_SUCCESS;
4856 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4857 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4858 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
4860 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4861 feat->Action = feat->Installed;
4862 return ERROR_SUCCESS;
4865 component = MSI_RecordGetString(rec, 3);
4866 comp = get_loaded_component(package, component);
4868 return ERROR_SUCCESS;
4870 compgroupid = MSI_RecordGetString(rec,1);
4871 qualifier = MSI_RecordGetString(rec,2);
4873 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4874 if (rc != ERROR_SUCCESS)
4877 text = MSI_RecordGetString(rec,4);
4878 advertise = create_component_advertise_string(package, comp, feature);
4880 sz = strlenW(advertise);
4883 sz += lstrlenW(text);
4886 sz *= sizeof(WCHAR);
4888 output = msi_alloc_zero(sz);
4889 strcpyW(output,advertise);
4890 msi_free(advertise);
4893 strcatW(output,text);
4895 msi_reg_set_val_multi_str( hkey, qualifier, output );
4902 uirow = MSI_CreateRecord( 2 );
4903 MSI_RecordSetStringW( uirow, 1, compgroupid );
4904 MSI_RecordSetStringW( uirow, 2, qualifier);
4905 ui_actiondata( package, szPublishComponents, uirow);
4906 msiobj_release( &uirow->hdr );
4907 /* FIXME: call ui_progress? */
4913 * At present I am ignorning the advertised components part of this and only
4914 * focusing on the qualified component sets
4916 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4920 static const WCHAR ExecSeqQuery[] =
4921 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4922 '`','P','u','b','l','i','s','h',
4923 'C','o','m','p','o','n','e','n','t','`',0};
4925 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4926 if (rc != ERROR_SUCCESS)
4927 return ERROR_SUCCESS;
4929 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4930 msiobj_release(&view->hdr);
4935 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4937 static const WCHAR szInstallerComponents[] = {
4938 'S','o','f','t','w','a','r','e','\\',
4939 'M','i','c','r','o','s','o','f','t','\\',
4940 'I','n','s','t','a','l','l','e','r','\\',
4941 'C','o','m','p','o','n','e','n','t','s','\\',0};
4943 MSIPACKAGE *package = param;
4944 LPCWSTR compgroupid, component, feature, qualifier;
4948 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4951 feature = MSI_RecordGetString( rec, 5 );
4952 feat = get_loaded_feature( package, feature );
4954 return ERROR_SUCCESS;
4956 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4958 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4959 feat->Action = feat->Installed;
4960 return ERROR_SUCCESS;
4963 component = MSI_RecordGetString( rec, 3 );
4964 comp = get_loaded_component( package, component );
4966 return ERROR_SUCCESS;
4968 compgroupid = MSI_RecordGetString( rec, 1 );
4969 qualifier = MSI_RecordGetString( rec, 2 );
4971 squash_guid( compgroupid, squashed );
4972 strcpyW( keypath, szInstallerComponents );
4973 strcatW( keypath, squashed );
4975 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4976 if (res != ERROR_SUCCESS)
4978 WARN("Unable to delete component key %d\n", res);
4981 uirow = MSI_CreateRecord( 2 );
4982 MSI_RecordSetStringW( uirow, 1, compgroupid );
4983 MSI_RecordSetStringW( uirow, 2, qualifier );
4984 ui_actiondata( package, szUnpublishComponents, uirow );
4985 msiobj_release( &uirow->hdr );
4987 return ERROR_SUCCESS;
4990 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4994 static const WCHAR query[] =
4995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4996 '`','P','u','b','l','i','s','h',
4997 'C','o','m','p','o','n','e','n','t','`',0};
4999 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5000 if (rc != ERROR_SUCCESS)
5001 return ERROR_SUCCESS;
5003 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5004 msiobj_release( &view->hdr );
5009 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5011 MSIPACKAGE *package = param;
5014 SC_HANDLE hscm, service = NULL;
5015 LPCWSTR comp, depends, pass;
5016 LPWSTR name = NULL, disp = NULL;
5017 LPCWSTR load_order, serv_name, key;
5018 DWORD serv_type, start_type;
5021 static const WCHAR query[] =
5022 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5023 '`','C','o','m','p','o','n','e','n','t','`',' ',
5024 'W','H','E','R','E',' ',
5025 '`','C','o','m','p','o','n','e','n','t','`',' ',
5026 '=','\'','%','s','\'',0};
5028 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5031 ERR("Failed to open the SC Manager!\n");
5035 start_type = MSI_RecordGetInteger(rec, 5);
5036 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5039 depends = MSI_RecordGetString(rec, 8);
5040 if (depends && *depends)
5041 FIXME("Dependency list unhandled!\n");
5043 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5044 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5045 serv_type = MSI_RecordGetInteger(rec, 4);
5046 err_control = MSI_RecordGetInteger(rec, 6);
5047 load_order = MSI_RecordGetString(rec, 7);
5048 serv_name = MSI_RecordGetString(rec, 9);
5049 pass = MSI_RecordGetString(rec, 10);
5050 comp = MSI_RecordGetString(rec, 12);
5052 /* fetch the service path */
5053 row = MSI_QueryGetRecord(package->db, query, comp);
5056 ERR("Control query failed!\n");
5060 key = MSI_RecordGetString(row, 6);
5062 file = get_loaded_file(package, key);
5063 msiobj_release(&row->hdr);
5066 ERR("Failed to load the service file\n");
5070 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5071 start_type, err_control, file->TargetPath,
5072 load_order, NULL, NULL, serv_name, pass);
5075 if (GetLastError() != ERROR_SERVICE_EXISTS)
5076 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5080 CloseServiceHandle(service);
5081 CloseServiceHandle(hscm);
5085 return ERROR_SUCCESS;
5088 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5092 static const WCHAR ExecSeqQuery[] =
5093 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5094 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5096 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5097 if (rc != ERROR_SUCCESS)
5098 return ERROR_SUCCESS;
5100 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5101 msiobj_release(&view->hdr);
5106 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5107 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5109 LPCWSTR *vector, *temp_vector;
5113 static const WCHAR separator[] = {'[','~',']',0};
5116 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5121 vector = msi_alloc(sizeof(LPWSTR));
5129 vector[*numargs - 1] = p;
5131 if ((q = strstrW(p, separator)))
5135 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5141 vector = temp_vector;
5150 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5152 MSIPACKAGE *package = param;
5155 SC_HANDLE scm = NULL, service = NULL;
5156 LPCWSTR component, *vector = NULL;
5157 LPWSTR name, args, display_name = NULL;
5158 DWORD event, numargs, len;
5159 UINT r = ERROR_FUNCTION_FAILED;
5161 component = MSI_RecordGetString(rec, 6);
5162 comp = get_loaded_component(package, component);
5164 return ERROR_SUCCESS;
5166 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5168 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5169 comp->Action = comp->Installed;
5170 return ERROR_SUCCESS;
5172 comp->Action = INSTALLSTATE_LOCAL;
5174 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5175 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5176 event = MSI_RecordGetInteger(rec, 3);
5178 if (!(event & msidbServiceControlEventStart))
5184 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5187 ERR("Failed to open the service control manager\n");
5192 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5193 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5195 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5196 GetServiceDisplayNameW( scm, name, display_name, &len );
5199 service = OpenServiceW(scm, name, SERVICE_START);
5202 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5206 vector = msi_service_args_to_vector(args, &numargs);
5208 if (!StartServiceW(service, numargs, vector) &&
5209 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5211 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5218 uirow = MSI_CreateRecord( 2 );
5219 MSI_RecordSetStringW( uirow, 1, display_name );
5220 MSI_RecordSetStringW( uirow, 2, name );
5221 ui_actiondata( package, szStartServices, uirow );
5222 msiobj_release( &uirow->hdr );
5224 CloseServiceHandle(service);
5225 CloseServiceHandle(scm);
5230 msi_free(display_name);
5234 static UINT ACTION_StartServices( MSIPACKAGE *package )
5239 static const WCHAR query[] = {
5240 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5241 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5243 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5244 if (rc != ERROR_SUCCESS)
5245 return ERROR_SUCCESS;
5247 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5248 msiobj_release(&view->hdr);
5253 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5255 DWORD i, needed, count;
5256 ENUM_SERVICE_STATUSW *dependencies;
5260 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5261 0, &needed, &count))
5264 if (GetLastError() != ERROR_MORE_DATA)
5267 dependencies = msi_alloc(needed);
5271 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5272 needed, &needed, &count))
5275 for (i = 0; i < count; i++)
5277 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5278 SERVICE_STOP | SERVICE_QUERY_STATUS);
5282 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5289 msi_free(dependencies);
5293 static UINT stop_service( LPCWSTR name )
5295 SC_HANDLE scm = NULL, service = NULL;
5296 SERVICE_STATUS status;
5297 SERVICE_STATUS_PROCESS ssp;
5300 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5303 WARN("Failed to open the SCM: %d\n", GetLastError());
5307 service = OpenServiceW(scm, name,
5309 SERVICE_QUERY_STATUS |
5310 SERVICE_ENUMERATE_DEPENDENTS);
5313 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5317 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5318 sizeof(SERVICE_STATUS_PROCESS), &needed))
5320 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5324 if (ssp.dwCurrentState == SERVICE_STOPPED)
5327 stop_service_dependents(scm, service);
5329 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5330 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5333 CloseServiceHandle(service);
5334 CloseServiceHandle(scm);
5336 return ERROR_SUCCESS;
5339 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5341 MSIPACKAGE *package = param;
5345 LPWSTR name = NULL, display_name = NULL;
5349 event = MSI_RecordGetInteger( rec, 3 );
5350 if (!(event & msidbServiceControlEventStop))
5351 return ERROR_SUCCESS;
5353 component = MSI_RecordGetString( rec, 6 );
5354 comp = get_loaded_component( package, component );
5356 return ERROR_SUCCESS;
5358 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5360 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5361 comp->Action = comp->Installed;
5362 return ERROR_SUCCESS;
5364 comp->Action = INSTALLSTATE_ABSENT;
5366 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5369 ERR("Failed to open the service control manager\n");
5374 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5375 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5377 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5378 GetServiceDisplayNameW( scm, name, display_name, &len );
5380 CloseServiceHandle( scm );
5382 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5383 stop_service( name );
5386 uirow = MSI_CreateRecord( 2 );
5387 MSI_RecordSetStringW( uirow, 1, display_name );
5388 MSI_RecordSetStringW( uirow, 2, name );
5389 ui_actiondata( package, szStopServices, uirow );
5390 msiobj_release( &uirow->hdr );
5393 msi_free( display_name );
5394 return ERROR_SUCCESS;
5397 static UINT ACTION_StopServices( MSIPACKAGE *package )
5402 static const WCHAR query[] = {
5403 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5404 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5406 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5407 if (rc != ERROR_SUCCESS)
5408 return ERROR_SUCCESS;
5410 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5411 msiobj_release(&view->hdr);
5416 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5418 MSIPACKAGE *package = param;
5422 LPWSTR name = NULL, display_name = NULL;
5424 SC_HANDLE scm = NULL, service = NULL;
5426 event = MSI_RecordGetInteger( rec, 3 );
5427 if (!(event & msidbServiceControlEventDelete))
5428 return ERROR_SUCCESS;
5430 component = MSI_RecordGetString(rec, 6);
5431 comp = get_loaded_component(package, component);
5433 return ERROR_SUCCESS;
5435 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5437 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5438 comp->Action = comp->Installed;
5439 return ERROR_SUCCESS;
5441 comp->Action = INSTALLSTATE_ABSENT;
5443 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5444 stop_service( name );
5446 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5449 WARN("Failed to open the SCM: %d\n", GetLastError());
5454 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5455 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5457 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5458 GetServiceDisplayNameW( scm, name, display_name, &len );
5461 service = OpenServiceW( scm, name, DELETE );
5464 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5468 if (!DeleteService( service ))
5469 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5472 uirow = MSI_CreateRecord( 2 );
5473 MSI_RecordSetStringW( uirow, 1, display_name );
5474 MSI_RecordSetStringW( uirow, 2, name );
5475 ui_actiondata( package, szDeleteServices, uirow );
5476 msiobj_release( &uirow->hdr );
5478 CloseServiceHandle( service );
5479 CloseServiceHandle( scm );
5481 msi_free( display_name );
5483 return ERROR_SUCCESS;
5486 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5491 static const WCHAR query[] = {
5492 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5493 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5495 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5496 if (rc != ERROR_SUCCESS)
5497 return ERROR_SUCCESS;
5499 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5500 msiobj_release( &view->hdr );
5505 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5509 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5511 if (!lstrcmpW(file->File, filename))
5518 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5520 MSIPACKAGE *package = param;
5521 LPWSTR driver, driver_path, ptr;
5522 WCHAR outpath[MAX_PATH];
5523 MSIFILE *driver_file, *setup_file;
5527 UINT r = ERROR_SUCCESS;
5529 static const WCHAR driver_fmt[] = {
5530 'D','r','i','v','e','r','=','%','s',0};
5531 static const WCHAR setup_fmt[] = {
5532 'S','e','t','u','p','=','%','s',0};
5533 static const WCHAR usage_fmt[] = {
5534 'F','i','l','e','U','s','a','g','e','=','1',0};
5536 desc = MSI_RecordGetString(rec, 3);
5538 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5539 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5543 ERR("ODBC Driver entry not found!\n");
5544 return ERROR_FUNCTION_FAILED;
5547 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5549 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5550 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5552 driver = msi_alloc(len * sizeof(WCHAR));
5554 return ERROR_OUTOFMEMORY;
5557 lstrcpyW(ptr, desc);
5558 ptr += lstrlenW(ptr) + 1;
5560 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5565 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5569 lstrcpyW(ptr, usage_fmt);
5570 ptr += lstrlenW(ptr) + 1;
5573 driver_path = strdupW(driver_file->TargetPath);
5574 ptr = strrchrW(driver_path, '\\');
5575 if (ptr) *ptr = '\0';
5577 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5578 NULL, ODBC_INSTALL_COMPLETE, &usage))
5580 ERR("Failed to install SQL driver!\n");
5581 r = ERROR_FUNCTION_FAILED;
5584 uirow = MSI_CreateRecord( 5 );
5585 MSI_RecordSetStringW( uirow, 1, desc );
5586 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5587 MSI_RecordSetStringW( uirow, 3, driver_path );
5588 ui_actiondata( package, szInstallODBC, uirow );
5589 msiobj_release( &uirow->hdr );
5592 msi_free(driver_path);
5597 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5599 MSIPACKAGE *package = param;
5600 LPWSTR translator, translator_path, ptr;
5601 WCHAR outpath[MAX_PATH];
5602 MSIFILE *translator_file, *setup_file;
5606 UINT r = ERROR_SUCCESS;
5608 static const WCHAR translator_fmt[] = {
5609 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5610 static const WCHAR setup_fmt[] = {
5611 'S','e','t','u','p','=','%','s',0};
5613 desc = MSI_RecordGetString(rec, 3);
5615 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5616 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5618 if (!translator_file)
5620 ERR("ODBC Translator entry not found!\n");
5621 return ERROR_FUNCTION_FAILED;
5624 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
5626 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5628 translator = msi_alloc(len * sizeof(WCHAR));
5630 return ERROR_OUTOFMEMORY;
5633 lstrcpyW(ptr, desc);
5634 ptr += lstrlenW(ptr) + 1;
5636 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5641 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5646 translator_path = strdupW(translator_file->TargetPath);
5647 ptr = strrchrW(translator_path, '\\');
5648 if (ptr) *ptr = '\0';
5650 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5651 NULL, ODBC_INSTALL_COMPLETE, &usage))
5653 ERR("Failed to install SQL translator!\n");
5654 r = ERROR_FUNCTION_FAILED;
5657 uirow = MSI_CreateRecord( 5 );
5658 MSI_RecordSetStringW( uirow, 1, desc );
5659 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5660 MSI_RecordSetStringW( uirow, 3, translator_path );
5661 ui_actiondata( package, szInstallODBC, uirow );
5662 msiobj_release( &uirow->hdr );
5664 msi_free(translator);
5665 msi_free(translator_path);
5670 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5672 MSIPACKAGE *package = param;
5674 LPCWSTR desc, driver;
5675 WORD request = ODBC_ADD_SYS_DSN;
5678 UINT r = ERROR_SUCCESS;
5681 static const WCHAR attrs_fmt[] = {
5682 'D','S','N','=','%','s',0 };
5684 desc = MSI_RecordGetString(rec, 3);
5685 driver = MSI_RecordGetString(rec, 4);
5686 registration = MSI_RecordGetInteger(rec, 5);
5688 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5689 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5691 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
5692 attrs = msi_alloc(len * sizeof(WCHAR));
5694 return ERROR_OUTOFMEMORY;
5696 len = sprintfW(attrs, attrs_fmt, desc);
5699 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5701 ERR("Failed to install SQL data source!\n");
5702 r = ERROR_FUNCTION_FAILED;
5705 uirow = MSI_CreateRecord( 5 );
5706 MSI_RecordSetStringW( uirow, 1, desc );
5707 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5708 MSI_RecordSetInteger( uirow, 3, request );
5709 ui_actiondata( package, szInstallODBC, uirow );
5710 msiobj_release( &uirow->hdr );
5717 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5722 static const WCHAR driver_query[] = {
5723 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5724 'O','D','B','C','D','r','i','v','e','r',0 };
5726 static const WCHAR translator_query[] = {
5727 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5728 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5730 static const WCHAR source_query[] = {
5731 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5732 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5734 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5735 if (rc != ERROR_SUCCESS)
5736 return ERROR_SUCCESS;
5738 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5739 msiobj_release(&view->hdr);
5741 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5742 if (rc != ERROR_SUCCESS)
5743 return ERROR_SUCCESS;
5745 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5746 msiobj_release(&view->hdr);
5748 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5749 if (rc != ERROR_SUCCESS)
5750 return ERROR_SUCCESS;
5752 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5753 msiobj_release(&view->hdr);
5758 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5760 MSIPACKAGE *package = param;
5765 desc = MSI_RecordGetString( rec, 3 );
5766 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5768 WARN("Failed to remove ODBC driver\n");
5772 FIXME("Usage count reached 0\n");
5775 uirow = MSI_CreateRecord( 2 );
5776 MSI_RecordSetStringW( uirow, 1, desc );
5777 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5778 ui_actiondata( package, szRemoveODBC, uirow );
5779 msiobj_release( &uirow->hdr );
5781 return ERROR_SUCCESS;
5784 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5786 MSIPACKAGE *package = param;
5791 desc = MSI_RecordGetString( rec, 3 );
5792 if (!SQLRemoveTranslatorW( desc, &usage ))
5794 WARN("Failed to remove ODBC translator\n");
5798 FIXME("Usage count reached 0\n");
5801 uirow = MSI_CreateRecord( 2 );
5802 MSI_RecordSetStringW( uirow, 1, desc );
5803 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5804 ui_actiondata( package, szRemoveODBC, uirow );
5805 msiobj_release( &uirow->hdr );
5807 return ERROR_SUCCESS;
5810 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5812 MSIPACKAGE *package = param;
5815 LPCWSTR desc, driver;
5816 WORD request = ODBC_REMOVE_SYS_DSN;
5820 static const WCHAR attrs_fmt[] = {
5821 'D','S','N','=','%','s',0 };
5823 desc = MSI_RecordGetString( rec, 3 );
5824 driver = MSI_RecordGetString( rec, 4 );
5825 registration = MSI_RecordGetInteger( rec, 5 );
5827 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5828 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5830 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
5831 attrs = msi_alloc( len * sizeof(WCHAR) );
5833 return ERROR_OUTOFMEMORY;
5835 FIXME("Use ODBCSourceAttribute table\n");
5837 len = sprintfW( attrs, attrs_fmt, desc );
5840 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5842 WARN("Failed to remove ODBC data source\n");
5846 uirow = MSI_CreateRecord( 3 );
5847 MSI_RecordSetStringW( uirow, 1, desc );
5848 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5849 MSI_RecordSetInteger( uirow, 3, request );
5850 ui_actiondata( package, szRemoveODBC, uirow );
5851 msiobj_release( &uirow->hdr );
5853 return ERROR_SUCCESS;
5856 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5861 static const WCHAR driver_query[] = {
5862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5863 'O','D','B','C','D','r','i','v','e','r',0 };
5865 static const WCHAR translator_query[] = {
5866 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5867 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5869 static const WCHAR source_query[] = {
5870 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5871 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5873 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5874 if (rc != ERROR_SUCCESS)
5875 return ERROR_SUCCESS;
5877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5878 msiobj_release( &view->hdr );
5880 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5881 if (rc != ERROR_SUCCESS)
5882 return ERROR_SUCCESS;
5884 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5885 msiobj_release( &view->hdr );
5887 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5888 if (rc != ERROR_SUCCESS)
5889 return ERROR_SUCCESS;
5891 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5892 msiobj_release( &view->hdr );
5897 #define ENV_ACT_SETALWAYS 0x1
5898 #define ENV_ACT_SETABSENT 0x2
5899 #define ENV_ACT_REMOVE 0x4
5900 #define ENV_ACT_REMOVEMATCH 0x8
5902 #define ENV_MOD_MACHINE 0x20000000
5903 #define ENV_MOD_APPEND 0x40000000
5904 #define ENV_MOD_PREFIX 0x80000000
5905 #define ENV_MOD_MASK 0xC0000000
5907 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5909 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5911 LPCWSTR cptr = *name;
5913 static const WCHAR prefix[] = {'[','~',']',0};
5914 static const int prefix_len = 3;
5920 *flags |= ENV_ACT_SETALWAYS;
5921 else if (*cptr == '+')
5922 *flags |= ENV_ACT_SETABSENT;
5923 else if (*cptr == '-')
5924 *flags |= ENV_ACT_REMOVE;
5925 else if (*cptr == '!')
5926 *flags |= ENV_ACT_REMOVEMATCH;
5927 else if (*cptr == '*')
5928 *flags |= ENV_MOD_MACHINE;
5938 ERR("Missing environment variable\n");
5939 return ERROR_FUNCTION_FAILED;
5944 LPCWSTR ptr = *value;
5945 if (!strncmpW(ptr, prefix, prefix_len))
5947 if (ptr[prefix_len] == szSemiColon[0])
5949 *flags |= ENV_MOD_APPEND;
5950 *value += lstrlenW(prefix);
5957 else if (lstrlenW(*value) >= prefix_len)
5959 ptr += lstrlenW(ptr) - prefix_len;
5960 if (!lstrcmpW(ptr, prefix))
5962 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5964 *flags |= ENV_MOD_PREFIX;
5965 /* the "[~]" will be removed by deformat_string */;
5975 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5976 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5977 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5978 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5980 ERR("Invalid flags: %08x\n", *flags);
5981 return ERROR_FUNCTION_FAILED;
5985 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5987 return ERROR_SUCCESS;
5990 static UINT open_env_key( DWORD flags, HKEY *key )
5992 static const WCHAR user_env[] =
5993 {'E','n','v','i','r','o','n','m','e','n','t',0};
5994 static const WCHAR machine_env[] =
5995 {'S','y','s','t','e','m','\\',
5996 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5997 'C','o','n','t','r','o','l','\\',
5998 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5999 'E','n','v','i','r','o','n','m','e','n','t',0};
6004 if (flags & ENV_MOD_MACHINE)
6007 root = HKEY_LOCAL_MACHINE;
6012 root = HKEY_CURRENT_USER;
6015 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6016 if (res != ERROR_SUCCESS)
6018 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6019 return ERROR_FUNCTION_FAILED;
6022 return ERROR_SUCCESS;
6025 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6027 MSIPACKAGE *package = param;
6028 LPCWSTR name, value, component;
6029 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6030 DWORD flags, type, size;
6037 component = MSI_RecordGetString(rec, 4);
6038 comp = get_loaded_component(package, component);
6040 return ERROR_SUCCESS;
6042 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6044 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6045 comp->Action = comp->Installed;
6046 return ERROR_SUCCESS;
6048 comp->Action = INSTALLSTATE_LOCAL;
6050 name = MSI_RecordGetString(rec, 2);
6051 value = MSI_RecordGetString(rec, 3);
6053 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6055 res = env_parse_flags(&name, &value, &flags);
6056 if (res != ERROR_SUCCESS || !value)
6059 if (value && !deformat_string(package, value, &deformatted))
6061 res = ERROR_OUTOFMEMORY;
6065 value = deformatted;
6067 res = open_env_key( flags, &env );
6068 if (res != ERROR_SUCCESS)
6071 if (flags & ENV_MOD_MACHINE)
6072 action |= 0x20000000;
6076 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6077 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6078 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6081 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6085 /* Nothing to do. */
6088 res = ERROR_SUCCESS;
6092 /* If we are appending but the string was empty, strip ; */
6093 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6095 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6096 newval = strdupW(value);
6099 res = ERROR_OUTOFMEMORY;
6107 /* Contrary to MSDN, +-variable to [~];path works */
6108 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6110 res = ERROR_SUCCESS;
6114 data = msi_alloc(size);
6118 return ERROR_OUTOFMEMORY;
6121 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6122 if (res != ERROR_SUCCESS)
6125 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6128 res = RegDeleteValueW(env, name);
6129 if (res != ERROR_SUCCESS)
6130 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6134 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6135 if (flags & ENV_MOD_MASK)
6139 if (flags & ENV_MOD_APPEND) multiplier++;
6140 if (flags & ENV_MOD_PREFIX) multiplier++;
6141 mod_size = lstrlenW(value) * multiplier;
6142 size += mod_size * sizeof(WCHAR);
6145 newval = msi_alloc(size);
6149 res = ERROR_OUTOFMEMORY;
6153 if (flags & ENV_MOD_PREFIX)
6155 lstrcpyW(newval, value);
6156 ptr = newval + lstrlenW(value);
6157 action |= 0x80000000;
6160 lstrcpyW(ptr, data);
6162 if (flags & ENV_MOD_APPEND)
6164 lstrcatW(newval, value);
6165 action |= 0x40000000;
6168 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6169 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6172 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6176 uirow = MSI_CreateRecord( 3 );
6177 MSI_RecordSetStringW( uirow, 1, name );
6178 MSI_RecordSetStringW( uirow, 2, newval );
6179 MSI_RecordSetInteger( uirow, 3, action );
6180 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6181 msiobj_release( &uirow->hdr );
6183 if (env) RegCloseKey(env);
6184 msi_free(deformatted);
6190 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6194 static const WCHAR ExecSeqQuery[] =
6195 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6196 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6197 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6198 if (rc != ERROR_SUCCESS)
6199 return ERROR_SUCCESS;
6201 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6202 msiobj_release(&view->hdr);
6207 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6209 MSIPACKAGE *package = param;
6210 LPCWSTR name, value, component;
6211 LPWSTR deformatted = NULL;
6220 component = MSI_RecordGetString( rec, 4 );
6221 comp = get_loaded_component( package, component );
6223 return ERROR_SUCCESS;
6225 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6227 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6228 comp->Action = comp->Installed;
6229 return ERROR_SUCCESS;
6231 comp->Action = INSTALLSTATE_ABSENT;
6233 name = MSI_RecordGetString( rec, 2 );
6234 value = MSI_RecordGetString( rec, 3 );
6236 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6238 r = env_parse_flags( &name, &value, &flags );
6239 if (r != ERROR_SUCCESS)
6242 if (!(flags & ENV_ACT_REMOVE))
6244 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6245 return ERROR_SUCCESS;
6248 if (value && !deformat_string( package, value, &deformatted ))
6249 return ERROR_OUTOFMEMORY;
6251 value = deformatted;
6253 r = open_env_key( flags, &env );
6254 if (r != ERROR_SUCCESS)
6260 if (flags & ENV_MOD_MACHINE)
6261 action |= 0x20000000;
6263 TRACE("Removing %s\n", debugstr_w(name));
6265 res = RegDeleteValueW( env, name );
6266 if (res != ERROR_SUCCESS)
6268 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6273 uirow = MSI_CreateRecord( 3 );
6274 MSI_RecordSetStringW( uirow, 1, name );
6275 MSI_RecordSetStringW( uirow, 2, value );
6276 MSI_RecordSetInteger( uirow, 3, action );
6277 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6278 msiobj_release( &uirow->hdr );
6280 if (env) RegCloseKey( env );
6281 msi_free( deformatted );
6285 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6289 static const WCHAR query[] =
6290 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6291 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6293 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6294 if (rc != ERROR_SUCCESS)
6295 return ERROR_SUCCESS;
6297 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6298 msiobj_release( &view->hdr );
6303 typedef struct tagMSIASSEMBLY
6306 MSICOMPONENT *component;
6307 MSIFEATURE *feature;
6311 LPWSTR display_name;
6316 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6318 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6319 LPVOID pvReserved, HMODULE *phModDll);
6321 static BOOL init_functionpointers(void)
6327 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6329 hmscoree = LoadLibraryA("mscoree.dll");
6332 WARN("mscoree.dll not available\n");
6336 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6337 if (!pLoadLibraryShim)
6339 WARN("LoadLibraryShim not available\n");
6340 FreeLibrary(hmscoree);
6344 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6347 WARN("fusion.dll not available\n");
6348 FreeLibrary(hmscoree);
6352 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6354 FreeLibrary(hmscoree);
6358 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6361 IAssemblyCache *cache;
6364 UINT r = ERROR_FUNCTION_FAILED;
6366 TRACE("installing assembly: %s\n", debugstr_w(path));
6368 uirow = MSI_CreateRecord( 2 );
6369 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6370 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6371 msiobj_release( &uirow->hdr );
6373 if (assembly->feature)
6374 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
6376 if (assembly->manifest)
6377 FIXME("Manifest unhandled\n");
6379 if (assembly->application)
6381 FIXME("Assembly should be privately installed\n");
6382 return ERROR_SUCCESS;
6385 if (assembly->attributes == msidbAssemblyAttributesWin32)
6387 FIXME("Win32 assemblies not handled\n");
6388 return ERROR_SUCCESS;
6391 hr = pCreateAssemblyCache(&cache, 0);
6395 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6397 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6402 IAssemblyCache_Release(cache);
6406 typedef struct tagASSEMBLY_LIST
6408 MSIPACKAGE *package;
6409 IAssemblyCache *cache;
6410 struct list *assemblies;
6413 typedef struct tagASSEMBLY_NAME
6421 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6423 ASSEMBLY_NAME *asmname = param;
6424 LPCWSTR name = MSI_RecordGetString(rec, 2);
6425 LPWSTR val = msi_dup_record_field(rec, 3);
6427 static const WCHAR Name[] = {'N','a','m','e',0};
6428 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6429 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6430 static const WCHAR PublicKeyToken[] = {
6431 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6433 if (!strcmpiW(name, Name))
6434 asmname->name = val;
6435 else if (!strcmpiW(name, Version))
6436 asmname->version = val;
6437 else if (!strcmpiW(name, Culture))
6438 asmname->culture = val;
6439 else if (!strcmpiW(name, PublicKeyToken))
6440 asmname->pubkeytoken = val;
6444 return ERROR_SUCCESS;
6447 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6451 *size = lstrlenW(append) + 1;
6452 *str = msi_alloc((*size) * sizeof(WCHAR));
6453 lstrcpyW(*str, append);
6457 (*size) += lstrlenW(append);
6458 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6459 lstrcatW(*str, append);
6462 static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
6464 static const WCHAR separator[] = {',',' ',0};
6465 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6466 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
6467 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6468 static const WCHAR query[] = {
6469 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6470 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6471 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6472 '=','\'','%','s','\'',0};
6475 LPWSTR display_name;
6479 display_name = NULL;
6480 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
6482 r = MSI_OpenQuery( db, &view, query, comp->Component );
6483 if (r != ERROR_SUCCESS)
6486 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6487 msiobj_release( &view->hdr );
6491 ERR("No assembly name specified!\n");
6495 append_str( &display_name, &size, name.name );
6499 append_str( &display_name, &size, separator );
6500 append_str( &display_name, &size, Version );
6501 append_str( &display_name, &size, name.version );
6505 append_str( &display_name, &size, separator );
6506 append_str( &display_name, &size, Culture );
6507 append_str( &display_name, &size, name.culture );
6509 if (name.pubkeytoken)
6511 append_str( &display_name, &size, separator );
6512 append_str( &display_name, &size, PublicKeyToken );
6513 append_str( &display_name, &size, name.pubkeytoken );
6516 msi_free( name.name );
6517 msi_free( name.version );
6518 msi_free( name.culture );
6519 msi_free( name.pubkeytoken );
6521 return display_name;
6524 static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6526 ASSEMBLY_INFO asminfo;
6531 disp = get_assembly_display_name( db, comp );
6535 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
6536 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6538 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6540 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6546 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6548 ASSEMBLY_LIST *list = param;
6549 MSIASSEMBLY *assembly;
6552 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6554 return ERROR_OUTOFMEMORY;
6556 component = MSI_RecordGetString(rec, 1);
6557 assembly->component = get_loaded_component(list->package, component);
6558 if (!assembly->component)
6559 return ERROR_SUCCESS;
6561 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6562 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
6564 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6565 assembly->component->Action = assembly->component->Installed;
6566 return ERROR_SUCCESS;
6568 assembly->component->Action = assembly->component->ActionRequest;
6570 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6571 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6573 if (!assembly->file)
6575 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6576 return ERROR_FUNCTION_FAILED;
6579 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6580 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6581 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6583 if (assembly->application)
6586 DWORD size = sizeof(version)/sizeof(WCHAR);
6588 /* FIXME: we should probably check the manifest file here */
6590 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
6591 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
6593 assembly->installed = TRUE;
6597 assembly->installed = check_assembly_installed(list->package->db,
6599 assembly->component);
6601 list_add_head(list->assemblies, &assembly->entry);
6602 return ERROR_SUCCESS;
6605 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6607 IAssemblyCache *cache = NULL;
6613 static const WCHAR query[] =
6614 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6615 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6617 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6618 if (r != ERROR_SUCCESS)
6619 return ERROR_SUCCESS;
6621 hr = pCreateAssemblyCache(&cache, 0);
6623 return ERROR_FUNCTION_FAILED;
6625 list.package = package;
6627 list.assemblies = assemblies;
6629 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6630 msiobj_release(&view->hdr);
6632 IAssemblyCache_Release(cache);
6637 static void free_assemblies(struct list *assemblies)
6639 struct list *item, *cursor;
6641 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6643 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6645 list_remove(&assembly->entry);
6646 msi_free(assembly->application);
6647 msi_free(assembly->manifest);
6648 msi_free(assembly->display_name);
6653 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6655 MSIASSEMBLY *assembly;
6657 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6659 if (!lstrcmpW(assembly->file->File, file))
6669 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6670 LPWSTR *path, DWORD *attrs, PVOID user)
6672 MSIASSEMBLY *assembly;
6673 WCHAR temppath[MAX_PATH];
6674 struct list *assemblies = user;
6677 if (!find_assembly(assemblies, file, &assembly))
6680 GetTempPathW(MAX_PATH, temppath);
6681 PathAddBackslashW(temppath);
6682 lstrcatW(temppath, assembly->file->FileName);
6684 if (action == MSICABEXTRACT_BEGINEXTRACT)
6686 if (assembly->installed)
6689 *path = strdupW(temppath);
6690 *attrs = assembly->file->Attributes;
6692 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6694 assembly->installed = TRUE;
6696 r = install_assembly(package, assembly, temppath);
6697 if (r != ERROR_SUCCESS)
6698 ERR("Failed to install assembly\n");
6704 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6707 struct list assemblies = LIST_INIT(assemblies);
6708 MSIASSEMBLY *assembly;
6711 if (!init_functionpointers() || !pCreateAssemblyCache)
6712 return ERROR_FUNCTION_FAILED;
6714 r = load_assemblies(package, &assemblies);
6715 if (r != ERROR_SUCCESS)
6718 if (list_empty(&assemblies))
6721 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6724 r = ERROR_OUTOFMEMORY;
6728 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6730 if (assembly->installed && !mi->is_continuous)
6733 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6734 (assembly->file->IsCompressed && !mi->is_extracted))
6738 r = ready_media(package, assembly->file, mi);
6739 if (r != ERROR_SUCCESS)
6741 ERR("Failed to ready media\n");
6746 data.package = package;
6747 data.cb = installassembly_cb;
6748 data.user = &assemblies;
6750 if (assembly->file->IsCompressed &&
6751 !msi_cabextract(package, mi, &data))
6753 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6754 r = ERROR_FUNCTION_FAILED;
6759 if (!assembly->file->IsCompressed)
6761 LPWSTR source = resolve_file_source(package, assembly->file);
6763 r = install_assembly(package, assembly, source);
6764 if (r != ERROR_SUCCESS)
6765 ERR("Failed to install assembly\n");
6770 /* FIXME: write Installer assembly reg values */
6774 free_assemblies(&assemblies);
6778 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6780 LPWSTR key, template, id;
6781 UINT r = ERROR_SUCCESS;
6783 id = msi_dup_property( package, szProductID );
6787 return ERROR_SUCCESS;
6789 template = msi_dup_property( package, szPIDTemplate );
6790 key = msi_dup_property( package, szPIDKEY );
6792 if (key && template)
6794 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6795 r = MSI_SetPropertyW( package, szProductID, key );
6797 msi_free( template );
6802 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6805 package->need_reboot = 1;
6806 return ERROR_SUCCESS;
6809 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6811 static const WCHAR szAvailableFreeReg[] =
6812 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6814 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
6816 TRACE("%p %d kilobytes\n", package, space);
6818 uirow = MSI_CreateRecord( 1 );
6819 MSI_RecordSetInteger( uirow, 1, space );
6820 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6821 msiobj_release( &uirow->hdr );
6823 return ERROR_SUCCESS;
6826 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6828 FIXME("%p\n", package);
6829 return ERROR_SUCCESS;
6832 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6834 FIXME("%p\n", package);
6835 return ERROR_SUCCESS;
6838 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6843 static const WCHAR driver_query[] = {
6844 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6845 'O','D','B','C','D','r','i','v','e','r',0 };
6847 static const WCHAR translator_query[] = {
6848 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6849 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6851 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6852 if (r == ERROR_SUCCESS)
6855 r = MSI_IterateRecords( view, &count, NULL, package );
6856 msiobj_release( &view->hdr );
6857 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6860 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6861 if (r == ERROR_SUCCESS)
6864 r = MSI_IterateRecords( view, &count, NULL, package );
6865 msiobj_release( &view->hdr );
6866 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6869 return ERROR_SUCCESS;
6872 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6873 LPCSTR action, LPCWSTR table )
6875 static const WCHAR query[] = {
6876 'S','E','L','E','C','T',' ','*',' ',
6877 'F','R','O','M',' ','`','%','s','`',0 };
6878 MSIQUERY *view = NULL;
6882 r = MSI_OpenQuery( package->db, &view, query, table );
6883 if (r == ERROR_SUCCESS)
6885 r = MSI_IterateRecords(view, &count, NULL, package);
6886 msiobj_release(&view->hdr);
6890 FIXME("%s -> %u ignored %s table values\n",
6891 action, count, debugstr_w(table));
6893 return ERROR_SUCCESS;
6896 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6898 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6899 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6902 static UINT ACTION_BindImage( MSIPACKAGE *package )
6904 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6905 return msi_unimplemented_action_stub( package, "BindImage", table );
6908 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6910 static const WCHAR table[] = {
6911 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6912 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6915 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6917 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6918 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6921 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6923 static const WCHAR table[] = {
6924 'M','s','i','A','s','s','e','m','b','l','y',0 };
6925 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6928 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6930 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6931 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6934 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6936 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6937 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6940 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6942 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6943 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6946 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6948 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6949 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6952 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6954 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6955 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6958 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6960 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6961 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6964 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6966 static const WCHAR table[] = { 'M','I','M','E',0 };
6967 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6970 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6972 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6973 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6976 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6980 const WCHAR *action;
6981 UINT (*handler)(MSIPACKAGE *);
6985 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6986 { szAppSearch, ACTION_AppSearch },
6987 { szBindImage, ACTION_BindImage },
6988 { szCCPSearch, ACTION_CCPSearch },
6989 { szCostFinalize, ACTION_CostFinalize },
6990 { szCostInitialize, ACTION_CostInitialize },
6991 { szCreateFolders, ACTION_CreateFolders },
6992 { szCreateShortcuts, ACTION_CreateShortcuts },
6993 { szDeleteServices, ACTION_DeleteServices },
6994 { szDisableRollback, ACTION_DisableRollback },
6995 { szDuplicateFiles, ACTION_DuplicateFiles },
6996 { szExecuteAction, ACTION_ExecuteAction },
6997 { szFileCost, ACTION_FileCost },
6998 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6999 { szForceReboot, ACTION_ForceReboot },
7000 { szInstallAdminPackage, ACTION_InstallAdminPackage },
7001 { szInstallExecute, ACTION_InstallExecute },
7002 { szInstallExecuteAgain, ACTION_InstallExecute },
7003 { szInstallFiles, ACTION_InstallFiles},
7004 { szInstallFinalize, ACTION_InstallFinalize },
7005 { szInstallInitialize, ACTION_InstallInitialize },
7006 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
7007 { szInstallValidate, ACTION_InstallValidate },
7008 { szIsolateComponents, ACTION_IsolateComponents },
7009 { szLaunchConditions, ACTION_LaunchConditions },
7010 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7011 { szMoveFiles, ACTION_MoveFiles },
7012 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7013 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
7014 { szInstallODBC, ACTION_InstallODBC },
7015 { szInstallServices, ACTION_InstallServices },
7016 { szPatchFiles, ACTION_PatchFiles },
7017 { szProcessComponents, ACTION_ProcessComponents },
7018 { szPublishComponents, ACTION_PublishComponents },
7019 { szPublishFeatures, ACTION_PublishFeatures },
7020 { szPublishProduct, ACTION_PublishProduct },
7021 { szRegisterClassInfo, ACTION_RegisterClassInfo },
7022 { szRegisterComPlus, ACTION_RegisterComPlus},
7023 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7024 { szRegisterFonts, ACTION_RegisterFonts },
7025 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7026 { szRegisterProduct, ACTION_RegisterProduct },
7027 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7028 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
7029 { szRegisterUser, ACTION_RegisterUser },
7030 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
7031 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
7032 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7033 { szRemoveFiles, ACTION_RemoveFiles },
7034 { szRemoveFolders, ACTION_RemoveFolders },
7035 { szRemoveIniValues, ACTION_RemoveIniValues },
7036 { szRemoveODBC, ACTION_RemoveODBC },
7037 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7038 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7039 { szResolveSource, ACTION_ResolveSource },
7040 { szRMCCPSearch, ACTION_RMCCPSearch },
7041 { szScheduleReboot, ACTION_ScheduleReboot },
7042 { szSelfRegModules, ACTION_SelfRegModules },
7043 { szSelfUnregModules, ACTION_SelfUnregModules },
7044 { szSetODBCFolders, ACTION_SetODBCFolders },
7045 { szStartServices, ACTION_StartServices },
7046 { szStopServices, ACTION_StopServices },
7047 { szUnpublishComponents, ACTION_UnpublishComponents },
7048 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7049 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7050 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7051 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
7052 { szUnregisterFonts, ACTION_UnregisterFonts },
7053 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7054 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7055 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7056 { szValidateProductID, ACTION_ValidateProductID },
7057 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7058 { szWriteIniValues, ACTION_WriteIniValues },
7059 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7063 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7064 UINT* rc, BOOL force )
7070 if (!run && !package->script->CurrentlyScripting)
7075 if (strcmpW(action,szInstallFinalize) == 0 ||
7076 strcmpW(action,szInstallExecute) == 0 ||
7077 strcmpW(action,szInstallExecuteAgain) == 0)
7082 while (StandardActions[i].action != NULL)
7084 if (strcmpW(StandardActions[i].action, action)==0)
7088 ui_actioninfo(package, action, TRUE, 0);
7089 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7090 ui_actioninfo(package, action, FALSE, *rc);
7094 ui_actionstart(package, action);
7095 if (StandardActions[i].handler)
7097 *rc = StandardActions[i].handler(package);
7101 FIXME("unhandled standard action %s\n",debugstr_w(action));
7102 *rc = ERROR_SUCCESS;
7113 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7115 UINT rc = ERROR_SUCCESS;
7118 TRACE("Performing action (%s)\n", debugstr_w(action));
7120 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7123 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7127 WARN("unhandled msi action %s\n", debugstr_w(action));
7128 rc = ERROR_FUNCTION_NOT_CALLED;
7134 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7136 UINT rc = ERROR_SUCCESS;
7137 BOOL handled = FALSE;
7139 TRACE("Performing action (%s)\n", debugstr_w(action));
7141 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7144 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7146 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7151 WARN("unhandled msi action %s\n", debugstr_w(action));
7152 rc = ERROR_FUNCTION_NOT_CALLED;
7158 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7160 UINT rc = ERROR_SUCCESS;
7163 static const WCHAR ExecSeqQuery[] =
7164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7165 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7166 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7167 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7168 static const WCHAR UISeqQuery[] =
7169 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7170 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7171 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7172 ' ', '=',' ','%','i',0};
7174 if (needs_ui_sequence(package))
7175 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7177 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7181 LPCWSTR action, cond;
7183 TRACE("Running the actions\n");
7185 /* check conditions */
7186 cond = MSI_RecordGetString(row, 2);
7188 /* this is a hack to skip errors in the condition code */
7189 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7191 msiobj_release(&row->hdr);
7192 return ERROR_SUCCESS;
7195 action = MSI_RecordGetString(row, 1);
7198 ERR("failed to fetch action\n");
7199 msiobj_release(&row->hdr);
7200 return ERROR_FUNCTION_FAILED;
7203 if (needs_ui_sequence(package))
7204 rc = ACTION_PerformUIAction(package, action, -1);
7206 rc = ACTION_PerformAction(package, action, -1, FALSE);
7208 msiobj_release(&row->hdr);
7214 /****************************************************
7215 * TOP level entry points
7216 *****************************************************/
7218 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7219 LPCWSTR szCommandLine )
7224 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7225 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7227 MSI_SetPropertyW(package, szAction, szInstall);
7229 package->script->InWhatSequence = SEQUENCE_INSTALL;
7236 dir = strdupW(szPackagePath);
7237 p = strrchrW(dir, '\\');
7241 file = szPackagePath + (p - dir);
7246 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7247 GetCurrentDirectoryW(MAX_PATH, dir);
7248 lstrcatW(dir, szBackSlash);
7249 file = szPackagePath;
7252 msi_free( package->PackagePath );
7253 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7254 if (!package->PackagePath)
7257 return ERROR_OUTOFMEMORY;
7260 lstrcpyW(package->PackagePath, dir);
7261 lstrcatW(package->PackagePath, file);
7264 msi_set_sourcedir_props(package, FALSE);
7267 msi_parse_command_line( package, szCommandLine, FALSE );
7269 msi_apply_transforms( package );
7270 msi_apply_patches( package );
7272 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7274 TRACE("setting reinstall property\n");
7275 MSI_SetPropertyW( package, szReinstall, szAll );
7278 /* properties may have been added by a transform */
7279 msi_clone_properties( package );
7280 msi_set_context( package );
7282 if (needs_ui_sequence( package))
7284 package->script->InWhatSequence |= SEQUENCE_UI;
7285 rc = ACTION_ProcessUISequence(package);
7286 ui_exists = ui_sequence_exists(package);
7287 if (rc == ERROR_SUCCESS || !ui_exists)
7289 package->script->InWhatSequence |= SEQUENCE_EXEC;
7290 rc = ACTION_ProcessExecSequence(package, ui_exists);
7294 rc = ACTION_ProcessExecSequence(package, FALSE);
7296 package->script->CurrentlyScripting = FALSE;
7298 /* process the ending type action */
7299 if (rc == ERROR_SUCCESS)
7300 ACTION_PerformActionSequence(package, -1);
7301 else if (rc == ERROR_INSTALL_USEREXIT)
7302 ACTION_PerformActionSequence(package, -2);
7303 else if (rc == ERROR_INSTALL_SUSPEND)
7304 ACTION_PerformActionSequence(package, -4);
7306 ACTION_PerformActionSequence(package, -3);
7308 /* finish up running custom actions */
7309 ACTION_FinishCustomActions(package);
7311 if (rc == ERROR_SUCCESS && package->need_reboot)
7312 return ERROR_SUCCESS_REBOOT_REQUIRED;