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
);
2767 return strdupW( file
->TargetPath
);
2772 static HKEY
openSharedDLLsKey(void)
2775 static const WCHAR path
[] =
2776 {'S','o','f','t','w','a','r','e','\\',
2777 'M','i','c','r','o','s','o','f','t','\\',
2778 'W','i','n','d','o','w','s','\\',
2779 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2780 'S','h','a','r','e','d','D','L','L','s',0};
2782 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2786 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2791 DWORD sz
= sizeof(count
);
2794 hkey
= openSharedDLLsKey();
2795 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2796 if (rc
!= ERROR_SUCCESS
)
2802 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2806 hkey
= openSharedDLLsKey();
2808 msi_reg_set_val_dword( hkey
, path
, count
);
2810 RegDeleteValueW(hkey
,path
);
2816 * Return TRUE if the count should be written out and FALSE if not
2818 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2820 MSIFEATURE
*feature
;
2824 /* only refcount DLLs */
2825 if (comp
->KeyPath
== NULL
||
2826 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2827 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2831 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2832 write
= (count
> 0);
2834 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2838 /* increment counts */
2839 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2843 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2846 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2848 if ( cl
->component
== comp
)
2853 /* decrement counts */
2854 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2858 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2861 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2863 if ( cl
->component
== comp
)
2868 /* ref count all the files in the component */
2873 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2875 if (file
->Component
== comp
)
2876 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2880 /* add a count for permanent */
2881 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2884 comp
->RefCount
= count
;
2887 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2890 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2892 WCHAR squished_pc
[GUID_SIZE
];
2893 WCHAR squished_cc
[GUID_SIZE
];
2900 squash_guid(package
->ProductCode
,squished_pc
);
2901 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2903 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2907 ui_progress(package
,2,0,0,0);
2908 if (!comp
->ComponentId
)
2911 squash_guid(comp
->ComponentId
,squished_cc
);
2913 msi_free(comp
->FullKeypath
);
2914 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2916 ACTION_RefCountComponent( package
, comp
);
2918 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2919 debugstr_w(comp
->Component
),
2920 debugstr_w(squished_cc
),
2921 debugstr_w(comp
->FullKeypath
),
2924 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
||
2925 comp
->ActionRequest
== INSTALLSTATE_SOURCE
)
2927 if (!comp
->FullKeypath
)
2930 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2931 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2934 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2937 if (rc
!= ERROR_SUCCESS
)
2940 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2942 static const WCHAR szPermKey
[] =
2943 { '0','0','0','0','0','0','0','0','0','0','0','0',
2944 '0','0','0','0','0','0','0','0','0','0','0','0',
2945 '0','0','0','0','0','0','0','0',0 };
2947 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2950 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2951 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2957 WCHAR source
[MAX_PATH
];
2958 WCHAR base
[MAX_PATH
];
2961 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2962 static const WCHAR query
[] = {
2963 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2964 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2965 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2966 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2967 '`','D','i','s','k','I','d','`',0};
2969 file
= get_loaded_file(package
, comp
->KeyPath
);
2973 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2974 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2975 ptr2
= strrchrW(source
, '\\') + 1;
2976 msiobj_release(&row
->hdr
);
2978 lstrcpyW(base
, package
->PackagePath
);
2979 ptr
= strrchrW(base
, '\\');
2982 sourcepath
= resolve_file_source(package
, file
);
2983 ptr
= sourcepath
+ lstrlenW(base
);
2984 lstrcpyW(ptr2
, ptr
);
2985 msi_free(sourcepath
);
2987 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2991 else if (comp
->ActionRequest
== INSTALLSTATE_ABSENT
)
2993 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2994 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
2996 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
3000 uirow
= MSI_CreateRecord(3);
3001 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
3002 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
3003 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
3004 ui_actiondata(package
,szProcessComponents
,uirow
);
3005 msiobj_release( &uirow
->hdr
);
3008 return ERROR_SUCCESS
;
3019 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
3020 LPWSTR lpszName
, LONG_PTR lParam
)
3023 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
3024 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
3028 if (!IS_INTRESOURCE(lpszName
))
3030 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
3034 sz
= strlenW(tl_struct
->source
)+4;
3035 sz
*= sizeof(WCHAR
);
3037 if ((INT_PTR
)lpszName
== 1)
3038 tl_struct
->path
= strdupW(tl_struct
->source
);
3041 tl_struct
->path
= msi_alloc(sz
);
3042 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
3045 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
3046 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
3049 msi_free(tl_struct
->path
);
3050 tl_struct
->path
= NULL
;
3055 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
3056 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
3058 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3062 msi_free(tl_struct
->path
);
3063 tl_struct
->path
= NULL
;
3065 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3066 ITypeLib_Release(tl_struct
->ptLib
);
3071 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3073 MSIPACKAGE
* package
= param
;
3077 typelib_struct tl_struct
;
3082 component
= MSI_RecordGetString(row
,3);
3083 comp
= get_loaded_component(package
,component
);
3085 return ERROR_SUCCESS
;
3087 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3089 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3090 comp
->Action
= comp
->Installed
;
3091 return ERROR_SUCCESS
;
3093 comp
->Action
= INSTALLSTATE_LOCAL
;
3095 file
= get_loaded_file( package
, comp
->KeyPath
);
3097 return ERROR_SUCCESS
;
3099 ui_actiondata( package
, szRegisterTypeLibraries
, row
);
3101 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3105 guid
= MSI_RecordGetString(row
,1);
3106 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3107 tl_struct
.source
= strdupW( file
->TargetPath
);
3108 tl_struct
.path
= NULL
;
3110 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3111 (LONG_PTR
)&tl_struct
);
3119 helpid
= MSI_RecordGetString(row
,6);
3122 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3123 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3127 ERR("Failed to register type library %s\n",
3128 debugstr_w(tl_struct
.path
));
3130 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3132 ITypeLib_Release(tl_struct
.ptLib
);
3133 msi_free(tl_struct
.path
);
3136 ERR("Failed to load type library %s\n",
3137 debugstr_w(tl_struct
.source
));
3139 FreeLibrary(module
);
3140 msi_free(tl_struct
.source
);
3144 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3147 ERR("Failed to load type library: %08x\n", hr
);
3148 return ERROR_INSTALL_FAILURE
;
3151 ITypeLib_Release(tlib
);
3154 return ERROR_SUCCESS
;
3157 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3160 * OK this is a bit confusing.. I am given a _Component key and I believe
3161 * that the file that is being registered as a type library is the "key file
3162 * of that component" which I interpret to mean "The file in the KeyPath of
3167 static const WCHAR Query
[] =
3168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3169 '`','T','y','p','e','L','i','b','`',0};
3171 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3172 if (rc
!= ERROR_SUCCESS
)
3173 return ERROR_SUCCESS
;
3175 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3176 msiobj_release(&view
->hdr
);
3180 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
3182 MSIPACKAGE
*package
= param
;
3183 LPCWSTR component
, guid
;
3191 component
= MSI_RecordGetString( row
, 3 );
3192 comp
= get_loaded_component( package
, component
);
3194 return ERROR_SUCCESS
;
3196 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3198 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3199 comp
->Action
= comp
->Installed
;
3200 return ERROR_SUCCESS
;
3202 comp
->Action
= INSTALLSTATE_ABSENT
;
3204 ui_actiondata( package
, szUnregisterTypeLibraries
, row
);
3206 guid
= MSI_RecordGetString( row
, 1 );
3207 CLSIDFromString( (LPWSTR
)guid
, &libid
);
3208 version
= MSI_RecordGetInteger( row
, 4 );
3209 language
= MSI_RecordGetInteger( row
, 2 );
3212 syskind
= SYS_WIN64
;
3214 syskind
= SYS_WIN32
;
3217 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
3220 WARN("Failed to unregister typelib: %08x\n", hr
);
3223 return ERROR_SUCCESS
;
3226 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
3230 static const WCHAR query
[] =
3231 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3232 '`','T','y','p','e','L','i','b','`',0};
3234 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3235 if (rc
!= ERROR_SUCCESS
)
3236 return ERROR_SUCCESS
;
3238 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
3239 msiobj_release( &view
->hdr
);
3243 static WCHAR
*get_link_file( MSIPACKAGE
*package
, MSIRECORD
*row
)
3245 static const WCHAR szlnk
[] = {'.','l','n','k',0};
3246 LPCWSTR directory
, extension
;
3247 LPWSTR link_folder
, link_file
, filename
;
3249 directory
= MSI_RecordGetString( row
, 2 );
3250 link_folder
= resolve_folder( package
, directory
, FALSE
, FALSE
, TRUE
, NULL
);
3252 /* may be needed because of a bug somewhere else */
3253 create_full_pathW( link_folder
);
3255 filename
= msi_dup_record_field( row
, 3 );
3256 reduce_to_longfilename( filename
);
3258 extension
= strchrW( filename
, '.' );
3259 if (!extension
|| strcmpiW( extension
, szlnk
))
3261 int len
= strlenW( filename
);
3262 filename
= msi_realloc( filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
) );
3263 memcpy( filename
+ len
, szlnk
, sizeof(szlnk
) );
3265 link_file
= build_directory_name( 2, link_folder
, filename
);
3266 msi_free( link_folder
);
3267 msi_free( filename
);
3272 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3274 MSIPACKAGE
*package
= param
;
3275 LPWSTR link_file
, deformated
, path
;
3276 LPCWSTR component
, target
;
3278 IShellLinkW
*sl
= NULL
;
3279 IPersistFile
*pf
= NULL
;
3282 component
= MSI_RecordGetString(row
, 4);
3283 comp
= get_loaded_component(package
, component
);
3285 return ERROR_SUCCESS
;
3287 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3289 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3290 comp
->Action
= comp
->Installed
;
3291 return ERROR_SUCCESS
;
3293 comp
->Action
= INSTALLSTATE_LOCAL
;
3295 ui_actiondata(package
,szCreateShortcuts
,row
);
3297 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3298 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3302 ERR("CLSID_ShellLink not available\n");
3306 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3309 ERR("QueryInterface(IID_IPersistFile) failed\n");
3313 target
= MSI_RecordGetString(row
, 5);
3314 if (strchrW(target
, '['))
3316 deformat_string(package
, target
, &deformated
);
3317 IShellLinkW_SetPath(sl
,deformated
);
3318 msi_free(deformated
);
3322 FIXME("poorly handled shortcut format, advertised shortcut\n");
3323 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3326 if (!MSI_RecordIsNull(row
,6))
3328 LPCWSTR arguments
= MSI_RecordGetString(row
, 6);
3329 deformat_string(package
, arguments
, &deformated
);
3330 IShellLinkW_SetArguments(sl
,deformated
);
3331 msi_free(deformated
);
3334 if (!MSI_RecordIsNull(row
,7))
3336 LPCWSTR description
= MSI_RecordGetString(row
, 7);
3337 IShellLinkW_SetDescription(sl
, description
);
3340 if (!MSI_RecordIsNull(row
,8))
3341 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3343 if (!MSI_RecordIsNull(row
,9))
3346 LPCWSTR icon
= MSI_RecordGetString(row
, 9);
3348 path
= build_icon_path(package
, icon
);
3349 index
= MSI_RecordGetInteger(row
,10);
3351 /* no value means 0 */
3352 if (index
== MSI_NULL_INTEGER
)
3355 IShellLinkW_SetIconLocation(sl
, path
, index
);
3359 if (!MSI_RecordIsNull(row
,11))
3360 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3362 if (!MSI_RecordIsNull(row
,12))
3364 LPCWSTR wkdir
= MSI_RecordGetString(row
, 12);
3365 path
= resolve_folder(package
, wkdir
, FALSE
, FALSE
, TRUE
, NULL
);
3367 IShellLinkW_SetWorkingDirectory(sl
, path
);
3371 link_file
= get_link_file(package
, row
);
3373 TRACE("Writing shortcut to %s\n", debugstr_w(link_file
));
3374 IPersistFile_Save(pf
, link_file
, FALSE
);
3376 msi_free(link_file
);
3380 IPersistFile_Release( pf
);
3382 IShellLinkW_Release( sl
);
3384 return ERROR_SUCCESS
;
3387 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3392 static const WCHAR Query
[] =
3393 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3394 '`','S','h','o','r','t','c','u','t','`',0};
3396 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3397 if (rc
!= ERROR_SUCCESS
)
3398 return ERROR_SUCCESS
;
3400 res
= CoInitialize( NULL
);
3402 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3403 msiobj_release(&view
->hdr
);
3411 static UINT
ITERATE_RemoveShortcuts( MSIRECORD
*row
, LPVOID param
)
3413 MSIPACKAGE
*package
= param
;
3418 component
= MSI_RecordGetString( row
, 4 );
3419 comp
= get_loaded_component( package
, component
);
3421 return ERROR_SUCCESS
;
3423 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3425 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3426 comp
->Action
= comp
->Installed
;
3427 return ERROR_SUCCESS
;
3429 comp
->Action
= INSTALLSTATE_ABSENT
;
3431 ui_actiondata( package
, szRemoveShortcuts
, row
);
3433 link_file
= get_link_file( package
, row
);
3435 TRACE("Removing shortcut file %s\n", debugstr_w( link_file
));
3436 if (!DeleteFileW( link_file
))
3438 WARN("Failed to remove shortcut file %u\n", GetLastError());
3440 msi_free( link_file
);
3442 return ERROR_SUCCESS
;
3445 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
3449 static const WCHAR query
[] =
3450 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3451 '`','S','h','o','r','t','c','u','t','`',0};
3453 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3454 if (rc
!= ERROR_SUCCESS
)
3455 return ERROR_SUCCESS
;
3457 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveShortcuts
, package
);
3458 msiobj_release( &view
->hdr
);
3463 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3465 MSIPACKAGE
* package
= param
;
3473 FileName
= MSI_RecordGetString(row
,1);
3476 ERR("Unable to get FileName\n");
3477 return ERROR_SUCCESS
;
3480 FilePath
= build_icon_path(package
,FileName
);
3482 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3484 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3485 FILE_ATTRIBUTE_NORMAL
, NULL
);
3487 if (the_file
== INVALID_HANDLE_VALUE
)
3489 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3491 return ERROR_SUCCESS
;
3498 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3499 if (rc
!= ERROR_SUCCESS
)
3501 ERR("Failed to get stream\n");
3502 CloseHandle(the_file
);
3503 DeleteFileW(FilePath
);
3506 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3507 } while (sz
== 1024);
3510 CloseHandle(the_file
);
3512 return ERROR_SUCCESS
;
3515 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3520 static const WCHAR query
[]= {
3521 'S','E','L','E','C','T',' ','*',' ',
3522 'F','R','O','M',' ','`','I','c','o','n','`',0};
3524 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3525 if (r
== ERROR_SUCCESS
)
3527 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3528 msiobj_release(&view
->hdr
);
3531 return ERROR_SUCCESS
;
3534 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3540 MSISOURCELISTINFO
*info
;
3542 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3543 if (r
!= ERROR_SUCCESS
)
3546 RegCloseKey(source
);
3548 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3549 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3550 package
->Context
, MSICODE_PRODUCT
,
3551 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3552 if (r
!= ERROR_SUCCESS
)
3555 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3556 package
->Context
, MSICODE_PRODUCT
,
3557 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3558 if (r
!= ERROR_SUCCESS
)
3561 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3562 package
->Context
, MSICODE_PRODUCT
,
3563 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3564 if (r
!= ERROR_SUCCESS
)
3567 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3569 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3570 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3571 info
->options
, info
->value
);
3573 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3574 info
->context
, info
->options
,
3575 info
->property
, info
->value
);
3578 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3580 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3581 disk
->context
, disk
->options
,
3582 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3585 return ERROR_SUCCESS
;
3588 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3590 MSIHANDLE hdb
, suminfo
;
3591 WCHAR guids
[MAX_PATH
];
3592 WCHAR packcode
[SQUISH_GUID_SIZE
];
3599 static const WCHAR szProductLanguage
[] =
3600 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3601 static const WCHAR szARPProductIcon
[] =
3602 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3603 static const WCHAR szProductVersion
[] =
3604 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3605 static const WCHAR szAssignment
[] =
3606 {'A','s','s','i','g','n','m','e','n','t',0};
3607 static const WCHAR szAdvertiseFlags
[] =
3608 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3609 static const WCHAR szClients
[] =
3610 {'C','l','i','e','n','t','s',0};
3611 static const WCHAR szColon
[] = {':',0};
3613 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3614 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3617 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3618 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3621 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3623 buffer
= msi_dup_property(package
, szARPProductIcon
);
3626 LPWSTR path
= build_icon_path(package
,buffer
);
3627 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3632 buffer
= msi_dup_property(package
, szProductVersion
);
3635 DWORD verdword
= msi_version_str_to_dword(buffer
);
3636 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3640 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3641 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3642 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3643 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3645 hdb
= alloc_msihandle(&package
->db
->hdr
);
3647 return ERROR_NOT_ENOUGH_MEMORY
;
3649 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3650 MsiCloseHandle(hdb
);
3651 if (r
!= ERROR_SUCCESS
)
3655 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3656 NULL
, guids
, &size
);
3657 if (r
!= ERROR_SUCCESS
)
3660 ptr
= strchrW(guids
, ';');
3662 squash_guid(guids
, packcode
);
3663 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3666 MsiCloseHandle(suminfo
);
3667 return ERROR_SUCCESS
;
3670 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3675 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3677 static const WCHAR szUpgradeCode
[] =
3678 {'U','p','g','r','a','d','e','C','o','d','e',0};
3680 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3682 return ERROR_SUCCESS
;
3684 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3686 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3687 if (r
!= ERROR_SUCCESS
)
3692 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3693 if (r
!= ERROR_SUCCESS
)
3697 squash_guid(package
->ProductCode
, squashed_pc
);
3698 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3707 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3709 MSIFEATURE
*feature
;
3711 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3713 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3720 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3722 MSIFEATURE
*feature
;
3724 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3726 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3733 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3735 WCHAR patch_squashed
[GUID_SIZE
];
3738 UINT r
= ERROR_FUNCTION_FAILED
;
3740 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3742 if (res
!= ERROR_SUCCESS
)
3743 return ERROR_FUNCTION_FAILED
;
3745 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3747 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3748 (const BYTE
*)patch_squashed
,
3749 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3750 if (res
!= ERROR_SUCCESS
)
3753 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3754 (const BYTE
*)package
->patch
->transforms
,
3755 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3756 if (res
== ERROR_SUCCESS
)
3760 RegCloseKey(patches
);
3765 * 99% of the work done here is only done for
3766 * advertised installs. However this is where the
3767 * Icon table is processed and written out
3768 * so that is what I am going to do here.
3770 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3773 HKEY hukey
= NULL
, hudkey
= NULL
;
3776 /* FIXME: also need to publish if the product is in advertise mode */
3777 if (!msi_check_publish(package
))
3778 return ERROR_SUCCESS
;
3780 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3782 if (rc
!= ERROR_SUCCESS
)
3785 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3786 NULL
, &hudkey
, TRUE
);
3787 if (rc
!= ERROR_SUCCESS
)
3790 rc
= msi_publish_upgrade_code(package
);
3791 if (rc
!= ERROR_SUCCESS
)
3796 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3797 if (rc
!= ERROR_SUCCESS
)
3801 rc
= msi_publish_product_properties(package
, hukey
);
3802 if (rc
!= ERROR_SUCCESS
)
3805 rc
= msi_publish_sourcelist(package
, hukey
);
3806 if (rc
!= ERROR_SUCCESS
)
3809 rc
= msi_publish_icons(package
);
3812 uirow
= MSI_CreateRecord( 1 );
3813 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
3814 ui_actiondata( package
, szPublishProduct
, uirow
);
3815 msiobj_release( &uirow
->hdr
);
3818 RegCloseKey(hudkey
);
3823 static WCHAR
*get_ini_file_name( MSIPACKAGE
*package
, MSIRECORD
*row
)
3825 WCHAR
*filename
, *ptr
, *folder
, *ret
;
3826 const WCHAR
*dirprop
;
3828 filename
= msi_dup_record_field( row
, 2 );
3829 if (filename
&& (ptr
= strchrW( filename
, '|' )))
3834 dirprop
= MSI_RecordGetString( row
, 3 );
3837 folder
= resolve_folder( package
, dirprop
, FALSE
, FALSE
, TRUE
, NULL
);
3839 folder
= msi_dup_property( package
, dirprop
);
3842 folder
= msi_dup_property( package
, szWindowsFolder
);
3846 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop
));
3847 msi_free( filename
);
3851 ret
= build_directory_name( 2, folder
, ptr
);
3853 msi_free( filename
);
3858 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3860 MSIPACKAGE
*package
= param
;
3861 LPCWSTR component
, section
, key
, value
, identifier
;
3862 LPWSTR deformated_section
, deformated_key
, deformated_value
, fullname
;
3867 component
= MSI_RecordGetString(row
, 8);
3868 comp
= get_loaded_component(package
,component
);
3870 return ERROR_SUCCESS
;
3872 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3874 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3875 comp
->Action
= comp
->Installed
;
3876 return ERROR_SUCCESS
;
3878 comp
->Action
= INSTALLSTATE_LOCAL
;
3880 identifier
= MSI_RecordGetString(row
,1);
3881 section
= MSI_RecordGetString(row
,4);
3882 key
= MSI_RecordGetString(row
,5);
3883 value
= MSI_RecordGetString(row
,6);
3884 action
= MSI_RecordGetInteger(row
,7);
3886 deformat_string(package
,section
,&deformated_section
);
3887 deformat_string(package
,key
,&deformated_key
);
3888 deformat_string(package
,value
,&deformated_value
);
3890 fullname
= get_ini_file_name(package
, row
);
3894 TRACE("Adding value %s to section %s in %s\n",
3895 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3896 debugstr_w(fullname
));
3897 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3898 deformated_value
, fullname
);
3900 else if (action
== 1)
3903 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3904 returned
, 10, fullname
);
3905 if (returned
[0] == 0)
3907 TRACE("Adding value %s to section %s in %s\n",
3908 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3909 debugstr_w(fullname
));
3911 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3912 deformated_value
, fullname
);
3915 else if (action
== 3)
3916 FIXME("Append to existing section not yet implemented\n");
3918 uirow
= MSI_CreateRecord(4);
3919 MSI_RecordSetStringW(uirow
,1,identifier
);
3920 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3921 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3922 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3923 ui_actiondata(package
,szWriteIniValues
,uirow
);
3924 msiobj_release( &uirow
->hdr
);
3927 msi_free(deformated_key
);
3928 msi_free(deformated_value
);
3929 msi_free(deformated_section
);
3930 return ERROR_SUCCESS
;
3933 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3937 static const WCHAR ExecSeqQuery
[] =
3938 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3939 '`','I','n','i','F','i','l','e','`',0};
3941 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3942 if (rc
!= ERROR_SUCCESS
)
3944 TRACE("no IniFile table\n");
3945 return ERROR_SUCCESS
;
3948 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3949 msiobj_release(&view
->hdr
);
3953 static UINT
ITERATE_RemoveIniValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
3955 MSIPACKAGE
*package
= param
;
3956 LPCWSTR component
, section
, key
, value
, identifier
;
3957 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
3962 component
= MSI_RecordGetString( row
, 8 );
3963 comp
= get_loaded_component( package
, component
);
3965 return ERROR_SUCCESS
;
3967 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3969 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3970 comp
->Action
= comp
->Installed
;
3971 return ERROR_SUCCESS
;
3973 comp
->Action
= INSTALLSTATE_ABSENT
;
3975 identifier
= MSI_RecordGetString( row
, 1 );
3976 section
= MSI_RecordGetString( row
, 4 );
3977 key
= MSI_RecordGetString( row
, 5 );
3978 value
= MSI_RecordGetString( row
, 6 );
3979 action
= MSI_RecordGetInteger( row
, 7 );
3981 deformat_string( package
, section
, &deformated_section
);
3982 deformat_string( package
, key
, &deformated_key
);
3983 deformat_string( package
, value
, &deformated_value
);
3985 if (action
== msidbIniFileActionAddLine
|| action
== msidbIniFileActionCreateLine
)
3987 filename
= get_ini_file_name( package
, row
);
3989 TRACE("Removing key %s from section %s in %s\n",
3990 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
3992 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
3994 WARN("Unable to remove key %u\n", GetLastError());
3996 msi_free( filename
);
3999 FIXME("Unsupported action %d\n", action
);
4002 uirow
= MSI_CreateRecord( 4 );
4003 MSI_RecordSetStringW( uirow
, 1, identifier
);
4004 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4005 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4006 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4007 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4008 msiobj_release( &uirow
->hdr
);
4010 msi_free( deformated_key
);
4011 msi_free( deformated_value
);
4012 msi_free( deformated_section
);
4013 return ERROR_SUCCESS
;
4016 static UINT
ITERATE_RemoveIniValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
4018 MSIPACKAGE
*package
= param
;
4019 LPCWSTR component
, section
, key
, value
, identifier
;
4020 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
4025 component
= MSI_RecordGetString( row
, 8 );
4026 comp
= get_loaded_component( package
, component
);
4028 return ERROR_SUCCESS
;
4030 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4032 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
4033 comp
->Action
= comp
->Installed
;
4034 return ERROR_SUCCESS
;
4036 comp
->Action
= INSTALLSTATE_LOCAL
;
4038 identifier
= MSI_RecordGetString( row
, 1 );
4039 section
= MSI_RecordGetString( row
, 4 );
4040 key
= MSI_RecordGetString( row
, 5 );
4041 value
= MSI_RecordGetString( row
, 6 );
4042 action
= MSI_RecordGetInteger( row
, 7 );
4044 deformat_string( package
, section
, &deformated_section
);
4045 deformat_string( package
, key
, &deformated_key
);
4046 deformat_string( package
, value
, &deformated_value
);
4048 if (action
== msidbIniFileActionRemoveLine
)
4050 filename
= get_ini_file_name( package
, row
);
4052 TRACE("Removing key %s from section %s in %s\n",
4053 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
4055 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
4057 WARN("Unable to remove key %u\n", GetLastError());
4059 msi_free( filename
);
4062 FIXME("Unsupported action %d\n", action
);
4064 uirow
= MSI_CreateRecord( 4 );
4065 MSI_RecordSetStringW( uirow
, 1, identifier
);
4066 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4067 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4068 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4069 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4070 msiobj_release( &uirow
->hdr
);
4072 msi_free( deformated_key
);
4073 msi_free( deformated_value
);
4074 msi_free( deformated_section
);
4075 return ERROR_SUCCESS
;
4078 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4082 static const WCHAR query
[] =
4083 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4084 '`','I','n','i','F','i','l','e','`',0};
4085 static const WCHAR remove_query
[] =
4086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4087 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4089 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4090 if (rc
== ERROR_SUCCESS
)
4092 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnUninstall
, package
);
4093 msiobj_release( &view
->hdr
);
4094 if (rc
!= ERROR_SUCCESS
)
4098 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_query
, &view
);
4099 if (rc
== ERROR_SUCCESS
)
4101 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnInstall
, package
);
4102 msiobj_release( &view
->hdr
);
4103 if (rc
!= ERROR_SUCCESS
)
4107 return ERROR_SUCCESS
;
4110 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
4112 MSIPACKAGE
*package
= param
;
4117 static const WCHAR ExeStr
[] =
4118 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4119 static const WCHAR close
[] = {'\"',0};
4121 PROCESS_INFORMATION info
;
4126 memset(&si
,0,sizeof(STARTUPINFOW
));
4128 filename
= MSI_RecordGetString(row
,1);
4129 file
= get_loaded_file( package
, filename
);
4133 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4134 return ERROR_SUCCESS
;
4137 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
4139 FullName
= msi_alloc(len
*sizeof(WCHAR
));
4140 strcpyW(FullName
,ExeStr
);
4141 strcatW( FullName
, file
->TargetPath
);
4142 strcatW(FullName
,close
);
4144 TRACE("Registering %s\n",debugstr_w(FullName
));
4145 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
4150 CloseHandle(info
.hThread
);
4151 msi_dialog_check_messages(info
.hProcess
);
4152 CloseHandle(info
.hProcess
);
4155 uirow
= MSI_CreateRecord( 2 );
4156 MSI_RecordSetStringW( uirow
, 1, filename
);
4157 uipath
= strdupW( file
->TargetPath
);
4158 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4159 MSI_RecordSetStringW( uirow
, 2, uipath
);
4160 ui_actiondata( package
, szSelfRegModules
, uirow
);
4161 msiobj_release( &uirow
->hdr
);
4163 msi_free( FullName
);
4165 return ERROR_SUCCESS
;
4168 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4172 static const WCHAR ExecSeqQuery
[] =
4173 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4174 '`','S','e','l','f','R','e','g','`',0};
4176 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4177 if (rc
!= ERROR_SUCCESS
)
4179 TRACE("no SelfReg table\n");
4180 return ERROR_SUCCESS
;
4183 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
4184 msiobj_release(&view
->hdr
);
4186 return ERROR_SUCCESS
;
4189 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
4191 static const WCHAR regsvr32
[] =
4192 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4193 static const WCHAR close
[] = {'\"',0};
4194 MSIPACKAGE
*package
= param
;
4200 PROCESS_INFORMATION pi
;
4205 memset( &si
, 0, sizeof(STARTUPINFOW
) );
4207 filename
= MSI_RecordGetString( row
, 1 );
4208 file
= get_loaded_file( package
, filename
);
4212 ERR("Unable to find file id %s\n", debugstr_w(filename
));
4213 return ERROR_SUCCESS
;
4216 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
4218 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
4219 strcpyW( cmdline
, regsvr32
);
4220 strcatW( cmdline
, file
->TargetPath
);
4221 strcatW( cmdline
, close
);
4223 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
4225 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
4228 CloseHandle( pi
.hThread
);
4229 msi_dialog_check_messages( pi
.hProcess
);
4230 CloseHandle( pi
.hProcess
);
4233 uirow
= MSI_CreateRecord( 2 );
4234 MSI_RecordSetStringW( uirow
, 1, filename
);
4235 uipath
= strdupW( file
->TargetPath
);
4236 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4237 MSI_RecordSetStringW( uirow
, 2, uipath
);
4238 ui_actiondata( package
, szSelfUnregModules
, uirow
);
4239 msiobj_release( &uirow
->hdr
);
4241 msi_free( cmdline
);
4243 return ERROR_SUCCESS
;
4246 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4250 static const WCHAR query
[] =
4251 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4252 '`','S','e','l','f','R','e','g','`',0};
4254 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4255 if (rc
!= ERROR_SUCCESS
)
4257 TRACE("no SelfReg table\n");
4258 return ERROR_SUCCESS
;
4261 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
4262 msiobj_release( &view
->hdr
);
4264 return ERROR_SUCCESS
;
4267 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4269 MSIFEATURE
*feature
;
4271 HKEY hkey
= NULL
, userdata
= NULL
;
4273 if (!msi_check_publish(package
))
4274 return ERROR_SUCCESS
;
4276 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4278 if (rc
!= ERROR_SUCCESS
)
4281 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4283 if (rc
!= ERROR_SUCCESS
)
4286 /* here the guids are base 85 encoded */
4287 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
4293 BOOL absent
= FALSE
;
4296 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4297 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4298 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
4301 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4305 if (feature
->Feature_Parent
)
4306 size
+= strlenW( feature
->Feature_Parent
)+2;
4308 data
= msi_alloc(size
* sizeof(WCHAR
));
4311 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4313 MSICOMPONENT
* component
= cl
->component
;
4317 if (component
->ComponentId
)
4319 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4320 CLSIDFromString(component
->ComponentId
, &clsid
);
4321 encode_base85_guid(&clsid
,buf
);
4322 TRACE("to %s\n",debugstr_w(buf
));
4327 if (feature
->Feature_Parent
)
4329 static const WCHAR sep
[] = {'\2',0};
4331 strcatW(data
,feature
->Feature_Parent
);
4334 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4338 if (feature
->Feature_Parent
)
4339 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4342 size
+= sizeof(WCHAR
);
4343 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4344 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
4348 size
+= 2*sizeof(WCHAR
);
4349 data
= msi_alloc(size
);
4352 if (feature
->Feature_Parent
)
4353 strcpyW( &data
[1], feature
->Feature_Parent
);
4354 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4360 uirow
= MSI_CreateRecord( 1 );
4361 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4362 ui_actiondata( package
, szPublishFeatures
, uirow
);
4363 msiobj_release( &uirow
->hdr
);
4364 /* FIXME: call ui_progress? */
4369 RegCloseKey(userdata
);
4373 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4378 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4380 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4382 if (r
== ERROR_SUCCESS
)
4384 RegDeleteValueW(hkey
, feature
->Feature
);
4388 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4390 if (r
== ERROR_SUCCESS
)
4392 RegDeleteValueW(hkey
, feature
->Feature
);
4396 return ERROR_SUCCESS
;
4399 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4401 MSIFEATURE
*feature
;
4403 if (!msi_check_unpublish(package
))
4404 return ERROR_SUCCESS
;
4406 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4408 msi_unpublish_feature(package
, feature
);
4411 return ERROR_SUCCESS
;
4414 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4416 LPWSTR prop
, val
, key
;
4422 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4423 static const WCHAR szWindowsInstaller
[] =
4424 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4425 static const WCHAR modpath_fmt
[] =
4426 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4427 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4428 static const WCHAR szModifyPath
[] =
4429 {'M','o','d','i','f','y','P','a','t','h',0};
4430 static const WCHAR szUninstallString
[] =
4431 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4432 static const WCHAR szEstimatedSize
[] =
4433 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4434 static const WCHAR szProductLanguage
[] =
4435 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4436 static const WCHAR szProductVersion
[] =
4437 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4438 static const WCHAR szProductName
[] =
4439 {'P','r','o','d','u','c','t','N','a','m','e',0};
4440 static const WCHAR szDisplayName
[] =
4441 {'D','i','s','p','l','a','y','N','a','m','e',0};
4442 static const WCHAR szDisplayVersion
[] =
4443 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4444 static const WCHAR szManufacturer
[] =
4445 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4447 static const LPCSTR propval
[] = {
4448 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4449 "ARPCONTACT", "Contact",
4450 "ARPCOMMENTS", "Comments",
4451 "ProductName", "DisplayName",
4452 "ProductVersion", "DisplayVersion",
4453 "ARPHELPLINK", "HelpLink",
4454 "ARPHELPTELEPHONE", "HelpTelephone",
4455 "ARPINSTALLLOCATION", "InstallLocation",
4456 "SourceDir", "InstallSource",
4457 "Manufacturer", "Publisher",
4458 "ARPREADME", "Readme",
4460 "ARPURLINFOABOUT", "URLInfoAbout",
4461 "ARPURLUPDATEINFO", "URLUpdateInfo",
4464 const LPCSTR
*p
= propval
;
4468 prop
= strdupAtoW(*p
++);
4469 key
= strdupAtoW(*p
++);
4470 val
= msi_dup_property(package
, prop
);
4471 msi_reg_set_val_str(hkey
, key
, val
);
4477 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4479 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4480 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4481 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4484 /* FIXME: Write real Estimated Size when we have it */
4485 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4487 buffer
= msi_dup_property(package
, szProductName
);
4488 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4491 buffer
= msi_dup_property(package
, cszSourceDir
);
4492 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4495 buffer
= msi_dup_property(package
, szManufacturer
);
4496 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4499 GetLocalTime(&systime
);
4500 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4501 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4503 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4504 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4506 buffer
= msi_dup_property(package
, szProductVersion
);
4507 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4510 DWORD verdword
= msi_version_str_to_dword(buffer
);
4512 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4513 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4514 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4518 return ERROR_SUCCESS
;
4521 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4523 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4525 LPWSTR upgrade_code
;
4530 static const WCHAR szUpgradeCode
[] = {
4531 'U','p','g','r','a','d','e','C','o','d','e',0};
4533 /* FIXME: also need to publish if the product is in advertise mode */
4534 if (!msi_check_publish(package
))
4535 return ERROR_SUCCESS
;
4537 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4538 if (rc
!= ERROR_SUCCESS
)
4541 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4542 NULL
, &props
, TRUE
);
4543 if (rc
!= ERROR_SUCCESS
)
4546 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4547 msi_free( package
->db
->localfile
);
4548 package
->db
->localfile
= NULL
;
4550 rc
= msi_publish_install_properties(package
, hkey
);
4551 if (rc
!= ERROR_SUCCESS
)
4554 rc
= msi_publish_install_properties(package
, props
);
4555 if (rc
!= ERROR_SUCCESS
)
4558 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4561 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4562 squash_guid(package
->ProductCode
, squashed_pc
);
4563 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4564 RegCloseKey(upgrade
);
4565 msi_free(upgrade_code
);
4569 uirow
= MSI_CreateRecord( 1 );
4570 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4571 ui_actiondata( package
, szRegisterProduct
, uirow
);
4572 msiobj_release( &uirow
->hdr
);
4575 return ERROR_SUCCESS
;
4578 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4580 return execute_script(package
,INSTALL_SCRIPT
);
4583 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4586 LPWSTR remove
= NULL
;
4587 LPWSTR
*features
= NULL
;
4588 BOOL full_uninstall
= TRUE
;
4589 MSIFEATURE
*feature
;
4591 static const WCHAR szUpgradeCode
[] =
4592 {'U','p','g','r','a','d','e','C','o','d','e',0};
4594 remove
= msi_dup_property(package
, szRemove
);
4596 return ERROR_SUCCESS
;
4598 features
= msi_split_string(remove
, ',');
4602 ERR("REMOVE feature list is empty!\n");
4603 return ERROR_FUNCTION_FAILED
;
4606 if (!lstrcmpW(features
[0], szAll
))
4607 full_uninstall
= TRUE
;
4610 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4612 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4613 full_uninstall
= FALSE
;
4617 if (!full_uninstall
)
4620 MSIREG_DeleteProductKey(package
->ProductCode
);
4621 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4622 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4624 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4626 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4627 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4631 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4632 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4635 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4638 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4645 return ERROR_SUCCESS
;
4648 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4652 rc
= msi_unpublish_product(package
);
4653 if (rc
!= ERROR_SUCCESS
)
4656 /* turn off scheduling */
4657 package
->script
->CurrentlyScripting
= FALSE
;
4659 /* first do the same as an InstallExecute */
4660 rc
= ACTION_InstallExecute(package
);
4661 if (rc
!= ERROR_SUCCESS
)
4664 /* then handle Commit Actions */
4665 rc
= execute_script(package
,COMMIT_SCRIPT
);
4670 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4672 static const WCHAR RunOnce
[] = {
4673 'S','o','f','t','w','a','r','e','\\',
4674 'M','i','c','r','o','s','o','f','t','\\',
4675 'W','i','n','d','o','w','s','\\',
4676 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4677 'R','u','n','O','n','c','e',0};
4678 static const WCHAR InstallRunOnce
[] = {
4679 'S','o','f','t','w','a','r','e','\\',
4680 'M','i','c','r','o','s','o','f','t','\\',
4681 'W','i','n','d','o','w','s','\\',
4682 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4683 'I','n','s','t','a','l','l','e','r','\\',
4684 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4686 static const WCHAR msiexec_fmt
[] = {
4688 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4689 '\"','%','s','\"',0};
4690 static const WCHAR install_fmt
[] = {
4691 '/','I',' ','\"','%','s','\"',' ',
4692 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4693 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4694 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4696 WCHAR squished_pc
[100];
4698 squash_guid(package
->ProductCode
,squished_pc
);
4700 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4701 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4702 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4705 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4708 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4710 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4711 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4713 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4716 return ERROR_INSTALL_SUSPEND
;
4719 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4725 * We are currently doing what should be done here in the top level Install
4726 * however for Administrative and uninstalls this step will be needed
4728 if (!package
->PackagePath
)
4729 return ERROR_SUCCESS
;
4731 msi_set_sourcedir_props(package
, TRUE
);
4733 attrib
= GetFileAttributesW(package
->db
->path
);
4734 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4740 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4741 package
->Context
, MSICODE_PRODUCT
,
4742 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4743 if (rc
== ERROR_MORE_DATA
)
4745 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4746 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4747 package
->Context
, MSICODE_PRODUCT
,
4748 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4751 prompt
= strdupW(package
->db
->path
);
4753 msg
= generate_error_string(package
,1302,1,prompt
);
4754 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4756 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4759 rc
= ERROR_INSTALL_USEREXIT
;
4762 attrib
= GetFileAttributesW(package
->db
->path
);
4768 return ERROR_SUCCESS
;
4773 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4776 LPWSTR buffer
, productid
= NULL
;
4777 UINT i
, rc
= ERROR_SUCCESS
;
4780 static const WCHAR szPropKeys
[][80] =
4782 {'P','r','o','d','u','c','t','I','D',0},
4783 {'U','S','E','R','N','A','M','E',0},
4784 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4788 static const WCHAR szRegKeys
[][80] =
4790 {'P','r','o','d','u','c','t','I','D',0},
4791 {'R','e','g','O','w','n','e','r',0},
4792 {'R','e','g','C','o','m','p','a','n','y',0},
4796 if (msi_check_unpublish(package
))
4798 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4802 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4806 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4808 if (rc
!= ERROR_SUCCESS
)
4811 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4813 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4814 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4819 uirow
= MSI_CreateRecord( 1 );
4820 MSI_RecordSetStringW( uirow
, 1, productid
);
4821 ui_actiondata( package
, szRegisterUser
, uirow
);
4822 msiobj_release( &uirow
->hdr
);
4824 msi_free(productid
);
4830 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4834 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4835 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4840 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4842 MSIPACKAGE
*package
= param
;
4843 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
4844 LPWSTR advertise
= NULL
, output
= NULL
;
4852 feature
= MSI_RecordGetString(rec
, 5);
4853 feat
= get_loaded_feature(package
, feature
);
4855 return ERROR_SUCCESS
;
4857 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4858 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4859 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
4861 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
4862 feat
->Action
= feat
->Installed
;
4863 return ERROR_SUCCESS
;
4866 component
= MSI_RecordGetString(rec
, 3);
4867 comp
= get_loaded_component(package
, component
);
4869 return ERROR_SUCCESS
;
4871 compgroupid
= MSI_RecordGetString(rec
,1);
4872 qualifier
= MSI_RecordGetString(rec
,2);
4874 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4875 if (rc
!= ERROR_SUCCESS
)
4878 text
= MSI_RecordGetString(rec
,4);
4879 advertise
= create_component_advertise_string(package
, comp
, feature
);
4881 sz
= strlenW(advertise
);
4884 sz
+= lstrlenW(text
);
4887 sz
*= sizeof(WCHAR
);
4889 output
= msi_alloc_zero(sz
);
4890 strcpyW(output
,advertise
);
4891 msi_free(advertise
);
4894 strcatW(output
,text
);
4896 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4903 uirow
= MSI_CreateRecord( 2 );
4904 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4905 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4906 ui_actiondata( package
, szPublishComponents
, uirow
);
4907 msiobj_release( &uirow
->hdr
);
4908 /* FIXME: call ui_progress? */
4914 * At present I am ignorning the advertised components part of this and only
4915 * focusing on the qualified component sets
4917 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4921 static const WCHAR ExecSeqQuery
[] =
4922 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4923 '`','P','u','b','l','i','s','h',
4924 'C','o','m','p','o','n','e','n','t','`',0};
4926 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4927 if (rc
!= ERROR_SUCCESS
)
4928 return ERROR_SUCCESS
;
4930 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4931 msiobj_release(&view
->hdr
);
4936 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
4938 static const WCHAR szInstallerComponents
[] = {
4939 'S','o','f','t','w','a','r','e','\\',
4940 'M','i','c','r','o','s','o','f','t','\\',
4941 'I','n','s','t','a','l','l','e','r','\\',
4942 'C','o','m','p','o','n','e','n','t','s','\\',0};
4944 MSIPACKAGE
*package
= param
;
4945 LPCWSTR compgroupid
, component
, feature
, qualifier
;
4949 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
4952 feature
= MSI_RecordGetString( rec
, 5 );
4953 feat
= get_loaded_feature( package
, feature
);
4955 return ERROR_SUCCESS
;
4957 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4959 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
4960 feat
->Action
= feat
->Installed
;
4961 return ERROR_SUCCESS
;
4964 component
= MSI_RecordGetString( rec
, 3 );
4965 comp
= get_loaded_component( package
, component
);
4967 return ERROR_SUCCESS
;
4969 compgroupid
= MSI_RecordGetString( rec
, 1 );
4970 qualifier
= MSI_RecordGetString( rec
, 2 );
4972 squash_guid( compgroupid
, squashed
);
4973 strcpyW( keypath
, szInstallerComponents
);
4974 strcatW( keypath
, squashed
);
4976 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
4977 if (res
!= ERROR_SUCCESS
)
4979 WARN("Unable to delete component key %d\n", res
);
4982 uirow
= MSI_CreateRecord( 2 );
4983 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4984 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4985 ui_actiondata( package
, szUnpublishComponents
, uirow
);
4986 msiobj_release( &uirow
->hdr
);
4988 return ERROR_SUCCESS
;
4991 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
4995 static const WCHAR query
[] =
4996 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4997 '`','P','u','b','l','i','s','h',
4998 'C','o','m','p','o','n','e','n','t','`',0};
5000 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5001 if (rc
!= ERROR_SUCCESS
)
5002 return ERROR_SUCCESS
;
5004 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
5005 msiobj_release( &view
->hdr
);
5010 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
5012 MSIPACKAGE
*package
= param
;
5015 SC_HANDLE hscm
, service
= NULL
;
5016 LPCWSTR comp
, depends
, pass
;
5017 LPWSTR name
= NULL
, disp
= NULL
;
5018 LPCWSTR load_order
, serv_name
, key
;
5019 DWORD serv_type
, start_type
;
5022 static const WCHAR query
[] =
5023 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5024 '`','C','o','m','p','o','n','e','n','t','`',' ',
5025 'W','H','E','R','E',' ',
5026 '`','C','o','m','p','o','n','e','n','t','`',' ',
5027 '=','\'','%','s','\'',0};
5029 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
5032 ERR("Failed to open the SC Manager!\n");
5036 start_type
= MSI_RecordGetInteger(rec
, 5);
5037 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
5040 depends
= MSI_RecordGetString(rec
, 8);
5041 if (depends
&& *depends
)
5042 FIXME("Dependency list unhandled!\n");
5044 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5045 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
5046 serv_type
= MSI_RecordGetInteger(rec
, 4);
5047 err_control
= MSI_RecordGetInteger(rec
, 6);
5048 load_order
= MSI_RecordGetString(rec
, 7);
5049 serv_name
= MSI_RecordGetString(rec
, 9);
5050 pass
= MSI_RecordGetString(rec
, 10);
5051 comp
= MSI_RecordGetString(rec
, 12);
5053 /* fetch the service path */
5054 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
5057 ERR("Control query failed!\n");
5061 key
= MSI_RecordGetString(row
, 6);
5063 file
= get_loaded_file(package
, key
);
5064 msiobj_release(&row
->hdr
);
5067 ERR("Failed to load the service file\n");
5071 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
5072 start_type
, err_control
, file
->TargetPath
,
5073 load_order
, NULL
, NULL
, serv_name
, pass
);
5076 if (GetLastError() != ERROR_SERVICE_EXISTS
)
5077 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
5081 CloseServiceHandle(service
);
5082 CloseServiceHandle(hscm
);
5086 return ERROR_SUCCESS
;
5089 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
5093 static const WCHAR ExecSeqQuery
[] =
5094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5095 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5097 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5098 if (rc
!= ERROR_SUCCESS
)
5099 return ERROR_SUCCESS
;
5101 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
5102 msiobj_release(&view
->hdr
);
5107 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5108 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
5110 LPCWSTR
*vector
, *temp_vector
;
5114 static const WCHAR separator
[] = {'[','~',']',0};
5117 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
5122 vector
= msi_alloc(sizeof(LPWSTR
));
5130 vector
[*numargs
- 1] = p
;
5132 if ((q
= strstrW(p
, separator
)))
5136 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
5142 vector
= temp_vector
;
5151 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
5153 MSIPACKAGE
*package
= param
;
5155 SC_HANDLE scm
= NULL
, service
= NULL
;
5156 LPCWSTR component
, *vector
= NULL
;
5158 DWORD event
, numargs
;
5159 UINT r
= ERROR_FUNCTION_FAILED
;
5161 component
= MSI_RecordGetString(rec
, 6);
5162 comp
= get_loaded_component(package
, component
);
5164 return ERROR_SUCCESS
;
5166 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5168 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
5169 comp
->Action
= comp
->Installed
;
5170 return ERROR_SUCCESS
;
5172 comp
->Action
= INSTALLSTATE_LOCAL
;
5174 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5175 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
5176 event
= MSI_RecordGetInteger(rec
, 3);
5178 if (!(event
& msidbServiceControlEventStart
))
5184 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
5187 ERR("Failed to open the service control manager\n");
5191 service
= OpenServiceW(scm
, name
, SERVICE_START
);
5194 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
5198 vector
= msi_service_args_to_vector(args
, &numargs
);
5200 if (!StartServiceW(service
, numargs
, vector
) &&
5201 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
5203 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
5210 CloseServiceHandle(service
);
5211 CloseServiceHandle(scm
);
5219 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
5224 static const WCHAR query
[] = {
5225 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5226 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5228 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5229 if (rc
!= ERROR_SUCCESS
)
5230 return ERROR_SUCCESS
;
5232 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
5233 msiobj_release(&view
->hdr
);
5238 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
5240 DWORD i
, needed
, count
;
5241 ENUM_SERVICE_STATUSW
*dependencies
;
5245 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
5246 0, &needed
, &count
))
5249 if (GetLastError() != ERROR_MORE_DATA
)
5252 dependencies
= msi_alloc(needed
);
5256 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
5257 needed
, &needed
, &count
))
5260 for (i
= 0; i
< count
; i
++)
5262 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
5263 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
5267 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
5274 msi_free(dependencies
);
5278 static UINT
stop_service( LPCWSTR name
)
5280 SC_HANDLE scm
= NULL
, service
= NULL
;
5281 SERVICE_STATUS status
;
5282 SERVICE_STATUS_PROCESS ssp
;
5285 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5288 WARN("Failed to open the SCM: %d\n", GetLastError());
5292 service
= OpenServiceW(scm
, name
,
5294 SERVICE_QUERY_STATUS
|
5295 SERVICE_ENUMERATE_DEPENDENTS
);
5298 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
5302 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
5303 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
5305 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
5309 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
5312 stop_service_dependents(scm
, service
);
5314 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5315 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5318 CloseServiceHandle(service
);
5319 CloseServiceHandle(scm
);
5321 return ERROR_SUCCESS
;
5324 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
5326 MSIPACKAGE
*package
= param
;
5332 event
= MSI_RecordGetInteger( rec
, 3 );
5333 if (!(event
& msidbServiceControlEventStop
))
5334 return ERROR_SUCCESS
;
5336 component
= MSI_RecordGetString( rec
, 6 );
5337 comp
= get_loaded_component( package
, component
);
5339 return ERROR_SUCCESS
;
5341 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5343 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5344 comp
->Action
= comp
->Installed
;
5345 return ERROR_SUCCESS
;
5347 comp
->Action
= INSTALLSTATE_ABSENT
;
5349 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
5350 stop_service( name
);
5353 return ERROR_SUCCESS
;
5356 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5361 static const WCHAR query
[] = {
5362 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5363 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5365 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5366 if (rc
!= ERROR_SUCCESS
)
5367 return ERROR_SUCCESS
;
5369 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5370 msiobj_release(&view
->hdr
);
5375 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
5377 MSIPACKAGE
*package
= param
;
5381 LPWSTR name
= NULL
, display_name
= NULL
;
5383 SC_HANDLE scm
= NULL
, service
= NULL
;
5385 event
= MSI_RecordGetInteger( rec
, 3 );
5386 if (!(event
& msidbServiceControlEventDelete
))
5387 return ERROR_SUCCESS
;
5389 component
= MSI_RecordGetString(rec
, 6);
5390 comp
= get_loaded_component(package
, component
);
5392 return ERROR_SUCCESS
;
5394 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5396 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5397 comp
->Action
= comp
->Installed
;
5398 return ERROR_SUCCESS
;
5400 comp
->Action
= INSTALLSTATE_ABSENT
;
5402 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
5403 stop_service( name
);
5405 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5408 WARN("Failed to open the SCM: %d\n", GetLastError());
5413 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5414 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5416 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5417 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5420 service
= OpenServiceW( scm
, name
, DELETE
);
5423 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
5427 if (!DeleteService( service
))
5428 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
5431 uirow
= MSI_CreateRecord( 2 );
5432 MSI_RecordSetStringW( uirow
, 1, display_name
);
5433 MSI_RecordSetStringW( uirow
, 2, name
);
5434 ui_actiondata( package
, szDeleteServices
, uirow
);
5435 msiobj_release( &uirow
->hdr
);
5437 CloseServiceHandle( service
);
5438 CloseServiceHandle( scm
);
5440 msi_free( display_name
);
5442 return ERROR_SUCCESS
;
5445 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5450 static const WCHAR query
[] = {
5451 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5452 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5454 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5455 if (rc
!= ERROR_SUCCESS
)
5456 return ERROR_SUCCESS
;
5458 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
5459 msiobj_release( &view
->hdr
);
5464 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5468 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5470 if (!lstrcmpW(file
->File
, filename
))
5477 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5479 MSIPACKAGE
*package
= param
;
5480 LPWSTR driver
, driver_path
, ptr
;
5481 WCHAR outpath
[MAX_PATH
];
5482 MSIFILE
*driver_file
, *setup_file
;
5486 UINT r
= ERROR_SUCCESS
;
5488 static const WCHAR driver_fmt
[] = {
5489 'D','r','i','v','e','r','=','%','s',0};
5490 static const WCHAR setup_fmt
[] = {
5491 'S','e','t','u','p','=','%','s',0};
5492 static const WCHAR usage_fmt
[] = {
5493 'F','i','l','e','U','s','a','g','e','=','1',0};
5495 desc
= MSI_RecordGetString(rec
, 3);
5497 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5498 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5502 ERR("ODBC Driver entry not found!\n");
5503 return ERROR_FUNCTION_FAILED
;
5506 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
5508 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5509 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
5511 driver
= msi_alloc(len
* sizeof(WCHAR
));
5513 return ERROR_OUTOFMEMORY
;
5516 lstrcpyW(ptr
, desc
);
5517 ptr
+= lstrlenW(ptr
) + 1;
5519 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5524 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5528 lstrcpyW(ptr
, usage_fmt
);
5529 ptr
+= lstrlenW(ptr
) + 1;
5532 driver_path
= strdupW(driver_file
->TargetPath
);
5533 ptr
= strrchrW(driver_path
, '\\');
5534 if (ptr
) *ptr
= '\0';
5536 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5537 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5539 ERR("Failed to install SQL driver!\n");
5540 r
= ERROR_FUNCTION_FAILED
;
5543 uirow
= MSI_CreateRecord( 5 );
5544 MSI_RecordSetStringW( uirow
, 1, desc
);
5545 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5546 MSI_RecordSetStringW( uirow
, 3, driver_path
);
5547 ui_actiondata( package
, szInstallODBC
, uirow
);
5548 msiobj_release( &uirow
->hdr
);
5551 msi_free(driver_path
);
5556 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5558 MSIPACKAGE
*package
= param
;
5559 LPWSTR translator
, translator_path
, ptr
;
5560 WCHAR outpath
[MAX_PATH
];
5561 MSIFILE
*translator_file
, *setup_file
;
5565 UINT r
= ERROR_SUCCESS
;
5567 static const WCHAR translator_fmt
[] = {
5568 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5569 static const WCHAR setup_fmt
[] = {
5570 'S','e','t','u','p','=','%','s',0};
5572 desc
= MSI_RecordGetString(rec
, 3);
5574 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5575 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5577 if (!translator_file
)
5579 ERR("ODBC Translator entry not found!\n");
5580 return ERROR_FUNCTION_FAILED
;
5583 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
5585 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5587 translator
= msi_alloc(len
* sizeof(WCHAR
));
5589 return ERROR_OUTOFMEMORY
;
5592 lstrcpyW(ptr
, desc
);
5593 ptr
+= lstrlenW(ptr
) + 1;
5595 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5600 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5605 translator_path
= strdupW(translator_file
->TargetPath
);
5606 ptr
= strrchrW(translator_path
, '\\');
5607 if (ptr
) *ptr
= '\0';
5609 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5610 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5612 ERR("Failed to install SQL translator!\n");
5613 r
= ERROR_FUNCTION_FAILED
;
5616 uirow
= MSI_CreateRecord( 5 );
5617 MSI_RecordSetStringW( uirow
, 1, desc
);
5618 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5619 MSI_RecordSetStringW( uirow
, 3, translator_path
);
5620 ui_actiondata( package
, szInstallODBC
, uirow
);
5621 msiobj_release( &uirow
->hdr
);
5623 msi_free(translator
);
5624 msi_free(translator_path
);
5629 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5631 MSIPACKAGE
*package
= param
;
5633 LPCWSTR desc
, driver
;
5634 WORD request
= ODBC_ADD_SYS_DSN
;
5637 UINT r
= ERROR_SUCCESS
;
5640 static const WCHAR attrs_fmt
[] = {
5641 'D','S','N','=','%','s',0 };
5643 desc
= MSI_RecordGetString(rec
, 3);
5644 driver
= MSI_RecordGetString(rec
, 4);
5645 registration
= MSI_RecordGetInteger(rec
, 5);
5647 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5648 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5650 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
5651 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5653 return ERROR_OUTOFMEMORY
;
5655 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5658 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5660 ERR("Failed to install SQL data source!\n");
5661 r
= ERROR_FUNCTION_FAILED
;
5664 uirow
= MSI_CreateRecord( 5 );
5665 MSI_RecordSetStringW( uirow
, 1, desc
);
5666 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5667 MSI_RecordSetInteger( uirow
, 3, request
);
5668 ui_actiondata( package
, szInstallODBC
, uirow
);
5669 msiobj_release( &uirow
->hdr
);
5676 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5681 static const WCHAR driver_query
[] = {
5682 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5683 'O','D','B','C','D','r','i','v','e','r',0 };
5685 static const WCHAR translator_query
[] = {
5686 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5687 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5689 static const WCHAR source_query
[] = {
5690 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5691 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5693 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5694 if (rc
!= ERROR_SUCCESS
)
5695 return ERROR_SUCCESS
;
5697 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5698 msiobj_release(&view
->hdr
);
5700 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5701 if (rc
!= ERROR_SUCCESS
)
5702 return ERROR_SUCCESS
;
5704 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5705 msiobj_release(&view
->hdr
);
5707 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5708 if (rc
!= ERROR_SUCCESS
)
5709 return ERROR_SUCCESS
;
5711 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5712 msiobj_release(&view
->hdr
);
5717 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5719 MSIPACKAGE
*package
= param
;
5724 desc
= MSI_RecordGetString( rec
, 3 );
5725 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5727 WARN("Failed to remove ODBC driver\n");
5731 FIXME("Usage count reached 0\n");
5734 uirow
= MSI_CreateRecord( 2 );
5735 MSI_RecordSetStringW( uirow
, 1, desc
);
5736 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5737 ui_actiondata( package
, szRemoveODBC
, uirow
);
5738 msiobj_release( &uirow
->hdr
);
5740 return ERROR_SUCCESS
;
5743 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5745 MSIPACKAGE
*package
= param
;
5750 desc
= MSI_RecordGetString( rec
, 3 );
5751 if (!SQLRemoveTranslatorW( desc
, &usage
))
5753 WARN("Failed to remove ODBC translator\n");
5757 FIXME("Usage count reached 0\n");
5760 uirow
= MSI_CreateRecord( 2 );
5761 MSI_RecordSetStringW( uirow
, 1, desc
);
5762 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5763 ui_actiondata( package
, szRemoveODBC
, uirow
);
5764 msiobj_release( &uirow
->hdr
);
5766 return ERROR_SUCCESS
;
5769 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5771 MSIPACKAGE
*package
= param
;
5774 LPCWSTR desc
, driver
;
5775 WORD request
= ODBC_REMOVE_SYS_DSN
;
5779 static const WCHAR attrs_fmt
[] = {
5780 'D','S','N','=','%','s',0 };
5782 desc
= MSI_RecordGetString( rec
, 3 );
5783 driver
= MSI_RecordGetString( rec
, 4 );
5784 registration
= MSI_RecordGetInteger( rec
, 5 );
5786 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5787 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5789 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
5790 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5792 return ERROR_OUTOFMEMORY
;
5794 FIXME("Use ODBCSourceAttribute table\n");
5796 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5799 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5801 WARN("Failed to remove ODBC data source\n");
5805 uirow
= MSI_CreateRecord( 3 );
5806 MSI_RecordSetStringW( uirow
, 1, desc
);
5807 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5808 MSI_RecordSetInteger( uirow
, 3, request
);
5809 ui_actiondata( package
, szRemoveODBC
, uirow
);
5810 msiobj_release( &uirow
->hdr
);
5812 return ERROR_SUCCESS
;
5815 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5820 static const WCHAR driver_query
[] = {
5821 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5822 'O','D','B','C','D','r','i','v','e','r',0 };
5824 static const WCHAR translator_query
[] = {
5825 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5826 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5828 static const WCHAR source_query
[] = {
5829 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5830 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5832 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
5833 if (rc
!= ERROR_SUCCESS
)
5834 return ERROR_SUCCESS
;
5836 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
5837 msiobj_release( &view
->hdr
);
5839 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
5840 if (rc
!= ERROR_SUCCESS
)
5841 return ERROR_SUCCESS
;
5843 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
5844 msiobj_release( &view
->hdr
);
5846 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
5847 if (rc
!= ERROR_SUCCESS
)
5848 return ERROR_SUCCESS
;
5850 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
5851 msiobj_release( &view
->hdr
);
5856 #define ENV_ACT_SETALWAYS 0x1
5857 #define ENV_ACT_SETABSENT 0x2
5858 #define ENV_ACT_REMOVE 0x4
5859 #define ENV_ACT_REMOVEMATCH 0x8
5861 #define ENV_MOD_MACHINE 0x20000000
5862 #define ENV_MOD_APPEND 0x40000000
5863 #define ENV_MOD_PREFIX 0x80000000
5864 #define ENV_MOD_MASK 0xC0000000
5866 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5868 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5870 LPCWSTR cptr
= *name
;
5872 static const WCHAR prefix
[] = {'[','~',']',0};
5873 static const int prefix_len
= 3;
5879 *flags
|= ENV_ACT_SETALWAYS
;
5880 else if (*cptr
== '+')
5881 *flags
|= ENV_ACT_SETABSENT
;
5882 else if (*cptr
== '-')
5883 *flags
|= ENV_ACT_REMOVE
;
5884 else if (*cptr
== '!')
5885 *flags
|= ENV_ACT_REMOVEMATCH
;
5886 else if (*cptr
== '*')
5887 *flags
|= ENV_MOD_MACHINE
;
5897 ERR("Missing environment variable\n");
5898 return ERROR_FUNCTION_FAILED
;
5903 LPCWSTR ptr
= *value
;
5904 if (!strncmpW(ptr
, prefix
, prefix_len
))
5906 if (ptr
[prefix_len
] == szSemiColon
[0])
5908 *flags
|= ENV_MOD_APPEND
;
5909 *value
+= lstrlenW(prefix
);
5916 else if (lstrlenW(*value
) >= prefix_len
)
5918 ptr
+= lstrlenW(ptr
) - prefix_len
;
5919 if (!lstrcmpW(ptr
, prefix
))
5921 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
5923 *flags
|= ENV_MOD_PREFIX
;
5924 /* the "[~]" will be removed by deformat_string */;
5934 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5935 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5936 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5937 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5939 ERR("Invalid flags: %08x\n", *flags
);
5940 return ERROR_FUNCTION_FAILED
;
5944 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
5946 return ERROR_SUCCESS
;
5949 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
5951 static const WCHAR user_env
[] =
5952 {'E','n','v','i','r','o','n','m','e','n','t',0};
5953 static const WCHAR machine_env
[] =
5954 {'S','y','s','t','e','m','\\',
5955 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5956 'C','o','n','t','r','o','l','\\',
5957 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5958 'E','n','v','i','r','o','n','m','e','n','t',0};
5963 if (flags
& ENV_MOD_MACHINE
)
5966 root
= HKEY_LOCAL_MACHINE
;
5971 root
= HKEY_CURRENT_USER
;
5974 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
5975 if (res
!= ERROR_SUCCESS
)
5977 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
5978 return ERROR_FUNCTION_FAILED
;
5981 return ERROR_SUCCESS
;
5984 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5986 MSIPACKAGE
*package
= param
;
5987 LPCWSTR name
, value
, component
;
5988 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
5989 DWORD flags
, type
, size
;
5996 component
= MSI_RecordGetString(rec
, 4);
5997 comp
= get_loaded_component(package
, component
);
5999 return ERROR_SUCCESS
;
6001 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6003 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6004 comp
->Action
= comp
->Installed
;
6005 return ERROR_SUCCESS
;
6007 comp
->Action
= INSTALLSTATE_LOCAL
;
6009 name
= MSI_RecordGetString(rec
, 2);
6010 value
= MSI_RecordGetString(rec
, 3);
6012 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6014 res
= env_parse_flags(&name
, &value
, &flags
);
6015 if (res
!= ERROR_SUCCESS
|| !value
)
6018 if (value
&& !deformat_string(package
, value
, &deformatted
))
6020 res
= ERROR_OUTOFMEMORY
;
6024 value
= deformatted
;
6026 res
= open_env_key( flags
, &env
);
6027 if (res
!= ERROR_SUCCESS
)
6030 if (flags
& ENV_MOD_MACHINE
)
6031 action
|= 0x20000000;
6035 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
6036 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
6037 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
6040 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
6044 /* Nothing to do. */
6047 res
= ERROR_SUCCESS
;
6051 /* If we are appending but the string was empty, strip ; */
6052 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
6054 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
6055 newval
= strdupW(value
);
6058 res
= ERROR_OUTOFMEMORY
;
6066 /* Contrary to MSDN, +-variable to [~];path works */
6067 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
6069 res
= ERROR_SUCCESS
;
6073 data
= msi_alloc(size
);
6077 return ERROR_OUTOFMEMORY
;
6080 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
6081 if (res
!= ERROR_SUCCESS
)
6084 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
6087 res
= RegDeleteValueW(env
, name
);
6088 if (res
!= ERROR_SUCCESS
)
6089 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
6093 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
6094 if (flags
& ENV_MOD_MASK
)
6098 if (flags
& ENV_MOD_APPEND
) multiplier
++;
6099 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
6100 mod_size
= lstrlenW(value
) * multiplier
;
6101 size
+= mod_size
* sizeof(WCHAR
);
6104 newval
= msi_alloc(size
);
6108 res
= ERROR_OUTOFMEMORY
;
6112 if (flags
& ENV_MOD_PREFIX
)
6114 lstrcpyW(newval
, value
);
6115 ptr
= newval
+ lstrlenW(value
);
6116 action
|= 0x80000000;
6119 lstrcpyW(ptr
, data
);
6121 if (flags
& ENV_MOD_APPEND
)
6123 lstrcatW(newval
, value
);
6124 action
|= 0x40000000;
6127 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
6128 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
6131 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
6135 uirow
= MSI_CreateRecord( 3 );
6136 MSI_RecordSetStringW( uirow
, 1, name
);
6137 MSI_RecordSetStringW( uirow
, 2, newval
);
6138 MSI_RecordSetInteger( uirow
, 3, action
);
6139 ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
6140 msiobj_release( &uirow
->hdr
);
6142 if (env
) RegCloseKey(env
);
6143 msi_free(deformatted
);
6149 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
6153 static const WCHAR ExecSeqQuery
[] =
6154 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6155 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6156 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6157 if (rc
!= ERROR_SUCCESS
)
6158 return ERROR_SUCCESS
;
6160 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
6161 msiobj_release(&view
->hdr
);
6166 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6168 MSIPACKAGE
*package
= param
;
6169 LPCWSTR name
, value
, component
;
6170 LPWSTR deformatted
= NULL
;
6179 component
= MSI_RecordGetString( rec
, 4 );
6180 comp
= get_loaded_component( package
, component
);
6182 return ERROR_SUCCESS
;
6184 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6186 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6187 comp
->Action
= comp
->Installed
;
6188 return ERROR_SUCCESS
;
6190 comp
->Action
= INSTALLSTATE_ABSENT
;
6192 name
= MSI_RecordGetString( rec
, 2 );
6193 value
= MSI_RecordGetString( rec
, 3 );
6195 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6197 r
= env_parse_flags( &name
, &value
, &flags
);
6198 if (r
!= ERROR_SUCCESS
)
6201 if (!(flags
& ENV_ACT_REMOVE
))
6203 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
6204 return ERROR_SUCCESS
;
6207 if (value
&& !deformat_string( package
, value
, &deformatted
))
6208 return ERROR_OUTOFMEMORY
;
6210 value
= deformatted
;
6212 r
= open_env_key( flags
, &env
);
6213 if (r
!= ERROR_SUCCESS
)
6219 if (flags
& ENV_MOD_MACHINE
)
6220 action
|= 0x20000000;
6222 TRACE("Removing %s\n", debugstr_w(name
));
6224 res
= RegDeleteValueW( env
, name
);
6225 if (res
!= ERROR_SUCCESS
)
6227 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
6232 uirow
= MSI_CreateRecord( 3 );
6233 MSI_RecordSetStringW( uirow
, 1, name
);
6234 MSI_RecordSetStringW( uirow
, 2, value
);
6235 MSI_RecordSetInteger( uirow
, 3, action
);
6236 ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
6237 msiobj_release( &uirow
->hdr
);
6239 if (env
) RegCloseKey( env
);
6240 msi_free( deformatted
);
6244 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6248 static const WCHAR query
[] =
6249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6250 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6252 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6253 if (rc
!= ERROR_SUCCESS
)
6254 return ERROR_SUCCESS
;
6256 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
6257 msiobj_release( &view
->hdr
);
6262 typedef struct tagMSIASSEMBLY
6265 MSICOMPONENT
*component
;
6266 MSIFEATURE
*feature
;
6270 LPWSTR display_name
;
6275 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
6277 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
6278 LPVOID pvReserved
, HMODULE
*phModDll
);
6280 static BOOL
init_functionpointers(void)
6286 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
6288 hmscoree
= LoadLibraryA("mscoree.dll");
6291 WARN("mscoree.dll not available\n");
6295 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
6296 if (!pLoadLibraryShim
)
6298 WARN("LoadLibraryShim not available\n");
6299 FreeLibrary(hmscoree
);
6303 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
6306 WARN("fusion.dll not available\n");
6307 FreeLibrary(hmscoree
);
6311 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
6313 FreeLibrary(hmscoree
);
6317 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
6320 IAssemblyCache
*cache
;
6323 UINT r
= ERROR_FUNCTION_FAILED
;
6325 TRACE("installing assembly: %s\n", debugstr_w(path
));
6327 uirow
= MSI_CreateRecord( 2 );
6328 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
6329 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
6330 msiobj_release( &uirow
->hdr
);
6332 if (assembly
->feature
)
6333 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
6335 if (assembly
->manifest
)
6336 FIXME("Manifest unhandled\n");
6338 if (assembly
->application
)
6340 FIXME("Assembly should be privately installed\n");
6341 return ERROR_SUCCESS
;
6344 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
6346 FIXME("Win32 assemblies not handled\n");
6347 return ERROR_SUCCESS
;
6350 hr
= pCreateAssemblyCache(&cache
, 0);
6354 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
6356 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
6361 IAssemblyCache_Release(cache
);
6365 typedef struct tagASSEMBLY_LIST
6367 MSIPACKAGE
*package
;
6368 IAssemblyCache
*cache
;
6369 struct list
*assemblies
;
6372 typedef struct tagASSEMBLY_NAME
6380 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
6382 ASSEMBLY_NAME
*asmname
= param
;
6383 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
6384 LPWSTR val
= msi_dup_record_field(rec
, 3);
6386 static const WCHAR Name
[] = {'N','a','m','e',0};
6387 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
6388 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
6389 static const WCHAR PublicKeyToken
[] = {
6390 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6392 if (!strcmpiW(name
, Name
))
6393 asmname
->name
= val
;
6394 else if (!strcmpiW(name
, Version
))
6395 asmname
->version
= val
;
6396 else if (!strcmpiW(name
, Culture
))
6397 asmname
->culture
= val
;
6398 else if (!strcmpiW(name
, PublicKeyToken
))
6399 asmname
->pubkeytoken
= val
;
6403 return ERROR_SUCCESS
;
6406 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
6410 *size
= lstrlenW(append
) + 1;
6411 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
6412 lstrcpyW(*str
, append
);
6416 (*size
) += lstrlenW(append
);
6417 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6418 lstrcatW(*str
, append
);
6421 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, MSICOMPONENT
*comp
)
6423 static const WCHAR separator
[] = {',',' ',0};
6424 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
6425 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
6426 static const WCHAR PublicKeyToken
[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6427 static const WCHAR query
[] = {
6428 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6429 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6430 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6431 '=','\'','%','s','\'',0};
6434 LPWSTR display_name
;
6438 display_name
= NULL
;
6439 memset( &name
, 0, sizeof(ASSEMBLY_NAME
) );
6441 r
= MSI_OpenQuery( db
, &view
, query
, comp
->Component
);
6442 if (r
!= ERROR_SUCCESS
)
6445 MSI_IterateRecords( view
, NULL
, parse_assembly_name
, &name
);
6446 msiobj_release( &view
->hdr
);
6450 ERR("No assembly name specified!\n");
6454 append_str( &display_name
, &size
, name
.name
);
6458 append_str( &display_name
, &size
, separator
);
6459 append_str( &display_name
, &size
, Version
);
6460 append_str( &display_name
, &size
, name
.version
);
6464 append_str( &display_name
, &size
, separator
);
6465 append_str( &display_name
, &size
, Culture
);
6466 append_str( &display_name
, &size
, name
.culture
);
6468 if (name
.pubkeytoken
)
6470 append_str( &display_name
, &size
, separator
);
6471 append_str( &display_name
, &size
, PublicKeyToken
);
6472 append_str( &display_name
, &size
, name
.pubkeytoken
);
6475 msi_free( name
.name
);
6476 msi_free( name
.version
);
6477 msi_free( name
.culture
);
6478 msi_free( name
.pubkeytoken
);
6480 return display_name
;
6483 static BOOL
check_assembly_installed( MSIDATABASE
*db
, IAssemblyCache
*cache
, MSICOMPONENT
*comp
)
6485 ASSEMBLY_INFO asminfo
;
6490 disp
= get_assembly_display_name( db
, comp
);
6494 memset( &asminfo
, 0, sizeof(ASSEMBLY_INFO
) );
6495 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6497 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, disp
, &asminfo
);
6499 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6505 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6507 ASSEMBLY_LIST
*list
= param
;
6508 MSIASSEMBLY
*assembly
;
6511 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6513 return ERROR_OUTOFMEMORY
;
6515 component
= MSI_RecordGetString(rec
, 1);
6516 assembly
->component
= get_loaded_component(list
->package
, component
);
6517 if (!assembly
->component
)
6518 return ERROR_SUCCESS
;
6520 if (assembly
->component
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6521 assembly
->component
->ActionRequest
!= INSTALLSTATE_SOURCE
)
6523 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6524 assembly
->component
->Action
= assembly
->component
->Installed
;
6525 return ERROR_SUCCESS
;
6527 assembly
->component
->Action
= assembly
->component
->ActionRequest
;
6529 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6530 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6532 if (!assembly
->file
)
6534 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6535 return ERROR_FUNCTION_FAILED
;
6538 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6539 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6540 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6542 if (assembly
->application
)
6545 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6547 /* FIXME: we should probably check the manifest file here */
6549 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6550 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6552 assembly
->installed
= TRUE
;
6556 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6558 assembly
->component
);
6560 list_add_head(list
->assemblies
, &assembly
->entry
);
6561 return ERROR_SUCCESS
;
6564 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6566 IAssemblyCache
*cache
= NULL
;
6572 static const WCHAR query
[] =
6573 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6574 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6576 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6577 if (r
!= ERROR_SUCCESS
)
6578 return ERROR_SUCCESS
;
6580 hr
= pCreateAssemblyCache(&cache
, 0);
6582 return ERROR_FUNCTION_FAILED
;
6584 list
.package
= package
;
6586 list
.assemblies
= assemblies
;
6588 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6589 msiobj_release(&view
->hdr
);
6591 IAssemblyCache_Release(cache
);
6596 static void free_assemblies(struct list
*assemblies
)
6598 struct list
*item
, *cursor
;
6600 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6602 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6604 list_remove(&assembly
->entry
);
6605 msi_free(assembly
->application
);
6606 msi_free(assembly
->manifest
);
6607 msi_free(assembly
->display_name
);
6612 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6614 MSIASSEMBLY
*assembly
;
6616 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6618 if (!lstrcmpW(assembly
->file
->File
, file
))
6628 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6629 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6631 MSIASSEMBLY
*assembly
;
6632 WCHAR temppath
[MAX_PATH
];
6633 struct list
*assemblies
= user
;
6636 if (!find_assembly(assemblies
, file
, &assembly
))
6639 GetTempPathW(MAX_PATH
, temppath
);
6640 PathAddBackslashW(temppath
);
6641 lstrcatW(temppath
, assembly
->file
->FileName
);
6643 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6645 if (assembly
->installed
)
6648 *path
= strdupW(temppath
);
6649 *attrs
= assembly
->file
->Attributes
;
6651 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6653 assembly
->installed
= TRUE
;
6655 r
= install_assembly(package
, assembly
, temppath
);
6656 if (r
!= ERROR_SUCCESS
)
6657 ERR("Failed to install assembly\n");
6663 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6666 struct list assemblies
= LIST_INIT(assemblies
);
6667 MSIASSEMBLY
*assembly
;
6670 if (!init_functionpointers() || !pCreateAssemblyCache
)
6671 return ERROR_FUNCTION_FAILED
;
6673 r
= load_assemblies(package
, &assemblies
);
6674 if (r
!= ERROR_SUCCESS
)
6677 if (list_empty(&assemblies
))
6680 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6683 r
= ERROR_OUTOFMEMORY
;
6687 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6689 if (assembly
->installed
&& !mi
->is_continuous
)
6692 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6693 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6697 r
= ready_media(package
, assembly
->file
, mi
);
6698 if (r
!= ERROR_SUCCESS
)
6700 ERR("Failed to ready media\n");
6705 data
.package
= package
;
6706 data
.cb
= installassembly_cb
;
6707 data
.user
= &assemblies
;
6709 if (assembly
->file
->IsCompressed
&&
6710 !msi_cabextract(package
, mi
, &data
))
6712 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6713 r
= ERROR_FUNCTION_FAILED
;
6718 if (!assembly
->file
->IsCompressed
)
6720 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6722 r
= install_assembly(package
, assembly
, source
);
6723 if (r
!= ERROR_SUCCESS
)
6724 ERR("Failed to install assembly\n");
6729 /* FIXME: write Installer assembly reg values */
6733 free_assemblies(&assemblies
);
6737 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6739 LPWSTR key
, template, id
;
6740 UINT r
= ERROR_SUCCESS
;
6742 id
= msi_dup_property( package
, szProductID
);
6746 return ERROR_SUCCESS
;
6748 template = msi_dup_property( package
, szPIDTemplate
);
6749 key
= msi_dup_property( package
, szPIDKEY
);
6751 if (key
&& template)
6753 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6754 r
= MSI_SetPropertyW( package
, szProductID
, key
);
6756 msi_free( template );
6761 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6764 package
->need_reboot
= 1;
6765 return ERROR_SUCCESS
;
6768 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6770 static const WCHAR szAvailableFreeReg
[] =
6771 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6773 int space
= msi_get_property_int( package
, szAvailableFreeReg
, 0 );
6775 TRACE("%p %d kilobytes\n", package
, space
);
6777 uirow
= MSI_CreateRecord( 1 );
6778 MSI_RecordSetInteger( uirow
, 1, space
);
6779 ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
6780 msiobj_release( &uirow
->hdr
);
6782 return ERROR_SUCCESS
;
6785 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6787 FIXME("%p\n", package
);
6788 return ERROR_SUCCESS
;
6791 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6793 FIXME("%p\n", package
);
6794 return ERROR_SUCCESS
;
6797 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6798 LPCSTR action
, LPCWSTR table
)
6800 static const WCHAR query
[] = {
6801 'S','E','L','E','C','T',' ','*',' ',
6802 'F','R','O','M',' ','`','%','s','`',0 };
6803 MSIQUERY
*view
= NULL
;
6807 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6808 if (r
== ERROR_SUCCESS
)
6810 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6811 msiobj_release(&view
->hdr
);
6815 FIXME("%s -> %u ignored %s table values\n",
6816 action
, count
, debugstr_w(table
));
6818 return ERROR_SUCCESS
;
6821 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6823 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6824 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6827 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6829 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6830 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6833 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6835 static const WCHAR table
[] = {
6836 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6837 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6840 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6842 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6843 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6846 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6848 static const WCHAR table
[] = {
6849 'M','s','i','A','s','s','e','m','b','l','y',0 };
6850 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6853 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6855 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6856 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6859 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6861 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6862 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6865 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6867 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6868 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6871 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6873 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6874 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6877 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6879 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6880 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6883 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6885 static const WCHAR table
[] = { 'D','i','r','e','c','t','o','r','y',0 };
6886 return msi_unimplemented_action_stub( package
, "SetODBCFolders", table
);
6889 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6891 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6892 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6895 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6897 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6898 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6901 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6903 static const WCHAR table
[] = { 'M','I','M','E',0 };
6904 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6907 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6909 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6910 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6913 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6917 const WCHAR
*action
;
6918 UINT (*handler
)(MSIPACKAGE
*);
6922 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6923 { szAppSearch
, ACTION_AppSearch
},
6924 { szBindImage
, ACTION_BindImage
},
6925 { szCCPSearch
, ACTION_CCPSearch
},
6926 { szCostFinalize
, ACTION_CostFinalize
},
6927 { szCostInitialize
, ACTION_CostInitialize
},
6928 { szCreateFolders
, ACTION_CreateFolders
},
6929 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6930 { szDeleteServices
, ACTION_DeleteServices
},
6931 { szDisableRollback
, ACTION_DisableRollback
},
6932 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6933 { szExecuteAction
, ACTION_ExecuteAction
},
6934 { szFileCost
, ACTION_FileCost
},
6935 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6936 { szForceReboot
, ACTION_ForceReboot
},
6937 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
6938 { szInstallExecute
, ACTION_InstallExecute
},
6939 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6940 { szInstallFiles
, ACTION_InstallFiles
},
6941 { szInstallFinalize
, ACTION_InstallFinalize
},
6942 { szInstallInitialize
, ACTION_InstallInitialize
},
6943 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6944 { szInstallValidate
, ACTION_InstallValidate
},
6945 { szIsolateComponents
, ACTION_IsolateComponents
},
6946 { szLaunchConditions
, ACTION_LaunchConditions
},
6947 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6948 { szMoveFiles
, ACTION_MoveFiles
},
6949 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6950 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6951 { szInstallODBC
, ACTION_InstallODBC
},
6952 { szInstallServices
, ACTION_InstallServices
},
6953 { szPatchFiles
, ACTION_PatchFiles
},
6954 { szProcessComponents
, ACTION_ProcessComponents
},
6955 { szPublishComponents
, ACTION_PublishComponents
},
6956 { szPublishFeatures
, ACTION_PublishFeatures
},
6957 { szPublishProduct
, ACTION_PublishProduct
},
6958 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6959 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6960 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6961 { szRegisterFonts
, ACTION_RegisterFonts
},
6962 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6963 { szRegisterProduct
, ACTION_RegisterProduct
},
6964 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6965 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6966 { szRegisterUser
, ACTION_RegisterUser
},
6967 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6968 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6969 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6970 { szRemoveFiles
, ACTION_RemoveFiles
},
6971 { szRemoveFolders
, ACTION_RemoveFolders
},
6972 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6973 { szRemoveODBC
, ACTION_RemoveODBC
},
6974 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6975 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6976 { szResolveSource
, ACTION_ResolveSource
},
6977 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6978 { szScheduleReboot
, ACTION_ScheduleReboot
},
6979 { szSelfRegModules
, ACTION_SelfRegModules
},
6980 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6981 { szSetODBCFolders
, ACTION_SetODBCFolders
},
6982 { szStartServices
, ACTION_StartServices
},
6983 { szStopServices
, ACTION_StopServices
},
6984 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6985 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6986 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6987 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6988 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6989 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6990 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6991 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6992 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6993 { szValidateProductID
, ACTION_ValidateProductID
},
6994 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6995 { szWriteIniValues
, ACTION_WriteIniValues
},
6996 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
7000 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
7001 UINT
* rc
, BOOL force
)
7007 if (!run
&& !package
->script
->CurrentlyScripting
)
7012 if (strcmpW(action
,szInstallFinalize
) == 0 ||
7013 strcmpW(action
,szInstallExecute
) == 0 ||
7014 strcmpW(action
,szInstallExecuteAgain
) == 0)
7019 while (StandardActions
[i
].action
!= NULL
)
7021 if (strcmpW(StandardActions
[i
].action
, action
)==0)
7025 ui_actioninfo(package
, action
, TRUE
, 0);
7026 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
7027 ui_actioninfo(package
, action
, FALSE
, *rc
);
7031 ui_actionstart(package
, action
);
7032 if (StandardActions
[i
].handler
)
7034 *rc
= StandardActions
[i
].handler(package
);
7038 FIXME("unhandled standard action %s\n",debugstr_w(action
));
7039 *rc
= ERROR_SUCCESS
;
7050 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
7052 UINT rc
= ERROR_SUCCESS
;
7055 TRACE("Performing action (%s)\n", debugstr_w(action
));
7057 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
7060 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
7064 WARN("unhandled msi action %s\n", debugstr_w(action
));
7065 rc
= ERROR_FUNCTION_NOT_CALLED
;
7071 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
7073 UINT rc
= ERROR_SUCCESS
;
7074 BOOL handled
= FALSE
;
7076 TRACE("Performing action (%s)\n", debugstr_w(action
));
7078 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
7081 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
7083 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
7088 WARN("unhandled msi action %s\n", debugstr_w(action
));
7089 rc
= ERROR_FUNCTION_NOT_CALLED
;
7095 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
7097 UINT rc
= ERROR_SUCCESS
;
7100 static const WCHAR ExecSeqQuery
[] =
7101 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7102 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7103 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7104 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7105 static const WCHAR UISeqQuery
[] =
7106 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7107 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7108 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7109 ' ', '=',' ','%','i',0};
7111 if (needs_ui_sequence(package
))
7112 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
7114 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
7118 LPCWSTR action
, cond
;
7120 TRACE("Running the actions\n");
7122 /* check conditions */
7123 cond
= MSI_RecordGetString(row
, 2);
7125 /* this is a hack to skip errors in the condition code */
7126 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
7128 msiobj_release(&row
->hdr
);
7129 return ERROR_SUCCESS
;
7132 action
= MSI_RecordGetString(row
, 1);
7135 ERR("failed to fetch action\n");
7136 msiobj_release(&row
->hdr
);
7137 return ERROR_FUNCTION_FAILED
;
7140 if (needs_ui_sequence(package
))
7141 rc
= ACTION_PerformUIAction(package
, action
, -1);
7143 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
7145 msiobj_release(&row
->hdr
);
7151 /****************************************************
7152 * TOP level entry points
7153 *****************************************************/
7155 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
7156 LPCWSTR szCommandLine
)
7161 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
7162 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
7164 MSI_SetPropertyW(package
, szAction
, szInstall
);
7166 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
7173 dir
= strdupW(szPackagePath
);
7174 p
= strrchrW(dir
, '\\');
7178 file
= szPackagePath
+ (p
- dir
);
7183 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
7184 GetCurrentDirectoryW(MAX_PATH
, dir
);
7185 lstrcatW(dir
, szBackSlash
);
7186 file
= szPackagePath
;
7189 msi_free( package
->PackagePath
);
7190 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
7191 if (!package
->PackagePath
)
7194 return ERROR_OUTOFMEMORY
;
7197 lstrcpyW(package
->PackagePath
, dir
);
7198 lstrcatW(package
->PackagePath
, file
);
7201 msi_set_sourcedir_props(package
, FALSE
);
7204 msi_parse_command_line( package
, szCommandLine
, FALSE
);
7206 msi_apply_transforms( package
);
7207 msi_apply_patches( package
);
7209 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
7211 TRACE("setting reinstall property\n");
7212 MSI_SetPropertyW( package
, szReinstall
, szAll
);
7215 /* properties may have been added by a transform */
7216 msi_clone_properties( package
);
7217 msi_set_context( package
);
7219 if (needs_ui_sequence( package
))
7221 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
7222 rc
= ACTION_ProcessUISequence(package
);
7223 ui_exists
= ui_sequence_exists(package
);
7224 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
7226 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
7227 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
7231 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
7233 package
->script
->CurrentlyScripting
= FALSE
;
7235 /* process the ending type action */
7236 if (rc
== ERROR_SUCCESS
)
7237 ACTION_PerformActionSequence(package
, -1);
7238 else if (rc
== ERROR_INSTALL_USEREXIT
)
7239 ACTION_PerformActionSequence(package
, -2);
7240 else if (rc
== ERROR_INSTALL_SUSPEND
)
7241 ACTION_PerformActionSequence(package
, -4);
7243 ACTION_PerformActionSequence(package
, -3);
7245 /* finish up running custom actions */
7246 ACTION_FinishCustomActions(package
);
7248 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
7249 return ERROR_SUCCESS_REBOOT_REQUIRED
;