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 szAppSearch
[] =
96 {'A','p','p','S','e','a','r','c','h',0};
97 static const WCHAR szAllocateRegistrySpace
[] =
98 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
99 static const WCHAR szBindImage
[] =
100 {'B','i','n','d','I','m','a','g','e',0};
101 static const WCHAR szCCPSearch
[] =
102 {'C','C','P','S','e','a','r','c','h',0};
103 static const WCHAR szDeleteServices
[] =
104 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
105 static const WCHAR szDisableRollback
[] =
106 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
107 static const WCHAR szExecuteAction
[] =
108 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
109 static const WCHAR szInstallAdminPackage
[] =
110 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
111 static const WCHAR szInstallSFPCatalogFile
[] =
112 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
113 static const WCHAR szIsolateComponents
[] =
114 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
115 static const WCHAR szMigrateFeatureStates
[] =
116 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
117 static const WCHAR szMoveFiles
[] =
118 {'M','o','v','e','F','i','l','e','s',0};
119 static const WCHAR szMsiPublishAssemblies
[] =
120 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
121 static const WCHAR szMsiUnpublishAssemblies
[] =
122 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
123 static const WCHAR szInstallODBC
[] =
124 {'I','n','s','t','a','l','l','O','D','B','C',0};
125 static const WCHAR szInstallServices
[] =
126 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szPatchFiles
[] =
128 {'P','a','t','c','h','F','i','l','e','s',0};
129 static const WCHAR szPublishComponents
[] =
130 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
131 static const WCHAR szRegisterComPlus
[] =
132 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
133 static const WCHAR szRegisterFonts
[] =
134 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
135 static const WCHAR szRegisterUser
[] =
136 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
137 static const WCHAR szRemoveDuplicateFiles
[] =
138 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
139 static const WCHAR szRemoveEnvironmentStrings
[] =
140 {'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};
141 static const WCHAR szRemoveExistingProducts
[] =
142 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
143 static const WCHAR szRemoveFolders
[] =
144 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
145 static const WCHAR szRemoveIniValues
[] =
146 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
147 static const WCHAR szRemoveODBC
[] =
148 {'R','e','m','o','v','e','O','D','B','C',0};
149 static const WCHAR szRemoveRegistryValues
[] =
150 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
151 static const WCHAR szRemoveShortcuts
[] =
152 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
153 static const WCHAR szRMCCPSearch
[] =
154 {'R','M','C','C','P','S','e','a','r','c','h',0};
155 static const WCHAR szScheduleReboot
[] =
156 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
157 static const WCHAR szSelfUnregModules
[] =
158 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
159 static const WCHAR szSetODBCFolders
[] =
160 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
161 static const WCHAR szStartServices
[] =
162 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
163 static const WCHAR szStopServices
[] =
164 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
165 static const WCHAR szUnpublishComponents
[] =
166 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
167 static const WCHAR szUnpublishFeatures
[] =
168 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
169 static const WCHAR szUnregisterClassInfo
[] =
170 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
171 static const WCHAR szUnregisterComPlus
[] =
172 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
173 static const WCHAR szUnregisterExtensionInfo
[] =
174 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
175 static const WCHAR szUnregisterFonts
[] =
176 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
177 static const WCHAR szUnregisterMIMEInfo
[] =
178 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
179 static const WCHAR szUnregisterProgIdInfo
[] =
180 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
181 static const WCHAR szUnregisterTypeLibraries
[] =
182 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
183 static const WCHAR szValidateProductID
[] =
184 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
185 static const WCHAR szWriteEnvironmentStrings
[] =
186 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
188 /********************************************************
190 ********************************************************/
192 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
194 static const WCHAR Query_t
[] =
195 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
196 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
197 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
198 ' ','\'','%','s','\'',0};
201 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
204 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
205 msiobj_release(&row
->hdr
);
208 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
212 static const WCHAR template_s
[]=
213 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
215 static const WCHAR template_e
[]=
216 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
217 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
219 static const WCHAR format
[] =
220 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
224 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
226 sprintfW(message
,template_s
,timet
,action
);
228 sprintfW(message
,template_e
,timet
,action
,rc
);
230 row
= MSI_CreateRecord(1);
231 MSI_RecordSetStringW(row
,1,message
);
233 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
234 msiobj_release(&row
->hdr
);
237 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
243 LPWSTR prop
= NULL
, val
= NULL
;
246 return ERROR_SUCCESS
;
258 TRACE("Looking at %s\n",debugstr_w(ptr
));
260 ptr2
= strchrW(ptr
,'=');
263 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
270 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
271 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
281 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
294 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
295 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
298 if (lstrlenW(prop
) > 0)
300 TRACE("Found commandline property (%s) = (%s)\n",
301 debugstr_w(prop
), debugstr_w(val
));
302 MSI_SetPropertyW(package
,prop
,val
);
308 return ERROR_SUCCESS
;
312 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
315 LPWSTR p
, *ret
= NULL
;
321 /* count the number of substrings */
322 for ( pc
= str
, count
= 0; pc
; count
++ )
324 pc
= strchrW( pc
, sep
);
329 /* allocate space for an array of substring pointers and the substrings */
330 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
331 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
335 /* copy the string and set the pointers */
336 p
= (LPWSTR
) &ret
[count
+1];
338 for( count
= 0; (ret
[count
] = p
); count
++ )
340 p
= strchrW( p
, sep
);
348 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
350 static const WCHAR szSystemLanguageID
[] =
351 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
353 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
354 UINT ret
= ERROR_FUNCTION_FAILED
;
356 prod_code
= msi_dup_property( package
, szProductCode
);
357 patch_product
= msi_get_suminfo_product( patch
);
359 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
361 if ( strstrW( patch_product
, prod_code
) )
366 si
= MSI_GetSummaryInformationW( patch
, 0 );
369 ERR("no summary information!\n");
373 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
376 ERR("no template property!\n");
377 msiobj_release( &si
->hdr
);
384 msiobj_release( &si
->hdr
);
388 langid
= msi_dup_property( package
, szSystemLanguageID
);
391 msiobj_release( &si
->hdr
);
395 p
= strchrW( template, ';' );
396 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, szZero
)))
398 TRACE("applicable transform\n");
402 /* FIXME: check platform */
404 msiobj_release( &si
->hdr
);
408 msi_free( patch_product
);
409 msi_free( prod_code
);
410 msi_free( template );
416 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
417 MSIDATABASE
*patch_db
, LPCWSTR name
)
419 UINT ret
= ERROR_FUNCTION_FAILED
;
420 IStorage
*stg
= NULL
;
423 TRACE("%p %s\n", package
, debugstr_w(name
) );
427 ERR("expected a colon in %s\n", debugstr_w(name
));
428 return ERROR_FUNCTION_FAILED
;
431 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
434 ret
= msi_check_transform_applicable( package
, stg
);
435 if (ret
== ERROR_SUCCESS
)
436 msi_table_apply_transform( package
->db
, stg
);
438 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
439 IStorage_Release( stg
);
442 ERR("failed to open substorage %s\n", debugstr_w(name
));
444 return ERROR_SUCCESS
;
447 UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
449 LPWSTR guid_list
, *guids
, product_code
;
450 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
452 product_code
= msi_dup_property( package
, szProductCode
);
455 /* FIXME: the property ProductCode should be written into the DB somewhere */
456 ERR("no product code to check\n");
457 return ERROR_SUCCESS
;
460 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
461 guids
= msi_split_string( guid_list
, ';' );
462 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
464 if (!lstrcmpW( guids
[i
], product_code
))
468 msi_free( guid_list
);
469 msi_free( product_code
);
474 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
477 MSIRECORD
*rec
= NULL
;
482 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
483 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
484 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
485 '`','S','o','u','r','c','e','`',' ','I','S',' ',
486 'N','O','T',' ','N','U','L','L',0};
488 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
489 if (r
!= ERROR_SUCCESS
)
492 r
= MSI_ViewExecute(view
, 0);
493 if (r
!= ERROR_SUCCESS
)
496 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
498 prop
= MSI_RecordGetString(rec
, 1);
499 patch
= msi_dup_property(package
, szPatch
);
500 MSI_SetPropertyW(package
, prop
, patch
);
505 if (rec
) msiobj_release(&rec
->hdr
);
506 msiobj_release(&view
->hdr
);
511 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
514 LPWSTR str
, *substorage
;
515 UINT i
, r
= ERROR_SUCCESS
;
517 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
519 return ERROR_FUNCTION_FAILED
;
521 if (msi_check_patch_applicable( package
, si
) != ERROR_SUCCESS
)
523 TRACE("Patch not applicable\n");
524 return ERROR_SUCCESS
;
527 package
->patch
= msi_alloc(sizeof(MSIPATCHINFO
));
529 return ERROR_OUTOFMEMORY
;
531 package
->patch
->patchcode
= msi_suminfo_dup_string(si
, PID_REVNUMBER
);
532 if (!package
->patch
->patchcode
)
533 return ERROR_OUTOFMEMORY
;
535 /* enumerate the substorage */
536 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
537 package
->patch
->transforms
= str
;
539 substorage
= msi_split_string( str
, ';' );
540 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
541 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
543 msi_free( substorage
);
544 msiobj_release( &si
->hdr
);
546 msi_set_media_source_prop(package
);
551 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
553 MSIDATABASE
*patch_db
= NULL
;
556 TRACE("%p %s\n", package
, debugstr_w( file
) );
559 * We probably want to make sure we only open a patch collection here.
560 * Patch collections (.msp) and databases (.msi) have different GUIDs
561 * but currently MSI_OpenDatabaseW will accept both.
563 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
564 if ( r
!= ERROR_SUCCESS
)
566 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
570 msi_parse_patch_summary( package
, patch_db
);
573 * There might be a CAB file in the patch package,
574 * so append it to the list of storage to search for streams.
576 append_storage_to_db( package
->db
, patch_db
->storage
);
578 msiobj_release( &patch_db
->hdr
);
580 return ERROR_SUCCESS
;
583 /* get the PATCH property, and apply all the patches it specifies */
584 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
586 LPWSTR patch_list
, *patches
;
587 UINT i
, r
= ERROR_SUCCESS
;
589 patch_list
= msi_dup_property( package
, szPatch
);
591 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
593 patches
= msi_split_string( patch_list
, ';' );
594 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
595 r
= msi_apply_patch_package( package
, patches
[i
] );
598 msi_free( patch_list
);
603 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
605 static const WCHAR szTransforms
[] = {
606 'T','R','A','N','S','F','O','R','M','S',0 };
607 LPWSTR xform_list
, *xforms
;
608 UINT i
, r
= ERROR_SUCCESS
;
610 xform_list
= msi_dup_property( package
, szTransforms
);
611 xforms
= msi_split_string( xform_list
, ';' );
613 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
615 if (xforms
[i
][0] == ':')
616 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
618 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
622 msi_free( xform_list
);
627 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
632 static const WCHAR ExecSeqQuery
[] =
633 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
634 '`','I','n','s','t','a','l','l',
635 'U','I','S','e','q','u','e','n','c','e','`',
636 ' ','W','H','E','R','E',' ',
637 '`','S','e','q','u','e','n','c','e','`',' ',
638 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
639 '`','S','e','q','u','e','n','c','e','`',0};
641 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
642 if (rc
== ERROR_SUCCESS
)
644 msiobj_release(&view
->hdr
);
651 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
654 LPWSTR source
, check
;
657 static const WCHAR szOriginalDatabase
[] =
658 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
660 db
= msi_dup_property( package
, szOriginalDatabase
);
662 return ERROR_OUTOFMEMORY
;
664 p
= strrchrW( db
, '\\' );
667 p
= strrchrW( db
, '/' );
671 return ERROR_SUCCESS
;
676 source
= msi_alloc( len
* sizeof(WCHAR
) );
677 lstrcpynW( source
, db
, len
);
679 check
= msi_dup_property( package
, cszSourceDir
);
680 if (!check
|| replace
)
681 MSI_SetPropertyW( package
, cszSourceDir
, source
);
685 check
= msi_dup_property( package
, cszSOURCEDIR
);
686 if (!check
|| replace
)
687 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
693 return ERROR_SUCCESS
;
696 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
698 INT level
= msi_get_property_int(package
, szUILevel
, 0);
699 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
702 static UINT
msi_set_context(MSIPACKAGE
*package
)
709 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
711 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
712 if (r
== ERROR_SUCCESS
)
715 if (num
== 1 || num
== 2)
716 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
719 return ERROR_SUCCESS
;
722 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
725 LPCWSTR cond
, action
;
726 MSIPACKAGE
*package
= param
;
728 action
= MSI_RecordGetString(row
,1);
731 ERR("Error is retrieving action name\n");
732 return ERROR_FUNCTION_FAILED
;
735 /* check conditions */
736 cond
= MSI_RecordGetString(row
,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
741 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
742 return ERROR_SUCCESS
;
745 if (needs_ui_sequence(package
))
746 rc
= ACTION_PerformUIAction(package
, action
, -1);
748 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
750 msi_dialog_check_messages( NULL
);
752 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
753 rc
= package
->CurrentInstallState
;
755 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
758 if (rc
!= ERROR_SUCCESS
)
759 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
764 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
768 static const WCHAR query
[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
771 ' ','W','H','E','R','E',' ',
772 '`','S','e','q','u','e','n','c','e','`',' ',
773 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
774 '`','S','e','q','u','e','n','c','e','`',0};
776 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
778 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
779 if (r
== ERROR_SUCCESS
)
781 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
782 msiobj_release(&view
->hdr
);
788 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
792 static const WCHAR ExecSeqQuery
[] =
793 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
794 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
795 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
796 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
797 'O','R','D','E','R',' ', 'B','Y',' ',
798 '`','S','e','q','u','e','n','c','e','`',0 };
799 static const WCHAR IVQuery
[] =
800 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
801 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
802 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
803 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
804 ' ','\'', 'I','n','s','t','a','l','l',
805 'V','a','l','i','d','a','t','e','\'', 0};
808 if (package
->script
->ExecuteSequenceRun
)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS
;
814 package
->script
->ExecuteSequenceRun
= TRUE
;
816 /* get the sequence number */
819 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
821 return ERROR_FUNCTION_FAILED
;
822 seq
= MSI_RecordGetInteger(row
,1);
823 msiobj_release(&row
->hdr
);
826 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
827 if (rc
== ERROR_SUCCESS
)
829 TRACE("Running the actions\n");
831 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
832 msiobj_release(&view
->hdr
);
838 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
842 static const WCHAR ExecSeqQuery
[] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
851 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
852 if (rc
== ERROR_SUCCESS
)
854 TRACE("Running the actions\n");
856 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
857 msiobj_release(&view
->hdr
);
863 /********************************************************
864 * ACTION helper functions and functions that perform the actions
865 *******************************************************/
866 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
867 UINT
* rc
, UINT script
, BOOL force
)
872 arc
= ACTION_CustomAction(package
, action
, script
, force
);
874 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
883 * Actual Action Handlers
886 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
888 MSIPACKAGE
*package
= param
;
894 dir
= MSI_RecordGetString(row
,1);
897 ERR("Unable to get folder id\n");
898 return ERROR_SUCCESS
;
901 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
904 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
905 return ERROR_SUCCESS
;
908 TRACE("Folder is %s\n",debugstr_w(full_path
));
911 uirow
= MSI_CreateRecord(1);
912 MSI_RecordSetStringW(uirow
,1,full_path
);
913 ui_actiondata(package
,szCreateFolders
,uirow
);
914 msiobj_release( &uirow
->hdr
);
916 if (folder
->State
== 0)
917 create_full_pathW(full_path
);
922 return ERROR_SUCCESS
;
925 /* FIXME: probably should merge this with the above function */
926 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
928 UINT rc
= ERROR_SUCCESS
;
932 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
934 return ERROR_FUNCTION_FAILED
;
936 /* create the path */
937 if (folder
->State
== 0)
939 create_full_pathW(install_path
);
942 msi_free(install_path
);
947 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
951 /* create all the folders required by the components are going to install */
952 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
954 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
956 msi_create_directory( package
, comp
->Directory
);
959 return ERROR_SUCCESS
;
962 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
964 static const WCHAR ExecSeqQuery
[] =
965 {'S','E','L','E','C','T',' ',
966 '`','D','i','r','e','c','t','o','r','y','_','`',
967 ' ','F','R','O','M',' ',
968 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
972 /* create all the empty folders specified in the CreateFolder table */
973 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
974 if (rc
!= ERROR_SUCCESS
)
975 return ERROR_SUCCESS
;
977 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
978 msiobj_release(&view
->hdr
);
983 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
985 MSIPACKAGE
*package
= param
;
991 dir
= MSI_RecordGetString( row
, 1 );
994 ERR("Unable to get folder id\n");
995 return ERROR_SUCCESS
;
998 full_path
= resolve_folder( package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1001 ERR("Unable to resolve folder id %s\n", debugstr_w(dir
));
1002 return ERROR_SUCCESS
;
1005 TRACE("folder is %s\n", debugstr_w(full_path
));
1007 uirow
= MSI_CreateRecord( 1 );
1008 MSI_RecordSetStringW( uirow
, 1, full_path
);
1009 ui_actiondata( package
, szRemoveFolders
, uirow
);
1010 msiobj_release( &uirow
->hdr
);
1012 RemoveDirectoryW( full_path
);
1015 msi_free( full_path
);
1016 return ERROR_SUCCESS
;
1019 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1021 static const WCHAR query
[] =
1022 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1023 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1028 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1029 if (rc
!= ERROR_SUCCESS
)
1030 return ERROR_SUCCESS
;
1032 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1033 msiobj_release( &view
->hdr
);
1038 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1040 MSIPACKAGE
*package
= param
;
1043 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1045 return ERROR_FUNCTION_FAILED
;
1047 list_add_tail( &package
->components
, &comp
->entry
);
1049 /* fill in the data */
1050 comp
->Component
= msi_dup_record_field( row
, 1 );
1052 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1054 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1055 comp
->Directory
= msi_dup_record_field( row
, 3 );
1056 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1057 comp
->Condition
= msi_dup_record_field( row
, 5 );
1058 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1060 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1061 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1063 return ERROR_SUCCESS
;
1066 static UINT
load_all_components( MSIPACKAGE
*package
)
1068 static const WCHAR query
[] = {
1069 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1070 '`','C','o','m','p','o','n','e','n','t','`',0 };
1074 if (!list_empty(&package
->components
))
1075 return ERROR_SUCCESS
;
1077 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1078 if (r
!= ERROR_SUCCESS
)
1081 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1082 msiobj_release(&view
->hdr
);
1087 MSIPACKAGE
*package
;
1088 MSIFEATURE
*feature
;
1091 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1095 cl
= msi_alloc( sizeof (*cl
) );
1097 return ERROR_NOT_ENOUGH_MEMORY
;
1098 cl
->component
= comp
;
1099 list_add_tail( &feature
->Components
, &cl
->entry
);
1101 return ERROR_SUCCESS
;
1104 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1108 fl
= msi_alloc( sizeof(*fl
) );
1110 return ERROR_NOT_ENOUGH_MEMORY
;
1111 fl
->feature
= child
;
1112 list_add_tail( &parent
->Children
, &fl
->entry
);
1114 return ERROR_SUCCESS
;
1117 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1119 _ilfs
* ilfs
= param
;
1123 component
= MSI_RecordGetString(row
,1);
1125 /* check to see if the component is already loaded */
1126 comp
= get_loaded_component( ilfs
->package
, component
);
1129 ERR("unknown component %s\n", debugstr_w(component
));
1130 return ERROR_FUNCTION_FAILED
;
1133 add_feature_component( ilfs
->feature
, comp
);
1134 comp
->Enabled
= TRUE
;
1136 return ERROR_SUCCESS
;
1139 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1141 MSIFEATURE
*feature
;
1146 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1148 if ( !lstrcmpW( feature
->Feature
, name
) )
1155 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1157 MSIPACKAGE
* package
= param
;
1158 MSIFEATURE
* feature
;
1159 static const WCHAR Query1
[] =
1160 {'S','E','L','E','C','T',' ',
1161 '`','C','o','m','p','o','n','e','n','t','_','`',
1162 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1163 'C','o','m','p','o','n','e','n','t','s','`',' ',
1164 'W','H','E','R','E',' ',
1165 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1170 /* fill in the data */
1172 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1174 return ERROR_NOT_ENOUGH_MEMORY
;
1176 list_init( &feature
->Children
);
1177 list_init( &feature
->Components
);
1179 feature
->Feature
= msi_dup_record_field( row
, 1 );
1181 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1183 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1184 feature
->Title
= msi_dup_record_field( row
, 3 );
1185 feature
->Description
= msi_dup_record_field( row
, 4 );
1187 if (!MSI_RecordIsNull(row
,5))
1188 feature
->Display
= MSI_RecordGetInteger(row
,5);
1190 feature
->Level
= MSI_RecordGetInteger(row
,6);
1191 feature
->Directory
= msi_dup_record_field( row
, 7 );
1192 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1194 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1195 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1197 list_add_tail( &package
->features
, &feature
->entry
);
1199 /* load feature components */
1201 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1202 if (rc
!= ERROR_SUCCESS
)
1203 return ERROR_SUCCESS
;
1205 ilfs
.package
= package
;
1206 ilfs
.feature
= feature
;
1208 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1209 msiobj_release(&view
->hdr
);
1211 return ERROR_SUCCESS
;
1214 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1216 MSIPACKAGE
* package
= param
;
1217 MSIFEATURE
*parent
, *child
;
1219 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1221 return ERROR_FUNCTION_FAILED
;
1223 if (!child
->Feature_Parent
)
1224 return ERROR_SUCCESS
;
1226 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1228 return ERROR_FUNCTION_FAILED
;
1230 add_feature_child( parent
, child
);
1231 return ERROR_SUCCESS
;
1234 static UINT
load_all_features( MSIPACKAGE
*package
)
1236 static const WCHAR query
[] = {
1237 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1238 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1239 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1243 if (!list_empty(&package
->features
))
1244 return ERROR_SUCCESS
;
1246 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1247 if (r
!= ERROR_SUCCESS
)
1250 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1251 if (r
!= ERROR_SUCCESS
)
1254 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1255 msiobj_release( &view
->hdr
);
1260 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1271 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1273 static const WCHAR query
[] = {
1274 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1275 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1276 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1277 MSIQUERY
*view
= NULL
;
1278 MSIRECORD
*row
= NULL
;
1281 TRACE("%s\n", debugstr_w(file
->File
));
1283 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1284 if (r
!= ERROR_SUCCESS
)
1287 r
= MSI_ViewExecute(view
, NULL
);
1288 if (r
!= ERROR_SUCCESS
)
1291 r
= MSI_ViewFetch(view
, &row
);
1292 if (r
!= ERROR_SUCCESS
)
1295 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1296 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1297 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1298 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1299 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1302 if (view
) msiobj_release(&view
->hdr
);
1303 if (row
) msiobj_release(&row
->hdr
);
1307 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1309 MSIPACKAGE
* package
= param
;
1313 /* fill in the data */
1315 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1317 return ERROR_NOT_ENOUGH_MEMORY
;
1319 file
->File
= msi_dup_record_field( row
, 1 );
1321 component
= MSI_RecordGetString( row
, 2 );
1322 file
->Component
= get_loaded_component( package
, component
);
1324 if (!file
->Component
)
1326 WARN("Component not found: %s\n", debugstr_w(component
));
1327 msi_free(file
->File
);
1329 return ERROR_SUCCESS
;
1332 file
->FileName
= msi_dup_record_field( row
, 3 );
1333 reduce_to_longfilename( file
->FileName
);
1335 file
->ShortName
= msi_dup_record_field( row
, 3 );
1336 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1338 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1339 file
->Version
= msi_dup_record_field( row
, 5 );
1340 file
->Language
= msi_dup_record_field( row
, 6 );
1341 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1342 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1344 file
->state
= msifs_invalid
;
1346 /* if the compressed bits are not set in the file attributes,
1347 * then read the information from the package word count property
1349 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1351 file
->IsCompressed
= FALSE
;
1353 else if (file
->Attributes
&
1354 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1356 file
->IsCompressed
= TRUE
;
1358 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1360 file
->IsCompressed
= FALSE
;
1364 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1367 load_file_hash(package
, file
);
1369 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1371 list_add_tail( &package
->files
, &file
->entry
);
1373 return ERROR_SUCCESS
;
1376 static UINT
load_all_files(MSIPACKAGE
*package
)
1380 static const WCHAR Query
[] =
1381 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1382 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1383 '`','S','e','q','u','e','n','c','e','`', 0};
1385 if (!list_empty(&package
->files
))
1386 return ERROR_SUCCESS
;
1388 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1389 if (rc
!= ERROR_SUCCESS
)
1390 return ERROR_SUCCESS
;
1392 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1393 msiobj_release(&view
->hdr
);
1395 return ERROR_SUCCESS
;
1398 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1400 MSIPACKAGE
*package
= param
;
1401 static WCHAR szEmpty
[] = { 0 };
1402 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1405 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1407 return ERROR_NOT_ENOUGH_MEMORY
;
1409 folder
->Directory
= msi_dup_record_field( row
, 1 );
1411 TRACE("%s\n", debugstr_w(folder
->Directory
));
1413 p
= msi_dup_record_field(row
, 3);
1415 /* split src and target dir */
1417 src_short
= folder_split_path( p
, ':' );
1419 /* split the long and short paths */
1420 tgt_long
= folder_split_path( tgt_short
, '|' );
1421 src_long
= folder_split_path( src_short
, '|' );
1423 /* check for no-op dirs */
1424 if (!lstrcmpW(szDot
, tgt_short
))
1425 tgt_short
= szEmpty
;
1426 if (!lstrcmpW(szDot
, src_short
))
1427 src_short
= szEmpty
;
1430 tgt_long
= tgt_short
;
1433 src_short
= tgt_short
;
1434 src_long
= tgt_long
;
1438 src_long
= src_short
;
1440 /* FIXME: use the target short path too */
1441 folder
->TargetDefault
= strdupW(tgt_long
);
1442 folder
->SourceShortPath
= strdupW(src_short
);
1443 folder
->SourceLongPath
= strdupW(src_long
);
1446 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1447 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1448 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1450 folder
->Parent
= msi_dup_record_field( row
, 2 );
1452 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1454 list_add_tail( &package
->folders
, &folder
->entry
);
1456 TRACE("returning %p\n", folder
);
1458 return ERROR_SUCCESS
;
1461 static UINT
load_all_folders( MSIPACKAGE
*package
)
1463 static const WCHAR query
[] = {
1464 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1465 '`','D','i','r','e','c','t','o','r','y','`',0 };
1469 if (!list_empty(&package
->folders
))
1470 return ERROR_SUCCESS
;
1472 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1473 if (r
!= ERROR_SUCCESS
)
1476 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1477 msiobj_release(&view
->hdr
);
1482 * I am not doing any of the costing functionality yet.
1483 * Mostly looking at doing the Component and Feature loading
1485 * The native MSI does A LOT of modification to tables here. Mostly adding
1486 * a lot of temporary columns to the Feature and Component tables.
1488 * note: Native msi also tracks the short filename. But I am only going to
1489 * track the long ones. Also looking at this directory table
1490 * it appears that the directory table does not get the parents
1491 * resolved base on property only based on their entries in the
1494 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1496 static const WCHAR szCosting
[] =
1497 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1499 MSI_SetPropertyW(package
, szCosting
, szZero
);
1500 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1502 load_all_folders( package
);
1503 load_all_components( package
);
1504 load_all_features( package
);
1505 load_all_files( package
);
1507 return ERROR_SUCCESS
;
1510 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1513 UINT rc
= ERROR_SUCCESS
;
1515 TRACE("Executing Script %i\n",script
);
1517 if (!package
->script
)
1519 ERR("no script!\n");
1520 return ERROR_FUNCTION_FAILED
;
1523 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1526 action
= package
->script
->Actions
[script
][i
];
1527 ui_actionstart(package
, action
);
1528 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1529 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1530 if (rc
!= ERROR_SUCCESS
)
1533 msi_free_action_script(package
, script
);
1537 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1539 return ERROR_SUCCESS
;
1542 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1548 state
= MsiQueryProductStateW(package
->ProductCode
);
1550 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1552 if (!comp
->ComponentId
)
1555 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1556 comp
->Installed
= INSTALLSTATE_ABSENT
;
1559 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1560 package
->Context
, comp
->ComponentId
,
1562 if (r
!= ERROR_SUCCESS
)
1563 comp
->Installed
= INSTALLSTATE_ABSENT
;
1568 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1570 MSIFEATURE
*feature
;
1573 state
= MsiQueryProductStateW(package
->ProductCode
);
1575 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1577 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1578 feature
->Installed
= INSTALLSTATE_ABSENT
;
1581 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1587 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1588 LPCWSTR property
, INSTALLSTATE state
)
1591 MSIFEATURE
*feature
;
1593 override
= msi_dup_property( package
, property
);
1597 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1599 if (lstrcmpW(property
, szRemove
) &&
1600 (feature
->Level
<= 0 || feature
->Level
> level
))
1603 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1605 if (strcmpiW(override
, szAll
)==0)
1606 msi_feature_set_state(package
, feature
, state
);
1609 LPWSTR ptr
= override
;
1610 LPWSTR ptr2
= strchrW(override
,',');
1614 int len
= ptr2
- ptr
;
1616 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1617 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1619 msi_feature_set_state(package
, feature
, state
);
1625 ptr2
= strchrW(ptr
,',');
1637 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
1639 static const WCHAR szAddLocal
[] =
1640 {'A','D','D','L','O','C','A','L',0};
1641 static const WCHAR szAddSource
[] =
1642 {'A','D','D','S','O','U','R','C','E',0};
1643 static const WCHAR szAdvertise
[] =
1644 {'A','D','V','E','R','T','I','S','E',0};
1647 /* all these activation/deactivation things happen in order and things
1648 * later on the list override things earlier on the list.
1650 * 0 INSTALLLEVEL processing
1663 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1664 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1665 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1666 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1667 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1670 MSI_SetPropertyW( package
, szPreselected
, szOne
);
1675 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1678 static const WCHAR szlevel
[] =
1679 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1680 MSICOMPONENT
* component
;
1681 MSIFEATURE
*feature
;
1683 TRACE("Checking Install Level\n");
1685 level
= msi_get_property_int(package
, szlevel
, 1);
1687 if (!msi_get_property_int( package
, szPreselected
, 0 ))
1689 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1691 BOOL feature_state
= ((feature
->Level
> 0) &&
1692 (feature
->Level
<= level
));
1694 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1696 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1697 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1698 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1699 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1701 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1705 /* disable child features of unselected parent features */
1706 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1710 if (feature
->Level
> 0 && feature
->Level
<= level
)
1713 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1714 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1719 * now we want to enable or disable components base on feature
1722 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1726 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1727 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1729 if (!feature
->Level
)
1732 /* features with components that have compressed files are made local */
1733 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1735 if (cl
->component
->Enabled
&&
1736 cl
->component
->ForceLocalState
&&
1737 feature
->Action
== INSTALLSTATE_SOURCE
)
1739 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1744 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1746 component
= cl
->component
;
1748 if (!component
->Enabled
)
1751 switch (feature
->Action
)
1753 case INSTALLSTATE_ABSENT
:
1754 component
->anyAbsent
= 1;
1756 case INSTALLSTATE_ADVERTISED
:
1757 component
->hasAdvertiseFeature
= 1;
1759 case INSTALLSTATE_SOURCE
:
1760 component
->hasSourceFeature
= 1;
1762 case INSTALLSTATE_LOCAL
:
1763 component
->hasLocalFeature
= 1;
1765 case INSTALLSTATE_DEFAULT
:
1766 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1767 component
->hasAdvertiseFeature
= 1;
1768 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1769 component
->hasSourceFeature
= 1;
1771 component
->hasLocalFeature
= 1;
1779 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1781 /* if the component isn't enabled, leave it alone */
1782 if (!component
->Enabled
)
1785 /* check if it's local or source */
1786 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1787 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1789 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1790 !component
->ForceLocalState
)
1791 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1793 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1797 /* if any feature is local, the component must be local too */
1798 if (component
->hasLocalFeature
)
1800 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1804 if (component
->hasSourceFeature
)
1806 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1810 if (component
->hasAdvertiseFeature
)
1812 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1816 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1817 if (component
->anyAbsent
)
1818 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1821 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1823 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1825 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1826 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1829 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1830 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1834 return ERROR_SUCCESS
;
1837 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1839 MSIPACKAGE
*package
= param
;
1844 name
= MSI_RecordGetString(row
,1);
1846 f
= get_loaded_folder(package
, name
);
1847 if (!f
) return ERROR_SUCCESS
;
1849 /* reset the ResolvedTarget */
1850 msi_free(f
->ResolvedTarget
);
1851 f
->ResolvedTarget
= NULL
;
1853 /* This helper function now does ALL the work */
1854 TRACE("Dir %s ...\n",debugstr_w(name
));
1855 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1856 TRACE("resolves to %s\n",debugstr_w(path
));
1859 return ERROR_SUCCESS
;
1862 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1864 MSIPACKAGE
*package
= param
;
1866 MSIFEATURE
*feature
;
1868 name
= MSI_RecordGetString( row
, 1 );
1870 feature
= get_loaded_feature( package
, name
);
1872 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1876 Condition
= MSI_RecordGetString(row
,3);
1878 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1880 int level
= MSI_RecordGetInteger(row
,2);
1881 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1882 feature
->Level
= level
;
1885 return ERROR_SUCCESS
;
1888 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1890 static const WCHAR name_fmt
[] =
1891 {'%','u','.','%','u','.','%','u','.','%','u',0};
1892 static const WCHAR name
[] = {'\\',0};
1893 VS_FIXEDFILEINFO
*lpVer
;
1894 WCHAR filever
[0x100];
1900 TRACE("%s\n", debugstr_w(filename
));
1902 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1906 version
= msi_alloc( versize
);
1907 GetFileVersionInfoW( filename
, 0, versize
, version
);
1909 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1911 msi_free( version
);
1915 sprintfW( filever
, name_fmt
,
1916 HIWORD(lpVer
->dwFileVersionMS
),
1917 LOWORD(lpVer
->dwFileVersionMS
),
1918 HIWORD(lpVer
->dwFileVersionLS
),
1919 LOWORD(lpVer
->dwFileVersionLS
));
1921 msi_free( version
);
1923 return strdupW( filever
);
1926 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1928 LPWSTR file_version
;
1931 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1933 MSICOMPONENT
* comp
= file
->Component
;
1939 if (file
->IsCompressed
)
1940 comp
->ForceLocalState
= TRUE
;
1942 /* calculate target */
1943 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
1945 msi_free(file
->TargetPath
);
1947 TRACE("file %s is named %s\n",
1948 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
1950 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1954 TRACE("file %s resolves to %s\n",
1955 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
1957 /* don't check files of components that aren't installed */
1958 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
1959 comp
->Installed
== INSTALLSTATE_ABSENT
)
1961 file
->state
= msifs_missing
; /* assume files are missing */
1965 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1967 file
->state
= msifs_missing
;
1968 comp
->Cost
+= file
->FileSize
;
1972 if (file
->Version
&&
1973 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
1975 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1976 debugstr_w(file_version
));
1977 /* FIXME: seems like a bad way to compare version numbers */
1978 if (lstrcmpiW(file_version
, file
->Version
)<0)
1980 file
->state
= msifs_overwrite
;
1981 comp
->Cost
+= file
->FileSize
;
1984 file
->state
= msifs_present
;
1985 msi_free( file_version
);
1988 file
->state
= msifs_present
;
1991 return ERROR_SUCCESS
;
1995 * A lot is done in this function aside from just the costing.
1996 * The costing needs to be implemented at some point but for now I am going
1997 * to focus on the directory building
2000 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2002 static const WCHAR ExecSeqQuery
[] =
2003 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2004 '`','D','i','r','e','c','t','o','r','y','`',0};
2005 static const WCHAR ConditionQuery
[] =
2006 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2007 '`','C','o','n','d','i','t','i','o','n','`',0};
2008 static const WCHAR szCosting
[] =
2009 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2010 static const WCHAR szlevel
[] =
2011 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2012 static const WCHAR szOutOfDiskSpace
[] =
2013 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2015 UINT rc
= ERROR_SUCCESS
;
2019 TRACE("Building Directory properties\n");
2021 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2022 if (rc
== ERROR_SUCCESS
)
2024 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2026 msiobj_release(&view
->hdr
);
2029 /* read components states from the registry */
2030 ACTION_GetComponentInstallStates(package
);
2031 ACTION_GetFeatureInstallStates(package
);
2033 TRACE("File calculations\n");
2034 msi_check_file_install_states( package
);
2036 if (!process_overrides( package
, msi_get_property_int( package
, szlevel
, 1 ) ))
2038 TRACE("Evaluating Condition Table\n");
2040 rc
= MSI_DatabaseOpenViewW( package
->db
, ConditionQuery
, &view
);
2041 if (rc
== ERROR_SUCCESS
)
2043 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
2044 msiobj_release( &view
->hdr
);
2047 TRACE("Enabling or Disabling Components\n");
2048 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2050 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
2052 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2053 comp
->Enabled
= FALSE
;
2056 comp
->Enabled
= TRUE
;
2060 MSI_SetPropertyW(package
,szCosting
,szOne
);
2061 /* set default run level if not set */
2062 level
= msi_dup_property( package
, szlevel
);
2064 MSI_SetPropertyW(package
,szlevel
, szOne
);
2067 /* FIXME: check volume disk space */
2068 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2070 return MSI_SetFeatureStates(package
);
2073 /* OK this value is "interpreted" and then formatted based on the
2074 first few characters */
2075 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2080 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2086 LPWSTR deformated
= NULL
;
2089 deformat_string(package
, &value
[2], &deformated
);
2091 /* binary value type */
2095 *size
= (strlenW(ptr
)/2)+1;
2097 *size
= strlenW(ptr
)/2;
2099 data
= msi_alloc(*size
);
2105 /* if uneven pad with a zero in front */
2111 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2113 TRACE("Uneven byte count\n");
2121 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2124 msi_free(deformated
);
2126 TRACE("Data %i bytes(%i)\n",*size
,count
);
2133 deformat_string(package
, &value
[1], &deformated
);
2136 *size
= sizeof(DWORD
);
2137 data
= msi_alloc(*size
);
2143 if ( (*p
< '0') || (*p
> '9') )
2149 if (deformated
[0] == '-')
2152 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2154 msi_free(deformated
);
2159 static const WCHAR szMulti
[] = {'[','~',']',0};
2168 *type
=REG_EXPAND_SZ
;
2176 if (strstrW(value
,szMulti
))
2177 *type
= REG_MULTI_SZ
;
2179 /* remove initial delimiter */
2180 if (!strncmpW(value
, szMulti
, 3))
2183 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2185 /* add double NULL terminator */
2186 if (*type
== REG_MULTI_SZ
)
2188 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2189 data
= msi_realloc_zero(data
, *size
);
2195 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2197 MSIPACKAGE
*package
= param
;
2198 static const WCHAR szHCR
[] =
2199 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2200 'R','O','O','T','\\',0};
2201 static const WCHAR szHCU
[] =
2202 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2203 'U','S','E','R','\\',0};
2204 static const WCHAR szHLM
[] =
2205 {'H','K','E','Y','_','L','O','C','A','L','_',
2206 'M','A','C','H','I','N','E','\\',0};
2207 static const WCHAR szHU
[] =
2208 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2210 LPSTR value_data
= NULL
;
2211 HKEY root_key
, hkey
;
2214 LPCWSTR szRoot
, component
, name
, key
, value
;
2219 BOOL check_first
= FALSE
;
2222 ui_progress(package
,2,0,0,0);
2229 component
= MSI_RecordGetString(row
, 6);
2230 comp
= get_loaded_component(package
,component
);
2232 return ERROR_SUCCESS
;
2234 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2236 TRACE("Skipping write due to disabled component %s\n",
2237 debugstr_w(component
));
2239 comp
->Action
= comp
->Installed
;
2241 return ERROR_SUCCESS
;
2244 comp
->Action
= INSTALLSTATE_LOCAL
;
2246 name
= MSI_RecordGetString(row
, 4);
2247 if( MSI_RecordIsNull(row
,5) && name
)
2249 /* null values can have special meanings */
2250 if (name
[0]=='-' && name
[1] == 0)
2251 return ERROR_SUCCESS
;
2252 else if ((name
[0]=='+' && name
[1] == 0) ||
2253 (name
[0] == '*' && name
[1] == 0))
2258 root
= MSI_RecordGetInteger(row
,2);
2259 key
= MSI_RecordGetString(row
, 3);
2261 /* get the root key */
2266 LPWSTR all_users
= msi_dup_property( package
, szAllUsers
);
2267 if (all_users
&& all_users
[0] == '1')
2269 root_key
= HKEY_LOCAL_MACHINE
;
2274 root_key
= HKEY_CURRENT_USER
;
2277 msi_free(all_users
);
2280 case 0: root_key
= HKEY_CLASSES_ROOT
;
2283 case 1: root_key
= HKEY_CURRENT_USER
;
2286 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2289 case 3: root_key
= HKEY_USERS
;
2293 ERR("Unknown root %i\n",root
);
2299 return ERROR_SUCCESS
;
2301 deformat_string(package
, key
, &deformated
);
2302 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2303 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2304 strcpyW(uikey
,szRoot
);
2305 strcatW(uikey
,deformated
);
2307 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2309 ERR("Could not create key %s\n",debugstr_w(deformated
));
2310 msi_free(deformated
);
2312 return ERROR_SUCCESS
;
2314 msi_free(deformated
);
2316 value
= MSI_RecordGetString(row
,5);
2318 value_data
= parse_value(package
, value
, &type
, &size
);
2321 value_data
= (LPSTR
)strdupW(szEmpty
);
2322 size
= sizeof(szEmpty
);
2326 deformat_string(package
, name
, &deformated
);
2330 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2332 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2337 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2338 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2340 TRACE("value %s of %s checked already exists\n",
2341 debugstr_w(deformated
), debugstr_w(uikey
));
2345 TRACE("Checked and setting value %s of %s\n",
2346 debugstr_w(deformated
), debugstr_w(uikey
));
2347 if (deformated
|| size
)
2348 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2353 uirow
= MSI_CreateRecord(3);
2354 MSI_RecordSetStringW(uirow
,2,deformated
);
2355 MSI_RecordSetStringW(uirow
,1,uikey
);
2358 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2360 MSI_RecordSetStringW(uirow
,3,value
);
2362 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2363 msiobj_release( &uirow
->hdr
);
2365 msi_free(value_data
);
2366 msi_free(deformated
);
2369 return ERROR_SUCCESS
;
2372 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2376 static const WCHAR ExecSeqQuery
[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','R','e','g','i','s','t','r','y','`',0 };
2380 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2381 if (rc
!= ERROR_SUCCESS
)
2382 return ERROR_SUCCESS
;
2384 /* increment progress bar each time action data is sent */
2385 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2387 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2389 msiobj_release(&view
->hdr
);
2393 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2395 package
->script
->CurrentlyScripting
= TRUE
;
2397 return ERROR_SUCCESS
;
2401 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2406 static const WCHAR q1
[]=
2407 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2408 '`','R','e','g','i','s','t','r','y','`',0};
2411 MSIFEATURE
*feature
;
2414 TRACE("InstallValidate\n");
2416 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2417 if (rc
== ERROR_SUCCESS
)
2419 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2420 msiobj_release( &view
->hdr
);
2421 total
+= progress
* REG_PROGRESS_VALUE
;
2424 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2425 total
+= COMPONENT_PROGRESS_VALUE
;
2427 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2428 total
+= file
->FileSize
;
2430 ui_progress(package
,0,total
,0,0);
2432 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2434 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2435 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2436 feature
->ActionRequest
);
2439 return ERROR_SUCCESS
;
2442 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2444 MSIPACKAGE
* package
= param
;
2445 LPCWSTR cond
= NULL
;
2446 LPCWSTR message
= NULL
;
2449 static const WCHAR title
[]=
2450 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2452 cond
= MSI_RecordGetString(row
,1);
2454 r
= MSI_EvaluateConditionW(package
,cond
);
2455 if (r
== MSICONDITION_FALSE
)
2457 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2460 message
= MSI_RecordGetString(row
,2);
2461 deformat_string(package
,message
,&deformated
);
2462 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2463 msi_free(deformated
);
2466 return ERROR_INSTALL_FAILURE
;
2469 return ERROR_SUCCESS
;
2472 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2475 MSIQUERY
* view
= NULL
;
2476 static const WCHAR ExecSeqQuery
[] =
2477 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2478 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2480 TRACE("Checking launch conditions\n");
2482 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2483 if (rc
!= ERROR_SUCCESS
)
2484 return ERROR_SUCCESS
;
2486 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2487 msiobj_release(&view
->hdr
);
2492 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2496 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2498 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2500 MSIRECORD
* row
= 0;
2502 LPWSTR deformated
,buffer
,deformated_name
;
2504 static const WCHAR ExecSeqQuery
[] =
2505 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2506 '`','R','e','g','i','s','t','r','y','`',' ',
2507 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2508 ' ','=',' ' ,'\'','%','s','\'',0 };
2509 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2510 static const WCHAR fmt2
[]=
2511 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2513 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2517 root
= MSI_RecordGetInteger(row
,2);
2518 key
= MSI_RecordGetString(row
, 3);
2519 name
= MSI_RecordGetString(row
, 4);
2520 deformat_string(package
, key
, &deformated
);
2521 deformat_string(package
, name
, &deformated_name
);
2523 len
= strlenW(deformated
) + 6;
2524 if (deformated_name
)
2525 len
+=strlenW(deformated_name
);
2527 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2529 if (deformated_name
)
2530 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2532 sprintfW(buffer
,fmt
,root
,deformated
);
2534 msi_free(deformated
);
2535 msi_free(deformated_name
);
2536 msiobj_release(&row
->hdr
);
2540 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2542 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2547 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2550 return strdupW( file
->TargetPath
);
2555 static HKEY
openSharedDLLsKey(void)
2558 static const WCHAR path
[] =
2559 {'S','o','f','t','w','a','r','e','\\',
2560 'M','i','c','r','o','s','o','f','t','\\',
2561 'W','i','n','d','o','w','s','\\',
2562 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2563 'S','h','a','r','e','d','D','L','L','s',0};
2565 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2569 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2574 DWORD sz
= sizeof(count
);
2577 hkey
= openSharedDLLsKey();
2578 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2579 if (rc
!= ERROR_SUCCESS
)
2585 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2589 hkey
= openSharedDLLsKey();
2591 msi_reg_set_val_dword( hkey
, path
, count
);
2593 RegDeleteValueW(hkey
,path
);
2599 * Return TRUE if the count should be written out and FALSE if not
2601 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2603 MSIFEATURE
*feature
;
2607 /* only refcount DLLs */
2608 if (comp
->KeyPath
== NULL
||
2609 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2610 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2614 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2615 write
= (count
> 0);
2617 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2621 /* increment counts */
2622 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2626 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2629 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2631 if ( cl
->component
== comp
)
2636 /* decrement counts */
2637 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2641 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2644 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2646 if ( cl
->component
== comp
)
2651 /* ref count all the files in the component */
2656 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2658 if (file
->Component
== comp
)
2659 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2663 /* add a count for permanent */
2664 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2667 comp
->RefCount
= count
;
2670 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2673 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2675 WCHAR squished_pc
[GUID_SIZE
];
2676 WCHAR squished_cc
[GUID_SIZE
];
2683 squash_guid(package
->ProductCode
,squished_pc
);
2684 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2686 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2690 ui_progress(package
,2,0,0,0);
2691 if (!comp
->ComponentId
)
2694 squash_guid(comp
->ComponentId
,squished_cc
);
2696 msi_free(comp
->FullKeypath
);
2697 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2699 ACTION_RefCountComponent( package
, comp
);
2701 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2702 debugstr_w(comp
->Component
),
2703 debugstr_w(squished_cc
),
2704 debugstr_w(comp
->FullKeypath
),
2707 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) ||
2708 ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
))
2710 if (!comp
->FullKeypath
)
2713 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2714 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2717 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2720 if (rc
!= ERROR_SUCCESS
)
2723 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2725 static const WCHAR szPermKey
[] =
2726 { '0','0','0','0','0','0','0','0','0','0','0','0',
2727 '0','0','0','0','0','0','0','0','0','0','0','0',
2728 '0','0','0','0','0','0','0','0',0 };
2730 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2733 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2734 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2740 WCHAR source
[MAX_PATH
];
2741 WCHAR base
[MAX_PATH
];
2744 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2745 static const WCHAR query
[] = {
2746 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2747 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2748 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2749 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2750 '`','D','i','s','k','I','d','`',0};
2752 file
= get_loaded_file(package
, comp
->KeyPath
);
2756 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2757 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2758 ptr2
= strrchrW(source
, '\\') + 1;
2759 msiobj_release(&row
->hdr
);
2761 lstrcpyW(base
, package
->PackagePath
);
2762 ptr
= strrchrW(base
, '\\');
2765 sourcepath
= resolve_file_source(package
, file
);
2766 ptr
= sourcepath
+ lstrlenW(base
);
2767 lstrcpyW(ptr2
, ptr
);
2768 msi_free(sourcepath
);
2770 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2774 else if (ACTION_VerifyComponentForAction(comp
, INSTALLSTATE_ABSENT
))
2776 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2777 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
2779 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
2783 uirow
= MSI_CreateRecord(3);
2784 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2785 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2786 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2787 ui_actiondata(package
,szProcessComponents
,uirow
);
2788 msiobj_release( &uirow
->hdr
);
2791 return ERROR_SUCCESS
;
2802 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2803 LPWSTR lpszName
, LONG_PTR lParam
)
2806 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2807 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2811 if (!IS_INTRESOURCE(lpszName
))
2813 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2817 sz
= strlenW(tl_struct
->source
)+4;
2818 sz
*= sizeof(WCHAR
);
2820 if ((INT_PTR
)lpszName
== 1)
2821 tl_struct
->path
= strdupW(tl_struct
->source
);
2824 tl_struct
->path
= msi_alloc(sz
);
2825 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2828 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2829 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2832 msi_free(tl_struct
->path
);
2833 tl_struct
->path
= NULL
;
2838 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2839 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2841 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2845 msi_free(tl_struct
->path
);
2846 tl_struct
->path
= NULL
;
2848 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2849 ITypeLib_Release(tl_struct
->ptLib
);
2854 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2856 MSIPACKAGE
* package
= param
;
2860 typelib_struct tl_struct
;
2865 component
= MSI_RecordGetString(row
,3);
2866 comp
= get_loaded_component(package
,component
);
2868 return ERROR_SUCCESS
;
2870 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2872 TRACE("Skipping typelib reg due to disabled component\n");
2874 comp
->Action
= comp
->Installed
;
2876 return ERROR_SUCCESS
;
2879 comp
->Action
= INSTALLSTATE_LOCAL
;
2881 file
= get_loaded_file( package
, comp
->KeyPath
);
2883 return ERROR_SUCCESS
;
2885 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2889 guid
= MSI_RecordGetString(row
,1);
2890 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2891 tl_struct
.source
= strdupW( file
->TargetPath
);
2892 tl_struct
.path
= NULL
;
2894 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2895 (LONG_PTR
)&tl_struct
);
2903 helpid
= MSI_RecordGetString(row
,6);
2906 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
2907 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2911 ERR("Failed to register type library %s\n",
2912 debugstr_w(tl_struct
.path
));
2915 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2917 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2920 ITypeLib_Release(tl_struct
.ptLib
);
2921 msi_free(tl_struct
.path
);
2924 ERR("Failed to load type library %s\n",
2925 debugstr_w(tl_struct
.source
));
2927 FreeLibrary(module
);
2928 msi_free(tl_struct
.source
);
2932 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
2935 ERR("Failed to load type library: %08x\n", hr
);
2936 return ERROR_FUNCTION_FAILED
;
2939 ITypeLib_Release(tlib
);
2942 return ERROR_SUCCESS
;
2945 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2948 * OK this is a bit confusing.. I am given a _Component key and I believe
2949 * that the file that is being registered as a type library is the "key file
2950 * of that component" which I interpret to mean "The file in the KeyPath of
2955 static const WCHAR Query
[] =
2956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2957 '`','T','y','p','e','L','i','b','`',0};
2959 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2960 if (rc
!= ERROR_SUCCESS
)
2961 return ERROR_SUCCESS
;
2963 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2964 msiobj_release(&view
->hdr
);
2968 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
2970 MSIPACKAGE
*package
= param
;
2971 LPCWSTR component
, guid
;
2979 component
= MSI_RecordGetString( row
, 3 );
2980 comp
= get_loaded_component( package
, component
);
2982 return ERROR_SUCCESS
;
2984 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2986 TRACE("Skipping, component is not scheduled for uninstall\n");
2988 comp
->Action
= comp
->Installed
;
2989 return ERROR_SUCCESS
;
2991 comp
->Action
= INSTALLSTATE_ABSENT
;
2993 guid
= MSI_RecordGetString( row
, 1 );
2994 CLSIDFromString( (LPWSTR
)guid
, &libid
);
2995 version
= MSI_RecordGetInteger( row
, 4 );
2996 language
= MSI_RecordGetInteger( row
, 2 );
2999 syskind
= SYS_WIN64
;
3001 syskind
= SYS_WIN32
;
3004 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
3007 WARN("Failed to unregister typelib: %08x\n", hr
);
3010 return ERROR_SUCCESS
;
3013 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
3017 static const WCHAR query
[] =
3018 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3019 '`','T','y','p','e','L','i','b','`',0};
3021 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3022 if (rc
!= ERROR_SUCCESS
)
3023 return ERROR_SUCCESS
;
3025 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
3026 msiobj_release( &view
->hdr
);
3030 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3032 MSIPACKAGE
*package
= param
;
3033 LPWSTR target_file
, target_folder
, filename
;
3034 LPCWSTR buffer
, extension
;
3036 static const WCHAR szlnk
[]={'.','l','n','k',0};
3037 IShellLinkW
*sl
= NULL
;
3038 IPersistFile
*pf
= NULL
;
3041 buffer
= MSI_RecordGetString(row
,4);
3042 comp
= get_loaded_component(package
,buffer
);
3044 return ERROR_SUCCESS
;
3046 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3048 TRACE("Skipping shortcut creation due to disabled component\n");
3050 comp
->Action
= comp
->Installed
;
3052 return ERROR_SUCCESS
;
3055 comp
->Action
= INSTALLSTATE_LOCAL
;
3057 ui_actiondata(package
,szCreateShortcuts
,row
);
3059 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3060 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3064 ERR("CLSID_ShellLink not available\n");
3068 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3071 ERR("QueryInterface(IID_IPersistFile) failed\n");
3075 buffer
= MSI_RecordGetString(row
,2);
3076 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
3078 /* may be needed because of a bug somewhere else */
3079 create_full_pathW(target_folder
);
3081 filename
= msi_dup_record_field( row
, 3 );
3082 reduce_to_longfilename(filename
);
3084 extension
= strchrW(filename
,'.');
3085 if (!extension
|| strcmpiW(extension
,szlnk
))
3087 int len
= strlenW(filename
);
3088 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
3089 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
3091 target_file
= build_directory_name(2, target_folder
, filename
);
3092 msi_free(target_folder
);
3095 buffer
= MSI_RecordGetString(row
,5);
3096 if (strchrW(buffer
,'['))
3099 deformat_string(package
,buffer
,&deformated
);
3100 IShellLinkW_SetPath(sl
,deformated
);
3101 msi_free(deformated
);
3105 FIXME("poorly handled shortcut format, advertised shortcut\n");
3106 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3109 if (!MSI_RecordIsNull(row
,6))
3112 buffer
= MSI_RecordGetString(row
,6);
3113 deformat_string(package
,buffer
,&deformated
);
3114 IShellLinkW_SetArguments(sl
,deformated
);
3115 msi_free(deformated
);
3118 if (!MSI_RecordIsNull(row
,7))
3120 buffer
= MSI_RecordGetString(row
,7);
3121 IShellLinkW_SetDescription(sl
,buffer
);
3124 if (!MSI_RecordIsNull(row
,8))
3125 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3127 if (!MSI_RecordIsNull(row
,9))
3132 buffer
= MSI_RecordGetString(row
,9);
3134 Path
= build_icon_path(package
,buffer
);
3135 index
= MSI_RecordGetInteger(row
,10);
3137 /* no value means 0 */
3138 if (index
== MSI_NULL_INTEGER
)
3141 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3145 if (!MSI_RecordIsNull(row
,11))
3146 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3148 if (!MSI_RecordIsNull(row
,12))
3151 buffer
= MSI_RecordGetString(row
,12);
3152 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3154 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3158 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3159 IPersistFile_Save(pf
,target_file
,FALSE
);
3161 msi_free(target_file
);
3165 IPersistFile_Release( pf
);
3167 IShellLinkW_Release( sl
);
3169 return ERROR_SUCCESS
;
3172 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3177 static const WCHAR Query
[] =
3178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3179 '`','S','h','o','r','t','c','u','t','`',0};
3181 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3182 if (rc
!= ERROR_SUCCESS
)
3183 return ERROR_SUCCESS
;
3185 res
= CoInitialize( NULL
);
3187 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3188 msiobj_release(&view
->hdr
);
3196 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3198 MSIPACKAGE
* package
= param
;
3207 FileName
= MSI_RecordGetString(row
,1);
3210 ERR("Unable to get FileName\n");
3211 return ERROR_SUCCESS
;
3214 FilePath
= build_icon_path(package
,FileName
);
3216 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3218 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3219 FILE_ATTRIBUTE_NORMAL
, NULL
);
3221 if (the_file
== INVALID_HANDLE_VALUE
)
3223 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3225 return ERROR_SUCCESS
;
3232 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3233 if (rc
!= ERROR_SUCCESS
)
3235 ERR("Failed to get stream\n");
3236 CloseHandle(the_file
);
3237 DeleteFileW(FilePath
);
3240 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3241 } while (sz
== 1024);
3245 CloseHandle(the_file
);
3247 uirow
= MSI_CreateRecord(1);
3248 MSI_RecordSetStringW(uirow
,1,FileName
);
3249 ui_actiondata(package
,szPublishProduct
,uirow
);
3250 msiobj_release( &uirow
->hdr
);
3252 return ERROR_SUCCESS
;
3255 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3260 static const WCHAR query
[]= {
3261 'S','E','L','E','C','T',' ','*',' ',
3262 'F','R','O','M',' ','`','I','c','o','n','`',0};
3264 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3265 if (r
== ERROR_SUCCESS
)
3267 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3268 msiobj_release(&view
->hdr
);
3271 return ERROR_SUCCESS
;
3274 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3280 MSISOURCELISTINFO
*info
;
3282 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3283 if (r
!= ERROR_SUCCESS
)
3286 RegCloseKey(source
);
3288 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3289 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3290 package
->Context
, MSICODE_PRODUCT
,
3291 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3292 if (r
!= ERROR_SUCCESS
)
3295 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3296 package
->Context
, MSICODE_PRODUCT
,
3297 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3298 if (r
!= ERROR_SUCCESS
)
3301 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3302 package
->Context
, MSICODE_PRODUCT
,
3303 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3304 if (r
!= ERROR_SUCCESS
)
3307 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3309 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3310 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3311 info
->options
, info
->value
);
3313 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3314 info
->context
, info
->options
,
3315 info
->property
, info
->value
);
3318 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3320 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3321 disk
->context
, disk
->options
,
3322 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3325 return ERROR_SUCCESS
;
3328 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3330 MSIHANDLE hdb
, suminfo
;
3331 WCHAR guids
[MAX_PATH
];
3332 WCHAR packcode
[SQUISH_GUID_SIZE
];
3339 static const WCHAR szProductLanguage
[] =
3340 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3341 static const WCHAR szARPProductIcon
[] =
3342 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3343 static const WCHAR szProductVersion
[] =
3344 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3345 static const WCHAR szAssignment
[] =
3346 {'A','s','s','i','g','n','m','e','n','t',0};
3347 static const WCHAR szAdvertiseFlags
[] =
3348 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3349 static const WCHAR szClients
[] =
3350 {'C','l','i','e','n','t','s',0};
3351 static const WCHAR szColon
[] = {':',0};
3353 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3354 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3357 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3358 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3361 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3363 buffer
= msi_dup_property(package
, szARPProductIcon
);
3366 LPWSTR path
= build_icon_path(package
,buffer
);
3367 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3372 buffer
= msi_dup_property(package
, szProductVersion
);
3375 DWORD verdword
= msi_version_str_to_dword(buffer
);
3376 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3380 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3381 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3382 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3383 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3385 hdb
= alloc_msihandle(&package
->db
->hdr
);
3387 return ERROR_NOT_ENOUGH_MEMORY
;
3389 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3390 MsiCloseHandle(hdb
);
3391 if (r
!= ERROR_SUCCESS
)
3395 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3396 NULL
, guids
, &size
);
3397 if (r
!= ERROR_SUCCESS
)
3400 ptr
= strchrW(guids
, ';');
3402 squash_guid(guids
, packcode
);
3403 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3406 MsiCloseHandle(suminfo
);
3407 return ERROR_SUCCESS
;
3410 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3415 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3417 static const WCHAR szUpgradeCode
[] =
3418 {'U','p','g','r','a','d','e','C','o','d','e',0};
3420 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3422 return ERROR_SUCCESS
;
3424 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3426 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3427 if (r
!= ERROR_SUCCESS
)
3432 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3433 if (r
!= ERROR_SUCCESS
)
3437 squash_guid(package
->ProductCode
, squashed_pc
);
3438 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3447 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3449 MSIFEATURE
*feature
;
3451 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3453 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3460 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3462 MSIFEATURE
*feature
;
3464 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3466 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3473 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3475 WCHAR patch_squashed
[GUID_SIZE
];
3478 UINT r
= ERROR_FUNCTION_FAILED
;
3480 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3482 if (res
!= ERROR_SUCCESS
)
3483 return ERROR_FUNCTION_FAILED
;
3485 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3487 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3488 (const BYTE
*)patch_squashed
,
3489 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3490 if (res
!= ERROR_SUCCESS
)
3493 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3494 (const BYTE
*)package
->patch
->transforms
,
3495 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3496 if (res
== ERROR_SUCCESS
)
3500 RegCloseKey(patches
);
3505 * 99% of the work done here is only done for
3506 * advertised installs. However this is where the
3507 * Icon table is processed and written out
3508 * so that is what I am going to do here.
3510 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3516 /* FIXME: also need to publish if the product is in advertise mode */
3517 if (!msi_check_publish(package
))
3518 return ERROR_SUCCESS
;
3520 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3522 if (rc
!= ERROR_SUCCESS
)
3525 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3526 NULL
, &hudkey
, TRUE
);
3527 if (rc
!= ERROR_SUCCESS
)
3530 rc
= msi_publish_upgrade_code(package
);
3531 if (rc
!= ERROR_SUCCESS
)
3536 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3537 if (rc
!= ERROR_SUCCESS
)
3541 rc
= msi_publish_product_properties(package
, hukey
);
3542 if (rc
!= ERROR_SUCCESS
)
3545 rc
= msi_publish_sourcelist(package
, hukey
);
3546 if (rc
!= ERROR_SUCCESS
)
3549 rc
= msi_publish_icons(package
);
3553 RegCloseKey(hudkey
);
3558 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3560 MSIPACKAGE
*package
= param
;
3561 LPCWSTR component
, section
, key
, value
, identifier
, dirproperty
;
3562 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3563 LPWSTR folder
, filename
, fullname
= NULL
;
3564 LPCWSTR filenameptr
;
3568 static const WCHAR szWindowsFolder
[] =
3569 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3571 component
= MSI_RecordGetString(row
, 8);
3572 comp
= get_loaded_component(package
,component
);
3574 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3576 TRACE("Skipping ini file due to disabled component %s\n",
3577 debugstr_w(component
));
3579 comp
->Action
= comp
->Installed
;
3581 return ERROR_SUCCESS
;
3584 comp
->Action
= INSTALLSTATE_LOCAL
;
3586 identifier
= MSI_RecordGetString(row
,1);
3587 dirproperty
= MSI_RecordGetString(row
,3);
3588 section
= MSI_RecordGetString(row
,4);
3589 key
= MSI_RecordGetString(row
,5);
3590 value
= MSI_RecordGetString(row
,6);
3591 action
= MSI_RecordGetInteger(row
,7);
3593 deformat_string(package
,section
,&deformated_section
);
3594 deformat_string(package
,key
,&deformated_key
);
3595 deformat_string(package
,value
,&deformated_value
);
3597 filename
= msi_dup_record_field(row
, 2);
3598 if (filename
&& (filenameptr
= strchrW(filename
, '|')))
3601 filenameptr
= filename
;
3605 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3607 folder
= msi_dup_property( package
, dirproperty
);
3610 folder
= msi_dup_property( package
, szWindowsFolder
);
3614 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3618 fullname
= build_directory_name(2, folder
, filenameptr
);
3622 TRACE("Adding value %s to section %s in %s\n",
3623 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3624 debugstr_w(fullname
));
3625 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3626 deformated_value
, fullname
);
3628 else if (action
== 1)
3631 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3632 returned
, 10, fullname
);
3633 if (returned
[0] == 0)
3635 TRACE("Adding value %s to section %s in %s\n",
3636 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3637 debugstr_w(fullname
));
3639 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3640 deformated_value
, fullname
);
3643 else if (action
== 3)
3644 FIXME("Append to existing section not yet implemented\n");
3646 uirow
= MSI_CreateRecord(4);
3647 MSI_RecordSetStringW(uirow
,1,identifier
);
3648 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3649 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3650 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3651 ui_actiondata(package
,szWriteIniValues
,uirow
);
3652 msiobj_release( &uirow
->hdr
);
3658 msi_free(deformated_key
);
3659 msi_free(deformated_value
);
3660 msi_free(deformated_section
);
3661 return ERROR_SUCCESS
;
3664 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3668 static const WCHAR ExecSeqQuery
[] =
3669 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3670 '`','I','n','i','F','i','l','e','`',0};
3672 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3673 if (rc
!= ERROR_SUCCESS
)
3675 TRACE("no IniFile table\n");
3676 return ERROR_SUCCESS
;
3679 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3680 msiobj_release(&view
->hdr
);
3684 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3686 MSIPACKAGE
*package
= param
;
3691 static const WCHAR ExeStr
[] =
3692 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3693 static const WCHAR close
[] = {'\"',0};
3695 PROCESS_INFORMATION info
;
3700 memset(&si
,0,sizeof(STARTUPINFOW
));
3702 filename
= MSI_RecordGetString(row
,1);
3703 file
= get_loaded_file( package
, filename
);
3707 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3708 return ERROR_SUCCESS
;
3711 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3713 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3714 strcpyW(FullName
,ExeStr
);
3715 strcatW( FullName
, file
->TargetPath
);
3716 strcatW(FullName
,close
);
3718 TRACE("Registering %s\n",debugstr_w(FullName
));
3719 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3724 CloseHandle(info
.hThread
);
3725 msi_dialog_check_messages(info
.hProcess
);
3726 CloseHandle(info
.hProcess
);
3732 uirow
= MSI_CreateRecord( 2 );
3733 uipath
= strdupW( file
->TargetPath
);
3734 p
= strrchrW(uipath
,'\\');
3737 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3738 MSI_RecordSetStringW( uirow
, 2, uipath
);
3739 ui_actiondata( package
, szSelfRegModules
, uirow
);
3740 msiobj_release( &uirow
->hdr
);
3742 /* FIXME: call ui_progress? */
3744 return ERROR_SUCCESS
;
3747 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3751 static const WCHAR ExecSeqQuery
[] =
3752 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3753 '`','S','e','l','f','R','e','g','`',0};
3755 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3756 if (rc
!= ERROR_SUCCESS
)
3758 TRACE("no SelfReg table\n");
3759 return ERROR_SUCCESS
;
3762 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3763 msiobj_release(&view
->hdr
);
3765 return ERROR_SUCCESS
;
3768 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
3770 static const WCHAR regsvr32
[] =
3771 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
3772 static const WCHAR close
[] = {'\"',0};
3773 MSIPACKAGE
*package
= param
;
3779 PROCESS_INFORMATION pi
;
3784 memset( &si
, 0, sizeof(STARTUPINFOW
) );
3786 filename
= MSI_RecordGetString( row
, 1 );
3787 file
= get_loaded_file( package
, filename
);
3791 ERR("Unable to find file id %s\n", debugstr_w(filename
));
3792 return ERROR_SUCCESS
;
3795 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
3797 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
3798 strcpyW( cmdline
, regsvr32
);
3799 strcatW( cmdline
, file
->TargetPath
);
3800 strcatW( cmdline
, close
);
3802 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
3804 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
3807 CloseHandle( pi
.hThread
);
3808 msi_dialog_check_messages( pi
.hProcess
);
3809 CloseHandle( pi
.hProcess
);
3812 msi_free( cmdline
);
3814 uirow
= MSI_CreateRecord( 2 );
3815 uipath
= strdupW( file
->TargetPath
);
3816 if ((p
= strrchrW( uipath
, '\\' )))
3819 MSI_RecordSetStringW( uirow
, 1, ++p
);
3821 MSI_RecordSetStringW( uirow
, 2, uipath
);
3822 ui_actiondata( package
, szSelfUnregModules
, uirow
);
3823 msiobj_release( &uirow
->hdr
);
3825 /* FIXME call ui_progress? */
3827 return ERROR_SUCCESS
;
3830 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
3834 static const WCHAR query
[] =
3835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3836 '`','S','e','l','f','R','e','g','`',0};
3838 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3839 if (rc
!= ERROR_SUCCESS
)
3841 TRACE("no SelfReg table\n");
3842 return ERROR_SUCCESS
;
3845 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
3846 msiobj_release( &view
->hdr
);
3848 return ERROR_SUCCESS
;
3851 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3853 MSIFEATURE
*feature
;
3856 HKEY userdata
= NULL
;
3858 if (!msi_check_publish(package
))
3859 return ERROR_SUCCESS
;
3861 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
3863 if (rc
!= ERROR_SUCCESS
)
3866 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
3868 if (rc
!= ERROR_SUCCESS
)
3871 /* here the guids are base 85 encoded */
3872 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3878 BOOL absent
= FALSE
;
3881 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3882 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3883 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3887 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3891 if (feature
->Feature_Parent
)
3892 size
+= strlenW( feature
->Feature_Parent
)+2;
3894 data
= msi_alloc(size
* sizeof(WCHAR
));
3897 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3899 MSICOMPONENT
* component
= cl
->component
;
3903 if (component
->ComponentId
)
3905 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3906 CLSIDFromString(component
->ComponentId
, &clsid
);
3907 encode_base85_guid(&clsid
,buf
);
3908 TRACE("to %s\n",debugstr_w(buf
));
3913 if (feature
->Feature_Parent
)
3915 static const WCHAR sep
[] = {'\2',0};
3917 strcatW(data
,feature
->Feature_Parent
);
3920 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
3924 if (feature
->Feature_Parent
)
3925 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3928 size
+= sizeof(WCHAR
);
3929 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3930 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
3934 size
+= 2*sizeof(WCHAR
);
3935 data
= msi_alloc(size
);
3938 if (feature
->Feature_Parent
)
3939 strcpyW( &data
[1], feature
->Feature_Parent
);
3940 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3946 uirow
= MSI_CreateRecord( 1 );
3947 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3948 ui_actiondata( package
, szPublishFeatures
, uirow
);
3949 msiobj_release( &uirow
->hdr
);
3950 /* FIXME: call ui_progress? */
3955 RegCloseKey(userdata
);
3959 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
3964 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
3966 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
3968 if (r
== ERROR_SUCCESS
)
3970 RegDeleteValueW(hkey
, feature
->Feature
);
3974 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
3976 if (r
== ERROR_SUCCESS
)
3978 RegDeleteValueW(hkey
, feature
->Feature
);
3982 return ERROR_SUCCESS
;
3985 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
3987 MSIFEATURE
*feature
;
3989 if (!msi_check_unpublish(package
))
3990 return ERROR_SUCCESS
;
3992 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3994 msi_unpublish_feature(package
, feature
);
3997 return ERROR_SUCCESS
;
4000 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4002 LPWSTR prop
, val
, key
;
4008 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4009 static const WCHAR szWindowsInstaller
[] =
4010 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4011 static const WCHAR modpath_fmt
[] =
4012 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4013 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4014 static const WCHAR szModifyPath
[] =
4015 {'M','o','d','i','f','y','P','a','t','h',0};
4016 static const WCHAR szUninstallString
[] =
4017 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4018 static const WCHAR szEstimatedSize
[] =
4019 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4020 static const WCHAR szProductLanguage
[] =
4021 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4022 static const WCHAR szProductVersion
[] =
4023 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4024 static const WCHAR szProductName
[] =
4025 {'P','r','o','d','u','c','t','N','a','m','e',0};
4026 static const WCHAR szDisplayName
[] =
4027 {'D','i','s','p','l','a','y','N','a','m','e',0};
4028 static const WCHAR szDisplayVersion
[] =
4029 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4030 static const WCHAR szManufacturer
[] =
4031 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4033 static const LPCSTR propval
[] = {
4034 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4035 "ARPCONTACT", "Contact",
4036 "ARPCOMMENTS", "Comments",
4037 "ProductName", "DisplayName",
4038 "ProductVersion", "DisplayVersion",
4039 "ARPHELPLINK", "HelpLink",
4040 "ARPHELPTELEPHONE", "HelpTelephone",
4041 "ARPINSTALLLOCATION", "InstallLocation",
4042 "SourceDir", "InstallSource",
4043 "Manufacturer", "Publisher",
4044 "ARPREADME", "Readme",
4046 "ARPURLINFOABOUT", "URLInfoAbout",
4047 "ARPURLUPDATEINFO", "URLUpdateInfo",
4050 const LPCSTR
*p
= propval
;
4054 prop
= strdupAtoW(*p
++);
4055 key
= strdupAtoW(*p
++);
4056 val
= msi_dup_property(package
, prop
);
4057 msi_reg_set_val_str(hkey
, key
, val
);
4063 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4065 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4066 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4067 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4070 /* FIXME: Write real Estimated Size when we have it */
4071 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4073 buffer
= msi_dup_property(package
, szProductName
);
4074 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4077 buffer
= msi_dup_property(package
, cszSourceDir
);
4078 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4081 buffer
= msi_dup_property(package
, szManufacturer
);
4082 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4085 GetLocalTime(&systime
);
4086 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4087 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4089 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4090 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4092 buffer
= msi_dup_property(package
, szProductVersion
);
4093 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4096 DWORD verdword
= msi_version_str_to_dword(buffer
);
4098 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4099 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4100 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4104 return ERROR_SUCCESS
;
4107 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4109 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4110 LPWSTR upgrade_code
;
4115 static const WCHAR szUpgradeCode
[] = {
4116 'U','p','g','r','a','d','e','C','o','d','e',0};
4118 /* FIXME: also need to publish if the product is in advertise mode */
4119 if (!msi_check_publish(package
))
4120 return ERROR_SUCCESS
;
4122 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4123 if (rc
!= ERROR_SUCCESS
)
4126 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4127 NULL
, &props
, TRUE
);
4128 if (rc
!= ERROR_SUCCESS
)
4131 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4132 msi_free( package
->db
->localfile
);
4133 package
->db
->localfile
= NULL
;
4135 rc
= msi_publish_install_properties(package
, hkey
);
4136 if (rc
!= ERROR_SUCCESS
)
4139 rc
= msi_publish_install_properties(package
, props
);
4140 if (rc
!= ERROR_SUCCESS
)
4143 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4146 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4147 squash_guid(package
->ProductCode
, squashed_pc
);
4148 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4149 RegCloseKey(upgrade
);
4150 msi_free(upgrade_code
);
4156 return ERROR_SUCCESS
;
4159 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4161 return execute_script(package
,INSTALL_SCRIPT
);
4164 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4167 LPWSTR remove
= NULL
;
4168 LPWSTR
*features
= NULL
;
4169 BOOL full_uninstall
= TRUE
;
4170 MSIFEATURE
*feature
;
4172 static const WCHAR szUpgradeCode
[] =
4173 {'U','p','g','r','a','d','e','C','o','d','e',0};
4175 remove
= msi_dup_property(package
, szRemove
);
4177 return ERROR_SUCCESS
;
4179 features
= msi_split_string(remove
, ',');
4183 ERR("REMOVE feature list is empty!\n");
4184 return ERROR_FUNCTION_FAILED
;
4187 if (!lstrcmpW(features
[0], szAll
))
4188 full_uninstall
= TRUE
;
4191 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4193 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4194 full_uninstall
= FALSE
;
4198 if (!full_uninstall
)
4201 MSIREG_DeleteProductKey(package
->ProductCode
);
4202 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4203 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4205 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4207 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4208 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4212 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4213 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4216 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4219 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4226 return ERROR_SUCCESS
;
4229 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4233 rc
= msi_unpublish_product(package
);
4234 if (rc
!= ERROR_SUCCESS
)
4237 /* turn off scheduling */
4238 package
->script
->CurrentlyScripting
= FALSE
;
4240 /* first do the same as an InstallExecute */
4241 rc
= ACTION_InstallExecute(package
);
4242 if (rc
!= ERROR_SUCCESS
)
4245 /* then handle Commit Actions */
4246 rc
= execute_script(package
,COMMIT_SCRIPT
);
4251 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4253 static const WCHAR RunOnce
[] = {
4254 'S','o','f','t','w','a','r','e','\\',
4255 'M','i','c','r','o','s','o','f','t','\\',
4256 'W','i','n','d','o','w','s','\\',
4257 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4258 'R','u','n','O','n','c','e',0};
4259 static const WCHAR InstallRunOnce
[] = {
4260 'S','o','f','t','w','a','r','e','\\',
4261 'M','i','c','r','o','s','o','f','t','\\',
4262 'W','i','n','d','o','w','s','\\',
4263 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4264 'I','n','s','t','a','l','l','e','r','\\',
4265 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4267 static const WCHAR msiexec_fmt
[] = {
4269 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4270 '\"','%','s','\"',0};
4271 static const WCHAR install_fmt
[] = {
4272 '/','I',' ','\"','%','s','\"',' ',
4273 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4274 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4275 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4277 WCHAR squished_pc
[100];
4279 squash_guid(package
->ProductCode
,squished_pc
);
4281 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4282 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4283 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4286 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4289 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4291 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4292 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4294 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4297 return ERROR_INSTALL_SUSPEND
;
4300 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4306 * We are currently doing what should be done here in the top level Install
4307 * however for Administrative and uninstalls this step will be needed
4309 if (!package
->PackagePath
)
4310 return ERROR_SUCCESS
;
4312 msi_set_sourcedir_props(package
, TRUE
);
4314 attrib
= GetFileAttributesW(package
->db
->path
);
4315 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4321 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4322 package
->Context
, MSICODE_PRODUCT
,
4323 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4324 if (rc
== ERROR_MORE_DATA
)
4326 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4327 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4328 package
->Context
, MSICODE_PRODUCT
,
4329 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4332 prompt
= strdupW(package
->db
->path
);
4334 msg
= generate_error_string(package
,1302,1,prompt
);
4335 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4337 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4340 rc
= ERROR_INSTALL_USEREXIT
;
4343 attrib
= GetFileAttributesW(package
->db
->path
);
4349 return ERROR_SUCCESS
;
4354 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4361 static const WCHAR szPropKeys
[][80] =
4363 {'P','r','o','d','u','c','t','I','D',0},
4364 {'U','S','E','R','N','A','M','E',0},
4365 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4369 static const WCHAR szRegKeys
[][80] =
4371 {'P','r','o','d','u','c','t','I','D',0},
4372 {'R','e','g','O','w','n','e','r',0},
4373 {'R','e','g','C','o','m','p','a','n','y',0},
4377 if (msi_check_unpublish(package
))
4379 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4380 return ERROR_SUCCESS
;
4383 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4385 return ERROR_SUCCESS
;
4387 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4389 if (rc
!= ERROR_SUCCESS
)
4392 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4394 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4395 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4400 msi_free(productid
);
4403 /* FIXME: call ui_actiondata */
4409 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4413 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4414 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4419 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4421 MSIPACKAGE
*package
= param
;
4422 LPCWSTR compgroupid
=NULL
;
4423 LPCWSTR feature
=NULL
;
4424 LPCWSTR text
= NULL
;
4425 LPCWSTR qualifier
= NULL
;
4426 LPCWSTR component
= NULL
;
4427 LPWSTR advertise
= NULL
;
4428 LPWSTR output
= NULL
;
4430 UINT rc
= ERROR_SUCCESS
;
4435 component
= MSI_RecordGetString(rec
,3);
4436 comp
= get_loaded_component(package
,component
);
4438 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4439 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4440 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4442 TRACE("Skipping: Component %s not scheduled for install\n",
4443 debugstr_w(component
));
4445 return ERROR_SUCCESS
;
4448 compgroupid
= MSI_RecordGetString(rec
,1);
4449 qualifier
= MSI_RecordGetString(rec
,2);
4451 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4452 if (rc
!= ERROR_SUCCESS
)
4455 text
= MSI_RecordGetString(rec
,4);
4456 feature
= MSI_RecordGetString(rec
,5);
4458 advertise
= create_component_advertise_string(package
, comp
, feature
);
4460 sz
= strlenW(advertise
);
4463 sz
+= lstrlenW(text
);
4466 sz
*= sizeof(WCHAR
);
4468 output
= msi_alloc_zero(sz
);
4469 strcpyW(output
,advertise
);
4470 msi_free(advertise
);
4473 strcatW(output
,text
);
4475 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4482 uirow
= MSI_CreateRecord( 2 );
4483 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4484 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4485 ui_actiondata( package
, szPublishComponents
, uirow
);
4486 msiobj_release( &uirow
->hdr
);
4487 /* FIXME: call ui_progress? */
4493 * At present I am ignorning the advertised components part of this and only
4494 * focusing on the qualified component sets
4496 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4500 static const WCHAR ExecSeqQuery
[] =
4501 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4502 '`','P','u','b','l','i','s','h',
4503 'C','o','m','p','o','n','e','n','t','`',0};
4505 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4506 if (rc
!= ERROR_SUCCESS
)
4507 return ERROR_SUCCESS
;
4509 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4510 msiobj_release(&view
->hdr
);
4515 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4517 MSIPACKAGE
*package
= param
;
4520 SC_HANDLE hscm
, service
= NULL
;
4521 LPCWSTR comp
, depends
, pass
;
4522 LPWSTR name
= NULL
, disp
= NULL
;
4523 LPCWSTR load_order
, serv_name
, key
;
4524 DWORD serv_type
, start_type
;
4527 static const WCHAR query
[] =
4528 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4529 '`','C','o','m','p','o','n','e','n','t','`',' ',
4530 'W','H','E','R','E',' ',
4531 '`','C','o','m','p','o','n','e','n','t','`',' ',
4532 '=','\'','%','s','\'',0};
4534 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4537 ERR("Failed to open the SC Manager!\n");
4541 start_type
= MSI_RecordGetInteger(rec
, 5);
4542 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4545 depends
= MSI_RecordGetString(rec
, 8);
4546 if (depends
&& *depends
)
4547 FIXME("Dependency list unhandled!\n");
4549 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4550 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4551 serv_type
= MSI_RecordGetInteger(rec
, 4);
4552 err_control
= MSI_RecordGetInteger(rec
, 6);
4553 load_order
= MSI_RecordGetString(rec
, 7);
4554 serv_name
= MSI_RecordGetString(rec
, 9);
4555 pass
= MSI_RecordGetString(rec
, 10);
4556 comp
= MSI_RecordGetString(rec
, 12);
4558 /* fetch the service path */
4559 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4562 ERR("Control query failed!\n");
4566 key
= MSI_RecordGetString(row
, 6);
4568 file
= get_loaded_file(package
, key
);
4569 msiobj_release(&row
->hdr
);
4572 ERR("Failed to load the service file\n");
4576 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4577 start_type
, err_control
, file
->TargetPath
,
4578 load_order
, NULL
, NULL
, serv_name
, pass
);
4581 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4582 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4586 CloseServiceHandle(service
);
4587 CloseServiceHandle(hscm
);
4591 return ERROR_SUCCESS
;
4594 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4598 static const WCHAR ExecSeqQuery
[] =
4599 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4600 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4602 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4603 if (rc
!= ERROR_SUCCESS
)
4604 return ERROR_SUCCESS
;
4606 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4607 msiobj_release(&view
->hdr
);
4612 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4613 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4615 LPCWSTR
*vector
, *temp_vector
;
4619 static const WCHAR separator
[] = {'[','~',']',0};
4622 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4627 vector
= msi_alloc(sizeof(LPWSTR
));
4635 vector
[*numargs
- 1] = p
;
4637 if ((q
= strstrW(p
, separator
)))
4641 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4647 vector
= temp_vector
;
4656 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4658 MSIPACKAGE
*package
= param
;
4660 SC_HANDLE scm
, service
= NULL
;
4661 LPCWSTR
*vector
= NULL
;
4663 DWORD event
, numargs
;
4664 UINT r
= ERROR_FUNCTION_FAILED
;
4666 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4667 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4668 return ERROR_SUCCESS
;
4670 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4671 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4672 event
= MSI_RecordGetInteger(rec
, 3);
4674 if (!(event
& msidbServiceControlEventStart
))
4675 return ERROR_SUCCESS
;
4677 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4680 ERR("Failed to open the service control manager\n");
4684 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4687 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
4691 vector
= msi_service_args_to_vector(args
, &numargs
);
4693 if (!StartServiceW(service
, numargs
, vector
) &&
4694 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
4696 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
4703 CloseServiceHandle(service
);
4704 CloseServiceHandle(scm
);
4712 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4717 static const WCHAR query
[] = {
4718 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4719 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4721 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4722 if (rc
!= ERROR_SUCCESS
)
4723 return ERROR_SUCCESS
;
4725 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4726 msiobj_release(&view
->hdr
);
4731 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4733 DWORD i
, needed
, count
;
4734 ENUM_SERVICE_STATUSW
*dependencies
;
4738 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4739 0, &needed
, &count
))
4742 if (GetLastError() != ERROR_MORE_DATA
)
4745 dependencies
= msi_alloc(needed
);
4749 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4750 needed
, &needed
, &count
))
4753 for (i
= 0; i
< count
; i
++)
4755 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4756 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4760 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4767 msi_free(dependencies
);
4771 static UINT
stop_service( LPCWSTR name
)
4773 SC_HANDLE scm
= NULL
, service
= NULL
;
4774 SERVICE_STATUS status
;
4775 SERVICE_STATUS_PROCESS ssp
;
4778 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4781 WARN("Failed to open the SCM: %d\n", GetLastError());
4785 service
= OpenServiceW(scm
, name
,
4787 SERVICE_QUERY_STATUS
|
4788 SERVICE_ENUMERATE_DEPENDENTS
);
4791 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
4795 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4796 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4798 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
4802 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4805 stop_service_dependents(scm
, service
);
4807 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
4808 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
4811 CloseServiceHandle(service
);
4812 CloseServiceHandle(scm
);
4814 return ERROR_SUCCESS
;
4817 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
4819 MSIPACKAGE
*package
= param
;
4824 event
= MSI_RecordGetInteger( rec
, 3 );
4825 if (!(event
& msidbServiceControlEventStop
))
4826 return ERROR_SUCCESS
;
4828 comp
= get_loaded_component( package
, MSI_RecordGetString( rec
, 6 ) );
4829 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4830 return ERROR_SUCCESS
;
4832 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
4833 stop_service( name
);
4836 return ERROR_SUCCESS
;
4839 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4844 static const WCHAR query
[] = {
4845 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4846 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4848 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4849 if (rc
!= ERROR_SUCCESS
)
4850 return ERROR_SUCCESS
;
4852 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
4853 msiobj_release(&view
->hdr
);
4858 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
4860 MSIPACKAGE
*package
= param
;
4864 SC_HANDLE scm
= NULL
, service
= NULL
;
4866 event
= MSI_RecordGetInteger( rec
, 3 );
4867 if (!(event
& msidbServiceControlEventDelete
))
4868 return ERROR_SUCCESS
;
4870 comp
= get_loaded_component( package
, MSI_RecordGetString(rec
, 6) );
4871 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4872 return ERROR_SUCCESS
;
4874 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
4875 stop_service( name
);
4877 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4880 WARN("Failed to open the SCM: %d\n", GetLastError());
4884 service
= OpenServiceW( scm
, name
, DELETE
);
4887 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
4891 if (!DeleteService( service
))
4892 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
4895 CloseServiceHandle( service
);
4896 CloseServiceHandle( scm
);
4899 return ERROR_SUCCESS
;
4902 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
4907 static const WCHAR query
[] = {
4908 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4909 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4911 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4912 if (rc
!= ERROR_SUCCESS
)
4913 return ERROR_SUCCESS
;
4915 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
4916 msiobj_release( &view
->hdr
);
4921 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4925 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4927 if (!lstrcmpW(file
->File
, filename
))
4934 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4936 MSIPACKAGE
*package
= param
;
4937 LPWSTR driver
, driver_path
, ptr
;
4938 WCHAR outpath
[MAX_PATH
];
4939 MSIFILE
*driver_file
, *setup_file
;
4942 UINT r
= ERROR_SUCCESS
;
4944 static const WCHAR driver_fmt
[] = {
4945 'D','r','i','v','e','r','=','%','s',0};
4946 static const WCHAR setup_fmt
[] = {
4947 'S','e','t','u','p','=','%','s',0};
4948 static const WCHAR usage_fmt
[] = {
4949 'F','i','l','e','U','s','a','g','e','=','1',0};
4951 desc
= MSI_RecordGetString(rec
, 3);
4953 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4954 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4958 ERR("ODBC Driver entry not found!\n");
4959 return ERROR_FUNCTION_FAILED
;
4962 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
4964 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
4965 len
+= lstrlenW(usage_fmt
) + 1;
4967 driver
= msi_alloc(len
* sizeof(WCHAR
));
4969 return ERROR_OUTOFMEMORY
;
4972 lstrcpyW(ptr
, desc
);
4973 ptr
+= lstrlenW(ptr
) + 1;
4975 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4976 ptr
+= lstrlenW(ptr
) + 1;
4980 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4981 ptr
+= lstrlenW(ptr
) + 1;
4984 lstrcpyW(ptr
, usage_fmt
);
4985 ptr
+= lstrlenW(ptr
) + 1;
4988 driver_path
= strdupW(driver_file
->TargetPath
);
4989 ptr
= strrchrW(driver_path
, '\\');
4990 if (ptr
) *ptr
= '\0';
4992 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4993 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4995 ERR("Failed to install SQL driver!\n");
4996 r
= ERROR_FUNCTION_FAILED
;
5000 msi_free(driver_path
);
5005 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5007 MSIPACKAGE
*package
= param
;
5008 LPWSTR translator
, translator_path
, ptr
;
5009 WCHAR outpath
[MAX_PATH
];
5010 MSIFILE
*translator_file
, *setup_file
;
5013 UINT r
= ERROR_SUCCESS
;
5015 static const WCHAR translator_fmt
[] = {
5016 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5017 static const WCHAR setup_fmt
[] = {
5018 'S','e','t','u','p','=','%','s',0};
5020 desc
= MSI_RecordGetString(rec
, 3);
5022 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5023 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5025 if (!translator_file
)
5027 ERR("ODBC Translator entry not found!\n");
5028 return ERROR_FUNCTION_FAILED
;
5031 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 1;
5033 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5035 translator
= msi_alloc(len
* sizeof(WCHAR
));
5037 return ERROR_OUTOFMEMORY
;
5040 lstrcpyW(ptr
, desc
);
5041 ptr
+= lstrlenW(ptr
) + 1;
5043 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5044 ptr
+= lstrlenW(ptr
) + 1;
5048 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5049 ptr
+= lstrlenW(ptr
) + 1;
5053 translator_path
= strdupW(translator_file
->TargetPath
);
5054 ptr
= strrchrW(translator_path
, '\\');
5055 if (ptr
) *ptr
= '\0';
5057 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5058 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5060 ERR("Failed to install SQL translator!\n");
5061 r
= ERROR_FUNCTION_FAILED
;
5064 msi_free(translator
);
5065 msi_free(translator_path
);
5070 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5073 LPCWSTR desc
, driver
;
5074 WORD request
= ODBC_ADD_SYS_DSN
;
5077 UINT r
= ERROR_SUCCESS
;
5079 static const WCHAR attrs_fmt
[] = {
5080 'D','S','N','=','%','s',0 };
5082 desc
= MSI_RecordGetString(rec
, 3);
5083 driver
= MSI_RecordGetString(rec
, 4);
5084 registration
= MSI_RecordGetInteger(rec
, 5);
5086 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5087 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5089 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
5090 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5092 return ERROR_OUTOFMEMORY
;
5094 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5097 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5099 ERR("Failed to install SQL data source!\n");
5100 r
= ERROR_FUNCTION_FAILED
;
5108 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5113 static const WCHAR driver_query
[] = {
5114 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5115 'O','D','B','C','D','r','i','v','e','r',0 };
5117 static const WCHAR translator_query
[] = {
5118 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5119 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5121 static const WCHAR source_query
[] = {
5122 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5123 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5125 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5126 if (rc
!= ERROR_SUCCESS
)
5127 return ERROR_SUCCESS
;
5129 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5130 msiobj_release(&view
->hdr
);
5132 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5133 if (rc
!= ERROR_SUCCESS
)
5134 return ERROR_SUCCESS
;
5136 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5137 msiobj_release(&view
->hdr
);
5139 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5140 if (rc
!= ERROR_SUCCESS
)
5141 return ERROR_SUCCESS
;
5143 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5144 msiobj_release(&view
->hdr
);
5149 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5154 desc
= MSI_RecordGetString( rec
, 3 );
5155 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5157 WARN("Failed to remove ODBC driver\n");
5161 FIXME("Usage count reached 0\n");
5164 return ERROR_SUCCESS
;
5167 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5172 desc
= MSI_RecordGetString( rec
, 3 );
5173 if (!SQLRemoveTranslatorW( desc
, &usage
))
5175 WARN("Failed to remove ODBC translator\n");
5179 FIXME("Usage count reached 0\n");
5182 return ERROR_SUCCESS
;
5185 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5188 LPCWSTR desc
, driver
;
5189 WORD request
= ODBC_REMOVE_SYS_DSN
;
5193 static const WCHAR attrs_fmt
[] = {
5194 'D','S','N','=','%','s',0 };
5196 desc
= MSI_RecordGetString( rec
, 3 );
5197 driver
= MSI_RecordGetString( rec
, 4 );
5198 registration
= MSI_RecordGetInteger( rec
, 5 );
5200 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5201 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5203 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 1 + 1;
5204 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5206 return ERROR_OUTOFMEMORY
;
5208 FIXME("Use ODBCSourceAttribute table\n");
5210 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5213 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5215 WARN("Failed to remove ODBC data source\n");
5219 return ERROR_SUCCESS
;
5222 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5227 static const WCHAR driver_query
[] = {
5228 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5229 'O','D','B','C','D','r','i','v','e','r',0 };
5231 static const WCHAR translator_query
[] = {
5232 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5233 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5235 static const WCHAR source_query
[] = {
5236 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5237 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5239 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
5240 if (rc
!= ERROR_SUCCESS
)
5241 return ERROR_SUCCESS
;
5243 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
5244 msiobj_release( &view
->hdr
);
5246 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
5247 if (rc
!= ERROR_SUCCESS
)
5248 return ERROR_SUCCESS
;
5250 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
5251 msiobj_release( &view
->hdr
);
5253 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
5254 if (rc
!= ERROR_SUCCESS
)
5255 return ERROR_SUCCESS
;
5257 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
5258 msiobj_release( &view
->hdr
);
5263 #define ENV_ACT_SETALWAYS 0x1
5264 #define ENV_ACT_SETABSENT 0x2
5265 #define ENV_ACT_REMOVE 0x4
5266 #define ENV_ACT_REMOVEMATCH 0x8
5268 #define ENV_MOD_MACHINE 0x20000000
5269 #define ENV_MOD_APPEND 0x40000000
5270 #define ENV_MOD_PREFIX 0x80000000
5271 #define ENV_MOD_MASK 0xC0000000
5273 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5275 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5277 LPCWSTR cptr
= *name
;
5279 static const WCHAR prefix
[] = {'[','~',']',0};
5280 static const int prefix_len
= 3;
5286 *flags
|= ENV_ACT_SETALWAYS
;
5287 else if (*cptr
== '+')
5288 *flags
|= ENV_ACT_SETABSENT
;
5289 else if (*cptr
== '-')
5290 *flags
|= ENV_ACT_REMOVE
;
5291 else if (*cptr
== '!')
5292 *flags
|= ENV_ACT_REMOVEMATCH
;
5293 else if (*cptr
== '*')
5294 *flags
|= ENV_MOD_MACHINE
;
5304 ERR("Missing environment variable\n");
5305 return ERROR_FUNCTION_FAILED
;
5310 LPCWSTR ptr
= *value
;
5311 if (!strncmpW(ptr
, prefix
, prefix_len
))
5313 if (ptr
[prefix_len
] == szSemiColon
[0])
5315 *flags
|= ENV_MOD_APPEND
;
5316 *value
+= lstrlenW(prefix
);
5323 else if (lstrlenW(*value
) >= prefix_len
)
5325 ptr
+= lstrlenW(ptr
) - prefix_len
;
5326 if (!lstrcmpW(ptr
, prefix
))
5328 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
5330 *flags
|= ENV_MOD_PREFIX
;
5331 /* the "[~]" will be removed by deformat_string */;
5341 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5342 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5343 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5344 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5346 ERR("Invalid flags: %08x\n", *flags
);
5347 return ERROR_FUNCTION_FAILED
;
5351 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
5353 return ERROR_SUCCESS
;
5356 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5358 MSIPACKAGE
*package
= param
;
5359 LPCWSTR name
, value
;
5360 LPWSTR data
= NULL
, newval
= NULL
;
5361 LPWSTR deformatted
= NULL
, ptr
;
5362 DWORD flags
, type
, size
;
5364 HKEY env
= NULL
, root
;
5365 LPCWSTR environment
;
5367 static const WCHAR user_env
[] =
5368 {'E','n','v','i','r','o','n','m','e','n','t',0};
5369 static const WCHAR machine_env
[] =
5370 {'S','y','s','t','e','m','\\',
5371 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5372 'C','o','n','t','r','o','l','\\',
5373 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5374 'E','n','v','i','r','o','n','m','e','n','t',0};
5376 name
= MSI_RecordGetString(rec
, 2);
5377 value
= MSI_RecordGetString(rec
, 3);
5379 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
5381 res
= env_set_flags(&name
, &value
, &flags
);
5382 if (res
!= ERROR_SUCCESS
|| !value
)
5385 if (value
&& !deformat_string(package
, value
, &deformatted
))
5387 res
= ERROR_OUTOFMEMORY
;
5391 value
= deformatted
;
5393 if (flags
& ENV_MOD_MACHINE
)
5395 environment
= machine_env
;
5396 root
= HKEY_LOCAL_MACHINE
;
5400 environment
= user_env
;
5401 root
= HKEY_CURRENT_USER
;
5404 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5405 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5406 if (res
!= ERROR_SUCCESS
)
5409 if (flags
& ENV_ACT_REMOVE
)
5410 FIXME("Not removing environment variable on uninstall!\n");
5414 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5415 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5416 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5419 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
5421 /* Nothing to do. */
5424 res
= ERROR_SUCCESS
;
5428 /* If we are appending but the string was empty, strip ; */
5429 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
5431 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5432 newval
= strdupW(value
);
5435 res
= ERROR_OUTOFMEMORY
;
5441 /* Contrary to MSDN, +-variable to [~];path works */
5442 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
5444 res
= ERROR_SUCCESS
;
5448 data
= msi_alloc(size
);
5452 return ERROR_OUTOFMEMORY
;
5455 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5456 if (res
!= ERROR_SUCCESS
)
5459 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5461 res
= RegDeleteKeyW(env
, name
);
5465 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
5466 if (flags
& ENV_MOD_MASK
)
5470 if (flags
& ENV_MOD_APPEND
) multiplier
++;
5471 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
5472 mod_size
= lstrlenW(value
) * multiplier
;
5473 size
+= mod_size
* sizeof(WCHAR
);
5476 newval
= msi_alloc(size
);
5480 res
= ERROR_OUTOFMEMORY
;
5484 if (flags
& ENV_MOD_PREFIX
)
5486 lstrcpyW(newval
, value
);
5487 ptr
= newval
+ lstrlenW(value
);
5490 lstrcpyW(ptr
, data
);
5492 if (flags
& ENV_MOD_APPEND
)
5494 lstrcatW(newval
, value
);
5497 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5498 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5501 if (env
) RegCloseKey(env
);
5502 msi_free(deformatted
);
5508 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5512 static const WCHAR ExecSeqQuery
[] =
5513 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5514 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5515 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5516 if (rc
!= ERROR_SUCCESS
)
5517 return ERROR_SUCCESS
;
5519 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5520 msiobj_release(&view
->hdr
);
5525 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5536 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5540 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5541 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5543 WARN("Source or dest is directory, not moving\n");
5547 if (options
== msidbMoveFileOptionsMove
)
5549 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5550 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5553 WARN("MoveFile failed: %d\n", GetLastError());
5559 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5560 ret
= CopyFileW(source
, dest
, FALSE
);
5563 WARN("CopyFile failed: %d\n", GetLastError());
5571 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5574 DWORD dirlen
, pathlen
;
5576 ptr
= strrchrW(wildcard
, '\\');
5577 dirlen
= ptr
- wildcard
+ 1;
5579 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5580 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5582 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5583 lstrcatW(path
, filename
);
5588 static void free_file_entry(FILE_LIST
*file
)
5590 msi_free(file
->source
);
5591 msi_free(file
->dest
);
5595 static void free_list(FILE_LIST
*list
)
5597 while (!list_empty(&list
->entry
))
5599 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5601 list_remove(&file
->entry
);
5602 free_file_entry(file
);
5606 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5608 FILE_LIST
*new, *file
;
5609 LPWSTR ptr
, filename
;
5612 new = msi_alloc_zero(sizeof(FILE_LIST
));
5616 new->source
= strdupW(source
);
5617 ptr
= strrchrW(dest
, '\\') + 1;
5618 filename
= strrchrW(new->source
, '\\') + 1;
5620 new->sourcename
= filename
;
5623 new->destname
= ptr
;
5625 new->destname
= new->sourcename
;
5627 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5628 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5631 free_file_entry(new);
5635 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5636 lstrcatW(new->dest
, filename
);
5638 if (list_empty(&files
->entry
))
5640 list_add_head(&files
->entry
, &new->entry
);
5644 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5646 if (lstrcmpW(source
, file
->source
) < 0)
5648 list_add_before(&file
->entry
, &new->entry
);
5653 list_add_after(&file
->entry
, &new->entry
);
5657 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5659 WIN32_FIND_DATAW wfd
;
5663 FILE_LIST files
, *file
;
5666 hfile
= FindFirstFileW(source
, &wfd
);
5667 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5669 list_init(&files
.entry
);
5671 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5673 if (is_dot_dir(wfd
.cFileName
)) continue;
5675 path
= wildcard_to_file(source
, wfd
.cFileName
);
5682 add_wildcard(&files
, path
, dest
);
5686 /* no files match the wildcard */
5687 if (list_empty(&files
.entry
))
5690 /* only the first wildcard match gets renamed to dest */
5691 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5692 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5693 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5700 /* file->dest may be shorter after the reallocation, so add a NULL
5701 * terminator. This is needed for the call to strrchrW, as there will no
5702 * longer be a NULL terminator within the bounds of the allocation in this case.
5704 file
->dest
[size
- 1] = '\0';
5705 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5707 while (!list_empty(&files
.entry
))
5709 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5711 msi_move_file(file
->source
, file
->dest
, options
);
5713 list_remove(&file
->entry
);
5714 free_file_entry(file
);
5725 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5727 MSIPACKAGE
*package
= param
;
5730 LPWSTR destname
= NULL
;
5731 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5732 LPWSTR source
= NULL
, dest
= NULL
;
5735 BOOL ret
, wildcards
;
5737 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5738 if (!comp
|| !comp
->Enabled
||
5739 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5741 TRACE("Component not set for install, not moving file\n");
5742 return ERROR_SUCCESS
;
5745 sourcename
= MSI_RecordGetString(rec
, 3);
5746 options
= MSI_RecordGetInteger(rec
, 7);
5748 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5752 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5758 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5761 source
= strdupW(sourcedir
);
5767 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5768 source
= msi_alloc(size
* sizeof(WCHAR
));
5772 lstrcpyW(source
, sourcedir
);
5773 if (source
[lstrlenW(source
) - 1] != '\\')
5774 lstrcatW(source
, szBackSlash
);
5775 lstrcatW(source
, sourcename
);
5778 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5780 if (MSI_RecordIsNull(rec
, 4))
5784 destname
= strdupW(sourcename
);
5791 destname
= strdupW(MSI_RecordGetString(rec
, 4));
5793 reduce_to_longfilename(destname
);
5798 size
= lstrlenW(destname
);
5800 size
+= lstrlenW(destdir
) + 2;
5801 dest
= msi_alloc(size
* sizeof(WCHAR
));
5805 lstrcpyW(dest
, destdir
);
5806 if (dest
[lstrlenW(dest
) - 1] != '\\')
5807 lstrcatW(dest
, szBackSlash
);
5810 lstrcatW(dest
, destname
);
5812 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5814 ret
= CreateDirectoryW(destdir
, NULL
);
5817 WARN("CreateDirectory failed: %d\n", GetLastError());
5818 return ERROR_SUCCESS
;
5823 msi_move_file(source
, dest
, options
);
5825 move_files_wildcard(source
, dest
, options
);
5828 msi_free(sourcedir
);
5834 return ERROR_SUCCESS
;
5837 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5842 static const WCHAR ExecSeqQuery
[] =
5843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5844 '`','M','o','v','e','F','i','l','e','`',0};
5846 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5847 if (rc
!= ERROR_SUCCESS
)
5848 return ERROR_SUCCESS
;
5850 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5851 msiobj_release(&view
->hdr
);
5856 typedef struct tagMSIASSEMBLY
5859 MSICOMPONENT
*component
;
5860 MSIFEATURE
*feature
;
5868 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5870 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5871 LPVOID pvReserved
, HMODULE
*phModDll
);
5873 static BOOL
init_functionpointers(void)
5879 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5881 hmscoree
= LoadLibraryA("mscoree.dll");
5884 WARN("mscoree.dll not available\n");
5888 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5889 if (!pLoadLibraryShim
)
5891 WARN("LoadLibraryShim not available\n");
5892 FreeLibrary(hmscoree
);
5896 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5899 WARN("fusion.dll not available\n");
5900 FreeLibrary(hmscoree
);
5904 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5906 FreeLibrary(hmscoree
);
5910 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
5913 IAssemblyCache
*cache
;
5915 UINT r
= ERROR_FUNCTION_FAILED
;
5917 TRACE("installing assembly: %s\n", debugstr_w(path
));
5919 if (assembly
->feature
)
5920 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
5922 if (assembly
->manifest
)
5923 FIXME("Manifest unhandled\n");
5925 if (assembly
->application
)
5927 FIXME("Assembly should be privately installed\n");
5928 return ERROR_SUCCESS
;
5931 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
5933 FIXME("Win32 assemblies not handled\n");
5934 return ERROR_SUCCESS
;
5937 hr
= pCreateAssemblyCache(&cache
, 0);
5941 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5943 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5948 IAssemblyCache_Release(cache
);
5952 typedef struct tagASSEMBLY_LIST
5954 MSIPACKAGE
*package
;
5955 IAssemblyCache
*cache
;
5956 struct list
*assemblies
;
5959 typedef struct tagASSEMBLY_NAME
5967 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
5969 ASSEMBLY_NAME
*asmname
= param
;
5970 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
5971 LPWSTR val
= msi_dup_record_field(rec
, 3);
5973 static const WCHAR Name
[] = {'N','a','m','e',0};
5974 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
5975 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
5976 static const WCHAR PublicKeyToken
[] = {
5977 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5979 if (!strcmpiW(name
, Name
))
5980 asmname
->name
= val
;
5981 else if (!strcmpiW(name
, Version
))
5982 asmname
->version
= val
;
5983 else if (!strcmpiW(name
, Culture
))
5984 asmname
->culture
= val
;
5985 else if (!strcmpiW(name
, PublicKeyToken
))
5986 asmname
->pubkeytoken
= val
;
5990 return ERROR_SUCCESS
;
5993 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
5997 *size
= lstrlenW(append
) + 1;
5998 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
5999 lstrcpyW(*str
, append
);
6003 (*size
) += lstrlenW(append
);
6004 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6005 lstrcatW(*str
, append
);
6008 static BOOL
check_assembly_installed(MSIDATABASE
*db
, IAssemblyCache
*cache
,
6011 ASSEMBLY_INFO asminfo
;
6019 static const WCHAR separator
[] = {',',' ',0};
6020 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
6021 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
6022 static const WCHAR PublicKeyToken
[] = {
6023 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6024 static const WCHAR query
[] = {
6025 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6026 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6027 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6028 '=','\'','%','s','\'',0};
6032 ZeroMemory(&name
, sizeof(ASSEMBLY_NAME
));
6033 ZeroMemory(&asminfo
, sizeof(ASSEMBLY_INFO
));
6035 r
= MSI_OpenQuery(db
, &view
, query
, comp
->Component
);
6036 if (r
!= ERROR_SUCCESS
)
6037 return ERROR_SUCCESS
;
6039 MSI_IterateRecords(view
, NULL
, parse_assembly_name
, &name
);
6040 msiobj_release(&view
->hdr
);
6044 ERR("No assembly name specified!\n");
6048 append_str(&disp
, &size
, name
.name
);
6052 append_str(&disp
, &size
, separator
);
6053 append_str(&disp
, &size
, Version
);
6054 append_str(&disp
, &size
, name
.version
);
6059 append_str(&disp
, &size
, separator
);
6060 append_str(&disp
, &size
, Culture
);
6061 append_str(&disp
, &size
, name
.culture
);
6064 if (name
.pubkeytoken
)
6066 append_str(&disp
, &size
, separator
);
6067 append_str(&disp
, &size
, PublicKeyToken
);
6068 append_str(&disp
, &size
, name
.pubkeytoken
);
6071 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6072 IAssemblyCache_QueryAssemblyInfo(cache
, QUERYASMINFO_FLAG_VALIDATE
,
6074 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6078 msi_free(name
.name
);
6079 msi_free(name
.version
);
6080 msi_free(name
.culture
);
6081 msi_free(name
.pubkeytoken
);
6086 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6088 ASSEMBLY_LIST
*list
= param
;
6089 MSIASSEMBLY
*assembly
;
6091 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6093 return ERROR_OUTOFMEMORY
;
6095 assembly
->component
= get_loaded_component(list
->package
, MSI_RecordGetString(rec
, 1));
6097 if (!assembly
->component
|| !assembly
->component
->Enabled
||
6098 !(assembly
->component
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
6100 TRACE("Component not set for install, not publishing assembly\n");
6102 return ERROR_SUCCESS
;
6105 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6106 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6108 if (!assembly
->file
)
6110 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6111 return ERROR_FUNCTION_FAILED
;
6114 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6115 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6116 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6118 if (assembly
->application
)
6121 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6123 /* FIXME: we should probably check the manifest file here */
6125 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6126 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6128 assembly
->installed
= TRUE
;
6132 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6134 assembly
->component
);
6136 list_add_head(list
->assemblies
, &assembly
->entry
);
6137 return ERROR_SUCCESS
;
6140 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6142 IAssemblyCache
*cache
= NULL
;
6148 static const WCHAR query
[] =
6149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6150 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6152 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6153 if (r
!= ERROR_SUCCESS
)
6154 return ERROR_SUCCESS
;
6156 hr
= pCreateAssemblyCache(&cache
, 0);
6158 return ERROR_FUNCTION_FAILED
;
6160 list
.package
= package
;
6162 list
.assemblies
= assemblies
;
6164 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6165 msiobj_release(&view
->hdr
);
6167 IAssemblyCache_Release(cache
);
6172 static void free_assemblies(struct list
*assemblies
)
6174 struct list
*item
, *cursor
;
6176 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6178 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6180 list_remove(&assembly
->entry
);
6181 msi_free(assembly
->application
);
6182 msi_free(assembly
->manifest
);
6187 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6189 MSIASSEMBLY
*assembly
;
6191 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6193 if (!lstrcmpW(assembly
->file
->File
, file
))
6203 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6204 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6206 MSIASSEMBLY
*assembly
;
6207 WCHAR temppath
[MAX_PATH
];
6208 struct list
*assemblies
= user
;
6211 if (!find_assembly(assemblies
, file
, &assembly
))
6214 GetTempPathW(MAX_PATH
, temppath
);
6215 PathAddBackslashW(temppath
);
6216 lstrcatW(temppath
, assembly
->file
->FileName
);
6218 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6220 if (assembly
->installed
)
6223 *path
= strdupW(temppath
);
6224 *attrs
= assembly
->file
->Attributes
;
6226 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6228 assembly
->installed
= TRUE
;
6230 r
= install_assembly(package
, assembly
, temppath
);
6231 if (r
!= ERROR_SUCCESS
)
6232 ERR("Failed to install assembly\n");
6238 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6241 struct list assemblies
= LIST_INIT(assemblies
);
6242 MSIASSEMBLY
*assembly
;
6245 if (!init_functionpointers() || !pCreateAssemblyCache
)
6246 return ERROR_FUNCTION_FAILED
;
6248 r
= load_assemblies(package
, &assemblies
);
6249 if (r
!= ERROR_SUCCESS
)
6252 if (list_empty(&assemblies
))
6255 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6258 r
= ERROR_OUTOFMEMORY
;
6262 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6264 if (assembly
->installed
&& !mi
->is_continuous
)
6267 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6268 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6272 r
= ready_media(package
, assembly
->file
, mi
);
6273 if (r
!= ERROR_SUCCESS
)
6275 ERR("Failed to ready media\n");
6280 data
.package
= package
;
6281 data
.cb
= installassembly_cb
;
6282 data
.user
= &assemblies
;
6284 if (assembly
->file
->IsCompressed
&&
6285 !msi_cabextract(package
, mi
, &data
))
6287 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6288 r
= ERROR_FUNCTION_FAILED
;
6293 if (!assembly
->file
->IsCompressed
)
6295 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6297 r
= install_assembly(package
, assembly
, source
);
6298 if (r
!= ERROR_SUCCESS
)
6299 ERR("Failed to install assembly\n");
6304 /* FIXME: write Installer assembly reg values */
6308 free_assemblies(&assemblies
);
6312 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6314 LPWSTR key
, template, id
;
6315 UINT r
= ERROR_SUCCESS
;
6317 id
= msi_dup_property( package
, szProductID
);
6321 return ERROR_SUCCESS
;
6323 template = msi_dup_property( package
, szPIDTemplate
);
6324 key
= msi_dup_property( package
, szPIDKEY
);
6326 if (key
&& template)
6328 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6329 r
= MSI_SetPropertyW( package
, szProductID
, key
);
6331 msi_free( template );
6336 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6339 package
->need_reboot
= 1;
6340 return ERROR_SUCCESS
;
6343 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6345 TRACE("%p\n", package
);
6346 return ERROR_SUCCESS
;
6349 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6351 FIXME("%p\n", package
);
6352 return ERROR_SUCCESS
;
6355 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6357 FIXME("%p\n", package
);
6358 return ERROR_SUCCESS
;
6361 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6362 LPCSTR action
, LPCWSTR table
)
6364 static const WCHAR query
[] = {
6365 'S','E','L','E','C','T',' ','*',' ',
6366 'F','R','O','M',' ','`','%','s','`',0 };
6367 MSIQUERY
*view
= NULL
;
6371 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6372 if (r
== ERROR_SUCCESS
)
6374 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6375 msiobj_release(&view
->hdr
);
6379 FIXME("%s -> %u ignored %s table values\n",
6380 action
, count
, debugstr_w(table
));
6382 return ERROR_SUCCESS
;
6385 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
6387 static const WCHAR table
[] =
6388 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6389 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
6392 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6394 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6395 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6398 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6400 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6401 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6404 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6406 static const WCHAR table
[] = {
6407 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6408 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6411 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6413 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6414 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6417 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6419 static const WCHAR table
[] = {
6420 'E','n','v','i','r','o','n','m','e','n','t',0 };
6421 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
6424 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6426 static const WCHAR table
[] = {
6427 'M','s','i','A','s','s','e','m','b','l','y',0 };
6428 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6431 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6433 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6434 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6437 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6439 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6440 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6443 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6445 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6446 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6449 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6451 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6452 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6455 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
6457 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6458 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
6461 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6463 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6464 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6467 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
6469 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6470 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
6473 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
6475 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
6476 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
6479 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6481 static const WCHAR table
[] = { 'D','i','r','e','c','t','o','r','y',0 };
6482 return msi_unimplemented_action_stub( package
, "SetODBCFolders", table
);
6485 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6487 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6488 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
6491 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6493 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6494 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6497 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6499 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6500 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6503 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6505 static const WCHAR table
[] = { 'M','I','M','E',0 };
6506 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6509 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6511 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6512 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6515 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6519 const WCHAR
*action
;
6520 UINT (*handler
)(MSIPACKAGE
*);
6524 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6525 { szAppSearch
, ACTION_AppSearch
},
6526 { szBindImage
, ACTION_BindImage
},
6527 { szCCPSearch
, ACTION_CCPSearch
},
6528 { szCostFinalize
, ACTION_CostFinalize
},
6529 { szCostInitialize
, ACTION_CostInitialize
},
6530 { szCreateFolders
, ACTION_CreateFolders
},
6531 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6532 { szDeleteServices
, ACTION_DeleteServices
},
6533 { szDisableRollback
, ACTION_DisableRollback
},
6534 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6535 { szExecuteAction
, ACTION_ExecuteAction
},
6536 { szFileCost
, ACTION_FileCost
},
6537 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6538 { szForceReboot
, ACTION_ForceReboot
},
6539 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
6540 { szInstallExecute
, ACTION_InstallExecute
},
6541 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6542 { szInstallFiles
, ACTION_InstallFiles
},
6543 { szInstallFinalize
, ACTION_InstallFinalize
},
6544 { szInstallInitialize
, ACTION_InstallInitialize
},
6545 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6546 { szInstallValidate
, ACTION_InstallValidate
},
6547 { szIsolateComponents
, ACTION_IsolateComponents
},
6548 { szLaunchConditions
, ACTION_LaunchConditions
},
6549 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6550 { szMoveFiles
, ACTION_MoveFiles
},
6551 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6552 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6553 { szInstallODBC
, ACTION_InstallODBC
},
6554 { szInstallServices
, ACTION_InstallServices
},
6555 { szPatchFiles
, ACTION_PatchFiles
},
6556 { szProcessComponents
, ACTION_ProcessComponents
},
6557 { szPublishComponents
, ACTION_PublishComponents
},
6558 { szPublishFeatures
, ACTION_PublishFeatures
},
6559 { szPublishProduct
, ACTION_PublishProduct
},
6560 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6561 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6562 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6563 { szRegisterFonts
, ACTION_RegisterFonts
},
6564 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6565 { szRegisterProduct
, ACTION_RegisterProduct
},
6566 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6567 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6568 { szRegisterUser
, ACTION_RegisterUser
},
6569 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6570 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6571 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6572 { szRemoveFiles
, ACTION_RemoveFiles
},
6573 { szRemoveFolders
, ACTION_RemoveFolders
},
6574 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6575 { szRemoveODBC
, ACTION_RemoveODBC
},
6576 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6577 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6578 { szResolveSource
, ACTION_ResolveSource
},
6579 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6580 { szScheduleReboot
, ACTION_ScheduleReboot
},
6581 { szSelfRegModules
, ACTION_SelfRegModules
},
6582 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6583 { szSetODBCFolders
, ACTION_SetODBCFolders
},
6584 { szStartServices
, ACTION_StartServices
},
6585 { szStopServices
, ACTION_StopServices
},
6586 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6587 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6588 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6589 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6590 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6591 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6592 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6593 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6594 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6595 { szValidateProductID
, ACTION_ValidateProductID
},
6596 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6597 { szWriteIniValues
, ACTION_WriteIniValues
},
6598 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6602 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6603 UINT
* rc
, BOOL force
)
6609 if (!run
&& !package
->script
->CurrentlyScripting
)
6614 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6615 strcmpW(action
,szInstallExecute
) == 0 ||
6616 strcmpW(action
,szInstallExecuteAgain
) == 0)
6621 while (StandardActions
[i
].action
!= NULL
)
6623 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6627 ui_actioninfo(package
, action
, TRUE
, 0);
6628 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6629 ui_actioninfo(package
, action
, FALSE
, *rc
);
6633 ui_actionstart(package
, action
);
6634 if (StandardActions
[i
].handler
)
6636 *rc
= StandardActions
[i
].handler(package
);
6640 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6641 *rc
= ERROR_SUCCESS
;
6652 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
6654 UINT rc
= ERROR_SUCCESS
;
6657 TRACE("Performing action (%s)\n", debugstr_w(action
));
6659 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
6662 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
6666 WARN("unhandled msi action %s\n", debugstr_w(action
));
6667 rc
= ERROR_FUNCTION_NOT_CALLED
;
6673 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
6675 UINT rc
= ERROR_SUCCESS
;
6676 BOOL handled
= FALSE
;
6678 TRACE("Performing action (%s)\n", debugstr_w(action
));
6680 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
6683 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
6685 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
6690 WARN("unhandled msi action %s\n", debugstr_w(action
));
6691 rc
= ERROR_FUNCTION_NOT_CALLED
;
6697 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
6699 UINT rc
= ERROR_SUCCESS
;
6702 static const WCHAR ExecSeqQuery
[] =
6703 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6704 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6705 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6706 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6707 static const WCHAR UISeqQuery
[] =
6708 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6709 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6710 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6711 ' ', '=',' ','%','i',0};
6713 if (needs_ui_sequence(package
))
6714 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
6716 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
6720 LPCWSTR action
, cond
;
6722 TRACE("Running the actions\n");
6724 /* check conditions */
6725 cond
= MSI_RecordGetString(row
, 2);
6727 /* this is a hack to skip errors in the condition code */
6728 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
6730 msiobj_release(&row
->hdr
);
6731 return ERROR_SUCCESS
;
6734 action
= MSI_RecordGetString(row
, 1);
6737 ERR("failed to fetch action\n");
6738 msiobj_release(&row
->hdr
);
6739 return ERROR_FUNCTION_FAILED
;
6742 if (needs_ui_sequence(package
))
6743 rc
= ACTION_PerformUIAction(package
, action
, -1);
6745 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
6747 msiobj_release(&row
->hdr
);
6753 /****************************************************
6754 * TOP level entry points
6755 *****************************************************/
6757 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
6758 LPCWSTR szCommandLine
)
6763 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
6764 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
6766 MSI_SetPropertyW(package
, szAction
, szInstall
);
6768 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
6775 dir
= strdupW(szPackagePath
);
6776 p
= strrchrW(dir
, '\\');
6780 file
= szPackagePath
+ (p
- dir
);
6785 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
6786 GetCurrentDirectoryW(MAX_PATH
, dir
);
6787 lstrcatW(dir
, szBackSlash
);
6788 file
= szPackagePath
;
6791 msi_free( package
->PackagePath
);
6792 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
6793 if (!package
->PackagePath
)
6796 return ERROR_OUTOFMEMORY
;
6799 lstrcpyW(package
->PackagePath
, dir
);
6800 lstrcatW(package
->PackagePath
, file
);
6803 msi_set_sourcedir_props(package
, FALSE
);
6806 msi_parse_command_line( package
, szCommandLine
, FALSE
);
6808 msi_apply_transforms( package
);
6809 msi_apply_patches( package
);
6811 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
6813 TRACE("setting reinstall property\n");
6814 MSI_SetPropertyW( package
, szReinstall
, szAll
);
6817 /* properties may have been added by a transform */
6818 msi_clone_properties( package
);
6819 msi_set_context( package
);
6821 if (needs_ui_sequence( package
))
6823 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
6824 rc
= ACTION_ProcessUISequence(package
);
6825 ui_exists
= ui_sequence_exists(package
);
6826 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
6828 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
6829 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
6833 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
6835 package
->script
->CurrentlyScripting
= FALSE
;
6837 /* process the ending type action */
6838 if (rc
== ERROR_SUCCESS
)
6839 ACTION_PerformActionSequence(package
, -1);
6840 else if (rc
== ERROR_INSTALL_USEREXIT
)
6841 ACTION_PerformActionSequence(package
, -2);
6842 else if (rc
== ERROR_INSTALL_SUSPEND
)
6843 ACTION_PerformActionSequence(package
, -4);
6845 ACTION_PerformActionSequence(package
, -3);
6847 /* finish up running custom actions */
6848 ACTION_FinishCustomActions(package
);
6850 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
6851 return ERROR_SUCCESS_REBOOT_REQUIRED
;