2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
49 * consts and values used
51 static const WCHAR c_colon
[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders
[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize
[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues
[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize
[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost
[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize
[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate
[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions
[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents
[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries
[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts
[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct
[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues
[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules
[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures
[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct
[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute
[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain
[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize
[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot
[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource
[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAllocateRegistrySpace
[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage
[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szCCPSearch
[] =
100 {'C','C','P','S','e','a','r','c','h',0};
101 static const WCHAR szDeleteServices
[] =
102 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
103 static const WCHAR szDisableRollback
[] =
104 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
105 static const WCHAR szExecuteAction
[] =
106 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
107 static const WCHAR szInstallAdminPackage
[] =
108 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
109 static const WCHAR szInstallSFPCatalogFile
[] =
110 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
111 static const WCHAR szIsolateComponents
[] =
112 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
113 static const WCHAR szMigrateFeatureStates
[] =
114 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
115 static const WCHAR szMsiPublishAssemblies
[] =
116 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szMsiUnpublishAssemblies
[] =
118 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
119 static const WCHAR szInstallODBC
[] =
120 {'I','n','s','t','a','l','l','O','D','B','C',0};
121 static const WCHAR szInstallServices
[] =
122 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
123 static const WCHAR szPatchFiles
[] =
124 {'P','a','t','c','h','F','i','l','e','s',0};
125 static const WCHAR szPublishComponents
[] =
126 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
127 static const WCHAR szRegisterComPlus
[] =
128 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
129 static const WCHAR szRegisterFonts
[] =
130 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
131 static const WCHAR szRegisterUser
[] =
132 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
133 static const WCHAR szRemoveEnvironmentStrings
[] =
134 {'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};
135 static const WCHAR szRemoveExistingProducts
[] =
136 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
137 static const WCHAR szRemoveFolders
[] =
138 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
139 static const WCHAR szRemoveIniValues
[] =
140 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveODBC
[] =
142 {'R','e','m','o','v','e','O','D','B','C',0};
143 static const WCHAR szRemoveRegistryValues
[] =
144 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
145 static const WCHAR szRemoveShortcuts
[] =
146 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
147 static const WCHAR szRMCCPSearch
[] =
148 {'R','M','C','C','P','S','e','a','r','c','h',0};
149 static const WCHAR szScheduleReboot
[] =
150 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
151 static const WCHAR szSelfUnregModules
[] =
152 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
153 static const WCHAR szSetODBCFolders
[] =
154 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
155 static const WCHAR szStartServices
[] =
156 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szStopServices
[] =
158 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
159 static const WCHAR szUnpublishComponents
[] =
160 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szUnpublishFeatures
[] =
162 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
163 static const WCHAR szUnregisterClassInfo
[] =
164 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
165 static const WCHAR szUnregisterComPlus
[] =
166 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
167 static const WCHAR szUnregisterExtensionInfo
[] =
168 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
169 static const WCHAR szUnregisterFonts
[] =
170 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
171 static const WCHAR szUnregisterMIMEInfo
[] =
172 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
173 static const WCHAR szUnregisterProgIdInfo
[] =
174 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
175 static const WCHAR szUnregisterTypeLibraries
[] =
176 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
177 static const WCHAR szValidateProductID
[] =
178 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
179 static const WCHAR szWriteEnvironmentStrings
[] =
180 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
182 /********************************************************
184 ********************************************************/
186 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
188 static const WCHAR Query_t
[] =
189 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
190 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
191 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
192 ' ','\'','%','s','\'',0};
195 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
198 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
199 msiobj_release(&row
->hdr
);
202 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
206 static const WCHAR template_s
[]=
207 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
209 static const WCHAR template_e
[]=
210 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
211 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
213 static const WCHAR format
[] =
214 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
218 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
220 sprintfW(message
,template_s
,timet
,action
);
222 sprintfW(message
,template_e
,timet
,action
,rc
);
224 row
= MSI_CreateRecord(1);
225 MSI_RecordSetStringW(row
,1,message
);
227 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
228 msiobj_release(&row
->hdr
);
231 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
237 LPWSTR prop
= NULL
, val
= NULL
;
240 return ERROR_SUCCESS
;
252 TRACE("Looking at %s\n",debugstr_w(ptr
));
254 ptr2
= strchrW(ptr
,'=');
257 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
264 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
265 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
275 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
288 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
289 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
292 if (lstrlenW(prop
) > 0)
294 TRACE("Found commandline property (%s) = (%s)\n",
295 debugstr_w(prop
), debugstr_w(val
));
296 MSI_SetPropertyW(package
,prop
,val
);
302 return ERROR_SUCCESS
;
306 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
309 LPWSTR p
, *ret
= NULL
;
315 /* count the number of substrings */
316 for ( pc
= str
, count
= 0; pc
; count
++ )
318 pc
= strchrW( pc
, sep
);
323 /* allocate space for an array of substring pointers and the substrings */
324 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
325 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
329 /* copy the string and set the pointers */
330 p
= (LPWSTR
) &ret
[count
+1];
332 for( count
= 0; (ret
[count
] = p
); count
++ )
334 p
= strchrW( p
, sep
);
342 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
344 static const WCHAR szSystemLanguageID
[] =
345 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
347 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
348 UINT ret
= ERROR_FUNCTION_FAILED
;
350 prod_code
= msi_dup_property( package
, szProductCode
);
351 patch_product
= msi_get_suminfo_product( patch
);
353 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
355 if ( strstrW( patch_product
, prod_code
) )
360 si
= MSI_GetSummaryInformationW( patch
, 0 );
363 ERR("no summary information!\n");
367 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
370 ERR("no template property!\n");
371 msiobj_release( &si
->hdr
);
378 msiobj_release( &si
->hdr
);
382 langid
= msi_dup_property( package
, szSystemLanguageID
);
385 msiobj_release( &si
->hdr
);
389 p
= strchrW( template, ';' );
390 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, szZero
)))
392 TRACE("applicable transform\n");
396 /* FIXME: check platform */
398 msiobj_release( &si
->hdr
);
402 msi_free( patch_product
);
403 msi_free( prod_code
);
404 msi_free( template );
410 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
411 MSIDATABASE
*patch_db
, LPCWSTR name
)
413 UINT ret
= ERROR_FUNCTION_FAILED
;
414 IStorage
*stg
= NULL
;
417 TRACE("%p %s\n", package
, debugstr_w(name
) );
421 ERR("expected a colon in %s\n", debugstr_w(name
));
422 return ERROR_FUNCTION_FAILED
;
425 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
428 ret
= msi_check_transform_applicable( package
, stg
);
429 if (ret
== ERROR_SUCCESS
)
430 msi_table_apply_transform( package
->db
, stg
);
432 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
433 IStorage_Release( stg
);
436 ERR("failed to open substorage %s\n", debugstr_w(name
));
438 return ERROR_SUCCESS
;
441 UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
443 LPWSTR guid_list
, *guids
, product_code
;
444 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
446 product_code
= msi_dup_property( package
, szProductCode
);
449 /* FIXME: the property ProductCode should be written into the DB somewhere */
450 ERR("no product code to check\n");
451 return ERROR_SUCCESS
;
454 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
455 guids
= msi_split_string( guid_list
, ';' );
456 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
458 if (!lstrcmpW( guids
[i
], product_code
))
462 msi_free( guid_list
);
463 msi_free( product_code
);
468 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
471 MSIRECORD
*rec
= NULL
;
476 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
477 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
478 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
479 '`','S','o','u','r','c','e','`',' ','I','S',' ',
480 'N','O','T',' ','N','U','L','L',0};
482 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
483 if (r
!= ERROR_SUCCESS
)
486 r
= MSI_ViewExecute(view
, 0);
487 if (r
!= ERROR_SUCCESS
)
490 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
492 prop
= MSI_RecordGetString(rec
, 1);
493 patch
= msi_dup_property(package
, szPatch
);
494 MSI_SetPropertyW(package
, prop
, patch
);
499 if (rec
) msiobj_release(&rec
->hdr
);
500 msiobj_release(&view
->hdr
);
505 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
508 LPWSTR str
, *substorage
;
509 UINT i
, r
= ERROR_SUCCESS
;
511 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
513 return ERROR_FUNCTION_FAILED
;
515 if (msi_check_patch_applicable( package
, si
) != ERROR_SUCCESS
)
517 TRACE("Patch not applicable\n");
518 return ERROR_SUCCESS
;
521 package
->patch
= msi_alloc(sizeof(MSIPATCHINFO
));
523 return ERROR_OUTOFMEMORY
;
525 package
->patch
->patchcode
= msi_suminfo_dup_string(si
, PID_REVNUMBER
);
526 if (!package
->patch
->patchcode
)
527 return ERROR_OUTOFMEMORY
;
529 /* enumerate the substorage */
530 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
531 package
->patch
->transforms
= str
;
533 substorage
= msi_split_string( str
, ';' );
534 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
535 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
537 msi_free( substorage
);
538 msiobj_release( &si
->hdr
);
540 msi_set_media_source_prop(package
);
545 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
547 MSIDATABASE
*patch_db
= NULL
;
550 TRACE("%p %s\n", package
, debugstr_w( file
) );
553 * We probably want to make sure we only open a patch collection here.
554 * Patch collections (.msp) and databases (.msi) have different GUIDs
555 * but currently MSI_OpenDatabaseW will accept both.
557 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
558 if ( r
!= ERROR_SUCCESS
)
560 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
564 msi_parse_patch_summary( package
, patch_db
);
567 * There might be a CAB file in the patch package,
568 * so append it to the list of storage to search for streams.
570 append_storage_to_db( package
->db
, patch_db
->storage
);
572 msiobj_release( &patch_db
->hdr
);
574 return ERROR_SUCCESS
;
577 /* get the PATCH property, and apply all the patches it specifies */
578 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
580 LPWSTR patch_list
, *patches
;
581 UINT i
, r
= ERROR_SUCCESS
;
583 patch_list
= msi_dup_property( package
, szPatch
);
585 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
587 patches
= msi_split_string( patch_list
, ';' );
588 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
589 r
= msi_apply_patch_package( package
, patches
[i
] );
592 msi_free( patch_list
);
597 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
599 static const WCHAR szTransforms
[] = {
600 'T','R','A','N','S','F','O','R','M','S',0 };
601 LPWSTR xform_list
, *xforms
;
602 UINT i
, r
= ERROR_SUCCESS
;
604 xform_list
= msi_dup_property( package
, szTransforms
);
605 xforms
= msi_split_string( xform_list
, ';' );
607 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
609 if (xforms
[i
][0] == ':')
610 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
612 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
616 msi_free( xform_list
);
621 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
626 static const WCHAR ExecSeqQuery
[] =
627 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
628 '`','I','n','s','t','a','l','l',
629 'U','I','S','e','q','u','e','n','c','e','`',
630 ' ','W','H','E','R','E',' ',
631 '`','S','e','q','u','e','n','c','e','`',' ',
632 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
633 '`','S','e','q','u','e','n','c','e','`',0};
635 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
636 if (rc
== ERROR_SUCCESS
)
638 msiobj_release(&view
->hdr
);
645 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
648 LPWSTR source
, check
;
651 static const WCHAR szOriginalDatabase
[] =
652 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
654 db
= msi_dup_property( package
, szOriginalDatabase
);
656 return ERROR_OUTOFMEMORY
;
658 p
= strrchrW( db
, '\\' );
661 p
= strrchrW( db
, '/' );
665 return ERROR_SUCCESS
;
670 source
= msi_alloc( len
* sizeof(WCHAR
) );
671 lstrcpynW( source
, db
, len
);
673 check
= msi_dup_property( package
, cszSourceDir
);
674 if (!check
|| replace
)
675 MSI_SetPropertyW( package
, cszSourceDir
, source
);
679 check
= msi_dup_property( package
, cszSOURCEDIR
);
680 if (!check
|| replace
)
681 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
687 return ERROR_SUCCESS
;
690 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
692 INT level
= msi_get_property_int(package
, szUILevel
, 0);
693 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
696 static UINT
msi_set_context(MSIPACKAGE
*package
)
703 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
705 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
706 if (r
== ERROR_SUCCESS
)
709 if (num
== 1 || num
== 2)
710 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
713 return ERROR_SUCCESS
;
716 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
719 LPCWSTR cond
, action
;
720 MSIPACKAGE
*package
= param
;
722 action
= MSI_RecordGetString(row
,1);
725 ERR("Error is retrieving action name\n");
726 return ERROR_FUNCTION_FAILED
;
729 /* check conditions */
730 cond
= MSI_RecordGetString(row
,2);
732 /* this is a hack to skip errors in the condition code */
733 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
735 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
736 return ERROR_SUCCESS
;
739 if (needs_ui_sequence(package
))
740 rc
= ACTION_PerformUIAction(package
, action
, -1);
742 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
744 msi_dialog_check_messages( NULL
);
746 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
747 rc
= package
->CurrentInstallState
;
749 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
752 if (rc
!= ERROR_SUCCESS
)
753 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
758 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
762 static const WCHAR query
[] =
763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
765 ' ','W','H','E','R','E',' ',
766 '`','S','e','q','u','e','n','c','e','`',' ',
767 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
768 '`','S','e','q','u','e','n','c','e','`',0};
770 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
772 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
773 if (r
== ERROR_SUCCESS
)
775 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
776 msiobj_release(&view
->hdr
);
782 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
786 static const WCHAR ExecSeqQuery
[] =
787 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
788 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
789 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
790 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
791 'O','R','D','E','R',' ', 'B','Y',' ',
792 '`','S','e','q','u','e','n','c','e','`',0 };
793 static const WCHAR IVQuery
[] =
794 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
795 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
796 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
797 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
798 ' ','\'', 'I','n','s','t','a','l','l',
799 'V','a','l','i','d','a','t','e','\'', 0};
802 if (package
->script
->ExecuteSequenceRun
)
804 TRACE("Execute Sequence already Run\n");
805 return ERROR_SUCCESS
;
808 package
->script
->ExecuteSequenceRun
= TRUE
;
810 /* get the sequence number */
813 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
815 return ERROR_FUNCTION_FAILED
;
816 seq
= MSI_RecordGetInteger(row
,1);
817 msiobj_release(&row
->hdr
);
820 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
821 if (rc
== ERROR_SUCCESS
)
823 TRACE("Running the actions\n");
825 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
826 msiobj_release(&view
->hdr
);
832 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
836 static const WCHAR ExecSeqQuery
[] =
837 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
838 '`','I','n','s','t','a','l','l',
839 'U','I','S','e','q','u','e','n','c','e','`',
840 ' ','W','H','E','R','E',' ',
841 '`','S','e','q','u','e','n','c','e','`',' ',
842 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
843 '`','S','e','q','u','e','n','c','e','`',0};
845 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
846 if (rc
== ERROR_SUCCESS
)
848 TRACE("Running the actions\n");
850 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
851 msiobj_release(&view
->hdr
);
857 /********************************************************
858 * ACTION helper functions and functions that perform the actions
859 *******************************************************/
860 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
861 UINT
* rc
, UINT script
, BOOL force
)
866 arc
= ACTION_CustomAction(package
, action
, script
, force
);
868 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
877 * Actual Action Handlers
880 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
882 MSIPACKAGE
*package
= param
;
883 LPCWSTR dir
, component
;
889 component
= MSI_RecordGetString(row
, 2);
890 comp
= get_loaded_component(package
, component
);
892 return ERROR_SUCCESS
;
894 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
896 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
897 comp
->Action
= comp
->Installed
;
898 return ERROR_SUCCESS
;
900 comp
->Action
= INSTALLSTATE_LOCAL
;
902 dir
= MSI_RecordGetString(row
,1);
905 ERR("Unable to get folder id\n");
906 return ERROR_SUCCESS
;
909 uirow
= MSI_CreateRecord(1);
910 MSI_RecordSetStringW(uirow
, 1, dir
);
911 ui_actiondata(package
, szCreateFolders
, uirow
);
912 msiobj_release(&uirow
->hdr
);
914 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
917 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
918 return ERROR_SUCCESS
;
921 TRACE("Folder is %s\n",debugstr_w(full_path
));
923 if (folder
->State
== 0)
924 create_full_pathW(full_path
);
929 return ERROR_SUCCESS
;
932 /* FIXME: probably should merge this with the above function */
933 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
935 UINT rc
= ERROR_SUCCESS
;
939 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
941 return ERROR_FUNCTION_FAILED
;
943 /* create the path */
944 if (folder
->State
== 0)
946 create_full_pathW(install_path
);
949 msi_free(install_path
);
954 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
958 /* create all the folders required by the components are going to install */
959 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
961 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
963 msi_create_directory( package
, comp
->Directory
);
966 return ERROR_SUCCESS
;
969 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
971 static const WCHAR ExecSeqQuery
[] =
972 {'S','E','L','E','C','T',' ',
973 '`','D','i','r','e','c','t','o','r','y','_','`',
974 ' ','F','R','O','M',' ',
975 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
979 /* create all the empty folders specified in the CreateFolder table */
980 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
981 if (rc
!= ERROR_SUCCESS
)
982 return ERROR_SUCCESS
;
984 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
985 msiobj_release(&view
->hdr
);
990 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
992 MSIPACKAGE
*package
= param
;
993 LPCWSTR dir
, component
;
999 component
= MSI_RecordGetString(row
, 2);
1000 comp
= get_loaded_component(package
, component
);
1002 return ERROR_SUCCESS
;
1004 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
1006 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
1007 comp
->Action
= comp
->Installed
;
1008 return ERROR_SUCCESS
;
1010 comp
->Action
= INSTALLSTATE_ABSENT
;
1012 dir
= MSI_RecordGetString( row
, 1 );
1015 ERR("Unable to get folder id\n");
1016 return ERROR_SUCCESS
;
1019 full_path
= resolve_folder( package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1022 ERR("Unable to resolve folder id %s\n", debugstr_w(dir
));
1023 return ERROR_SUCCESS
;
1026 TRACE("folder is %s\n", debugstr_w(full_path
));
1028 uirow
= MSI_CreateRecord( 1 );
1029 MSI_RecordSetStringW( uirow
, 1, full_path
);
1030 ui_actiondata( package
, szRemoveFolders
, uirow
);
1031 msiobj_release( &uirow
->hdr
);
1033 RemoveDirectoryW( full_path
);
1036 msi_free( full_path
);
1037 return ERROR_SUCCESS
;
1040 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1042 static const WCHAR query
[] =
1043 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1044 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1049 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1050 if (rc
!= ERROR_SUCCESS
)
1051 return ERROR_SUCCESS
;
1053 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1054 msiobj_release( &view
->hdr
);
1059 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1061 MSIPACKAGE
*package
= param
;
1064 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1066 return ERROR_FUNCTION_FAILED
;
1068 list_add_tail( &package
->components
, &comp
->entry
);
1070 /* fill in the data */
1071 comp
->Component
= msi_dup_record_field( row
, 1 );
1073 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1075 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1076 comp
->Directory
= msi_dup_record_field( row
, 3 );
1077 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1078 comp
->Condition
= msi_dup_record_field( row
, 5 );
1079 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1081 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1082 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1084 return ERROR_SUCCESS
;
1087 static UINT
load_all_components( MSIPACKAGE
*package
)
1089 static const WCHAR query
[] = {
1090 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1091 '`','C','o','m','p','o','n','e','n','t','`',0 };
1095 if (!list_empty(&package
->components
))
1096 return ERROR_SUCCESS
;
1098 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1099 if (r
!= ERROR_SUCCESS
)
1102 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1103 msiobj_release(&view
->hdr
);
1108 MSIPACKAGE
*package
;
1109 MSIFEATURE
*feature
;
1112 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1116 cl
= msi_alloc( sizeof (*cl
) );
1118 return ERROR_NOT_ENOUGH_MEMORY
;
1119 cl
->component
= comp
;
1120 list_add_tail( &feature
->Components
, &cl
->entry
);
1122 return ERROR_SUCCESS
;
1125 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1129 fl
= msi_alloc( sizeof(*fl
) );
1131 return ERROR_NOT_ENOUGH_MEMORY
;
1132 fl
->feature
= child
;
1133 list_add_tail( &parent
->Children
, &fl
->entry
);
1135 return ERROR_SUCCESS
;
1138 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1140 _ilfs
* ilfs
= param
;
1144 component
= MSI_RecordGetString(row
,1);
1146 /* check to see if the component is already loaded */
1147 comp
= get_loaded_component( ilfs
->package
, component
);
1150 ERR("unknown component %s\n", debugstr_w(component
));
1151 return ERROR_FUNCTION_FAILED
;
1154 add_feature_component( ilfs
->feature
, comp
);
1155 comp
->Enabled
= TRUE
;
1157 return ERROR_SUCCESS
;
1160 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1162 MSIFEATURE
*feature
;
1167 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1169 if ( !lstrcmpW( feature
->Feature
, name
) )
1176 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1178 MSIPACKAGE
* package
= param
;
1179 MSIFEATURE
* feature
;
1180 static const WCHAR Query1
[] =
1181 {'S','E','L','E','C','T',' ',
1182 '`','C','o','m','p','o','n','e','n','t','_','`',
1183 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1184 'C','o','m','p','o','n','e','n','t','s','`',' ',
1185 'W','H','E','R','E',' ',
1186 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1191 /* fill in the data */
1193 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1195 return ERROR_NOT_ENOUGH_MEMORY
;
1197 list_init( &feature
->Children
);
1198 list_init( &feature
->Components
);
1200 feature
->Feature
= msi_dup_record_field( row
, 1 );
1202 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1204 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1205 feature
->Title
= msi_dup_record_field( row
, 3 );
1206 feature
->Description
= msi_dup_record_field( row
, 4 );
1208 if (!MSI_RecordIsNull(row
,5))
1209 feature
->Display
= MSI_RecordGetInteger(row
,5);
1211 feature
->Level
= MSI_RecordGetInteger(row
,6);
1212 feature
->Directory
= msi_dup_record_field( row
, 7 );
1213 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1215 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1216 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1218 list_add_tail( &package
->features
, &feature
->entry
);
1220 /* load feature components */
1222 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1223 if (rc
!= ERROR_SUCCESS
)
1224 return ERROR_SUCCESS
;
1226 ilfs
.package
= package
;
1227 ilfs
.feature
= feature
;
1229 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1230 msiobj_release(&view
->hdr
);
1232 return ERROR_SUCCESS
;
1235 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1237 MSIPACKAGE
* package
= param
;
1238 MSIFEATURE
*parent
, *child
;
1240 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1242 return ERROR_FUNCTION_FAILED
;
1244 if (!child
->Feature_Parent
)
1245 return ERROR_SUCCESS
;
1247 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1249 return ERROR_FUNCTION_FAILED
;
1251 add_feature_child( parent
, child
);
1252 return ERROR_SUCCESS
;
1255 static UINT
load_all_features( MSIPACKAGE
*package
)
1257 static const WCHAR query
[] = {
1258 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1259 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1260 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1264 if (!list_empty(&package
->features
))
1265 return ERROR_SUCCESS
;
1267 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1268 if (r
!= ERROR_SUCCESS
)
1271 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1272 if (r
!= ERROR_SUCCESS
)
1275 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1276 msiobj_release( &view
->hdr
);
1281 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1292 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1294 static const WCHAR query
[] = {
1295 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1296 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1297 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1298 MSIQUERY
*view
= NULL
;
1299 MSIRECORD
*row
= NULL
;
1302 TRACE("%s\n", debugstr_w(file
->File
));
1304 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1305 if (r
!= ERROR_SUCCESS
)
1308 r
= MSI_ViewExecute(view
, NULL
);
1309 if (r
!= ERROR_SUCCESS
)
1312 r
= MSI_ViewFetch(view
, &row
);
1313 if (r
!= ERROR_SUCCESS
)
1316 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1317 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1318 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1319 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1320 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1323 if (view
) msiobj_release(&view
->hdr
);
1324 if (row
) msiobj_release(&row
->hdr
);
1328 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1330 MSIPACKAGE
* package
= param
;
1334 /* fill in the data */
1336 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1338 return ERROR_NOT_ENOUGH_MEMORY
;
1340 file
->File
= msi_dup_record_field( row
, 1 );
1342 component
= MSI_RecordGetString( row
, 2 );
1343 file
->Component
= get_loaded_component( package
, component
);
1345 if (!file
->Component
)
1347 WARN("Component not found: %s\n", debugstr_w(component
));
1348 msi_free(file
->File
);
1350 return ERROR_SUCCESS
;
1353 file
->FileName
= msi_dup_record_field( row
, 3 );
1354 reduce_to_longfilename( file
->FileName
);
1356 file
->ShortName
= msi_dup_record_field( row
, 3 );
1357 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1359 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1360 file
->Version
= msi_dup_record_field( row
, 5 );
1361 file
->Language
= msi_dup_record_field( row
, 6 );
1362 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1363 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1365 file
->state
= msifs_invalid
;
1367 /* if the compressed bits are not set in the file attributes,
1368 * then read the information from the package word count property
1370 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1372 file
->IsCompressed
= FALSE
;
1374 else if (file
->Attributes
&
1375 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1377 file
->IsCompressed
= TRUE
;
1379 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1381 file
->IsCompressed
= FALSE
;
1385 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1388 load_file_hash(package
, file
);
1390 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1392 list_add_tail( &package
->files
, &file
->entry
);
1394 return ERROR_SUCCESS
;
1397 static UINT
load_all_files(MSIPACKAGE
*package
)
1401 static const WCHAR Query
[] =
1402 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1403 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1404 '`','S','e','q','u','e','n','c','e','`', 0};
1406 if (!list_empty(&package
->files
))
1407 return ERROR_SUCCESS
;
1409 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1410 if (rc
!= ERROR_SUCCESS
)
1411 return ERROR_SUCCESS
;
1413 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1414 msiobj_release(&view
->hdr
);
1416 return ERROR_SUCCESS
;
1419 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1421 MSIPACKAGE
*package
= param
;
1422 static WCHAR szEmpty
[] = { 0 };
1423 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1426 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1428 return ERROR_NOT_ENOUGH_MEMORY
;
1430 folder
->Directory
= msi_dup_record_field( row
, 1 );
1432 TRACE("%s\n", debugstr_w(folder
->Directory
));
1434 p
= msi_dup_record_field(row
, 3);
1436 /* split src and target dir */
1438 src_short
= folder_split_path( p
, ':' );
1440 /* split the long and short paths */
1441 tgt_long
= folder_split_path( tgt_short
, '|' );
1442 src_long
= folder_split_path( src_short
, '|' );
1444 /* check for no-op dirs */
1445 if (!lstrcmpW(szDot
, tgt_short
))
1446 tgt_short
= szEmpty
;
1447 if (!lstrcmpW(szDot
, src_short
))
1448 src_short
= szEmpty
;
1451 tgt_long
= tgt_short
;
1454 src_short
= tgt_short
;
1455 src_long
= tgt_long
;
1459 src_long
= src_short
;
1461 /* FIXME: use the target short path too */
1462 folder
->TargetDefault
= strdupW(tgt_long
);
1463 folder
->SourceShortPath
= strdupW(src_short
);
1464 folder
->SourceLongPath
= strdupW(src_long
);
1467 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1468 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1469 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1471 folder
->Parent
= msi_dup_record_field( row
, 2 );
1473 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1475 list_add_tail( &package
->folders
, &folder
->entry
);
1477 TRACE("returning %p\n", folder
);
1479 return ERROR_SUCCESS
;
1482 static UINT
load_all_folders( MSIPACKAGE
*package
)
1484 static const WCHAR query
[] = {
1485 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1486 '`','D','i','r','e','c','t','o','r','y','`',0 };
1490 if (!list_empty(&package
->folders
))
1491 return ERROR_SUCCESS
;
1493 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1494 if (r
!= ERROR_SUCCESS
)
1497 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1498 msiobj_release(&view
->hdr
);
1503 * I am not doing any of the costing functionality yet.
1504 * Mostly looking at doing the Component and Feature loading
1506 * The native MSI does A LOT of modification to tables here. Mostly adding
1507 * a lot of temporary columns to the Feature and Component tables.
1509 * note: Native msi also tracks the short filename. But I am only going to
1510 * track the long ones. Also looking at this directory table
1511 * it appears that the directory table does not get the parents
1512 * resolved base on property only based on their entries in the
1515 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1517 static const WCHAR szCosting
[] =
1518 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1520 MSI_SetPropertyW(package
, szCosting
, szZero
);
1521 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1523 load_all_folders( package
);
1524 load_all_components( package
);
1525 load_all_features( package
);
1526 load_all_files( package
);
1528 return ERROR_SUCCESS
;
1531 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1534 UINT rc
= ERROR_SUCCESS
;
1536 TRACE("Executing Script %i\n",script
);
1538 if (!package
->script
)
1540 ERR("no script!\n");
1541 return ERROR_FUNCTION_FAILED
;
1544 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1547 action
= package
->script
->Actions
[script
][i
];
1548 ui_actionstart(package
, action
);
1549 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1550 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1551 if (rc
!= ERROR_SUCCESS
)
1554 msi_free_action_script(package
, script
);
1558 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1560 return ERROR_SUCCESS
;
1563 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1569 state
= MsiQueryProductStateW(package
->ProductCode
);
1571 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1573 if (!comp
->ComponentId
)
1576 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1577 comp
->Installed
= INSTALLSTATE_ABSENT
;
1580 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1581 package
->Context
, comp
->ComponentId
,
1583 if (r
!= ERROR_SUCCESS
)
1584 comp
->Installed
= INSTALLSTATE_ABSENT
;
1589 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1591 MSIFEATURE
*feature
;
1594 state
= MsiQueryProductStateW(package
->ProductCode
);
1596 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1598 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1599 feature
->Installed
= INSTALLSTATE_ABSENT
;
1602 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1608 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1609 LPCWSTR property
, INSTALLSTATE state
)
1612 MSIFEATURE
*feature
;
1614 override
= msi_dup_property( package
, property
);
1618 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1620 if (lstrcmpW(property
, szRemove
) &&
1621 (feature
->Level
<= 0 || feature
->Level
> level
))
1624 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1626 if (strcmpiW(override
, szAll
)==0)
1627 msi_feature_set_state(package
, feature
, state
);
1630 LPWSTR ptr
= override
;
1631 LPWSTR ptr2
= strchrW(override
,',');
1635 int len
= ptr2
- ptr
;
1637 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1638 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1640 msi_feature_set_state(package
, feature
, state
);
1646 ptr2
= strchrW(ptr
,',');
1658 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
1660 static const WCHAR szAddLocal
[] =
1661 {'A','D','D','L','O','C','A','L',0};
1662 static const WCHAR szAddSource
[] =
1663 {'A','D','D','S','O','U','R','C','E',0};
1664 static const WCHAR szAdvertise
[] =
1665 {'A','D','V','E','R','T','I','S','E',0};
1668 /* all these activation/deactivation things happen in order and things
1669 * later on the list override things earlier on the list.
1671 * 0 INSTALLLEVEL processing
1684 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1685 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1686 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1687 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1688 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1691 MSI_SetPropertyW( package
, szPreselected
, szOne
);
1696 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1699 static const WCHAR szlevel
[] =
1700 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1701 MSICOMPONENT
* component
;
1702 MSIFEATURE
*feature
;
1704 TRACE("Checking Install Level\n");
1706 level
= msi_get_property_int(package
, szlevel
, 1);
1708 if (!msi_get_property_int( package
, szPreselected
, 0 ))
1710 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1712 BOOL feature_state
= ((feature
->Level
> 0) &&
1713 (feature
->Level
<= level
));
1715 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1717 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1718 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1719 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1720 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1722 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1726 /* disable child features of unselected parent features */
1727 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1731 if (feature
->Level
> 0 && feature
->Level
<= level
)
1734 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1735 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1740 * now we want to enable or disable components base on feature
1743 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1747 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1748 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1750 if (!feature
->Level
)
1753 /* features with components that have compressed files are made local */
1754 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1756 if (cl
->component
->Enabled
&&
1757 cl
->component
->ForceLocalState
&&
1758 feature
->Action
== INSTALLSTATE_SOURCE
)
1760 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1765 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1767 component
= cl
->component
;
1769 if (!component
->Enabled
)
1772 switch (feature
->Action
)
1774 case INSTALLSTATE_ABSENT
:
1775 component
->anyAbsent
= 1;
1777 case INSTALLSTATE_ADVERTISED
:
1778 component
->hasAdvertiseFeature
= 1;
1780 case INSTALLSTATE_SOURCE
:
1781 component
->hasSourceFeature
= 1;
1783 case INSTALLSTATE_LOCAL
:
1784 component
->hasLocalFeature
= 1;
1786 case INSTALLSTATE_DEFAULT
:
1787 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1788 component
->hasAdvertiseFeature
= 1;
1789 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1790 component
->hasSourceFeature
= 1;
1792 component
->hasLocalFeature
= 1;
1800 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1802 /* if the component isn't enabled, leave it alone */
1803 if (!component
->Enabled
)
1806 /* check if it's local or source */
1807 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1808 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1810 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1811 !component
->ForceLocalState
)
1812 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1814 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1818 /* if any feature is local, the component must be local too */
1819 if (component
->hasLocalFeature
)
1821 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1825 if (component
->hasSourceFeature
)
1827 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1831 if (component
->hasAdvertiseFeature
)
1833 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1837 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1838 if (component
->anyAbsent
)
1839 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1842 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1844 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1846 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1847 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1850 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1851 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1855 return ERROR_SUCCESS
;
1858 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1860 MSIPACKAGE
*package
= param
;
1865 name
= MSI_RecordGetString(row
,1);
1867 f
= get_loaded_folder(package
, name
);
1868 if (!f
) return ERROR_SUCCESS
;
1870 /* reset the ResolvedTarget */
1871 msi_free(f
->ResolvedTarget
);
1872 f
->ResolvedTarget
= NULL
;
1874 /* This helper function now does ALL the work */
1875 TRACE("Dir %s ...\n",debugstr_w(name
));
1876 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1877 TRACE("resolves to %s\n",debugstr_w(path
));
1880 return ERROR_SUCCESS
;
1883 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1885 MSIPACKAGE
*package
= param
;
1887 MSIFEATURE
*feature
;
1889 name
= MSI_RecordGetString( row
, 1 );
1891 feature
= get_loaded_feature( package
, name
);
1893 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1897 Condition
= MSI_RecordGetString(row
,3);
1899 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1901 int level
= MSI_RecordGetInteger(row
,2);
1902 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1903 feature
->Level
= level
;
1906 return ERROR_SUCCESS
;
1909 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1911 static const WCHAR name_fmt
[] =
1912 {'%','u','.','%','u','.','%','u','.','%','u',0};
1913 static const WCHAR name
[] = {'\\',0};
1914 VS_FIXEDFILEINFO
*lpVer
;
1915 WCHAR filever
[0x100];
1921 TRACE("%s\n", debugstr_w(filename
));
1923 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1927 version
= msi_alloc( versize
);
1928 GetFileVersionInfoW( filename
, 0, versize
, version
);
1930 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1932 msi_free( version
);
1936 sprintfW( filever
, name_fmt
,
1937 HIWORD(lpVer
->dwFileVersionMS
),
1938 LOWORD(lpVer
->dwFileVersionMS
),
1939 HIWORD(lpVer
->dwFileVersionLS
),
1940 LOWORD(lpVer
->dwFileVersionLS
));
1942 msi_free( version
);
1944 return strdupW( filever
);
1947 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1949 LPWSTR file_version
;
1952 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1954 MSICOMPONENT
* comp
= file
->Component
;
1960 if (file
->IsCompressed
)
1961 comp
->ForceLocalState
= TRUE
;
1963 /* calculate target */
1964 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
1966 msi_free(file
->TargetPath
);
1968 TRACE("file %s is named %s\n",
1969 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
1971 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1975 TRACE("file %s resolves to %s\n",
1976 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
1978 /* don't check files of components that aren't installed */
1979 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
1980 comp
->Installed
== INSTALLSTATE_ABSENT
)
1982 file
->state
= msifs_missing
; /* assume files are missing */
1986 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1988 file
->state
= msifs_missing
;
1989 comp
->Cost
+= file
->FileSize
;
1993 if (file
->Version
&&
1994 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
1996 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1997 debugstr_w(file_version
));
1998 /* FIXME: seems like a bad way to compare version numbers */
1999 if (lstrcmpiW(file_version
, file
->Version
)<0)
2001 file
->state
= msifs_overwrite
;
2002 comp
->Cost
+= file
->FileSize
;
2005 file
->state
= msifs_present
;
2006 msi_free( file_version
);
2009 file
->state
= msifs_present
;
2012 return ERROR_SUCCESS
;
2016 * A lot is done in this function aside from just the costing.
2017 * The costing needs to be implemented at some point but for now I am going
2018 * to focus on the directory building
2021 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2023 static const WCHAR ExecSeqQuery
[] =
2024 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2025 '`','D','i','r','e','c','t','o','r','y','`',0};
2026 static const WCHAR ConditionQuery
[] =
2027 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2028 '`','C','o','n','d','i','t','i','o','n','`',0};
2029 static const WCHAR szCosting
[] =
2030 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2031 static const WCHAR szlevel
[] =
2032 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2033 static const WCHAR szOutOfDiskSpace
[] =
2034 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2036 UINT rc
= ERROR_SUCCESS
;
2040 TRACE("Building Directory properties\n");
2042 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2043 if (rc
== ERROR_SUCCESS
)
2045 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2047 msiobj_release(&view
->hdr
);
2050 /* read components states from the registry */
2051 ACTION_GetComponentInstallStates(package
);
2052 ACTION_GetFeatureInstallStates(package
);
2054 TRACE("File calculations\n");
2055 msi_check_file_install_states( package
);
2057 if (!process_overrides( package
, msi_get_property_int( package
, szlevel
, 1 ) ))
2059 TRACE("Evaluating Condition Table\n");
2061 rc
= MSI_DatabaseOpenViewW( package
->db
, ConditionQuery
, &view
);
2062 if (rc
== ERROR_SUCCESS
)
2064 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
2065 msiobj_release( &view
->hdr
);
2068 TRACE("Enabling or Disabling Components\n");
2069 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2071 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
2073 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2074 comp
->Enabled
= FALSE
;
2077 comp
->Enabled
= TRUE
;
2081 MSI_SetPropertyW(package
,szCosting
,szOne
);
2082 /* set default run level if not set */
2083 level
= msi_dup_property( package
, szlevel
);
2085 MSI_SetPropertyW(package
,szlevel
, szOne
);
2088 /* FIXME: check volume disk space */
2089 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2091 return MSI_SetFeatureStates(package
);
2094 /* OK this value is "interpreted" and then formatted based on the
2095 first few characters */
2096 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2101 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2107 LPWSTR deformated
= NULL
;
2110 deformat_string(package
, &value
[2], &deformated
);
2112 /* binary value type */
2116 *size
= (strlenW(ptr
)/2)+1;
2118 *size
= strlenW(ptr
)/2;
2120 data
= msi_alloc(*size
);
2126 /* if uneven pad with a zero in front */
2132 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2134 TRACE("Uneven byte count\n");
2142 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2145 msi_free(deformated
);
2147 TRACE("Data %i bytes(%i)\n",*size
,count
);
2154 deformat_string(package
, &value
[1], &deformated
);
2157 *size
= sizeof(DWORD
);
2158 data
= msi_alloc(*size
);
2164 if ( (*p
< '0') || (*p
> '9') )
2170 if (deformated
[0] == '-')
2173 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2175 msi_free(deformated
);
2180 static const WCHAR szMulti
[] = {'[','~',']',0};
2189 *type
=REG_EXPAND_SZ
;
2197 if (strstrW(value
,szMulti
))
2198 *type
= REG_MULTI_SZ
;
2200 /* remove initial delimiter */
2201 if (!strncmpW(value
, szMulti
, 3))
2204 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2206 /* add double NULL terminator */
2207 if (*type
== REG_MULTI_SZ
)
2209 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2210 data
= msi_realloc_zero(data
, *size
);
2216 static const WCHAR
*get_root_key( MSIPACKAGE
*package
, INT root
, HKEY
*root_key
)
2223 if (msi_get_property_int( package
, szAllUsers
, 0 ))
2225 *root_key
= HKEY_LOCAL_MACHINE
;
2230 *root_key
= HKEY_CURRENT_USER
;
2235 *root_key
= HKEY_CLASSES_ROOT
;
2239 *root_key
= HKEY_CURRENT_USER
;
2243 *root_key
= HKEY_LOCAL_MACHINE
;
2247 *root_key
= HKEY_USERS
;
2251 ERR("Unknown root %i\n", root
);
2258 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2260 MSIPACKAGE
*package
= param
;
2261 LPSTR value_data
= NULL
;
2262 HKEY root_key
, hkey
;
2265 LPCWSTR szRoot
, component
, name
, key
, value
;
2270 BOOL check_first
= FALSE
;
2273 ui_progress(package
,2,0,0,0);
2280 component
= MSI_RecordGetString(row
, 6);
2281 comp
= get_loaded_component(package
,component
);
2283 return ERROR_SUCCESS
;
2285 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2287 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2288 comp
->Action
= comp
->Installed
;
2289 return ERROR_SUCCESS
;
2291 comp
->Action
= INSTALLSTATE_LOCAL
;
2293 name
= MSI_RecordGetString(row
, 4);
2294 if( MSI_RecordIsNull(row
,5) && name
)
2296 /* null values can have special meanings */
2297 if (name
[0]=='-' && name
[1] == 0)
2298 return ERROR_SUCCESS
;
2299 else if ((name
[0]=='+' && name
[1] == 0) ||
2300 (name
[0] == '*' && name
[1] == 0))
2305 root
= MSI_RecordGetInteger(row
,2);
2306 key
= MSI_RecordGetString(row
, 3);
2308 szRoot
= get_root_key( package
, root
, &root_key
);
2310 return ERROR_SUCCESS
;
2312 deformat_string(package
, key
, &deformated
);
2313 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2314 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2315 strcpyW(uikey
,szRoot
);
2316 strcatW(uikey
,deformated
);
2318 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2320 ERR("Could not create key %s\n",debugstr_w(deformated
));
2321 msi_free(deformated
);
2323 return ERROR_SUCCESS
;
2325 msi_free(deformated
);
2327 value
= MSI_RecordGetString(row
,5);
2329 value_data
= parse_value(package
, value
, &type
, &size
);
2332 value_data
= (LPSTR
)strdupW(szEmpty
);
2333 size
= sizeof(szEmpty
);
2337 deformat_string(package
, name
, &deformated
);
2341 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2343 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2348 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2349 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2351 TRACE("value %s of %s checked already exists\n",
2352 debugstr_w(deformated
), debugstr_w(uikey
));
2356 TRACE("Checked and setting value %s of %s\n",
2357 debugstr_w(deformated
), debugstr_w(uikey
));
2358 if (deformated
|| size
)
2359 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2364 uirow
= MSI_CreateRecord(3);
2365 MSI_RecordSetStringW(uirow
,2,deformated
);
2366 MSI_RecordSetStringW(uirow
,1,uikey
);
2369 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2371 MSI_RecordSetStringW(uirow
,3,value
);
2373 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2374 msiobj_release( &uirow
->hdr
);
2376 msi_free(value_data
);
2377 msi_free(deformated
);
2380 return ERROR_SUCCESS
;
2383 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2387 static const WCHAR ExecSeqQuery
[] =
2388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2389 '`','R','e','g','i','s','t','r','y','`',0 };
2391 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2392 if (rc
!= ERROR_SUCCESS
)
2393 return ERROR_SUCCESS
;
2395 /* increment progress bar each time action data is sent */
2396 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2398 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2400 msiobj_release(&view
->hdr
);
2404 static void delete_reg_key_or_value( HKEY hkey_root
, LPCWSTR key
, LPCWSTR value
, BOOL delete_key
)
2408 DWORD num_subkeys
, num_values
;
2412 if ((res
= RegDeleteTreeW( hkey_root
, key
)))
2414 WARN("Failed to delete key %s (%d)\n", debugstr_w(key
), res
);
2419 if (!(res
= RegOpenKeyW( hkey_root
, key
, &hkey
)))
2421 if ((res
= RegDeleteValueW( hkey
, value
)))
2423 WARN("Failed to delete value %s (%d)\n", debugstr_w(value
), res
);
2425 res
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
, NULL
, &num_values
,
2426 NULL
, NULL
, NULL
, NULL
);
2427 RegCloseKey( hkey
);
2429 if (!res
&& !num_subkeys
&& !num_values
)
2431 TRACE("Removing empty key %s\n", debugstr_w(key
));
2432 RegDeleteKeyW( hkey_root
, key
);
2436 WARN("Failed to open key %s (%d)\n", debugstr_w(key
), res
);
2440 static UINT
ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
2442 MSIPACKAGE
*package
= param
;
2443 LPCWSTR component
, name
, key_str
, root_key_str
;
2444 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2447 BOOL delete_key
= FALSE
;
2452 ui_progress( package
, 2, 0, 0, 0 );
2454 component
= MSI_RecordGetString( row
, 6 );
2455 comp
= get_loaded_component( package
, component
);
2457 return ERROR_SUCCESS
;
2459 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2461 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
2462 comp
->Action
= comp
->Installed
;
2463 return ERROR_SUCCESS
;
2465 comp
->Action
= INSTALLSTATE_ABSENT
;
2467 name
= MSI_RecordGetString( row
, 4 );
2468 if (MSI_RecordIsNull( row
, 5 ) && name
)
2470 if (name
[0] == '+' && !name
[1])
2471 return ERROR_SUCCESS
;
2472 else if ((name
[0] == '-' && !name
[1]) || (name
[0] == '*' && !name
[1]))
2479 root
= MSI_RecordGetInteger( row
, 2 );
2480 key_str
= MSI_RecordGetString( row
, 3 );
2482 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2484 return ERROR_SUCCESS
;
2486 deformat_string( package
, key_str
, &deformated_key
);
2487 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2488 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2489 strcpyW( ui_key_str
, root_key_str
);
2490 strcatW( ui_key_str
, deformated_key
);
2492 deformat_string( package
, name
, &deformated_name
);
2494 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2495 msi_free( deformated_key
);
2497 uirow
= MSI_CreateRecord( 2 );
2498 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2499 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2501 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2502 msiobj_release( &uirow
->hdr
);
2504 msi_free( ui_key_str
);
2505 msi_free( deformated_name
);
2506 return ERROR_SUCCESS
;
2509 static UINT
ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
2511 MSIPACKAGE
*package
= param
;
2512 LPCWSTR component
, name
, key_str
, root_key_str
;
2513 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2516 BOOL delete_key
= FALSE
;
2521 ui_progress( package
, 2, 0, 0, 0 );
2523 component
= MSI_RecordGetString( row
, 5 );
2524 comp
= get_loaded_component( package
, component
);
2526 return ERROR_SUCCESS
;
2528 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2530 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2531 comp
->Action
= comp
->Installed
;
2532 return ERROR_SUCCESS
;
2534 comp
->Action
= INSTALLSTATE_LOCAL
;
2536 if ((name
= MSI_RecordGetString( row
, 4 )))
2538 if (name
[0] == '-' && !name
[1])
2545 root
= MSI_RecordGetInteger( row
, 2 );
2546 key_str
= MSI_RecordGetString( row
, 3 );
2548 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2550 return ERROR_SUCCESS
;
2552 deformat_string( package
, key_str
, &deformated_key
);
2553 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2554 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2555 strcpyW( ui_key_str
, root_key_str
);
2556 strcatW( ui_key_str
, deformated_key
);
2558 deformat_string( package
, name
, &deformated_name
);
2560 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2561 msi_free( deformated_key
);
2563 uirow
= MSI_CreateRecord( 2 );
2564 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2565 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2567 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2568 msiobj_release( &uirow
->hdr
);
2570 msi_free( ui_key_str
);
2571 msi_free( deformated_name
);
2572 return ERROR_SUCCESS
;
2575 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
2579 static const WCHAR registry_query
[] =
2580 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2581 '`','R','e','g','i','s','t','r','y','`',0 };
2582 static const WCHAR remove_registry_query
[] =
2583 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2584 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2586 /* increment progress bar each time action data is sent */
2587 ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
2589 rc
= MSI_DatabaseOpenViewW( package
->db
, registry_query
, &view
);
2590 if (rc
== ERROR_SUCCESS
)
2592 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnUninstall
, package
);
2593 msiobj_release( &view
->hdr
);
2594 if (rc
!= ERROR_SUCCESS
)
2598 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_registry_query
, &view
);
2599 if (rc
== ERROR_SUCCESS
)
2601 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnInstall
, package
);
2602 msiobj_release( &view
->hdr
);
2603 if (rc
!= ERROR_SUCCESS
)
2607 return ERROR_SUCCESS
;
2610 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2612 package
->script
->CurrentlyScripting
= TRUE
;
2614 return ERROR_SUCCESS
;
2618 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2623 static const WCHAR q1
[]=
2624 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2625 '`','R','e','g','i','s','t','r','y','`',0};
2628 MSIFEATURE
*feature
;
2631 TRACE("InstallValidate\n");
2633 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2634 if (rc
== ERROR_SUCCESS
)
2636 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2637 msiobj_release( &view
->hdr
);
2638 total
+= progress
* REG_PROGRESS_VALUE
;
2641 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2642 total
+= COMPONENT_PROGRESS_VALUE
;
2644 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2645 total
+= file
->FileSize
;
2647 ui_progress(package
,0,total
,0,0);
2649 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2651 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2652 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2653 feature
->ActionRequest
);
2656 return ERROR_SUCCESS
;
2659 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2661 MSIPACKAGE
* package
= param
;
2662 LPCWSTR cond
= NULL
;
2663 LPCWSTR message
= NULL
;
2666 static const WCHAR title
[]=
2667 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2669 cond
= MSI_RecordGetString(row
,1);
2671 r
= MSI_EvaluateConditionW(package
,cond
);
2672 if (r
== MSICONDITION_FALSE
)
2674 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2677 message
= MSI_RecordGetString(row
,2);
2678 deformat_string(package
,message
,&deformated
);
2679 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2680 msi_free(deformated
);
2683 return ERROR_INSTALL_FAILURE
;
2686 return ERROR_SUCCESS
;
2689 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2692 MSIQUERY
* view
= NULL
;
2693 static const WCHAR ExecSeqQuery
[] =
2694 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2695 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2697 TRACE("Checking launch conditions\n");
2699 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2700 if (rc
!= ERROR_SUCCESS
)
2701 return ERROR_SUCCESS
;
2703 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2704 msiobj_release(&view
->hdr
);
2709 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2713 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2715 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2717 MSIRECORD
* row
= 0;
2719 LPWSTR deformated
,buffer
,deformated_name
;
2721 static const WCHAR ExecSeqQuery
[] =
2722 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2723 '`','R','e','g','i','s','t','r','y','`',' ',
2724 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2725 ' ','=',' ' ,'\'','%','s','\'',0 };
2726 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2727 static const WCHAR fmt2
[]=
2728 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2730 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2734 root
= MSI_RecordGetInteger(row
,2);
2735 key
= MSI_RecordGetString(row
, 3);
2736 name
= MSI_RecordGetString(row
, 4);
2737 deformat_string(package
, key
, &deformated
);
2738 deformat_string(package
, name
, &deformated_name
);
2740 len
= strlenW(deformated
) + 6;
2741 if (deformated_name
)
2742 len
+=strlenW(deformated_name
);
2744 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2746 if (deformated_name
)
2747 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2749 sprintfW(buffer
,fmt
,root
,deformated
);
2751 msi_free(deformated
);
2752 msi_free(deformated_name
);
2753 msiobj_release(&row
->hdr
);
2757 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2759 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2764 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);