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
;
963 * Also we cannot enable/disable components either, so for now I am just going
964 * to do all the directories for all the components.
966 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
968 static const WCHAR ExecSeqQuery
[] =
969 {'S','E','L','E','C','T',' ',
970 '`','D','i','r','e','c','t','o','r','y','_','`',
971 ' ','F','R','O','M',' ',
972 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
976 /* create all the empty folders specified in the CreateFolder table */
977 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
978 if (rc
!= ERROR_SUCCESS
)
979 return ERROR_SUCCESS
;
981 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
982 msiobj_release(&view
->hdr
);
984 msi_create_component_directories( package
);
989 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
991 MSIPACKAGE
*package
= param
;
994 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
996 return ERROR_FUNCTION_FAILED
;
998 list_add_tail( &package
->components
, &comp
->entry
);
1000 /* fill in the data */
1001 comp
->Component
= msi_dup_record_field( row
, 1 );
1003 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1005 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1006 comp
->Directory
= msi_dup_record_field( row
, 3 );
1007 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1008 comp
->Condition
= msi_dup_record_field( row
, 5 );
1009 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1011 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1012 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1014 return ERROR_SUCCESS
;
1017 static UINT
load_all_components( MSIPACKAGE
*package
)
1019 static const WCHAR query
[] = {
1020 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1021 '`','C','o','m','p','o','n','e','n','t','`',0 };
1025 if (!list_empty(&package
->components
))
1026 return ERROR_SUCCESS
;
1028 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1029 if (r
!= ERROR_SUCCESS
)
1032 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1033 msiobj_release(&view
->hdr
);
1038 MSIPACKAGE
*package
;
1039 MSIFEATURE
*feature
;
1042 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1046 cl
= msi_alloc( sizeof (*cl
) );
1048 return ERROR_NOT_ENOUGH_MEMORY
;
1049 cl
->component
= comp
;
1050 list_add_tail( &feature
->Components
, &cl
->entry
);
1052 return ERROR_SUCCESS
;
1055 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1059 fl
= msi_alloc( sizeof(*fl
) );
1061 return ERROR_NOT_ENOUGH_MEMORY
;
1062 fl
->feature
= child
;
1063 list_add_tail( &parent
->Children
, &fl
->entry
);
1065 return ERROR_SUCCESS
;
1068 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1070 _ilfs
* ilfs
= param
;
1074 component
= MSI_RecordGetString(row
,1);
1076 /* check to see if the component is already loaded */
1077 comp
= get_loaded_component( ilfs
->package
, component
);
1080 ERR("unknown component %s\n", debugstr_w(component
));
1081 return ERROR_FUNCTION_FAILED
;
1084 add_feature_component( ilfs
->feature
, comp
);
1085 comp
->Enabled
= TRUE
;
1087 return ERROR_SUCCESS
;
1090 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1092 MSIFEATURE
*feature
;
1097 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1099 if ( !lstrcmpW( feature
->Feature
, name
) )
1106 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1108 MSIPACKAGE
* package
= param
;
1109 MSIFEATURE
* feature
;
1110 static const WCHAR Query1
[] =
1111 {'S','E','L','E','C','T',' ',
1112 '`','C','o','m','p','o','n','e','n','t','_','`',
1113 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1114 'C','o','m','p','o','n','e','n','t','s','`',' ',
1115 'W','H','E','R','E',' ',
1116 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1121 /* fill in the data */
1123 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1125 return ERROR_NOT_ENOUGH_MEMORY
;
1127 list_init( &feature
->Children
);
1128 list_init( &feature
->Components
);
1130 feature
->Feature
= msi_dup_record_field( row
, 1 );
1132 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1134 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1135 feature
->Title
= msi_dup_record_field( row
, 3 );
1136 feature
->Description
= msi_dup_record_field( row
, 4 );
1138 if (!MSI_RecordIsNull(row
,5))
1139 feature
->Display
= MSI_RecordGetInteger(row
,5);
1141 feature
->Level
= MSI_RecordGetInteger(row
,6);
1142 feature
->Directory
= msi_dup_record_field( row
, 7 );
1143 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1145 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1146 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1148 list_add_tail( &package
->features
, &feature
->entry
);
1150 /* load feature components */
1152 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1153 if (rc
!= ERROR_SUCCESS
)
1154 return ERROR_SUCCESS
;
1156 ilfs
.package
= package
;
1157 ilfs
.feature
= feature
;
1159 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1160 msiobj_release(&view
->hdr
);
1162 return ERROR_SUCCESS
;
1165 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1167 MSIPACKAGE
* package
= param
;
1168 MSIFEATURE
*parent
, *child
;
1170 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1172 return ERROR_FUNCTION_FAILED
;
1174 if (!child
->Feature_Parent
)
1175 return ERROR_SUCCESS
;
1177 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1179 return ERROR_FUNCTION_FAILED
;
1181 add_feature_child( parent
, child
);
1182 return ERROR_SUCCESS
;
1185 static UINT
load_all_features( MSIPACKAGE
*package
)
1187 static const WCHAR query
[] = {
1188 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1189 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1190 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1194 if (!list_empty(&package
->features
))
1195 return ERROR_SUCCESS
;
1197 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1198 if (r
!= ERROR_SUCCESS
)
1201 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1202 if (r
!= ERROR_SUCCESS
)
1205 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1206 msiobj_release( &view
->hdr
);
1211 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1222 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1224 static const WCHAR query
[] = {
1225 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1226 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1227 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1228 MSIQUERY
*view
= NULL
;
1229 MSIRECORD
*row
= NULL
;
1232 TRACE("%s\n", debugstr_w(file
->File
));
1234 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1235 if (r
!= ERROR_SUCCESS
)
1238 r
= MSI_ViewExecute(view
, NULL
);
1239 if (r
!= ERROR_SUCCESS
)
1242 r
= MSI_ViewFetch(view
, &row
);
1243 if (r
!= ERROR_SUCCESS
)
1246 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1247 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1248 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1249 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1250 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1253 if (view
) msiobj_release(&view
->hdr
);
1254 if (row
) msiobj_release(&row
->hdr
);
1258 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1260 MSIPACKAGE
* package
= param
;
1264 /* fill in the data */
1266 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1268 return ERROR_NOT_ENOUGH_MEMORY
;
1270 file
->File
= msi_dup_record_field( row
, 1 );
1272 component
= MSI_RecordGetString( row
, 2 );
1273 file
->Component
= get_loaded_component( package
, component
);
1275 if (!file
->Component
)
1277 WARN("Component not found: %s\n", debugstr_w(component
));
1278 msi_free(file
->File
);
1280 return ERROR_SUCCESS
;
1283 file
->FileName
= msi_dup_record_field( row
, 3 );
1284 reduce_to_longfilename( file
->FileName
);
1286 file
->ShortName
= msi_dup_record_field( row
, 3 );
1287 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1289 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1290 file
->Version
= msi_dup_record_field( row
, 5 );
1291 file
->Language
= msi_dup_record_field( row
, 6 );
1292 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1293 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1295 file
->state
= msifs_invalid
;
1297 /* if the compressed bits are not set in the file attributes,
1298 * then read the information from the package word count property
1300 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1302 file
->IsCompressed
= FALSE
;
1304 else if (file
->Attributes
&
1305 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1307 file
->IsCompressed
= TRUE
;
1309 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1311 file
->IsCompressed
= FALSE
;
1315 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1318 load_file_hash(package
, file
);
1320 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1322 list_add_tail( &package
->files
, &file
->entry
);
1324 return ERROR_SUCCESS
;
1327 static UINT
load_all_files(MSIPACKAGE
*package
)
1331 static const WCHAR Query
[] =
1332 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1333 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1334 '`','S','e','q','u','e','n','c','e','`', 0};
1336 if (!list_empty(&package
->files
))
1337 return ERROR_SUCCESS
;
1339 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1340 if (rc
!= ERROR_SUCCESS
)
1341 return ERROR_SUCCESS
;
1343 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1344 msiobj_release(&view
->hdr
);
1346 return ERROR_SUCCESS
;
1349 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1351 MSIPACKAGE
*package
= param
;
1352 static WCHAR szEmpty
[] = { 0 };
1353 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1356 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1358 return ERROR_NOT_ENOUGH_MEMORY
;
1360 folder
->Directory
= msi_dup_record_field( row
, 1 );
1362 TRACE("%s\n", debugstr_w(folder
->Directory
));
1364 p
= msi_dup_record_field(row
, 3);
1366 /* split src and target dir */
1368 src_short
= folder_split_path( p
, ':' );
1370 /* split the long and short paths */
1371 tgt_long
= folder_split_path( tgt_short
, '|' );
1372 src_long
= folder_split_path( src_short
, '|' );
1374 /* check for no-op dirs */
1375 if (!lstrcmpW(szDot
, tgt_short
))
1376 tgt_short
= szEmpty
;
1377 if (!lstrcmpW(szDot
, src_short
))
1378 src_short
= szEmpty
;
1381 tgt_long
= tgt_short
;
1384 src_short
= tgt_short
;
1385 src_long
= tgt_long
;
1389 src_long
= src_short
;
1391 /* FIXME: use the target short path too */
1392 folder
->TargetDefault
= strdupW(tgt_long
);
1393 folder
->SourceShortPath
= strdupW(src_short
);
1394 folder
->SourceLongPath
= strdupW(src_long
);
1397 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1398 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1399 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1401 folder
->Parent
= msi_dup_record_field( row
, 2 );
1403 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1405 list_add_tail( &package
->folders
, &folder
->entry
);
1407 TRACE("returning %p\n", folder
);
1409 return ERROR_SUCCESS
;
1412 static UINT
load_all_folders( MSIPACKAGE
*package
)
1414 static const WCHAR query
[] = {
1415 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1416 '`','D','i','r','e','c','t','o','r','y','`',0 };
1420 if (!list_empty(&package
->folders
))
1421 return ERROR_SUCCESS
;
1423 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1424 if (r
!= ERROR_SUCCESS
)
1427 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1428 msiobj_release(&view
->hdr
);
1433 * I am not doing any of the costing functionality yet.
1434 * Mostly looking at doing the Component and Feature loading
1436 * The native MSI does A LOT of modification to tables here. Mostly adding
1437 * a lot of temporary columns to the Feature and Component tables.
1439 * note: Native msi also tracks the short filename. But I am only going to
1440 * track the long ones. Also looking at this directory table
1441 * it appears that the directory table does not get the parents
1442 * resolved base on property only based on their entries in the
1445 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1447 static const WCHAR szCosting
[] =
1448 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1450 MSI_SetPropertyW(package
, szCosting
, szZero
);
1451 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1453 load_all_folders( package
);
1454 load_all_components( package
);
1455 load_all_features( package
);
1456 load_all_files( package
);
1458 return ERROR_SUCCESS
;
1461 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1464 UINT rc
= ERROR_SUCCESS
;
1466 TRACE("Executing Script %i\n",script
);
1468 if (!package
->script
)
1470 ERR("no script!\n");
1471 return ERROR_FUNCTION_FAILED
;
1474 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1477 action
= package
->script
->Actions
[script
][i
];
1478 ui_actionstart(package
, action
);
1479 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1480 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1481 if (rc
!= ERROR_SUCCESS
)
1484 msi_free_action_script(package
, script
);
1488 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1490 return ERROR_SUCCESS
;
1493 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1499 state
= MsiQueryProductStateW(package
->ProductCode
);
1501 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1503 if (!comp
->ComponentId
)
1506 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1507 comp
->Installed
= INSTALLSTATE_ABSENT
;
1510 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1511 package
->Context
, comp
->ComponentId
,
1513 if (r
!= ERROR_SUCCESS
)
1514 comp
->Installed
= INSTALLSTATE_ABSENT
;
1519 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1521 MSIFEATURE
*feature
;
1524 state
= MsiQueryProductStateW(package
->ProductCode
);
1526 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1528 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1529 feature
->Installed
= INSTALLSTATE_ABSENT
;
1532 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1538 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1539 LPCWSTR property
, INSTALLSTATE state
)
1542 MSIFEATURE
*feature
;
1544 override
= msi_dup_property( package
, property
);
1548 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1550 if (lstrcmpW(property
, szRemove
) &&
1551 (feature
->Level
<= 0 || feature
->Level
> level
))
1554 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1556 if (strcmpiW(override
, szAll
)==0)
1557 msi_feature_set_state(package
, feature
, state
);
1560 LPWSTR ptr
= override
;
1561 LPWSTR ptr2
= strchrW(override
,',');
1565 int len
= ptr2
- ptr
;
1567 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1568 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1570 msi_feature_set_state(package
, feature
, state
);
1576 ptr2
= strchrW(ptr
,',');
1588 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1591 static const WCHAR szlevel
[] =
1592 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1593 static const WCHAR szAddLocal
[] =
1594 {'A','D','D','L','O','C','A','L',0};
1595 static const WCHAR szAddSource
[] =
1596 {'A','D','D','S','O','U','R','C','E',0};
1597 static const WCHAR szAdvertise
[] =
1598 {'A','D','V','E','R','T','I','S','E',0};
1599 BOOL override
= FALSE
;
1600 MSICOMPONENT
* component
;
1601 MSIFEATURE
*feature
;
1604 /* I do not know if this is where it should happen.. but */
1606 TRACE("Checking Install Level\n");
1608 level
= msi_get_property_int(package
, szlevel
, 1);
1610 /* ok here is the _real_ rub
1611 * all these activation/deactivation things happen in order and things
1612 * later on the list override things earlier on the list.
1613 * 0) INSTALLLEVEL processing
1624 * 11) FILEADDDEFAULT
1626 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1627 * REMOVE are the big ones, since we don't handle administrative installs
1630 override
|= process_state_property(package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1631 override
|= process_state_property(package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1632 override
|= process_state_property(package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1633 override
|= process_state_property(package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1634 override
|= process_state_property(package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1638 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1640 BOOL feature_state
= ((feature
->Level
> 0) &&
1641 (feature
->Level
<= level
));
1643 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1645 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1646 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1647 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1648 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1650 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1654 /* disable child features of unselected parent features */
1655 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1659 if (feature
->Level
> 0 && feature
->Level
<= level
)
1662 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1663 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1667 MSI_SetPropertyW(package
, szPreselected
, szOne
);
1670 * now we want to enable or disable components base on feature
1673 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1677 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1678 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1680 if (!feature
->Level
)
1683 /* features with components that have compressed files are made local */
1684 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1686 if (cl
->component
->Enabled
&&
1687 cl
->component
->ForceLocalState
&&
1688 feature
->Action
== INSTALLSTATE_SOURCE
)
1690 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1695 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1697 component
= cl
->component
;
1699 if (!component
->Enabled
)
1702 switch (feature
->Action
)
1704 case INSTALLSTATE_ABSENT
:
1705 component
->anyAbsent
= 1;
1707 case INSTALLSTATE_ADVERTISED
:
1708 component
->hasAdvertiseFeature
= 1;
1710 case INSTALLSTATE_SOURCE
:
1711 component
->hasSourceFeature
= 1;
1713 case INSTALLSTATE_LOCAL
:
1714 component
->hasLocalFeature
= 1;
1716 case INSTALLSTATE_DEFAULT
:
1717 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1718 component
->hasAdvertiseFeature
= 1;
1719 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1720 component
->hasSourceFeature
= 1;
1722 component
->hasLocalFeature
= 1;
1730 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1732 /* if the component isn't enabled, leave it alone */
1733 if (!component
->Enabled
)
1736 /* check if it's local or source */
1737 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1738 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1740 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1741 !component
->ForceLocalState
)
1742 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1744 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1748 /* if any feature is local, the component must be local too */
1749 if (component
->hasLocalFeature
)
1751 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1755 if (component
->hasSourceFeature
)
1757 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1761 if (component
->hasAdvertiseFeature
)
1763 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1767 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1768 if (component
->anyAbsent
)
1769 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1772 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1774 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1776 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1777 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1780 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1781 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1785 return ERROR_SUCCESS
;
1788 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1790 MSIPACKAGE
*package
= param
;
1795 name
= MSI_RecordGetString(row
,1);
1797 f
= get_loaded_folder(package
, name
);
1798 if (!f
) return ERROR_SUCCESS
;
1800 /* reset the ResolvedTarget */
1801 msi_free(f
->ResolvedTarget
);
1802 f
->ResolvedTarget
= NULL
;
1804 /* This helper function now does ALL the work */
1805 TRACE("Dir %s ...\n",debugstr_w(name
));
1806 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1807 TRACE("resolves to %s\n",debugstr_w(path
));
1810 return ERROR_SUCCESS
;
1813 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1815 MSIPACKAGE
*package
= param
;
1817 MSIFEATURE
*feature
;
1819 name
= MSI_RecordGetString( row
, 1 );
1821 feature
= get_loaded_feature( package
, name
);
1823 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1827 Condition
= MSI_RecordGetString(row
,3);
1829 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1831 int level
= MSI_RecordGetInteger(row
,2);
1832 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1833 feature
->Level
= level
;
1836 return ERROR_SUCCESS
;
1839 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1841 static const WCHAR name_fmt
[] =
1842 {'%','u','.','%','u','.','%','u','.','%','u',0};
1843 static const WCHAR name
[] = {'\\',0};
1844 VS_FIXEDFILEINFO
*lpVer
;
1845 WCHAR filever
[0x100];
1851 TRACE("%s\n", debugstr_w(filename
));
1853 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1857 version
= msi_alloc( versize
);
1858 GetFileVersionInfoW( filename
, 0, versize
, version
);
1860 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1862 msi_free( version
);
1866 sprintfW( filever
, name_fmt
,
1867 HIWORD(lpVer
->dwFileVersionMS
),
1868 LOWORD(lpVer
->dwFileVersionMS
),
1869 HIWORD(lpVer
->dwFileVersionLS
),
1870 LOWORD(lpVer
->dwFileVersionLS
));
1872 msi_free( version
);
1874 return strdupW( filever
);
1877 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1879 LPWSTR file_version
;
1882 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1884 MSICOMPONENT
* comp
= file
->Component
;
1890 if (file
->IsCompressed
)
1891 comp
->ForceLocalState
= TRUE
;
1893 /* calculate target */
1894 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
1896 msi_free(file
->TargetPath
);
1898 TRACE("file %s is named %s\n",
1899 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
1901 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1905 TRACE("file %s resolves to %s\n",
1906 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
1908 /* don't check files of components that aren't installed */
1909 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
1910 comp
->Installed
== INSTALLSTATE_ABSENT
)
1912 file
->state
= msifs_missing
; /* assume files are missing */
1916 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1918 file
->state
= msifs_missing
;
1919 comp
->Cost
+= file
->FileSize
;
1923 if (file
->Version
&&
1924 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
1926 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1927 debugstr_w(file_version
));
1928 /* FIXME: seems like a bad way to compare version numbers */
1929 if (lstrcmpiW(file_version
, file
->Version
)<0)
1931 file
->state
= msifs_overwrite
;
1932 comp
->Cost
+= file
->FileSize
;
1935 file
->state
= msifs_present
;
1936 msi_free( file_version
);
1939 file
->state
= msifs_present
;
1942 return ERROR_SUCCESS
;
1946 * A lot is done in this function aside from just the costing.
1947 * The costing needs to be implemented at some point but for now I am going
1948 * to focus on the directory building
1951 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1953 static const WCHAR ExecSeqQuery
[] =
1954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1955 '`','D','i','r','e','c','t','o','r','y','`',0};
1956 static const WCHAR ConditionQuery
[] =
1957 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1958 '`','C','o','n','d','i','t','i','o','n','`',0};
1959 static const WCHAR szCosting
[] =
1960 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1961 static const WCHAR szlevel
[] =
1962 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1963 static const WCHAR szOutOfDiskSpace
[] =
1964 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1970 TRACE("Building Directory properties\n");
1972 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1973 if (rc
== ERROR_SUCCESS
)
1975 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
1977 msiobj_release(&view
->hdr
);
1980 /* read components states from the registry */
1981 ACTION_GetComponentInstallStates(package
);
1982 ACTION_GetFeatureInstallStates(package
);
1984 TRACE("File calculations\n");
1985 msi_check_file_install_states( package
);
1987 TRACE("Evaluating Condition Table\n");
1989 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
1990 if (rc
== ERROR_SUCCESS
)
1992 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
1994 msiobj_release(&view
->hdr
);
1997 TRACE("Enabling or Disabling Components\n");
1998 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2000 if (MSI_EvaluateConditionW(package
, comp
->Condition
) == MSICONDITION_FALSE
)
2002 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2003 comp
->Enabled
= FALSE
;
2006 comp
->Enabled
= TRUE
;
2009 MSI_SetPropertyW(package
,szCosting
,szOne
);
2010 /* set default run level if not set */
2011 level
= msi_dup_property( package
, szlevel
);
2013 MSI_SetPropertyW(package
,szlevel
, szOne
);
2016 /* FIXME: check volume disk space */
2017 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2019 return MSI_SetFeatureStates(package
);
2022 /* OK this value is "interpreted" and then formatted based on the
2023 first few characters */
2024 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2029 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2035 LPWSTR deformated
= NULL
;
2038 deformat_string(package
, &value
[2], &deformated
);
2040 /* binary value type */
2044 *size
= (strlenW(ptr
)/2)+1;
2046 *size
= strlenW(ptr
)/2;
2048 data
= msi_alloc(*size
);
2054 /* if uneven pad with a zero in front */
2060 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2062 TRACE("Uneven byte count\n");
2070 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2073 msi_free(deformated
);
2075 TRACE("Data %i bytes(%i)\n",*size
,count
);
2082 deformat_string(package
, &value
[1], &deformated
);
2085 *size
= sizeof(DWORD
);
2086 data
= msi_alloc(*size
);
2092 if ( (*p
< '0') || (*p
> '9') )
2098 if (deformated
[0] == '-')
2101 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2103 msi_free(deformated
);
2108 static const WCHAR szMulti
[] = {'[','~',']',0};
2117 *type
=REG_EXPAND_SZ
;
2125 if (strstrW(value
,szMulti
))
2126 *type
= REG_MULTI_SZ
;
2128 /* remove initial delimiter */
2129 if (!strncmpW(value
, szMulti
, 3))
2132 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2134 /* add double NULL terminator */
2135 if (*type
== REG_MULTI_SZ
)
2137 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2138 data
= msi_realloc_zero(data
, *size
);
2144 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2146 MSIPACKAGE
*package
= param
;
2147 static const WCHAR szHCR
[] =
2148 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2149 'R','O','O','T','\\',0};
2150 static const WCHAR szHCU
[] =
2151 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2152 'U','S','E','R','\\',0};
2153 static const WCHAR szHLM
[] =
2154 {'H','K','E','Y','_','L','O','C','A','L','_',
2155 'M','A','C','H','I','N','E','\\',0};
2156 static const WCHAR szHU
[] =
2157 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2159 LPSTR value_data
= NULL
;
2160 HKEY root_key
, hkey
;
2163 LPCWSTR szRoot
, component
, name
, key
, value
;
2168 BOOL check_first
= FALSE
;
2171 ui_progress(package
,2,0,0,0);
2178 component
= MSI_RecordGetString(row
, 6);
2179 comp
= get_loaded_component(package
,component
);
2181 return ERROR_SUCCESS
;
2183 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2185 TRACE("Skipping write due to disabled component %s\n",
2186 debugstr_w(component
));
2188 comp
->Action
= comp
->Installed
;
2190 return ERROR_SUCCESS
;
2193 comp
->Action
= INSTALLSTATE_LOCAL
;
2195 name
= MSI_RecordGetString(row
, 4);
2196 if( MSI_RecordIsNull(row
,5) && name
)
2198 /* null values can have special meanings */
2199 if (name
[0]=='-' && name
[1] == 0)
2200 return ERROR_SUCCESS
;
2201 else if ((name
[0]=='+' && name
[1] == 0) ||
2202 (name
[0] == '*' && name
[1] == 0))
2207 root
= MSI_RecordGetInteger(row
,2);
2208 key
= MSI_RecordGetString(row
, 3);
2210 /* get the root key */
2215 LPWSTR all_users
= msi_dup_property( package
, szAllUsers
);
2216 if (all_users
&& all_users
[0] == '1')
2218 root_key
= HKEY_LOCAL_MACHINE
;
2223 root_key
= HKEY_CURRENT_USER
;
2226 msi_free(all_users
);
2229 case 0: root_key
= HKEY_CLASSES_ROOT
;
2232 case 1: root_key
= HKEY_CURRENT_USER
;
2235 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2238 case 3: root_key
= HKEY_USERS
;
2242 ERR("Unknown root %i\n",root
);
2248 return ERROR_SUCCESS
;
2250 deformat_string(package
, key
, &deformated
);
2251 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2252 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2253 strcpyW(uikey
,szRoot
);
2254 strcatW(uikey
,deformated
);
2256 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2258 ERR("Could not create key %s\n",debugstr_w(deformated
));
2259 msi_free(deformated
);
2261 return ERROR_SUCCESS
;
2263 msi_free(deformated
);
2265 value
= MSI_RecordGetString(row
,5);
2267 value_data
= parse_value(package
, value
, &type
, &size
);
2270 value_data
= (LPSTR
)strdupW(szEmpty
);
2271 size
= sizeof(szEmpty
);
2275 deformat_string(package
, name
, &deformated
);
2279 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2281 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2286 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2287 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2289 TRACE("value %s of %s checked already exists\n",
2290 debugstr_w(deformated
), debugstr_w(uikey
));
2294 TRACE("Checked and setting value %s of %s\n",
2295 debugstr_w(deformated
), debugstr_w(uikey
));
2296 if (deformated
|| size
)
2297 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2302 uirow
= MSI_CreateRecord(3);
2303 MSI_RecordSetStringW(uirow
,2,deformated
);
2304 MSI_RecordSetStringW(uirow
,1,uikey
);
2307 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2309 MSI_RecordSetStringW(uirow
,3,value
);
2311 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2312 msiobj_release( &uirow
->hdr
);
2314 msi_free(value_data
);
2315 msi_free(deformated
);
2318 return ERROR_SUCCESS
;
2321 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2325 static const WCHAR ExecSeqQuery
[] =
2326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2327 '`','R','e','g','i','s','t','r','y','`',0 };
2329 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2330 if (rc
!= ERROR_SUCCESS
)
2331 return ERROR_SUCCESS
;
2333 /* increment progress bar each time action data is sent */
2334 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2336 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2338 msiobj_release(&view
->hdr
);
2342 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2344 package
->script
->CurrentlyScripting
= TRUE
;
2346 return ERROR_SUCCESS
;
2350 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2355 static const WCHAR q1
[]=
2356 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2357 '`','R','e','g','i','s','t','r','y','`',0};
2360 MSIFEATURE
*feature
;
2363 TRACE("InstallValidate\n");
2365 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2366 if (rc
== ERROR_SUCCESS
)
2368 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2369 msiobj_release( &view
->hdr
);
2370 total
+= progress
* REG_PROGRESS_VALUE
;
2373 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2374 total
+= COMPONENT_PROGRESS_VALUE
;
2376 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2377 total
+= file
->FileSize
;
2379 ui_progress(package
,0,total
,0,0);
2381 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2383 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2384 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2385 feature
->ActionRequest
);
2388 return ERROR_SUCCESS
;
2391 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2393 MSIPACKAGE
* package
= param
;
2394 LPCWSTR cond
= NULL
;
2395 LPCWSTR message
= NULL
;
2398 static const WCHAR title
[]=
2399 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2401 cond
= MSI_RecordGetString(row
,1);
2403 r
= MSI_EvaluateConditionW(package
,cond
);
2404 if (r
== MSICONDITION_FALSE
)
2406 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2409 message
= MSI_RecordGetString(row
,2);
2410 deformat_string(package
,message
,&deformated
);
2411 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2412 msi_free(deformated
);
2415 return ERROR_INSTALL_FAILURE
;
2418 return ERROR_SUCCESS
;
2421 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2424 MSIQUERY
* view
= NULL
;
2425 static const WCHAR ExecSeqQuery
[] =
2426 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2427 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2429 TRACE("Checking launch conditions\n");
2431 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2432 if (rc
!= ERROR_SUCCESS
)
2433 return ERROR_SUCCESS
;
2435 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2436 msiobj_release(&view
->hdr
);
2441 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2445 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2447 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2449 MSIRECORD
* row
= 0;
2451 LPWSTR deformated
,buffer
,deformated_name
;
2453 static const WCHAR ExecSeqQuery
[] =
2454 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2455 '`','R','e','g','i','s','t','r','y','`',' ',
2456 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2457 ' ','=',' ' ,'\'','%','s','\'',0 };
2458 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2459 static const WCHAR fmt2
[]=
2460 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2462 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2466 root
= MSI_RecordGetInteger(row
,2);
2467 key
= MSI_RecordGetString(row
, 3);
2468 name
= MSI_RecordGetString(row
, 4);
2469 deformat_string(package
, key
, &deformated
);
2470 deformat_string(package
, name
, &deformated_name
);
2472 len
= strlenW(deformated
) + 6;
2473 if (deformated_name
)
2474 len
+=strlenW(deformated_name
);
2476 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2478 if (deformated_name
)
2479 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2481 sprintfW(buffer
,fmt
,root
,deformated
);
2483 msi_free(deformated
);
2484 msi_free(deformated_name
);
2485 msiobj_release(&row
->hdr
);
2489 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2491 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2496 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2499 return strdupW( file
->TargetPath
);
2504 static HKEY
openSharedDLLsKey(void)
2507 static const WCHAR path
[] =
2508 {'S','o','f','t','w','a','r','e','\\',
2509 'M','i','c','r','o','s','o','f','t','\\',
2510 'W','i','n','d','o','w','s','\\',
2511 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2512 'S','h','a','r','e','d','D','L','L','s',0};
2514 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2518 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2523 DWORD sz
= sizeof(count
);
2526 hkey
= openSharedDLLsKey();
2527 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2528 if (rc
!= ERROR_SUCCESS
)
2534 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2538 hkey
= openSharedDLLsKey();
2540 msi_reg_set_val_dword( hkey
, path
, count
);
2542 RegDeleteValueW(hkey
,path
);
2548 * Return TRUE if the count should be written out and FALSE if not
2550 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2552 MSIFEATURE
*feature
;
2556 /* only refcount DLLs */
2557 if (comp
->KeyPath
== NULL
||
2558 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2559 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2563 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2564 write
= (count
> 0);
2566 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2570 /* increment counts */
2571 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2575 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2578 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2580 if ( cl
->component
== comp
)
2585 /* decrement counts */
2586 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2590 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2593 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2595 if ( cl
->component
== comp
)
2600 /* ref count all the files in the component */
2605 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2607 if (file
->Component
== comp
)
2608 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2612 /* add a count for permanent */
2613 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2616 comp
->RefCount
= count
;
2619 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2622 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2624 WCHAR squished_pc
[GUID_SIZE
];
2625 WCHAR squished_cc
[GUID_SIZE
];
2632 squash_guid(package
->ProductCode
,squished_pc
);
2633 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2635 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2639 ui_progress(package
,2,0,0,0);
2640 if (!comp
->ComponentId
)
2643 squash_guid(comp
->ComponentId
,squished_cc
);
2645 msi_free(comp
->FullKeypath
);
2646 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2648 ACTION_RefCountComponent( package
, comp
);
2650 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2651 debugstr_w(comp
->Component
),
2652 debugstr_w(squished_cc
),
2653 debugstr_w(comp
->FullKeypath
),
2656 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) ||
2657 ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
))
2659 if (!comp
->FullKeypath
)
2662 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2663 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2666 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2669 if (rc
!= ERROR_SUCCESS
)
2672 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2674 static const WCHAR szPermKey
[] =
2675 { '0','0','0','0','0','0','0','0','0','0','0','0',
2676 '0','0','0','0','0','0','0','0','0','0','0','0',
2677 '0','0','0','0','0','0','0','0',0 };
2679 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2682 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2683 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2689 WCHAR source
[MAX_PATH
];
2690 WCHAR base
[MAX_PATH
];
2693 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2694 static const WCHAR query
[] = {
2695 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2696 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2697 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2698 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2699 '`','D','i','s','k','I','d','`',0};
2701 file
= get_loaded_file(package
, comp
->KeyPath
);
2705 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2706 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2707 ptr2
= strrchrW(source
, '\\') + 1;
2708 msiobj_release(&row
->hdr
);
2710 lstrcpyW(base
, package
->PackagePath
);
2711 ptr
= strrchrW(base
, '\\');
2714 sourcepath
= resolve_file_source(package
, file
);
2715 ptr
= sourcepath
+ lstrlenW(base
);
2716 lstrcpyW(ptr2
, ptr
);
2717 msi_free(sourcepath
);
2719 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2723 else if (ACTION_VerifyComponentForAction(comp
, INSTALLSTATE_ABSENT
))
2725 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2726 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
2728 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
2732 uirow
= MSI_CreateRecord(3);
2733 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2734 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2735 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2736 ui_actiondata(package
,szProcessComponents
,uirow
);
2737 msiobj_release( &uirow
->hdr
);
2740 return ERROR_SUCCESS
;
2751 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2752 LPWSTR lpszName
, LONG_PTR lParam
)
2755 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2756 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2760 if (!IS_INTRESOURCE(lpszName
))
2762 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2766 sz
= strlenW(tl_struct
->source
)+4;
2767 sz
*= sizeof(WCHAR
);
2769 if ((INT_PTR
)lpszName
== 1)
2770 tl_struct
->path
= strdupW(tl_struct
->source
);
2773 tl_struct
->path
= msi_alloc(sz
);
2774 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2777 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2778 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2781 msi_free(tl_struct
->path
);
2782 tl_struct
->path
= NULL
;
2787 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2788 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2790 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2794 msi_free(tl_struct
->path
);
2795 tl_struct
->path
= NULL
;
2797 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2798 ITypeLib_Release(tl_struct
->ptLib
);
2803 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2805 MSIPACKAGE
* package
= param
;
2809 typelib_struct tl_struct
;
2814 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2816 component
= MSI_RecordGetString(row
,3);
2817 comp
= get_loaded_component(package
,component
);
2819 return ERROR_SUCCESS
;
2821 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2823 TRACE("Skipping typelib reg due to disabled component\n");
2825 comp
->Action
= comp
->Installed
;
2827 return ERROR_SUCCESS
;
2830 comp
->Action
= INSTALLSTATE_LOCAL
;
2832 file
= get_loaded_file( package
, comp
->KeyPath
);
2834 return ERROR_SUCCESS
;
2836 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2840 guid
= MSI_RecordGetString(row
,1);
2841 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2842 tl_struct
.source
= strdupW( file
->TargetPath
);
2843 tl_struct
.path
= NULL
;
2845 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2846 (LONG_PTR
)&tl_struct
);
2854 helpid
= MSI_RecordGetString(row
,6);
2857 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
2858 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2862 ERR("Failed to register type library %s\n",
2863 debugstr_w(tl_struct
.path
));
2866 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2868 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2871 ITypeLib_Release(tl_struct
.ptLib
);
2872 msi_free(tl_struct
.path
);
2875 ERR("Failed to load type library %s\n",
2876 debugstr_w(tl_struct
.source
));
2878 FreeLibrary(module
);
2879 msi_free(tl_struct
.source
);
2883 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
2886 ERR("Failed to load type library: %08x\n", hr
);
2887 return ERROR_FUNCTION_FAILED
;
2890 ITypeLib_Release(tlib
);
2893 return ERROR_SUCCESS
;
2896 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2899 * OK this is a bit confusing.. I am given a _Component key and I believe
2900 * that the file that is being registered as a type library is the "key file
2901 * of that component" which I interpret to mean "The file in the KeyPath of
2906 static const WCHAR Query
[] =
2907 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2908 '`','T','y','p','e','L','i','b','`',0};
2910 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2911 if (rc
!= ERROR_SUCCESS
)
2912 return ERROR_SUCCESS
;
2914 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2915 msiobj_release(&view
->hdr
);
2919 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
2921 MSIPACKAGE
*package
= param
;
2922 LPWSTR target_file
, target_folder
, filename
;
2923 LPCWSTR buffer
, extension
;
2925 static const WCHAR szlnk
[]={'.','l','n','k',0};
2926 IShellLinkW
*sl
= NULL
;
2927 IPersistFile
*pf
= NULL
;
2930 buffer
= MSI_RecordGetString(row
,4);
2931 comp
= get_loaded_component(package
,buffer
);
2933 return ERROR_SUCCESS
;
2935 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2937 TRACE("Skipping shortcut creation due to disabled component\n");
2939 comp
->Action
= comp
->Installed
;
2941 return ERROR_SUCCESS
;
2944 comp
->Action
= INSTALLSTATE_LOCAL
;
2946 ui_actiondata(package
,szCreateShortcuts
,row
);
2948 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
2949 &IID_IShellLinkW
, (LPVOID
*) &sl
);
2953 ERR("CLSID_ShellLink not available\n");
2957 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
2960 ERR("QueryInterface(IID_IPersistFile) failed\n");
2964 buffer
= MSI_RecordGetString(row
,2);
2965 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,TRUE
,NULL
);
2967 /* may be needed because of a bug somewhere else */
2968 create_full_pathW(target_folder
);
2970 filename
= msi_dup_record_field( row
, 3 );
2971 reduce_to_longfilename(filename
);
2973 extension
= strchrW(filename
,'.');
2974 if (!extension
|| strcmpiW(extension
,szlnk
))
2976 int len
= strlenW(filename
);
2977 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
2978 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
2980 target_file
= build_directory_name(2, target_folder
, filename
);
2981 msi_free(target_folder
);
2984 buffer
= MSI_RecordGetString(row
,5);
2985 if (strchrW(buffer
,'['))
2988 deformat_string(package
,buffer
,&deformated
);
2989 IShellLinkW_SetPath(sl
,deformated
);
2990 msi_free(deformated
);
2994 FIXME("poorly handled shortcut format, advertised shortcut\n");
2995 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
2998 if (!MSI_RecordIsNull(row
,6))
3001 buffer
= MSI_RecordGetString(row
,6);
3002 deformat_string(package
,buffer
,&deformated
);
3003 IShellLinkW_SetArguments(sl
,deformated
);
3004 msi_free(deformated
);
3007 if (!MSI_RecordIsNull(row
,7))
3009 buffer
= MSI_RecordGetString(row
,7);
3010 IShellLinkW_SetDescription(sl
,buffer
);
3013 if (!MSI_RecordIsNull(row
,8))
3014 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3016 if (!MSI_RecordIsNull(row
,9))
3021 buffer
= MSI_RecordGetString(row
,9);
3023 Path
= build_icon_path(package
,buffer
);
3024 index
= MSI_RecordGetInteger(row
,10);
3026 /* no value means 0 */
3027 if (index
== MSI_NULL_INTEGER
)
3030 IShellLinkW_SetIconLocation(sl
,Path
,index
);
3034 if (!MSI_RecordIsNull(row
,11))
3035 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3037 if (!MSI_RecordIsNull(row
,12))
3040 buffer
= MSI_RecordGetString(row
,12);
3041 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, TRUE
, NULL
);
3043 IShellLinkW_SetWorkingDirectory(sl
,Path
);
3047 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
3048 IPersistFile_Save(pf
,target_file
,FALSE
);
3050 msi_free(target_file
);
3054 IPersistFile_Release( pf
);
3056 IShellLinkW_Release( sl
);
3058 return ERROR_SUCCESS
;
3061 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3066 static const WCHAR Query
[] =
3067 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3068 '`','S','h','o','r','t','c','u','t','`',0};
3070 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3071 if (rc
!= ERROR_SUCCESS
)
3072 return ERROR_SUCCESS
;
3074 res
= CoInitialize( NULL
);
3076 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3077 msiobj_release(&view
->hdr
);
3085 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3087 MSIPACKAGE
* package
= param
;
3096 FileName
= MSI_RecordGetString(row
,1);
3099 ERR("Unable to get FileName\n");
3100 return ERROR_SUCCESS
;
3103 FilePath
= build_icon_path(package
,FileName
);
3105 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3107 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3108 FILE_ATTRIBUTE_NORMAL
, NULL
);
3110 if (the_file
== INVALID_HANDLE_VALUE
)
3112 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3114 return ERROR_SUCCESS
;
3121 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3122 if (rc
!= ERROR_SUCCESS
)
3124 ERR("Failed to get stream\n");
3125 CloseHandle(the_file
);
3126 DeleteFileW(FilePath
);
3129 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3130 } while (sz
== 1024);
3134 CloseHandle(the_file
);
3136 uirow
= MSI_CreateRecord(1);
3137 MSI_RecordSetStringW(uirow
,1,FileName
);
3138 ui_actiondata(package
,szPublishProduct
,uirow
);
3139 msiobj_release( &uirow
->hdr
);
3141 return ERROR_SUCCESS
;
3144 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3149 static const WCHAR query
[]= {
3150 'S','E','L','E','C','T',' ','*',' ',
3151 'F','R','O','M',' ','`','I','c','o','n','`',0};
3153 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3154 if (r
== ERROR_SUCCESS
)
3156 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3157 msiobj_release(&view
->hdr
);
3160 return ERROR_SUCCESS
;
3163 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3169 MSISOURCELISTINFO
*info
;
3171 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3172 if (r
!= ERROR_SUCCESS
)
3175 RegCloseKey(source
);
3177 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3178 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3179 package
->Context
, MSICODE_PRODUCT
,
3180 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3181 if (r
!= ERROR_SUCCESS
)
3184 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3185 package
->Context
, MSICODE_PRODUCT
,
3186 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3187 if (r
!= ERROR_SUCCESS
)
3190 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3191 package
->Context
, MSICODE_PRODUCT
,
3192 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3193 if (r
!= ERROR_SUCCESS
)
3196 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3198 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3199 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3200 info
->options
, info
->value
);
3202 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3203 info
->context
, info
->options
,
3204 info
->property
, info
->value
);
3207 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3209 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3210 disk
->context
, disk
->options
,
3211 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3214 return ERROR_SUCCESS
;
3217 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3219 MSIHANDLE hdb
, suminfo
;
3220 WCHAR guids
[MAX_PATH
];
3221 WCHAR packcode
[SQUISH_GUID_SIZE
];
3228 static const WCHAR szProductLanguage
[] =
3229 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3230 static const WCHAR szARPProductIcon
[] =
3231 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3232 static const WCHAR szProductVersion
[] =
3233 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3234 static const WCHAR szAssignment
[] =
3235 {'A','s','s','i','g','n','m','e','n','t',0};
3236 static const WCHAR szAdvertiseFlags
[] =
3237 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3238 static const WCHAR szClients
[] =
3239 {'C','l','i','e','n','t','s',0};
3240 static const WCHAR szColon
[] = {':',0};
3242 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3243 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3246 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3247 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3250 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3252 buffer
= msi_dup_property(package
, szARPProductIcon
);
3255 LPWSTR path
= build_icon_path(package
,buffer
);
3256 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3261 buffer
= msi_dup_property(package
, szProductVersion
);
3264 DWORD verdword
= msi_version_str_to_dword(buffer
);
3265 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3269 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3270 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3271 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3272 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3274 hdb
= alloc_msihandle(&package
->db
->hdr
);
3276 return ERROR_NOT_ENOUGH_MEMORY
;
3278 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3279 MsiCloseHandle(hdb
);
3280 if (r
!= ERROR_SUCCESS
)
3284 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3285 NULL
, guids
, &size
);
3286 if (r
!= ERROR_SUCCESS
)
3289 ptr
= strchrW(guids
, ';');
3291 squash_guid(guids
, packcode
);
3292 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3295 MsiCloseHandle(suminfo
);
3296 return ERROR_SUCCESS
;
3299 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3304 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3306 static const WCHAR szUpgradeCode
[] =
3307 {'U','p','g','r','a','d','e','C','o','d','e',0};
3309 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3311 return ERROR_SUCCESS
;
3313 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3315 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3316 if (r
!= ERROR_SUCCESS
)
3321 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3322 if (r
!= ERROR_SUCCESS
)
3326 squash_guid(package
->ProductCode
, squashed_pc
);
3327 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3336 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3338 MSIFEATURE
*feature
;
3340 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3342 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3349 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3351 MSIFEATURE
*feature
;
3353 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3355 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3362 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3364 WCHAR patch_squashed
[GUID_SIZE
];
3367 UINT r
= ERROR_FUNCTION_FAILED
;
3369 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3371 if (res
!= ERROR_SUCCESS
)
3372 return ERROR_FUNCTION_FAILED
;
3374 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3376 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3377 (const BYTE
*)patch_squashed
,
3378 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3379 if (res
!= ERROR_SUCCESS
)
3382 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3383 (const BYTE
*)package
->patch
->transforms
,
3384 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3385 if (res
== ERROR_SUCCESS
)
3389 RegCloseKey(patches
);
3394 * 99% of the work done here is only done for
3395 * advertised installs. However this is where the
3396 * Icon table is processed and written out
3397 * so that is what I am going to do here.
3399 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3405 /* FIXME: also need to publish if the product is in advertise mode */
3406 if (!msi_check_publish(package
))
3407 return ERROR_SUCCESS
;
3409 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3411 if (rc
!= ERROR_SUCCESS
)
3414 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3415 NULL
, &hudkey
, TRUE
);
3416 if (rc
!= ERROR_SUCCESS
)
3419 rc
= msi_publish_upgrade_code(package
);
3420 if (rc
!= ERROR_SUCCESS
)
3425 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3426 if (rc
!= ERROR_SUCCESS
)
3430 rc
= msi_publish_product_properties(package
, hukey
);
3431 if (rc
!= ERROR_SUCCESS
)
3434 rc
= msi_publish_sourcelist(package
, hukey
);
3435 if (rc
!= ERROR_SUCCESS
)
3438 rc
= msi_publish_icons(package
);
3442 RegCloseKey(hudkey
);
3447 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3449 MSIPACKAGE
*package
= param
;
3450 LPCWSTR component
, section
, key
, value
, identifier
, dirproperty
;
3451 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3452 LPWSTR folder
, filename
, fullname
= NULL
;
3453 LPCWSTR filenameptr
;
3457 static const WCHAR szWindowsFolder
[] =
3458 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3460 component
= MSI_RecordGetString(row
, 8);
3461 comp
= get_loaded_component(package
,component
);
3463 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3465 TRACE("Skipping ini file due to disabled component %s\n",
3466 debugstr_w(component
));
3468 comp
->Action
= comp
->Installed
;
3470 return ERROR_SUCCESS
;
3473 comp
->Action
= INSTALLSTATE_LOCAL
;
3475 identifier
= MSI_RecordGetString(row
,1);
3476 dirproperty
= MSI_RecordGetString(row
,3);
3477 section
= MSI_RecordGetString(row
,4);
3478 key
= MSI_RecordGetString(row
,5);
3479 value
= MSI_RecordGetString(row
,6);
3480 action
= MSI_RecordGetInteger(row
,7);
3482 deformat_string(package
,section
,&deformated_section
);
3483 deformat_string(package
,key
,&deformated_key
);
3484 deformat_string(package
,value
,&deformated_value
);
3486 filename
= msi_dup_record_field(row
, 2);
3487 if (filename
&& (filenameptr
= strchrW(filename
, '|')))
3490 filenameptr
= filename
;
3494 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, TRUE
, NULL
);
3496 folder
= msi_dup_property( package
, dirproperty
);
3499 folder
= msi_dup_property( package
, szWindowsFolder
);
3503 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3507 fullname
= build_directory_name(2, folder
, filenameptr
);
3511 TRACE("Adding value %s to section %s in %s\n",
3512 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3513 debugstr_w(fullname
));
3514 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3515 deformated_value
, fullname
);
3517 else if (action
== 1)
3520 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3521 returned
, 10, fullname
);
3522 if (returned
[0] == 0)
3524 TRACE("Adding value %s to section %s in %s\n",
3525 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3526 debugstr_w(fullname
));
3528 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3529 deformated_value
, fullname
);
3532 else if (action
== 3)
3533 FIXME("Append to existing section not yet implemented\n");
3535 uirow
= MSI_CreateRecord(4);
3536 MSI_RecordSetStringW(uirow
,1,identifier
);
3537 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3538 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3539 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3540 ui_actiondata(package
,szWriteIniValues
,uirow
);
3541 msiobj_release( &uirow
->hdr
);
3547 msi_free(deformated_key
);
3548 msi_free(deformated_value
);
3549 msi_free(deformated_section
);
3550 return ERROR_SUCCESS
;
3553 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3557 static const WCHAR ExecSeqQuery
[] =
3558 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3559 '`','I','n','i','F','i','l','e','`',0};
3561 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3562 if (rc
!= ERROR_SUCCESS
)
3564 TRACE("no IniFile table\n");
3565 return ERROR_SUCCESS
;
3568 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3569 msiobj_release(&view
->hdr
);
3573 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3575 MSIPACKAGE
*package
= param
;
3580 static const WCHAR ExeStr
[] =
3581 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3582 static const WCHAR close
[] = {'\"',0};
3584 PROCESS_INFORMATION info
;
3589 memset(&si
,0,sizeof(STARTUPINFOW
));
3591 filename
= MSI_RecordGetString(row
,1);
3592 file
= get_loaded_file( package
, filename
);
3596 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3597 return ERROR_SUCCESS
;
3600 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3602 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3603 strcpyW(FullName
,ExeStr
);
3604 strcatW( FullName
, file
->TargetPath
);
3605 strcatW(FullName
,close
);
3607 TRACE("Registering %s\n",debugstr_w(FullName
));
3608 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3613 CloseHandle(info
.hThread
);
3614 msi_dialog_check_messages(info
.hProcess
);
3615 CloseHandle(info
.hProcess
);
3621 uirow
= MSI_CreateRecord( 2 );
3622 uipath
= strdupW( file
->TargetPath
);
3623 p
= strrchrW(uipath
,'\\');
3626 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
3627 MSI_RecordSetStringW( uirow
, 2, uipath
);
3628 ui_actiondata( package
, szSelfRegModules
, uirow
);
3629 msiobj_release( &uirow
->hdr
);
3631 /* FIXME: call ui_progress? */
3633 return ERROR_SUCCESS
;
3636 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3640 static const WCHAR ExecSeqQuery
[] =
3641 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3642 '`','S','e','l','f','R','e','g','`',0};
3644 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3645 if (rc
!= ERROR_SUCCESS
)
3647 TRACE("no SelfReg table\n");
3648 return ERROR_SUCCESS
;
3651 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3652 msiobj_release(&view
->hdr
);
3654 return ERROR_SUCCESS
;
3657 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3659 MSIFEATURE
*feature
;
3662 HKEY userdata
= NULL
;
3664 if (!msi_check_publish(package
))
3665 return ERROR_SUCCESS
;
3667 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
3669 if (rc
!= ERROR_SUCCESS
)
3672 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
3674 if (rc
!= ERROR_SUCCESS
)
3677 /* here the guids are base 85 encoded */
3678 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3684 BOOL absent
= FALSE
;
3687 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3688 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3689 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3693 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3697 if (feature
->Feature_Parent
)
3698 size
+= strlenW( feature
->Feature_Parent
)+2;
3700 data
= msi_alloc(size
* sizeof(WCHAR
));
3703 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3705 MSICOMPONENT
* component
= cl
->component
;
3709 if (component
->ComponentId
)
3711 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3712 CLSIDFromString(component
->ComponentId
, &clsid
);
3713 encode_base85_guid(&clsid
,buf
);
3714 TRACE("to %s\n",debugstr_w(buf
));
3719 if (feature
->Feature_Parent
)
3721 static const WCHAR sep
[] = {'\2',0};
3723 strcatW(data
,feature
->Feature_Parent
);
3726 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
3730 if (feature
->Feature_Parent
)
3731 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3734 size
+= sizeof(WCHAR
);
3735 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3736 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
3740 size
+= 2*sizeof(WCHAR
);
3741 data
= msi_alloc(size
);
3744 if (feature
->Feature_Parent
)
3745 strcpyW( &data
[1], feature
->Feature_Parent
);
3746 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
3752 uirow
= MSI_CreateRecord( 1 );
3753 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3754 ui_actiondata( package
, szPublishFeatures
, uirow
);
3755 msiobj_release( &uirow
->hdr
);
3756 /* FIXME: call ui_progress? */
3761 RegCloseKey(userdata
);
3765 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
3770 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
3772 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
3774 if (r
== ERROR_SUCCESS
)
3776 RegDeleteValueW(hkey
, feature
->Feature
);
3780 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
3782 if (r
== ERROR_SUCCESS
)
3784 RegDeleteValueW(hkey
, feature
->Feature
);
3788 return ERROR_SUCCESS
;
3791 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
3793 MSIFEATURE
*feature
;
3795 if (!msi_check_unpublish(package
))
3796 return ERROR_SUCCESS
;
3798 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3800 msi_unpublish_feature(package
, feature
);
3803 return ERROR_SUCCESS
;
3806 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
3808 LPWSTR prop
, val
, key
;
3814 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
3815 static const WCHAR szWindowsInstaller
[] =
3816 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3817 static const WCHAR modpath_fmt
[] =
3818 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3819 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3820 static const WCHAR szModifyPath
[] =
3821 {'M','o','d','i','f','y','P','a','t','h',0};
3822 static const WCHAR szUninstallString
[] =
3823 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3824 static const WCHAR szEstimatedSize
[] =
3825 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3826 static const WCHAR szProductLanguage
[] =
3827 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3828 static const WCHAR szProductVersion
[] =
3829 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3830 static const WCHAR szProductName
[] =
3831 {'P','r','o','d','u','c','t','N','a','m','e',0};
3832 static const WCHAR szDisplayName
[] =
3833 {'D','i','s','p','l','a','y','N','a','m','e',0};
3834 static const WCHAR szDisplayVersion
[] =
3835 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3836 static const WCHAR szManufacturer
[] =
3837 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3839 static const LPCSTR propval
[] = {
3840 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3841 "ARPCONTACT", "Contact",
3842 "ARPCOMMENTS", "Comments",
3843 "ProductName", "DisplayName",
3844 "ProductVersion", "DisplayVersion",
3845 "ARPHELPLINK", "HelpLink",
3846 "ARPHELPTELEPHONE", "HelpTelephone",
3847 "ARPINSTALLLOCATION", "InstallLocation",
3848 "SourceDir", "InstallSource",
3849 "Manufacturer", "Publisher",
3850 "ARPREADME", "Readme",
3852 "ARPURLINFOABOUT", "URLInfoAbout",
3853 "ARPURLUPDATEINFO", "URLUpdateInfo",
3856 const LPCSTR
*p
= propval
;
3860 prop
= strdupAtoW(*p
++);
3861 key
= strdupAtoW(*p
++);
3862 val
= msi_dup_property(package
, prop
);
3863 msi_reg_set_val_str(hkey
, key
, val
);
3869 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
3871 size
= deformat_string(package
, modpath_fmt
, &buffer
);
3872 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
3873 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
3876 /* FIXME: Write real Estimated Size when we have it */
3877 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
3879 buffer
= msi_dup_property(package
, szProductName
);
3880 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
3883 buffer
= msi_dup_property(package
, cszSourceDir
);
3884 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
3887 buffer
= msi_dup_property(package
, szManufacturer
);
3888 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
3891 GetLocalTime(&systime
);
3892 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
3893 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
3895 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3896 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3898 buffer
= msi_dup_property(package
, szProductVersion
);
3899 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
3902 DWORD verdword
= msi_version_str_to_dword(buffer
);
3904 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3905 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
3906 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
3910 return ERROR_SUCCESS
;
3913 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
3915 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3916 LPWSTR upgrade_code
;
3921 static const WCHAR szUpgradeCode
[] = {
3922 'U','p','g','r','a','d','e','C','o','d','e',0};
3924 /* FIXME: also need to publish if the product is in advertise mode */
3925 if (!msi_check_publish(package
))
3926 return ERROR_SUCCESS
;
3928 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
3929 if (rc
!= ERROR_SUCCESS
)
3932 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
3933 NULL
, &props
, TRUE
);
3934 if (rc
!= ERROR_SUCCESS
)
3937 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
3938 msi_free( package
->db
->localfile
);
3939 package
->db
->localfile
= NULL
;
3941 rc
= msi_publish_install_properties(package
, hkey
);
3942 if (rc
!= ERROR_SUCCESS
)
3945 rc
= msi_publish_install_properties(package
, props
);
3946 if (rc
!= ERROR_SUCCESS
)
3949 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
3952 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
3953 squash_guid(package
->ProductCode
, squashed_pc
);
3954 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
3955 RegCloseKey(upgrade
);
3956 msi_free(upgrade_code
);
3962 return ERROR_SUCCESS
;
3965 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
3967 return execute_script(package
,INSTALL_SCRIPT
);
3970 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
3973 LPWSTR remove
= NULL
;
3974 LPWSTR
*features
= NULL
;
3975 BOOL full_uninstall
= TRUE
;
3976 MSIFEATURE
*feature
;
3978 static const WCHAR szUpgradeCode
[] =
3979 {'U','p','g','r','a','d','e','C','o','d','e',0};
3981 remove
= msi_dup_property(package
, szRemove
);
3983 return ERROR_SUCCESS
;
3985 features
= msi_split_string(remove
, ',');
3989 ERR("REMOVE feature list is empty!\n");
3990 return ERROR_FUNCTION_FAILED
;
3993 if (!lstrcmpW(features
[0], szAll
))
3994 full_uninstall
= TRUE
;
3997 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3999 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4000 full_uninstall
= FALSE
;
4004 if (!full_uninstall
)
4007 MSIREG_DeleteProductKey(package
->ProductCode
);
4008 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4009 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4011 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4013 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4014 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4018 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4019 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4022 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4025 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4032 return ERROR_SUCCESS
;
4035 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4039 rc
= msi_unpublish_product(package
);
4040 if (rc
!= ERROR_SUCCESS
)
4043 /* turn off scheduling */
4044 package
->script
->CurrentlyScripting
= FALSE
;
4046 /* first do the same as an InstallExecute */
4047 rc
= ACTION_InstallExecute(package
);
4048 if (rc
!= ERROR_SUCCESS
)
4051 /* then handle Commit Actions */
4052 rc
= execute_script(package
,COMMIT_SCRIPT
);
4057 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4059 static const WCHAR RunOnce
[] = {
4060 'S','o','f','t','w','a','r','e','\\',
4061 'M','i','c','r','o','s','o','f','t','\\',
4062 'W','i','n','d','o','w','s','\\',
4063 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4064 'R','u','n','O','n','c','e',0};
4065 static const WCHAR InstallRunOnce
[] = {
4066 'S','o','f','t','w','a','r','e','\\',
4067 'M','i','c','r','o','s','o','f','t','\\',
4068 'W','i','n','d','o','w','s','\\',
4069 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4070 'I','n','s','t','a','l','l','e','r','\\',
4071 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4073 static const WCHAR msiexec_fmt
[] = {
4075 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4076 '\"','%','s','\"',0};
4077 static const WCHAR install_fmt
[] = {
4078 '/','I',' ','\"','%','s','\"',' ',
4079 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4080 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4081 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4083 WCHAR squished_pc
[100];
4085 squash_guid(package
->ProductCode
,squished_pc
);
4087 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4088 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4089 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4092 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4095 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4097 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4098 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4100 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4103 return ERROR_INSTALL_SUSPEND
;
4106 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4112 * We are currently doing what should be done here in the top level Install
4113 * however for Administrative and uninstalls this step will be needed
4115 if (!package
->PackagePath
)
4116 return ERROR_SUCCESS
;
4118 msi_set_sourcedir_props(package
, TRUE
);
4120 attrib
= GetFileAttributesW(package
->db
->path
);
4121 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4127 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4128 package
->Context
, MSICODE_PRODUCT
,
4129 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4130 if (rc
== ERROR_MORE_DATA
)
4132 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4133 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4134 package
->Context
, MSICODE_PRODUCT
,
4135 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4138 prompt
= strdupW(package
->db
->path
);
4140 msg
= generate_error_string(package
,1302,1,prompt
);
4141 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4143 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4146 rc
= ERROR_INSTALL_USEREXIT
;
4149 attrib
= GetFileAttributesW(package
->db
->path
);
4155 return ERROR_SUCCESS
;
4160 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4167 static const WCHAR szPropKeys
[][80] =
4169 {'P','r','o','d','u','c','t','I','D',0},
4170 {'U','S','E','R','N','A','M','E',0},
4171 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4175 static const WCHAR szRegKeys
[][80] =
4177 {'P','r','o','d','u','c','t','I','D',0},
4178 {'R','e','g','O','w','n','e','r',0},
4179 {'R','e','g','C','o','m','p','a','n','y',0},
4183 if (msi_check_unpublish(package
))
4185 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4186 return ERROR_SUCCESS
;
4189 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4191 return ERROR_SUCCESS
;
4193 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4195 if (rc
!= ERROR_SUCCESS
)
4198 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4200 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4201 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4206 msi_free(productid
);
4209 /* FIXME: call ui_actiondata */
4215 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4219 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4220 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4225 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4227 MSIPACKAGE
*package
= param
;
4228 LPCWSTR compgroupid
=NULL
;
4229 LPCWSTR feature
=NULL
;
4230 LPCWSTR text
= NULL
;
4231 LPCWSTR qualifier
= NULL
;
4232 LPCWSTR component
= NULL
;
4233 LPWSTR advertise
= NULL
;
4234 LPWSTR output
= NULL
;
4236 UINT rc
= ERROR_SUCCESS
;
4241 component
= MSI_RecordGetString(rec
,3);
4242 comp
= get_loaded_component(package
,component
);
4244 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4245 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4246 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4248 TRACE("Skipping: Component %s not scheduled for install\n",
4249 debugstr_w(component
));
4251 return ERROR_SUCCESS
;
4254 compgroupid
= MSI_RecordGetString(rec
,1);
4255 qualifier
= MSI_RecordGetString(rec
,2);
4257 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4258 if (rc
!= ERROR_SUCCESS
)
4261 text
= MSI_RecordGetString(rec
,4);
4262 feature
= MSI_RecordGetString(rec
,5);
4264 advertise
= create_component_advertise_string(package
, comp
, feature
);
4266 sz
= strlenW(advertise
);
4269 sz
+= lstrlenW(text
);
4272 sz
*= sizeof(WCHAR
);
4274 output
= msi_alloc_zero(sz
);
4275 strcpyW(output
,advertise
);
4276 msi_free(advertise
);
4279 strcatW(output
,text
);
4281 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4288 uirow
= MSI_CreateRecord( 2 );
4289 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4290 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4291 ui_actiondata( package
, szPublishComponents
, uirow
);
4292 msiobj_release( &uirow
->hdr
);
4293 /* FIXME: call ui_progress? */
4299 * At present I am ignorning the advertised components part of this and only
4300 * focusing on the qualified component sets
4302 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4306 static const WCHAR ExecSeqQuery
[] =
4307 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4308 '`','P','u','b','l','i','s','h',
4309 'C','o','m','p','o','n','e','n','t','`',0};
4311 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4312 if (rc
!= ERROR_SUCCESS
)
4313 return ERROR_SUCCESS
;
4315 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4316 msiobj_release(&view
->hdr
);
4321 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
4323 MSIPACKAGE
*package
= param
;
4326 SC_HANDLE hscm
, service
= NULL
;
4327 LPCWSTR comp
, depends
, pass
;
4328 LPWSTR name
= NULL
, disp
= NULL
;
4329 LPCWSTR load_order
, serv_name
, key
;
4330 DWORD serv_type
, start_type
;
4333 static const WCHAR query
[] =
4334 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4335 '`','C','o','m','p','o','n','e','n','t','`',' ',
4336 'W','H','E','R','E',' ',
4337 '`','C','o','m','p','o','n','e','n','t','`',' ',
4338 '=','\'','%','s','\'',0};
4340 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
4343 ERR("Failed to open the SC Manager!\n");
4347 start_type
= MSI_RecordGetInteger(rec
, 5);
4348 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
4351 depends
= MSI_RecordGetString(rec
, 8);
4352 if (depends
&& *depends
)
4353 FIXME("Dependency list unhandled!\n");
4355 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4356 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
4357 serv_type
= MSI_RecordGetInteger(rec
, 4);
4358 err_control
= MSI_RecordGetInteger(rec
, 6);
4359 load_order
= MSI_RecordGetString(rec
, 7);
4360 serv_name
= MSI_RecordGetString(rec
, 9);
4361 pass
= MSI_RecordGetString(rec
, 10);
4362 comp
= MSI_RecordGetString(rec
, 12);
4364 /* fetch the service path */
4365 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
4368 ERR("Control query failed!\n");
4372 key
= MSI_RecordGetString(row
, 6);
4374 file
= get_loaded_file(package
, key
);
4375 msiobj_release(&row
->hdr
);
4378 ERR("Failed to load the service file\n");
4382 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
4383 start_type
, err_control
, file
->TargetPath
,
4384 load_order
, NULL
, NULL
, serv_name
, pass
);
4387 if (GetLastError() != ERROR_SERVICE_EXISTS
)
4388 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
4392 CloseServiceHandle(service
);
4393 CloseServiceHandle(hscm
);
4397 return ERROR_SUCCESS
;
4400 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4404 static const WCHAR ExecSeqQuery
[] =
4405 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4406 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4408 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4409 if (rc
!= ERROR_SUCCESS
)
4410 return ERROR_SUCCESS
;
4412 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
4413 msiobj_release(&view
->hdr
);
4418 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4419 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
4421 LPCWSTR
*vector
, *temp_vector
;
4425 static const WCHAR separator
[] = {'[','~',']',0};
4428 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
4433 vector
= msi_alloc(sizeof(LPWSTR
));
4441 vector
[*numargs
- 1] = p
;
4443 if ((q
= strstrW(p
, separator
)))
4447 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
4453 vector
= temp_vector
;
4462 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
4464 MSIPACKAGE
*package
= param
;
4466 SC_HANDLE scm
, service
= NULL
;
4467 LPCWSTR name
, *vector
= NULL
;
4469 DWORD event
, numargs
;
4470 UINT r
= ERROR_FUNCTION_FAILED
;
4472 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4473 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4474 return ERROR_SUCCESS
;
4476 name
= MSI_RecordGetString(rec
, 2);
4477 event
= MSI_RecordGetInteger(rec
, 3);
4478 args
= strdupW(MSI_RecordGetString(rec
, 4));
4480 if (!(event
& msidbServiceControlEventStart
))
4481 return ERROR_SUCCESS
;
4483 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
4486 ERR("Failed to open the service control manager\n");
4490 service
= OpenServiceW(scm
, name
, SERVICE_START
);
4493 ERR("Failed to open service %s\n", debugstr_w(name
));
4497 vector
= msi_service_args_to_vector(args
, &numargs
);
4499 if (!StartServiceW(service
, numargs
, vector
))
4501 ERR("Failed to start service %s\n", debugstr_w(name
));
4508 CloseServiceHandle(service
);
4509 CloseServiceHandle(scm
);
4516 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4521 static const WCHAR query
[] = {
4522 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4523 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4525 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4526 if (rc
!= ERROR_SUCCESS
)
4527 return ERROR_SUCCESS
;
4529 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
4530 msiobj_release(&view
->hdr
);
4535 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
4537 DWORD i
, needed
, count
;
4538 ENUM_SERVICE_STATUSW
*dependencies
;
4542 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
4543 0, &needed
, &count
))
4546 if (GetLastError() != ERROR_MORE_DATA
)
4549 dependencies
= msi_alloc(needed
);
4553 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
4554 needed
, &needed
, &count
))
4557 for (i
= 0; i
< count
; i
++)
4559 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
4560 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
4564 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
4571 msi_free(dependencies
);
4575 static UINT
ITERATE_StopService(MSIRECORD
*rec
, LPVOID param
)
4577 MSIPACKAGE
*package
= param
;
4579 SERVICE_STATUS status
;
4580 SERVICE_STATUS_PROCESS ssp
;
4581 SC_HANDLE scm
= NULL
, service
= NULL
;
4583 DWORD event
, needed
;
4585 event
= MSI_RecordGetInteger(rec
, 3);
4586 if (!(event
& msidbServiceControlEventStop
))
4587 return ERROR_SUCCESS
;
4589 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 6));
4590 if (!comp
|| comp
->Action
== INSTALLSTATE_UNKNOWN
|| comp
->Action
== INSTALLSTATE_ABSENT
)
4591 return ERROR_SUCCESS
;
4593 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
4594 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
4595 args
= strdupW(MSI_RecordGetString(rec
, 4));
4597 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
4600 WARN("Failed to open the SCM: %d\n", GetLastError());
4604 service
= OpenServiceW(scm
, name
,
4606 SERVICE_QUERY_STATUS
|
4607 SERVICE_ENUMERATE_DEPENDENTS
);
4610 WARN("Failed to open service (%s): %d\n",
4611 debugstr_w(name
), GetLastError());
4615 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
4616 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
4618 WARN("Failed to query service status (%s): %d\n",
4619 debugstr_w(name
), GetLastError());
4623 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
4626 stop_service_dependents(scm
, service
);
4628 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
4629 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
4632 CloseServiceHandle(service
);
4633 CloseServiceHandle(scm
);
4637 return ERROR_SUCCESS
;
4640 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4645 static const WCHAR query
[] = {
4646 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4647 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4649 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4650 if (rc
!= ERROR_SUCCESS
)
4651 return ERROR_SUCCESS
;
4653 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
4654 msiobj_release(&view
->hdr
);
4659 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
4663 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
4665 if (!lstrcmpW(file
->File
, filename
))
4672 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
4674 MSIPACKAGE
*package
= param
;
4675 LPWSTR driver
, driver_path
, ptr
;
4676 WCHAR outpath
[MAX_PATH
];
4677 MSIFILE
*driver_file
, *setup_file
;
4680 UINT r
= ERROR_SUCCESS
;
4682 static const WCHAR driver_fmt
[] = {
4683 'D','r','i','v','e','r','=','%','s',0};
4684 static const WCHAR setup_fmt
[] = {
4685 'S','e','t','u','p','=','%','s',0};
4686 static const WCHAR usage_fmt
[] = {
4687 'F','i','l','e','U','s','a','g','e','=','1',0};
4689 desc
= MSI_RecordGetString(rec
, 3);
4691 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4692 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4694 if (!driver_file
|| !setup_file
)
4696 ERR("ODBC Driver entry not found!\n");
4697 return ERROR_FUNCTION_FAILED
;
4700 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
) +
4701 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) +
4702 lstrlenW(usage_fmt
) + 1;
4703 driver
= msi_alloc(len
* sizeof(WCHAR
));
4705 return ERROR_OUTOFMEMORY
;
4708 lstrcpyW(ptr
, desc
);
4709 ptr
+= lstrlenW(ptr
) + 1;
4711 sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
4712 ptr
+= lstrlenW(ptr
) + 1;
4714 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4715 ptr
+= lstrlenW(ptr
) + 1;
4717 lstrcpyW(ptr
, usage_fmt
);
4718 ptr
+= lstrlenW(ptr
) + 1;
4721 driver_path
= strdupW(driver_file
->TargetPath
);
4722 ptr
= strrchrW(driver_path
, '\\');
4723 if (ptr
) *ptr
= '\0';
4725 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
4726 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4728 ERR("Failed to install SQL driver!\n");
4729 r
= ERROR_FUNCTION_FAILED
;
4733 msi_free(driver_path
);
4738 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
4740 MSIPACKAGE
*package
= param
;
4741 LPWSTR translator
, translator_path
, ptr
;
4742 WCHAR outpath
[MAX_PATH
];
4743 MSIFILE
*translator_file
, *setup_file
;
4746 UINT r
= ERROR_SUCCESS
;
4748 static const WCHAR translator_fmt
[] = {
4749 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4750 static const WCHAR setup_fmt
[] = {
4751 'S','e','t','u','p','=','%','s',0};
4753 desc
= MSI_RecordGetString(rec
, 3);
4755 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
4756 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
4758 if (!translator_file
|| !setup_file
)
4760 ERR("ODBC Translator entry not found!\n");
4761 return ERROR_FUNCTION_FAILED
;
4764 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) +
4765 lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
) + 1;
4766 translator
= msi_alloc(len
* sizeof(WCHAR
));
4768 return ERROR_OUTOFMEMORY
;
4771 lstrcpyW(ptr
, desc
);
4772 ptr
+= lstrlenW(ptr
) + 1;
4774 sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
4775 ptr
+= lstrlenW(ptr
) + 1;
4777 sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
4778 ptr
+= lstrlenW(ptr
) + 1;
4781 translator_path
= strdupW(translator_file
->TargetPath
);
4782 ptr
= strrchrW(translator_path
, '\\');
4783 if (ptr
) *ptr
= '\0';
4785 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
4786 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
4788 ERR("Failed to install SQL translator!\n");
4789 r
= ERROR_FUNCTION_FAILED
;
4792 msi_free(translator
);
4793 msi_free(translator_path
);
4798 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
4801 LPCWSTR desc
, driver
;
4802 WORD request
= ODBC_ADD_SYS_DSN
;
4805 UINT r
= ERROR_SUCCESS
;
4807 static const WCHAR attrs_fmt
[] = {
4808 'D','S','N','=','%','s',0 };
4810 desc
= MSI_RecordGetString(rec
, 3);
4811 driver
= MSI_RecordGetString(rec
, 4);
4812 registration
= MSI_RecordGetInteger(rec
, 5);
4814 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
4815 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
4817 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 1 + 1;
4818 attrs
= msi_alloc(len
* sizeof(WCHAR
));
4820 return ERROR_OUTOFMEMORY
;
4822 sprintfW(attrs
, attrs_fmt
, desc
);
4823 attrs
[len
- 1] = '\0';
4825 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
4827 ERR("Failed to install SQL data source!\n");
4828 r
= ERROR_FUNCTION_FAILED
;
4836 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
4841 static const WCHAR driver_query
[] = {
4842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4843 'O','D','B','C','D','r','i','v','e','r',0 };
4845 static const WCHAR translator_query
[] = {
4846 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4847 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4849 static const WCHAR source_query
[] = {
4850 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4851 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4853 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
4854 if (rc
!= ERROR_SUCCESS
)
4855 return ERROR_SUCCESS
;
4857 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
4858 msiobj_release(&view
->hdr
);
4860 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
4861 if (rc
!= ERROR_SUCCESS
)
4862 return ERROR_SUCCESS
;
4864 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
4865 msiobj_release(&view
->hdr
);
4867 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
4868 if (rc
!= ERROR_SUCCESS
)
4869 return ERROR_SUCCESS
;
4871 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
4872 msiobj_release(&view
->hdr
);
4877 #define ENV_ACT_SETALWAYS 0x1
4878 #define ENV_ACT_SETABSENT 0x2
4879 #define ENV_ACT_REMOVE 0x4
4880 #define ENV_ACT_REMOVEMATCH 0x8
4882 #define ENV_MOD_MACHINE 0x20000000
4883 #define ENV_MOD_APPEND 0x40000000
4884 #define ENV_MOD_PREFIX 0x80000000
4885 #define ENV_MOD_MASK 0xC0000000
4887 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4889 static LONG
env_set_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
4891 LPCWSTR cptr
= *name
;
4893 static const WCHAR prefix
[] = {'[','~',']',0};
4894 static const int prefix_len
= 3;
4900 *flags
|= ENV_ACT_SETALWAYS
;
4901 else if (*cptr
== '+')
4902 *flags
|= ENV_ACT_SETABSENT
;
4903 else if (*cptr
== '-')
4904 *flags
|= ENV_ACT_REMOVE
;
4905 else if (*cptr
== '!')
4906 *flags
|= ENV_ACT_REMOVEMATCH
;
4907 else if (*cptr
== '*')
4908 *flags
|= ENV_MOD_MACHINE
;
4918 ERR("Missing environment variable\n");
4919 return ERROR_FUNCTION_FAILED
;
4924 LPCWSTR ptr
= *value
;
4925 if (!strncmpW(ptr
, prefix
, prefix_len
))
4927 if (ptr
[prefix_len
] == szSemiColon
[0])
4929 *flags
|= ENV_MOD_APPEND
;
4930 *value
+= lstrlenW(prefix
);
4937 else if (lstrlenW(*value
) >= prefix_len
)
4939 ptr
+= lstrlenW(ptr
) - prefix_len
;
4940 if (!lstrcmpW(ptr
, prefix
))
4942 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
4944 *flags
|= ENV_MOD_PREFIX
;
4945 /* the "[~]" will be removed by deformat_string */;
4955 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
4956 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
4957 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
4958 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
4960 ERR("Invalid flags: %08x\n", *flags
);
4961 return ERROR_FUNCTION_FAILED
;
4965 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
4967 return ERROR_SUCCESS
;
4970 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
4972 MSIPACKAGE
*package
= param
;
4973 LPCWSTR name
, value
;
4974 LPWSTR data
= NULL
, newval
= NULL
;
4975 LPWSTR deformatted
= NULL
, ptr
;
4976 DWORD flags
, type
, size
;
4978 HKEY env
= NULL
, root
;
4979 LPCWSTR environment
;
4981 static const WCHAR user_env
[] =
4982 {'E','n','v','i','r','o','n','m','e','n','t',0};
4983 static const WCHAR machine_env
[] =
4984 {'S','y','s','t','e','m','\\',
4985 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4986 'C','o','n','t','r','o','l','\\',
4987 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4988 'E','n','v','i','r','o','n','m','e','n','t',0};
4990 name
= MSI_RecordGetString(rec
, 2);
4991 value
= MSI_RecordGetString(rec
, 3);
4993 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
4995 res
= env_set_flags(&name
, &value
, &flags
);
4996 if (res
!= ERROR_SUCCESS
|| !value
)
4999 if (value
&& !deformat_string(package
, value
, &deformatted
))
5001 res
= ERROR_OUTOFMEMORY
;
5005 value
= deformatted
;
5007 if (flags
& ENV_MOD_MACHINE
)
5009 environment
= machine_env
;
5010 root
= HKEY_LOCAL_MACHINE
;
5014 environment
= user_env
;
5015 root
= HKEY_CURRENT_USER
;
5018 res
= RegCreateKeyExW(root
, environment
, 0, NULL
, 0,
5019 KEY_ALL_ACCESS
, NULL
, &env
, NULL
);
5020 if (res
!= ERROR_SUCCESS
)
5023 if (flags
& ENV_ACT_REMOVE
)
5024 FIXME("Not removing environment variable on uninstall!\n");
5028 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
5029 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
5030 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
5033 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
5035 /* Nothing to do. */
5038 res
= ERROR_SUCCESS
;
5042 /* If we are appending but the string was empty, strip ; */
5043 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
5045 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
5046 newval
= strdupW(value
);
5049 res
= ERROR_OUTOFMEMORY
;
5055 /* Contrary to MSDN, +-variable to [~];path works */
5056 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
5058 res
= ERROR_SUCCESS
;
5062 data
= msi_alloc(size
);
5066 return ERROR_OUTOFMEMORY
;
5069 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
5070 if (res
!= ERROR_SUCCESS
)
5073 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
5075 res
= RegDeleteKeyW(env
, name
);
5079 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
5080 if (flags
& ENV_MOD_MASK
)
5084 if (flags
& ENV_MOD_APPEND
) multiplier
++;
5085 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
5086 mod_size
= lstrlenW(value
) * multiplier
;
5087 size
+= mod_size
* sizeof(WCHAR
);
5090 newval
= msi_alloc(size
);
5094 res
= ERROR_OUTOFMEMORY
;
5098 if (flags
& ENV_MOD_PREFIX
)
5100 lstrcpyW(newval
, value
);
5101 ptr
= newval
+ lstrlenW(value
);
5104 lstrcpyW(ptr
, data
);
5106 if (flags
& ENV_MOD_APPEND
)
5108 lstrcatW(newval
, value
);
5111 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
5112 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
5115 if (env
) RegCloseKey(env
);
5116 msi_free(deformatted
);
5122 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
5126 static const WCHAR ExecSeqQuery
[] =
5127 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5128 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5129 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5130 if (rc
!= ERROR_SUCCESS
)
5131 return ERROR_SUCCESS
;
5133 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
5134 msiobj_release(&view
->hdr
);
5139 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5150 static BOOL
msi_move_file(LPCWSTR source
, LPCWSTR dest
, int options
)
5154 if (GetFileAttributesW(source
) == FILE_ATTRIBUTE_DIRECTORY
||
5155 GetFileAttributesW(dest
) == FILE_ATTRIBUTE_DIRECTORY
)
5157 WARN("Source or dest is directory, not moving\n");
5161 if (options
== msidbMoveFileOptionsMove
)
5163 TRACE("moving %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5164 ret
= MoveFileExW(source
, dest
, MOVEFILE_REPLACE_EXISTING
);
5167 WARN("MoveFile failed: %d\n", GetLastError());
5173 TRACE("copying %s -> %s\n", debugstr_w(source
), debugstr_w(dest
));
5174 ret
= CopyFileW(source
, dest
, FALSE
);
5177 WARN("CopyFile failed: %d\n", GetLastError());
5185 static LPWSTR
wildcard_to_file(LPWSTR wildcard
, LPWSTR filename
)
5188 DWORD dirlen
, pathlen
;
5190 ptr
= strrchrW(wildcard
, '\\');
5191 dirlen
= ptr
- wildcard
+ 1;
5193 pathlen
= dirlen
+ lstrlenW(filename
) + 1;
5194 path
= msi_alloc(pathlen
* sizeof(WCHAR
));
5196 lstrcpynW(path
, wildcard
, dirlen
+ 1);
5197 lstrcatW(path
, filename
);
5202 static void free_file_entry(FILE_LIST
*file
)
5204 msi_free(file
->source
);
5205 msi_free(file
->dest
);
5209 static void free_list(FILE_LIST
*list
)
5211 while (!list_empty(&list
->entry
))
5213 FILE_LIST
*file
= LIST_ENTRY(list_head(&list
->entry
), FILE_LIST
, entry
);
5215 list_remove(&file
->entry
);
5216 free_file_entry(file
);
5220 static BOOL
add_wildcard(FILE_LIST
*files
, LPWSTR source
, LPWSTR dest
)
5222 FILE_LIST
*new, *file
;
5223 LPWSTR ptr
, filename
;
5226 new = msi_alloc_zero(sizeof(FILE_LIST
));
5230 new->source
= strdupW(source
);
5231 ptr
= strrchrW(dest
, '\\') + 1;
5232 filename
= strrchrW(new->source
, '\\') + 1;
5234 new->sourcename
= filename
;
5237 new->destname
= ptr
;
5239 new->destname
= new->sourcename
;
5241 size
= (ptr
- dest
) + lstrlenW(filename
) + 1;
5242 new->dest
= msi_alloc(size
* sizeof(WCHAR
));
5245 free_file_entry(new);
5249 lstrcpynW(new->dest
, dest
, ptr
- dest
+ 1);
5250 lstrcatW(new->dest
, filename
);
5252 if (list_empty(&files
->entry
))
5254 list_add_head(&files
->entry
, &new->entry
);
5258 LIST_FOR_EACH_ENTRY(file
, &files
->entry
, FILE_LIST
, entry
)
5260 if (lstrcmpW(source
, file
->source
) < 0)
5262 list_add_before(&file
->entry
, &new->entry
);
5267 list_add_after(&file
->entry
, &new->entry
);
5271 static BOOL
move_files_wildcard(LPWSTR source
, LPWSTR dest
, int options
)
5273 WIN32_FIND_DATAW wfd
;
5277 FILE_LIST files
, *file
;
5280 hfile
= FindFirstFileW(source
, &wfd
);
5281 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
5283 list_init(&files
.entry
);
5285 for (res
= TRUE
; res
; res
= FindNextFileW(hfile
, &wfd
))
5287 if (is_dot_dir(wfd
.cFileName
)) continue;
5289 path
= wildcard_to_file(source
, wfd
.cFileName
);
5296 add_wildcard(&files
, path
, dest
);
5300 /* no files match the wildcard */
5301 if (list_empty(&files
.entry
))
5304 /* only the first wildcard match gets renamed to dest */
5305 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5306 size
= (strrchrW(file
->dest
, '\\') - file
->dest
) + lstrlenW(file
->destname
) + 2;
5307 file
->dest
= msi_realloc(file
->dest
, size
* sizeof(WCHAR
));
5314 /* file->dest may be shorter after the reallocation, so add a NULL
5315 * terminator. This is needed for the call to strrchrW, as there will no
5316 * longer be a NULL terminator within the bounds of the allocation in this case.
5318 file
->dest
[size
- 1] = '\0';
5319 lstrcpyW(strrchrW(file
->dest
, '\\') + 1, file
->destname
);
5321 while (!list_empty(&files
.entry
))
5323 file
= LIST_ENTRY(list_head(&files
.entry
), FILE_LIST
, entry
);
5325 msi_move_file(file
->source
, file
->dest
, options
);
5327 list_remove(&file
->entry
);
5328 free_file_entry(file
);
5339 static UINT
ITERATE_MoveFiles( MSIRECORD
*rec
, LPVOID param
)
5341 MSIPACKAGE
*package
= param
;
5344 LPWSTR destname
= NULL
;
5345 LPWSTR sourcedir
= NULL
, destdir
= NULL
;
5346 LPWSTR source
= NULL
, dest
= NULL
;
5349 BOOL ret
, wildcards
;
5351 comp
= get_loaded_component(package
, MSI_RecordGetString(rec
, 2));
5352 if (!comp
|| !comp
->Enabled
||
5353 !(comp
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5355 TRACE("Component not set for install, not moving file\n");
5356 return ERROR_SUCCESS
;
5359 sourcename
= MSI_RecordGetString(rec
, 3);
5360 options
= MSI_RecordGetInteger(rec
, 7);
5362 sourcedir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 5));
5366 destdir
= msi_dup_property(package
, MSI_RecordGetString(rec
, 6));
5372 if (GetFileAttributesW(sourcedir
) == INVALID_FILE_ATTRIBUTES
)
5375 source
= strdupW(sourcedir
);
5381 size
= lstrlenW(sourcedir
) + lstrlenW(sourcename
) + 2;
5382 source
= msi_alloc(size
* sizeof(WCHAR
));
5386 lstrcpyW(source
, sourcedir
);
5387 if (source
[lstrlenW(source
) - 1] != '\\')
5388 lstrcatW(source
, szBackSlash
);
5389 lstrcatW(source
, sourcename
);
5392 wildcards
= strchrW(source
, '*') || strchrW(source
, '?');
5394 if (MSI_RecordIsNull(rec
, 4))
5398 destname
= strdupW(sourcename
);
5405 destname
= strdupW(MSI_RecordGetString(rec
, 4));
5407 reduce_to_longfilename(destname
);
5412 size
= lstrlenW(destname
);
5414 size
+= lstrlenW(destdir
) + 2;
5415 dest
= msi_alloc(size
* sizeof(WCHAR
));
5419 lstrcpyW(dest
, destdir
);
5420 if (dest
[lstrlenW(dest
) - 1] != '\\')
5421 lstrcatW(dest
, szBackSlash
);
5424 lstrcatW(dest
, destname
);
5426 if (GetFileAttributesW(destdir
) == INVALID_FILE_ATTRIBUTES
)
5428 ret
= CreateDirectoryW(destdir
, NULL
);
5431 WARN("CreateDirectory failed: %d\n", GetLastError());
5432 return ERROR_SUCCESS
;
5437 msi_move_file(source
, dest
, options
);
5439 move_files_wildcard(source
, dest
, options
);
5442 msi_free(sourcedir
);
5448 return ERROR_SUCCESS
;
5451 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
5456 static const WCHAR ExecSeqQuery
[] =
5457 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5458 '`','M','o','v','e','F','i','l','e','`',0};
5460 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5461 if (rc
!= ERROR_SUCCESS
)
5462 return ERROR_SUCCESS
;
5464 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_MoveFiles
, package
);
5465 msiobj_release(&view
->hdr
);
5470 typedef struct tagMSIASSEMBLY
5473 MSICOMPONENT
*component
;
5474 MSIFEATURE
*feature
;
5482 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
5484 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
5485 LPVOID pvReserved
, HMODULE
*phModDll
);
5487 static BOOL
init_functionpointers(void)
5493 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
5495 hmscoree
= LoadLibraryA("mscoree.dll");
5498 WARN("mscoree.dll not available\n");
5502 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
5503 if (!pLoadLibraryShim
)
5505 WARN("LoadLibraryShim not available\n");
5506 FreeLibrary(hmscoree
);
5510 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
5513 WARN("fusion.dll not available\n");
5514 FreeLibrary(hmscoree
);
5518 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
5520 FreeLibrary(hmscoree
);
5524 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
5527 IAssemblyCache
*cache
;
5529 UINT r
= ERROR_FUNCTION_FAILED
;
5531 TRACE("installing assembly: %s\n", debugstr_w(path
));
5533 if (assembly
->feature
)
5534 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
5536 if (assembly
->manifest
)
5537 FIXME("Manifest unhandled\n");
5539 if (assembly
->application
)
5541 FIXME("Assembly should be privately installed\n");
5542 return ERROR_SUCCESS
;
5545 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
5547 FIXME("Win32 assemblies not handled\n");
5548 return ERROR_SUCCESS
;
5551 hr
= pCreateAssemblyCache(&cache
, 0);
5555 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
5557 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
5562 IAssemblyCache_Release(cache
);
5566 typedef struct tagASSEMBLY_LIST
5568 MSIPACKAGE
*package
;
5569 IAssemblyCache
*cache
;
5570 struct list
*assemblies
;
5573 typedef struct tagASSEMBLY_NAME
5581 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
5583 ASSEMBLY_NAME
*asmname
= param
;
5584 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
5585 LPWSTR val
= msi_dup_record_field(rec
, 3);
5587 static const WCHAR Name
[] = {'N','a','m','e',0};
5588 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
5589 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
5590 static const WCHAR PublicKeyToken
[] = {
5591 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5593 if (!strcmpiW(name
, Name
))
5594 asmname
->name
= val
;
5595 else if (!strcmpiW(name
, Version
))
5596 asmname
->version
= val
;
5597 else if (!strcmpiW(name
, Culture
))
5598 asmname
->culture
= val
;
5599 else if (!strcmpiW(name
, PublicKeyToken
))
5600 asmname
->pubkeytoken
= val
;
5604 return ERROR_SUCCESS
;
5607 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
5611 *size
= lstrlenW(append
) + 1;
5612 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
5613 lstrcpyW(*str
, append
);
5617 (*size
) += lstrlenW(append
);
5618 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
5619 lstrcatW(*str
, append
);
5622 static BOOL
check_assembly_installed(MSIDATABASE
*db
, IAssemblyCache
*cache
,
5625 ASSEMBLY_INFO asminfo
;
5633 static const WCHAR separator
[] = {',',' ',0};
5634 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
5635 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
5636 static const WCHAR PublicKeyToken
[] = {
5637 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5638 static const WCHAR query
[] = {
5639 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5640 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5641 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5642 '=','\'','%','s','\'',0};
5646 ZeroMemory(&name
, sizeof(ASSEMBLY_NAME
));
5647 ZeroMemory(&asminfo
, sizeof(ASSEMBLY_INFO
));
5649 r
= MSI_OpenQuery(db
, &view
, query
, comp
->Component
);
5650 if (r
!= ERROR_SUCCESS
)
5651 return ERROR_SUCCESS
;
5653 MSI_IterateRecords(view
, NULL
, parse_assembly_name
, &name
);
5654 msiobj_release(&view
->hdr
);
5658 ERR("No assembly name specified!\n");
5662 append_str(&disp
, &size
, name
.name
);
5666 append_str(&disp
, &size
, separator
);
5667 append_str(&disp
, &size
, Version
);
5668 append_str(&disp
, &size
, name
.version
);
5673 append_str(&disp
, &size
, separator
);
5674 append_str(&disp
, &size
, Culture
);
5675 append_str(&disp
, &size
, name
.culture
);
5678 if (name
.pubkeytoken
)
5680 append_str(&disp
, &size
, separator
);
5681 append_str(&disp
, &size
, PublicKeyToken
);
5682 append_str(&disp
, &size
, name
.pubkeytoken
);
5685 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
5686 IAssemblyCache_QueryAssemblyInfo(cache
, QUERYASMINFO_FLAG_VALIDATE
,
5688 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
5692 msi_free(name
.name
);
5693 msi_free(name
.version
);
5694 msi_free(name
.culture
);
5695 msi_free(name
.pubkeytoken
);
5700 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
5702 ASSEMBLY_LIST
*list
= param
;
5703 MSIASSEMBLY
*assembly
;
5705 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
5707 return ERROR_OUTOFMEMORY
;
5709 assembly
->component
= get_loaded_component(list
->package
, MSI_RecordGetString(rec
, 1));
5711 if (!assembly
->component
|| !assembly
->component
->Enabled
||
5712 !(assembly
->component
->Action
& (INSTALLSTATE_LOCAL
| INSTALLSTATE_SOURCE
)))
5714 TRACE("Component not set for install, not publishing assembly\n");
5716 return ERROR_SUCCESS
;
5719 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
5720 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
5722 if (!assembly
->file
)
5724 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
5725 return ERROR_FUNCTION_FAILED
;
5728 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
5729 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
5730 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
5732 if (assembly
->application
)
5735 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
5737 /* FIXME: we should probably check the manifest file here */
5739 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
5740 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
5742 assembly
->installed
= TRUE
;
5746 assembly
->installed
= check_assembly_installed(list
->package
->db
,
5748 assembly
->component
);
5750 list_add_head(list
->assemblies
, &assembly
->entry
);
5751 return ERROR_SUCCESS
;
5754 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
5756 IAssemblyCache
*cache
= NULL
;
5762 static const WCHAR query
[] =
5763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5764 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5766 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5767 if (r
!= ERROR_SUCCESS
)
5768 return ERROR_SUCCESS
;
5770 hr
= pCreateAssemblyCache(&cache
, 0);
5772 return ERROR_FUNCTION_FAILED
;
5774 list
.package
= package
;
5776 list
.assemblies
= assemblies
;
5778 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
5779 msiobj_release(&view
->hdr
);
5781 IAssemblyCache_Release(cache
);
5786 static void free_assemblies(struct list
*assemblies
)
5788 struct list
*item
, *cursor
;
5790 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
5792 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
5794 list_remove(&assembly
->entry
);
5795 msi_free(assembly
->application
);
5796 msi_free(assembly
->manifest
);
5801 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
5803 MSIASSEMBLY
*assembly
;
5805 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
5807 if (!lstrcmpW(assembly
->file
->File
, file
))
5817 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
5818 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
5820 MSIASSEMBLY
*assembly
;
5821 WCHAR temppath
[MAX_PATH
];
5822 struct list
*assemblies
= user
;
5825 if (!find_assembly(assemblies
, file
, &assembly
))
5828 GetTempPathW(MAX_PATH
, temppath
);
5829 PathAddBackslashW(temppath
);
5830 lstrcatW(temppath
, assembly
->file
->FileName
);
5832 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
5834 if (assembly
->installed
)
5837 *path
= strdupW(temppath
);
5838 *attrs
= assembly
->file
->Attributes
;
5840 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
5842 assembly
->installed
= TRUE
;
5844 r
= install_assembly(package
, assembly
, temppath
);
5845 if (r
!= ERROR_SUCCESS
)
5846 ERR("Failed to install assembly\n");
5852 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
5855 struct list assemblies
= LIST_INIT(assemblies
);
5856 MSIASSEMBLY
*assembly
;
5859 if (!init_functionpointers() || !pCreateAssemblyCache
)
5860 return ERROR_FUNCTION_FAILED
;
5862 r
= load_assemblies(package
, &assemblies
);
5863 if (r
!= ERROR_SUCCESS
)
5866 if (list_empty(&assemblies
))
5869 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
5872 r
= ERROR_OUTOFMEMORY
;
5876 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
5878 if (assembly
->installed
&& !mi
->is_continuous
)
5881 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
5882 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
5886 r
= ready_media(package
, assembly
->file
, mi
);
5887 if (r
!= ERROR_SUCCESS
)
5889 ERR("Failed to ready media\n");
5894 data
.package
= package
;
5895 data
.cb
= installassembly_cb
;
5896 data
.user
= &assemblies
;
5898 if (assembly
->file
->IsCompressed
&&
5899 !msi_cabextract(package
, mi
, &data
))
5901 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
5902 r
= ERROR_FUNCTION_FAILED
;
5907 if (!assembly
->file
->IsCompressed
)
5909 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
5911 r
= install_assembly(package
, assembly
, source
);
5912 if (r
!= ERROR_SUCCESS
)
5913 ERR("Failed to install assembly\n");
5918 /* FIXME: write Installer assembly reg values */
5922 free_assemblies(&assemblies
);
5926 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
5927 LPCSTR action
, LPCWSTR table
)
5929 static const WCHAR query
[] = {
5930 'S','E','L','E','C','T',' ','*',' ',
5931 'F','R','O','M',' ','`','%','s','`',0 };
5932 MSIQUERY
*view
= NULL
;
5936 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
5937 if (r
== ERROR_SUCCESS
)
5939 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
5940 msiobj_release(&view
->hdr
);
5944 FIXME("%s -> %u ignored %s table values\n",
5945 action
, count
, debugstr_w(table
));
5947 return ERROR_SUCCESS
;
5950 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
5952 TRACE("%p\n", package
);
5953 return ERROR_SUCCESS
;
5956 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
5958 static const WCHAR table
[] =
5959 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5960 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
5963 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
5965 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
5966 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
5969 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
5971 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
5972 return msi_unimplemented_action_stub( package
, "BindImage", table
);
5975 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
5977 static const WCHAR table
[] = {
5978 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5979 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
5982 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
5984 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
5985 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
5988 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
5990 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
5991 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
5994 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5996 static const WCHAR table
[] = {
5997 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5998 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
6000 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6002 static const WCHAR table
[] = {
6003 'P','r','o','d','u','c','t','I','D',0 };
6004 return msi_unimplemented_action_stub( package
, "ValidateProductID", table
);
6007 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6009 static const WCHAR table
[] = {
6010 'E','n','v','i','r','o','n','m','e','n','t',0 };
6011 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
6014 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6016 static const WCHAR table
[] = {
6017 'M','s','i','A','s','s','e','m','b','l','y',0 };
6018 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6021 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
6023 static const WCHAR table
[] = { 'F','o','n','t',0 };
6024 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
6027 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6029 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6030 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6033 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6035 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6036 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6039 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6041 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6042 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6045 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6047 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6048 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6051 static UINT
ACTION_RemoveDuplicateFiles( MSIPACKAGE
*package
)
6053 static const WCHAR table
[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6054 return msi_unimplemented_action_stub( package
, "RemoveDuplicateFiles", table
);
6057 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6059 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6060 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6063 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
6065 static const WCHAR table
[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6066 return msi_unimplemented_action_stub( package
, "RemoveFolders", table
);
6069 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
6071 static const WCHAR table
[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6072 return msi_unimplemented_action_stub( package
, "RemoveODBC", table
);
6075 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
6077 static const WCHAR table
[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6078 return msi_unimplemented_action_stub( package
, "RemoveRegistryValues", table
);
6081 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
6083 static const WCHAR table
[] = { 'S','h','o','r','t','c','u','t',0 };
6084 return msi_unimplemented_action_stub( package
, "RemoveShortcuts", table
);
6087 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6089 static const WCHAR table
[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6090 return msi_unimplemented_action_stub( package
, "UnpublishComponents", table
);
6093 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6095 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6096 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6099 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6101 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6102 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6105 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6107 static const WCHAR table
[] = { 'M','I','M','E',0 };
6108 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6111 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6113 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6114 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6117 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
6119 static const WCHAR table
[] = { 'T','y','p','e','L','i','b',0 };
6120 return msi_unimplemented_action_stub( package
, "UnregisterTypeLibraries", table
);
6123 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6127 const WCHAR
*action
;
6128 UINT (*handler
)(MSIPACKAGE
*);
6132 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6133 { szAppSearch
, ACTION_AppSearch
},
6134 { szBindImage
, ACTION_BindImage
},
6135 { szCCPSearch
, ACTION_CCPSearch
},
6136 { szCostFinalize
, ACTION_CostFinalize
},
6137 { szCostInitialize
, ACTION_CostInitialize
},
6138 { szCreateFolders
, ACTION_CreateFolders
},
6139 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6140 { szDeleteServices
, ACTION_DeleteServices
},
6141 { szDisableRollback
, NULL
},
6142 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6143 { szExecuteAction
, ACTION_ExecuteAction
},
6144 { szFileCost
, ACTION_FileCost
},
6145 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6146 { szForceReboot
, ACTION_ForceReboot
},
6147 { szInstallAdminPackage
, NULL
},
6148 { szInstallExecute
, ACTION_InstallExecute
},
6149 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6150 { szInstallFiles
, ACTION_InstallFiles
},
6151 { szInstallFinalize
, ACTION_InstallFinalize
},
6152 { szInstallInitialize
, ACTION_InstallInitialize
},
6153 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6154 { szInstallValidate
, ACTION_InstallValidate
},
6155 { szIsolateComponents
, ACTION_IsolateComponents
},
6156 { szLaunchConditions
, ACTION_LaunchConditions
},
6157 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6158 { szMoveFiles
, ACTION_MoveFiles
},
6159 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6160 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6161 { szInstallODBC
, ACTION_InstallODBC
},
6162 { szInstallServices
, ACTION_InstallServices
},
6163 { szPatchFiles
, ACTION_PatchFiles
},
6164 { szProcessComponents
, ACTION_ProcessComponents
},
6165 { szPublishComponents
, ACTION_PublishComponents
},
6166 { szPublishFeatures
, ACTION_PublishFeatures
},
6167 { szPublishProduct
, ACTION_PublishProduct
},
6168 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6169 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6170 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6171 { szRegisterFonts
, ACTION_RegisterFonts
},
6172 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6173 { szRegisterProduct
, ACTION_RegisterProduct
},
6174 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6175 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6176 { szRegisterUser
, ACTION_RegisterUser
},
6177 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6178 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6179 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6180 { szRemoveFiles
, ACTION_RemoveFiles
},
6181 { szRemoveFolders
, ACTION_RemoveFolders
},
6182 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6183 { szRemoveODBC
, ACTION_RemoveODBC
},
6184 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6185 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6186 { szResolveSource
, ACTION_ResolveSource
},
6187 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6188 { szScheduleReboot
, NULL
},
6189 { szSelfRegModules
, ACTION_SelfRegModules
},
6190 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6191 { szSetODBCFolders
, NULL
},
6192 { szStartServices
, ACTION_StartServices
},
6193 { szStopServices
, ACTION_StopServices
},
6194 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6195 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6196 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6197 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6198 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6199 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6200 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6201 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6202 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6203 { szValidateProductID
, ACTION_ValidateProductID
},
6204 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6205 { szWriteIniValues
, ACTION_WriteIniValues
},
6206 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6210 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6211 UINT
* rc
, BOOL force
)
6217 if (!run
&& !package
->script
->CurrentlyScripting
)
6222 if (strcmpW(action
,szInstallFinalize
) == 0 ||
6223 strcmpW(action
,szInstallExecute
) == 0 ||
6224 strcmpW(action
,szInstallExecuteAgain
) == 0)
6229 while (StandardActions
[i
].action
!= NULL
)
6231 if (strcmpW(StandardActions
[i
].action
, action
)==0)
6235 ui_actioninfo(package
, action
, TRUE
, 0);
6236 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
6237 ui_actioninfo(package
, action
, FALSE
, *rc
);
6241 ui_actionstart(package
, action
);
6242 if (StandardActions
[i
].handler
)
6244 *rc
= StandardActions
[i
].handler(package
);
6248 FIXME("unhandled standard action %s\n",debugstr_w(action
));
6249 *rc
= ERROR_SUCCESS
;
6260 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
6262 UINT rc
= ERROR_SUCCESS
;
6265 TRACE("Performing action (%s)\n", debugstr_w(action
));
6267 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
6270 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
6274 WARN("unhandled msi action %s\n", debugstr_w(action
));
6275 rc
= ERROR_FUNCTION_NOT_CALLED
;
6281 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
6283 UINT rc
= ERROR_SUCCESS
;
6284 BOOL handled
= FALSE
;
6286 TRACE("Performing action (%s)\n", debugstr_w(action
));
6288 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
6291 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
6293 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
6298 WARN("unhandled msi action %s\n", debugstr_w(action
));
6299 rc
= ERROR_FUNCTION_NOT_CALLED
;
6305 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
6307 UINT rc
= ERROR_SUCCESS
;
6310 static const WCHAR ExecSeqQuery
[] =
6311 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6312 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
6313 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
6314 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
6315 static const WCHAR UISeqQuery
[] =
6316 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6317 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
6318 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
6319 ' ', '=',' ','%','i',0};
6321 if (needs_ui_sequence(package
))
6322 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
6324 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
6328 LPCWSTR action
, cond
;
6330 TRACE("Running the actions\n");
6332 /* check conditions */
6333 cond
= MSI_RecordGetString(row
, 2);
6335 /* this is a hack to skip errors in the condition code */
6336 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
6338 msiobj_release(&row
->hdr
);
6339 return ERROR_SUCCESS
;
6342 action
= MSI_RecordGetString(row
, 1);
6345 ERR("failed to fetch action\n");
6346 msiobj_release(&row
->hdr
);
6347 return ERROR_FUNCTION_FAILED
;
6350 if (needs_ui_sequence(package
))
6351 rc
= ACTION_PerformUIAction(package
, action
, -1);
6353 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
6355 msiobj_release(&row
->hdr
);
6361 /****************************************************
6362 * TOP level entry points
6363 *****************************************************/
6365 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
6366 LPCWSTR szCommandLine
)
6371 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
6372 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
6374 MSI_SetPropertyW(package
, szAction
, szInstall
);
6376 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
6383 dir
= strdupW(szPackagePath
);
6384 p
= strrchrW(dir
, '\\');
6388 file
= szPackagePath
+ (p
- dir
);
6393 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
6394 GetCurrentDirectoryW(MAX_PATH
, dir
);
6395 lstrcatW(dir
, szBackSlash
);
6396 file
= szPackagePath
;
6399 msi_free( package
->PackagePath
);
6400 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
6401 if (!package
->PackagePath
)
6404 return ERROR_OUTOFMEMORY
;
6407 lstrcpyW(package
->PackagePath
, dir
);
6408 lstrcatW(package
->PackagePath
, file
);
6411 msi_set_sourcedir_props(package
, FALSE
);
6414 msi_parse_command_line( package
, szCommandLine
, FALSE
);
6416 msi_apply_transforms( package
);
6417 msi_apply_patches( package
);
6419 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
6421 TRACE("setting reinstall property\n");
6422 MSI_SetPropertyW( package
, szReinstall
, szAll
);
6425 /* properties may have been added by a transform */
6426 msi_clone_properties( package
);
6427 msi_set_context( package
);
6429 if (needs_ui_sequence( package
))
6431 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
6432 rc
= ACTION_ProcessUISequence(package
);
6433 ui_exists
= ui_sequence_exists(package
);
6434 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
6436 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
6437 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
6441 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
6443 package
->script
->CurrentlyScripting
= FALSE
;
6445 /* process the ending type action */
6446 if (rc
== ERROR_SUCCESS
)
6447 ACTION_PerformActionSequence(package
, -1);
6448 else if (rc
== ERROR_INSTALL_USEREXIT
)
6449 ACTION_PerformActionSequence(package
, -2);
6450 else if (rc
== ERROR_INSTALL_SUSPEND
)
6451 ACTION_PerformActionSequence(package
, -4);
6453 ACTION_PerformActionSequence(package
, -3);
6455 /* finish up running custom actions */
6456 ACTION_FinishCustomActions(package
);
6458 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
6459 return ERROR_SUCCESS_REBOOT_REQUIRED
;