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
);
4158 uirow
= MSI_CreateRecord( 2 );
4159 uipath
= strdupW( file
->TargetPath
);
4160 p
= strrchrW(uipath
,'\\');
4163 MSI_RecordSetStringW( uirow
, 1, &p
[1] );
4164 MSI_RecordSetStringW( uirow
, 2, uipath
);
4165 ui_actiondata( package
, szSelfRegModules
, uirow
);
4166 msiobj_release( &uirow
->hdr
);
4168 /* FIXME: call ui_progress? */
4170 return ERROR_SUCCESS
;
4173 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4177 static const WCHAR ExecSeqQuery
[] =
4178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4179 '`','S','e','l','f','R','e','g','`',0};
4181 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4182 if (rc
!= ERROR_SUCCESS
)
4184 TRACE("no SelfReg table\n");
4185 return ERROR_SUCCESS
;
4188 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
4189 msiobj_release(&view
->hdr
);
4191 return ERROR_SUCCESS
;
4194 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
4196 static const WCHAR regsvr32
[] =
4197 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4198 static const WCHAR close
[] = {'\"',0};
4199 MSIPACKAGE
*package
= param
;
4205 PROCESS_INFORMATION pi
;
4210 memset( &si
, 0, sizeof(STARTUPINFOW
) );
4212 filename
= MSI_RecordGetString( row
, 1 );
4213 file
= get_loaded_file( package
, filename
);
4217 ERR("Unable to find file id %s\n", debugstr_w(filename
));
4218 return ERROR_SUCCESS
;
4221 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
4223 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
4224 strcpyW( cmdline
, regsvr32
);
4225 strcatW( cmdline
, file
->TargetPath
);
4226 strcatW( cmdline
, close
);
4228 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
4230 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
4233 CloseHandle( pi
.hThread
);
4234 msi_dialog_check_messages( pi
.hProcess
);
4235 CloseHandle( pi
.hProcess
);
4238 msi_free( cmdline
);
4240 uirow
= MSI_CreateRecord( 2 );
4241 uipath
= strdupW( file
->TargetPath
);
4242 if ((p
= strrchrW( uipath
, '\\' )))
4245 MSI_RecordSetStringW( uirow
, 1, ++p
);
4247 MSI_RecordSetStringW( uirow
, 2, uipath
);
4248 ui_actiondata( package
, szSelfUnregModules
, uirow
);
4249 msiobj_release( &uirow
->hdr
);
4251 /* FIXME call ui_progress? */
4253 return ERROR_SUCCESS
;
4256 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4260 static const WCHAR query
[] =
4261 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4262 '`','S','e','l','f','R','e','g','`',0};
4264 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4265 if (rc
!= ERROR_SUCCESS
)
4267 TRACE("no SelfReg table\n");
4268 return ERROR_SUCCESS
;
4271 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
4272 msiobj_release( &view
->hdr
);
4274 return ERROR_SUCCESS
;
4277 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4279 MSIFEATURE
*feature
;
4281 HKEY hkey
= NULL
, userdata
= NULL
;
4283 if (!msi_check_publish(package
))
4284 return ERROR_SUCCESS
;
4286 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4288 if (rc
!= ERROR_SUCCESS
)
4291 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4293 if (rc
!= ERROR_SUCCESS
)
4296 /* here the guids are base 85 encoded */
4297 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
4303 BOOL absent
= FALSE
;
4306 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4307 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4308 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
4311 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4315 if (feature
->Feature_Parent
)
4316 size
+= strlenW( feature
->Feature_Parent
)+2;
4318 data
= msi_alloc(size
* sizeof(WCHAR
));
4321 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4323 MSICOMPONENT
* component
= cl
->component
;
4327 if (component
->ComponentId
)
4329 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4330 CLSIDFromString(component
->ComponentId
, &clsid
);
4331 encode_base85_guid(&clsid
,buf
);
4332 TRACE("to %s\n",debugstr_w(buf
));
4337 if (feature
->Feature_Parent
)
4339 static const WCHAR sep
[] = {'\2',0};
4341 strcatW(data
,feature
->Feature_Parent
);
4344 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4348 if (feature
->Feature_Parent
)
4349 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4352 size
+= sizeof(WCHAR
);
4353 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4354 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
4358 size
+= 2*sizeof(WCHAR
);
4359 data
= msi_alloc(size
);
4362 if (feature
->Feature_Parent
)
4363 strcpyW( &data
[1], feature
->Feature_Parent
);
4364 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4370 uirow
= MSI_CreateRecord( 1 );
4371 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4372 ui_actiondata( package
, szPublishFeatures
, uirow
);
4373 msiobj_release( &uirow
->hdr
);
4374 /* FIXME: call ui_progress? */
4379 RegCloseKey(userdata
);
4383 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4388 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4390 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4392 if (r
== ERROR_SUCCESS
)
4394 RegDeleteValueW(hkey
, feature
->Feature
);
4398 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4400 if (r
== ERROR_SUCCESS
)
4402 RegDeleteValueW(hkey
, feature
->Feature
);
4406 return ERROR_SUCCESS
;
4409 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4411 MSIFEATURE
*feature
;
4413 if (!msi_check_unpublish(package
))
4414 return ERROR_SUCCESS
;
4416 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4418 msi_unpublish_feature(package
, feature
);
4421 return ERROR_SUCCESS
;
4424 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4426 LPWSTR prop
, val
, key
;
4432 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4433 static const WCHAR szWindowsInstaller
[] =
4434 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4435 static const WCHAR modpath_fmt
[] =
4436 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4437 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4438 static const WCHAR szModifyPath
[] =
4439 {'M','o','d','i','f','y','P','a','t','h',0};
4440 static const WCHAR szUninstallString
[] =
4441 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4442 static const WCHAR szEstimatedSize
[] =
4443 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4444 static const WCHAR szProductLanguage
[] =
4445 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4446 static const WCHAR szProductVersion
[] =
4447 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4448 static const WCHAR szProductName
[] =
4449 {'P','r','o','d','u','c','t','N','a','m','e',0};
4450 static const WCHAR szDisplayName
[] =
4451 {'D','i','s','p','l','a','y','N','a','m','e',0};
4452 static const WCHAR szDisplayVersion
[] =
4453 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4454 static const WCHAR szManufacturer
[] =
4455 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4457 static const LPCSTR propval
[] = {
4458 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4459 "ARPCONTACT", "Contact",
4460 "ARPCOMMENTS", "Comments",
4461 "ProductName", "DisplayName",
4462 "ProductVersion", "DisplayVersion",
4463 "ARPHELPLINK", "HelpLink",
4464 "ARPHELPTELEPHONE", "HelpTelephone",
4465 "ARPINSTALLLOCATION", "InstallLocation",
4466 "SourceDir", "InstallSource",
4467 "Manufacturer", "Publisher",
4468 "ARPREADME", "Readme",
4470 "ARPURLINFOABOUT", "URLInfoAbout",
4471 "ARPURLUPDATEINFO", "URLUpdateInfo",
4474 const LPCSTR
*p
= propval
;
4478 prop
= strdupAtoW(*p
++);
4479 key
= strdupAtoW(*p
++);
4480 val
= msi_dup_property(package
, prop
);
4481 msi_reg_set_val_str(hkey
, key
, val
);
4487 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4489 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4490 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4491 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4494 /* FIXME: Write real Estimated Size when we have it */
4495 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4497 buffer
= msi_dup_property(package
, szProductName
);
4498 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4501 buffer
= msi_dup_property(package
, cszSourceDir
);
4502 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4505 buffer
= msi_dup_property(package
, szManufacturer
);
4506 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4509 GetLocalTime(&systime
);
4510 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4511 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4513 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4514 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4516 buffer
= msi_dup_property(package
, szProductVersion
);
4517 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4520 DWORD verdword
= msi_version_str_to_dword(buffer
);
4522 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4523 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4524 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4528 return ERROR_SUCCESS
;
4531 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4533 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4535 LPWSTR upgrade_code
;
4540 static const WCHAR szUpgradeCode
[] = {
4541 'U','p','g','r','a','d','e','C','o','d','e',0};
4543 /* FIXME: also need to publish if the product is in advertise mode */
4544 if (!msi_check_publish(package
))
4545 return ERROR_SUCCESS
;
4547 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4548 if (rc
!= ERROR_SUCCESS
)
4551 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4552 NULL
, &props
, TRUE
);
4553 if (rc
!= ERROR_SUCCESS
)
4556 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4557 msi_free( package
->db
->localfile
);
4558 package
->db
->localfile
= NULL
;
4560 rc
= msi_publish_install_properties(package
, hkey
);
4561 if (rc
!= ERROR_SUCCESS
)
4564 rc
= msi_publish_install_properties(package
, props
);
4565 if (rc
!= ERROR_SUCCESS
)
4568 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4571 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4572 squash_guid(package
->ProductCode
, squashed_pc
);
4573 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4574 RegCloseKey(upgrade
);
4575 msi_free(upgrade_code
);
4579 uirow
= MSI_CreateRecord( 1 );
4580 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4581 ui_actiondata( package
, szRegisterProduct
, uirow
);
4582 msiobj_release( &uirow
->hdr
);
4585 return ERROR_SUCCESS
;
4588 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4590 return execute_script(package
,INSTALL_SCRIPT
);
4593 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4596 LPWSTR remove
= NULL
;
4597 LPWSTR
*features
= NULL
;
4598 BOOL full_uninstall
= TRUE
;
4599 MSIFEATURE
*feature
;
4601 static const WCHAR szUpgradeCode
[] =
4602 {'U','p','g','r','a','d','e','C','o','d','e',0};
4604 remove
= msi_dup_property(package
, szRemove
);
4606 return ERROR_SUCCESS
;
4608 features
= msi_split_string(remove
, ',');
4612 ERR("REMOVE feature list is empty!\n");
4613 return ERROR_FUNCTION_FAILED
;
4616 if (!lstrcmpW(features
[0], szAll
))
4617 full_uninstall
= TRUE
;
4620 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4622 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4623 full_uninstall
= FALSE
;
4627 if (!full_uninstall
)
4630 MSIREG_DeleteProductKey(package
->ProductCode
);
4631 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4632 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4634 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4636 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4637 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4641 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4642 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4645 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4648 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4655 return ERROR_SUCCESS
;
4658 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4662 rc
= msi_unpublish_product(package
);
4663 if (rc
!= ERROR_SUCCESS
)
4666 /* turn off scheduling */
4667 package
->script
->CurrentlyScripting
= FALSE
;
4669 /* first do the same as an InstallExecute */
4670 rc
= ACTION_InstallExecute(package
);
4671 if (rc
!= ERROR_SUCCESS
)
4674 /* then handle Commit Actions */
4675 rc
= execute_script(package
,COMMIT_SCRIPT
);
4680 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4682 static const WCHAR RunOnce
[] = {
4683 'S','o','f','t','w','a','r','e','\\',
4684 'M','i','c','r','o','s','o','f','t','\\',
4685 'W','i','n','d','o','w','s','\\',
4686 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4687 'R','u','n','O','n','c','e',0};
4688 static const WCHAR InstallRunOnce
[] = {
4689 'S','o','f','t','w','a','r','e','\\',
4690 'M','i','c','r','o','s','o','f','t','\\',
4691 'W','i','n','d','o','w','s','\\',
4692 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4693 'I','n','s','t','a','l','l','e','r','\\',
4694 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4696 static const WCHAR msiexec_fmt
[] = {
4698 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4699 '\"','%','s','\"',0};
4700 static const WCHAR install_fmt
[] = {
4701 '/','I',' ','\"','%','s','\"',' ',
4702 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4703 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4704 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4706 WCHAR squished_pc
[100];
4708 squash_guid(package
->ProductCode
,squished_pc
);
4710 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4711 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4712 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4715 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4718 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4720 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4721 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4723 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4726 return ERROR_INSTALL_SUSPEND
;
4729 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4735 * We are currently doing what should be done here in the top level Install
4736 * however for Administrative and uninstalls this step will be needed
4738 if (!package
->PackagePath
)
4739 return ERROR_SUCCESS
;
4741 msi_set_sourcedir_props(package
, TRUE
);
4743 attrib
= GetFileAttributesW(package
->db
->path
);
4744 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4750 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4751 package
->Context
, MSICODE_PRODUCT
,
4752 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4753 if (rc
== ERROR_MORE_DATA
)
4755 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4756 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4757 package
->Context
, MSICODE_PRODUCT
,
4758 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4761 prompt
= strdupW(package
->db
->path
);
4763 msg
= generate_error_string(package
,1302,1,prompt
);
4764 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4766 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4769 rc
= ERROR_INSTALL_USEREXIT
;
4772 attrib
= GetFileAttributesW(package
->db
->path
);
4778 return ERROR_SUCCESS
;
4783 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4786 LPWSTR buffer
, productid
= NULL
;
4787 UINT i
, rc
= ERROR_SUCCESS
;
4790 static const WCHAR szPropKeys
[][80] =
4792 {'P','r','o','d','u','c','t','I','D',0},
4793 {'U','S','E','R','N','A','M','E',0},
4794 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4798 static const WCHAR szRegKeys
[][80] =
4800 {'P','r','o','d','u','c','t','I','D',0},
4801 {'R','e','g','O','w','n','e','r',0},
4802 {'R','e','g','C','o','m','p','a','n','y',0},
4806 if (msi_check_unpublish(package
))
4808 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4812 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4816 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4818 if (rc
!= ERROR_SUCCESS
)
4821 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4823 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4824 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4829 uirow
= MSI_CreateRecord( 1 );
4830 MSI_RecordSetStringW( uirow
, 1, productid
);
4831 ui_actiondata( package
, szRegisterUser
, uirow
);
4832 msiobj_release( &uirow
->hdr
);
4834 msi_free(productid
);
4840 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4844 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4845 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4850 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4852 MSIPACKAGE
*package
= param
;
4853 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
4854 LPWSTR advertise
= NULL
, output
= NULL
;
4862 feature
= MSI_RecordGetString(rec
, 5);
4863 feat
= get_loaded_feature(package
, feature
);
4865 return ERROR_SUCCESS
;
4867 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4868 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4869 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
4871 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
4872 feat
->Action
= feat
->Installed
;
4873 return ERROR_SUCCESS
;
4876 component
= MSI_RecordGetString(rec
, 3);
4877 comp
= get_loaded_component(package
, component
);
4879 return ERROR_SUCCESS
;
4881 compgroupid
= MSI_RecordGetString(rec
,1);
4882 qualifier
= MSI_RecordGetString(rec
,2);
4884 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4885 if (rc
!= ERROR_SUCCESS
)
4888 text
= MSI_RecordGetString(rec
,4);
4889 advertise
= create_component_advertise_string(package
, comp
, feature
);
4891 sz
= strlenW(advertise
);
4894 sz
+= lstrlenW(text
);
4897 sz
*= sizeof(WCHAR
);
4899 output
= msi_alloc_zero(sz
);
4900 strcpyW(output
,advertise
);
4901 msi_free(advertise
);
4904 strcatW(output
,text
);
4906 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4913 uirow
= MSI_CreateRecord( 2 );
4914 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4915 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4916 ui_actiondata( package
, szPublishComponents
, uirow
);
4917 msiobj_release( &uirow
->hdr
);
4918 /* FIXME: call ui_progress? */
4924 * At present I am ignorning the advertised components part of this and only
4925 * focusing on the qualified component sets
4927 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4931 static const WCHAR ExecSeqQuery
[] =
4932 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4933 '`','P','u','b','l','i','s','h',
4934 'C','o','m','p','o','n','e','n','t','`',0};
4936 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4937 if (rc
!= ERROR_SUCCESS
)
4938 return ERROR_SUCCESS
;
4940 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4941 msiobj_release(&view
->hdr
);
4946 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
4948 static const WCHAR szInstallerComponents
[] = {
4949 'S','o','f','t','w','a','r','e','\\',
4950 'M','i','c','r','o','s','o','f','t','\\',
4951 'I','n','s','t','a','l','l','e','r','\\',
4952 'C','o','m','p','o','n','e','n','t','s','\\',0};
4954 MSIPACKAGE
*package
= param
;
4955 LPCWSTR compgroupid
, component
, feature
, qualifier
;
4959 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
4962 feature
= MSI_RecordGetString( rec
, 5 );
4963 feat
= get_loaded_feature( package
, feature
);
4965 return ERROR_SUCCESS
;
4967 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4969 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
4970 feat
->Action
= feat
->Installed
;
4971 return ERROR_SUCCESS
;
4974 component
= MSI_RecordGetString( rec
, 3 );
4975 comp
= get_loaded_component( package
, component
);
4977 return ERROR_SUCCESS
;
4979 compgroupid
= MSI_RecordGetString( rec
, 1 );
4980 qualifier
= MSI_RecordGetString( rec
, 2 );
4982 squash_guid( compgroupid
, squashed
);
4983 strcpyW( keypath
, szInstallerComponents
);
4984 strcatW( keypath
, squashed
);
4986 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
4987 if (res
!= ERROR_SUCCESS
)
4989 WARN("Unable to delete component key %d\n", res
);
4992 uirow
= MSI_CreateRecord( 2 );
4993 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4994 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4995 ui_actiondata( package
, szUnpublishComponents
, uirow
);
4996 msiobj_release( &uirow
->hdr
);
4998 return ERROR_SUCCESS
;
5001 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
5005 static const WCHAR query
[] =
5006 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5007 '`','P','u','b','l','i','s','h',
5008 'C','o','m','p','o','n','e','n','t','`',0};
5010 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5011 if (rc
!= ERROR_SUCCESS
)
5012 return ERROR_SUCCESS
;
5014 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
5015 msiobj_release( &view
->hdr
);
5020 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
5022 MSIPACKAGE
*package
= param
;
5025 SC_HANDLE hscm
, service
= NULL
;
5026 LPCWSTR comp
, depends
, pass
;
5027 LPWSTR name
= NULL
, disp
= NULL
;
5028 LPCWSTR load_order
, serv_name
, key
;
5029 DWORD serv_type
, start_type
;
5032 static const WCHAR query
[] =
5033 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5034 '`','C','o','m','p','o','n','e','n','t','`',' ',
5035 'W','H','E','R','E',' ',
5036 '`','C','o','m','p','o','n','e','n','t','`',' ',
5037 '=','\'','%','s','\'',0};
5039 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
5042 ERR("Failed to open the SC Manager!\n");
5046 start_type
= MSI_RecordGetInteger(rec
, 5);
5047 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
5050 depends
= MSI_RecordGetString(rec
, 8);
5051 if (depends
&& *depends
)
5052 FIXME("Dependency list unhandled!\n");
5054 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5055 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
5056 serv_type
= MSI_RecordGetInteger(rec
, 4);
5057 err_control
= MSI_RecordGetInteger(rec
, 6);
5058 load_order
= MSI_RecordGetString(rec
, 7);
5059 serv_name
= MSI_RecordGetString(rec
, 9);
5060 pass
= MSI_RecordGetString(rec
, 10);
5061 comp
= MSI_RecordGetString(rec
, 12);
5063 /* fetch the service path */
5064 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
5067 ERR("Control query failed!\n");
5071 key
= MSI_RecordGetString(row
, 6);
5073 file
= get_loaded_file(package
, key
);
5074 msiobj_release(&row
->hdr
);
5077 ERR("Failed to load the service file\n");
5081 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
5082 start_type
, err_control
, file
->TargetPath
,
5083 load_order
, NULL
, NULL
, serv_name
, pass
);
5086 if (GetLastError() != ERROR_SERVICE_EXISTS
)
5087 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
5091 CloseServiceHandle(service
);
5092 CloseServiceHandle(hscm
);
5096 return ERROR_SUCCESS
;
5099 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
5103 static const WCHAR ExecSeqQuery
[] =
5104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5105 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5107 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5108 if (rc
!= ERROR_SUCCESS
)
5109 return ERROR_SUCCESS
;
5111 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
5112 msiobj_release(&view
->hdr
);
5117 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5118 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
5120 LPCWSTR
*vector
, *temp_vector
;
5124 static const WCHAR separator
[] = {'[','~',']',0};
5127 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
5132 vector
= msi_alloc(sizeof(LPWSTR
));
5140 vector
[*numargs
- 1] = p
;
5142 if ((q
= strstrW(p
, separator
)))
5146 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
5152 vector
= temp_vector
;
5161 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
5163 MSIPACKAGE
*package
= param
;
5165 SC_HANDLE scm
= NULL
, service
= NULL
;
5166 LPCWSTR component
, *vector
= NULL
;
5168 DWORD event
, numargs
;
5169 UINT r
= ERROR_FUNCTION_FAILED
;
5171 component
= MSI_RecordGetString(rec
, 6);
5172 comp
= get_loaded_component(package
, component
);
5174 return ERROR_SUCCESS
;
5176 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5178 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
5179 comp
->Action
= comp
->Installed
;
5180 return ERROR_SUCCESS
;
5182 comp
->Action
= INSTALLSTATE_LOCAL
;
5184 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5185 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
5186 event
= MSI_RecordGetInteger(rec
, 3);
5188 if (!(event
& msidbServiceControlEventStart
))
5194 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
5197 ERR("Failed to open the service control manager\n");
5201 service
= OpenServiceW(scm
, name
, SERVICE_START
);
5204 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
5208 vector
= msi_service_args_to_vector(args
, &numargs
);
5210 if (!StartServiceW(service
, numargs
, vector
) &&
5211 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
5213 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
5220 CloseServiceHandle(service
);
5221 CloseServiceHandle(scm
);
5229 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
5234 static const WCHAR query
[] = {
5235 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5236 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5238 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5239 if (rc
!= ERROR_SUCCESS
)
5240 return ERROR_SUCCESS
;
5242 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
5243 msiobj_release(&view
->hdr
);
5248 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
5250 DWORD i
, needed
, count
;
5251 ENUM_SERVICE_STATUSW
*dependencies
;
5255 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
5256 0, &needed
, &count
))
5259 if (GetLastError() != ERROR_MORE_DATA
)
5262 dependencies
= msi_alloc(needed
);
5266 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
5267 needed
, &needed
, &count
))
5270 for (i
= 0; i
< count
; i
++)
5272 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
5273 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
5277 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
5284 msi_free(dependencies
);
5288 static UINT
stop_service( LPCWSTR name
)
5290 SC_HANDLE scm
= NULL
, service
= NULL
;
5291 SERVICE_STATUS status
;
5292 SERVICE_STATUS_PROCESS ssp
;
5295 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5298 WARN("Failed to open the SCM: %d\n", GetLastError());
5302 service
= OpenServiceW(scm
, name
,
5304 SERVICE_QUERY_STATUS
|
5305 SERVICE_ENUMERATE_DEPENDENTS
);
5308 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
5312 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
5313 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
5315 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
5319 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
5322 stop_service_dependents(scm
, service
);
5324 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5325 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5328 CloseServiceHandle(service
);
5329 CloseServiceHandle(scm
);
5331 return ERROR_SUCCESS
;
5334 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
5336 MSIPACKAGE
*package
= param
;
5342 event
= MSI_RecordGetInteger( rec
, 3 );
5343 if (!(event
& msidbServiceControlEventStop
))
5344 return ERROR_SUCCESS
;
5346 component
= MSI_RecordGetString( rec
, 6 );
5347 comp
= get_loaded_component( package
, component
);
5349 return ERROR_SUCCESS
;
5351 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5353 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5354 comp
->Action
= comp
->Installed
;
5355 return ERROR_SUCCESS
;
5357 comp
->Action
= INSTALLSTATE_ABSENT
;
5359 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
5360 stop_service( name
);
5363 return ERROR_SUCCESS
;
5366 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5371 static const WCHAR query
[] = {
5372 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5373 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5375 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5376 if (rc
!= ERROR_SUCCESS
)
5377 return ERROR_SUCCESS
;
5379 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5380 msiobj_release(&view
->hdr
);
5385 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
5387 MSIPACKAGE
*package
= param
;
5391 LPWSTR name
= NULL
, display_name
= NULL
;
5393 SC_HANDLE scm
= NULL
, service
= NULL
;
5395 event
= MSI_RecordGetInteger( rec
, 3 );
5396 if (!(event
& msidbServiceControlEventDelete
))
5397 return ERROR_SUCCESS
;
5399 component
= MSI_RecordGetString(rec
, 6);
5400 comp
= get_loaded_component(package
, component
);
5402 return ERROR_SUCCESS
;
5404 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5406 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5407 comp
->Action
= comp
->Installed
;
5408 return ERROR_SUCCESS
;
5410 comp
->Action
= INSTALLSTATE_ABSENT
;
5412 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
5413 stop_service( name
);
5415 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5418 WARN("Failed to open the SCM: %d\n", GetLastError());
5423 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5424 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5426 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5427 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5430 service
= OpenServiceW( scm
, name
, DELETE
);
5433 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
5437 if (!DeleteService( service
))
5438 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
5441 uirow
= MSI_CreateRecord( 2 );
5442 MSI_RecordSetStringW( uirow
, 1, display_name
);
5443 MSI_RecordSetStringW( uirow
, 2, name
);
5444 ui_actiondata( package
, szDeleteServices
, uirow
);
5445 msiobj_release( &uirow
->hdr
);
5447 CloseServiceHandle( service
);
5448 CloseServiceHandle( scm
);
5450 msi_free( display_name
);
5452 return ERROR_SUCCESS
;
5455 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5460 static const WCHAR query
[] = {
5461 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5462 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5464 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5465 if (rc
!= ERROR_SUCCESS
)
5466 return ERROR_SUCCESS
;
5468 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
5469 msiobj_release( &view
->hdr
);
5474 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5478 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5480 if (!lstrcmpW(file
->File
, filename
))
5487 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5489 MSIPACKAGE
*package
= param
;
5490 LPWSTR driver
, driver_path
, ptr
;
5491 WCHAR outpath
[MAX_PATH
];
5492 MSIFILE
*driver_file
, *setup_file
;
5496 UINT r
= ERROR_SUCCESS
;
5498 static const WCHAR driver_fmt
[] = {
5499 'D','r','i','v','e','r','=','%','s',0};
5500 static const WCHAR setup_fmt
[] = {
5501 'S','e','t','u','p','=','%','s',0};
5502 static const WCHAR usage_fmt
[] = {
5503 'F','i','l','e','U','s','a','g','e','=','1',0};
5505 desc
= MSI_RecordGetString(rec
, 3);
5507 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5508 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5512 ERR("ODBC Driver entry not found!\n");
5513 return ERROR_FUNCTION_FAILED
;
5516 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
5518 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5519 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
5521 driver
= msi_alloc(len
* sizeof(WCHAR
));
5523 return ERROR_OUTOFMEMORY
;
5526 lstrcpyW(ptr
, desc
);
5527 ptr
+= lstrlenW(ptr
) + 1;
5529 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5534 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5538 lstrcpyW(ptr
, usage_fmt
);
5539 ptr
+= lstrlenW(ptr
) + 1;
5542 driver_path
= strdupW(driver_file
->TargetPath
);
5543 ptr
= strrchrW(driver_path
, '\\');
5544 if (ptr
) *ptr
= '\0';
5546 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5547 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5549 ERR("Failed to install SQL driver!\n");
5550 r
= ERROR_FUNCTION_FAILED
;
5553 uirow
= MSI_CreateRecord( 5 );
5554 MSI_RecordSetStringW( uirow
, 1, desc
);
5555 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5556 MSI_RecordSetStringW( uirow
, 3, driver_path
);
5557 ui_actiondata( package
, szInstallODBC
, uirow
);
5558 msiobj_release( &uirow
->hdr
);
5561 msi_free(driver_path
);
5566 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5568 MSIPACKAGE
*package
= param
;
5569 LPWSTR translator
, translator_path
, ptr
;
5570 WCHAR outpath
[MAX_PATH
];
5571 MSIFILE
*translator_file
, *setup_file
;
5575 UINT r
= ERROR_SUCCESS
;
5577 static const WCHAR translator_fmt
[] = {
5578 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5579 static const WCHAR setup_fmt
[] = {
5580 'S','e','t','u','p','=','%','s',0};
5582 desc
= MSI_RecordGetString(rec
, 3);
5584 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5585 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5587 if (!translator_file
)
5589 ERR("ODBC Translator entry not found!\n");
5590 return ERROR_FUNCTION_FAILED
;
5593 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
5595 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5597 translator
= msi_alloc(len
* sizeof(WCHAR
));
5599 return ERROR_OUTOFMEMORY
;
5602 lstrcpyW(ptr
, desc
);
5603 ptr
+= lstrlenW(ptr
) + 1;
5605 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5610 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5615 translator_path
= strdupW(translator_file
->TargetPath
);
5616 ptr
= strrchrW(translator_path
, '\\');
5617 if (ptr
) *ptr
= '\0';
5619 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5620 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5622 ERR("Failed to install SQL translator!\n");
5623 r
= ERROR_FUNCTION_FAILED
;
5626 uirow
= MSI_CreateRecord( 5 );
5627 MSI_RecordSetStringW( uirow
, 1, desc
);
5628 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5629 MSI_RecordSetStringW( uirow
, 3, translator_path
);
5630 ui_actiondata( package
, szInstallODBC
, uirow
);
5631 msiobj_release( &uirow
->hdr
);
5633 msi_free(translator
);
5634 msi_free(translator_path
);
5639 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5641 MSIPACKAGE
*package
= param
;
5643 LPCWSTR desc
, driver
;
5644 WORD request
= ODBC_ADD_SYS_DSN
;
5647 UINT r
= ERROR_SUCCESS
;
5650 static const WCHAR attrs_fmt
[] = {
5651 'D','S','N','=','%','s',0 };
5653 desc
= MSI_RecordGetString(rec
, 3);
5654 driver
= MSI_RecordGetString(rec
, 4);
5655 registration
= MSI_RecordGetInteger(rec
, 5);
5657 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5658 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5660 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
5661 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5663 return ERROR_OUTOFMEMORY
;
5665 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5668 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5670 ERR("Failed to install SQL data source!\n");
5671 r
= ERROR_FUNCTION_FAILED
;
5674 uirow
= MSI_CreateRecord( 5 );
5675 MSI_RecordSetStringW( uirow
, 1, desc
);
5676 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5677 MSI_RecordSetInteger( uirow
, 3, request
);
5678 ui_actiondata( package
, szInstallODBC
, uirow
);
5679 msiobj_release( &uirow
->hdr
);
5686 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5691 static const WCHAR driver_query
[] = {
5692 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5693 'O','D','B','C','D','r','i','v','e','r',0 };
5695 static const WCHAR translator_query
[] = {
5696 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5697 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5699 static const WCHAR source_query
[] = {
5700 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5701 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5703 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5704 if (rc
!= ERROR_SUCCESS
)
5705 return ERROR_SUCCESS
;
5707 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5708 msiobj_release(&view
->hdr
);
5710 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5711 if (rc
!= ERROR_SUCCESS
)
5712 return ERROR_SUCCESS
;
5714 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5715 msiobj_release(&view
->hdr
);
5717 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5718 if (rc
!= ERROR_SUCCESS
)
5719 return ERROR_SUCCESS
;
5721 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5722 msiobj_release(&view
->hdr
);
5727 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5729 MSIPACKAGE
*package
= param
;
5734 desc
= MSI_RecordGetString( rec
, 3 );
5735 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5737 WARN("Failed to remove ODBC driver\n");
5741 FIXME("Usage count reached 0\n");
5744 uirow
= MSI_CreateRecord( 2 );
5745 MSI_RecordSetStringW( uirow
, 1, desc
);
5746 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5747 ui_actiondata( package
, szRemoveODBC
, uirow
);
5748 msiobj_release( &uirow
->hdr
);
5750 return ERROR_SUCCESS
;
5753 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5755 MSIPACKAGE
*package
= param
;
5760 desc
= MSI_RecordGetString( rec
, 3 );
5761 if (!SQLRemoveTranslatorW( desc
, &usage
))
5763 WARN("Failed to remove ODBC translator\n");
5767 FIXME("Usage count reached 0\n");
5770 uirow
= MSI_CreateRecord( 2 );
5771 MSI_RecordSetStringW( uirow
, 1, desc
);
5772 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5773 ui_actiondata( package
, szRemoveODBC
, uirow
);
5774 msiobj_release( &uirow
->hdr
);
5776 return ERROR_SUCCESS
;
5779 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5781 MSIPACKAGE
*package
= param
;
5784 LPCWSTR desc
, driver
;
5785 WORD request
= ODBC_REMOVE_SYS_DSN
;
5789 static const WCHAR attrs_fmt
[] = {
5790 'D','S','N','=','%','s',0 };
5792 desc
= MSI_RecordGetString( rec
, 3 );
5793 driver
= MSI_RecordGetString( rec
, 4 );
5794 registration
= MSI_RecordGetInteger( rec
, 5 );
5796 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5797 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5799 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
5800 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5802 return ERROR_OUTOFMEMORY
;
5804 FIXME("Use ODBCSourceAttribute table\n");
5806 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5809 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5811 WARN("Failed to remove ODBC data source\n");
5815 uirow
= MSI_CreateRecord( 3 );
5816 MSI_RecordSetStringW( uirow
, 1, desc
);
5817 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5818 MSI_RecordSetInteger( uirow
, 3, request
);
5819 ui_actiondata( package
, szRemoveODBC
, uirow
);
5820 msiobj_release( &uirow
->hdr
);
5822 return ERROR_SUCCESS
;
5825 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5830 static const WCHAR driver_query
[] = {
5831 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5832 'O','D','B','C','D','r','i','v','e','r',0 };
5834 static const WCHAR translator_query
[] = {
5835 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5836 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5838 static const WCHAR source_query
[] = {
5839 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5840 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5842 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
5843 if (rc
!= ERROR_SUCCESS
)
5844 return ERROR_SUCCESS
;
5846 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
5847 msiobj_release( &view
->hdr
);
5849 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
5850 if (rc
!= ERROR_SUCCESS
)
5851 return ERROR_SUCCESS
;
5853 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
5854 msiobj_release( &view
->hdr
);
5856 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
5857 if (rc
!= ERROR_SUCCESS
)
5858 return ERROR_SUCCESS
;
5860 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
5861 msiobj_release( &view
->hdr
);
5866 #define ENV_ACT_SETALWAYS 0x1
5867 #define ENV_ACT_SETABSENT 0x2
5868 #define ENV_ACT_REMOVE 0x4
5869 #define ENV_ACT_REMOVEMATCH 0x8
5871 #define ENV_MOD_MACHINE 0x20000000
5872 #define ENV_MOD_APPEND 0x40000000
5873 #define ENV_MOD_PREFIX 0x80000000
5874 #define ENV_MOD_MASK 0xC0000000
5876 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5878 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5880 LPCWSTR cptr
= *name
;
5882 static const WCHAR prefix
[] = {'[','~',']',0};
5883 static const int prefix_len
= 3;
5889 *flags
|= ENV_ACT_SETALWAYS
;
5890 else if (*cptr
== '+')
5891 *flags
|= ENV_ACT_SETABSENT
;
5892 else if (*cptr
== '-')
5893 *flags
|= ENV_ACT_REMOVE
;
5894 else if (*cptr
== '!')
5895 *flags
|= ENV_ACT_REMOVEMATCH
;
5896 else if (*cptr
== '*')
5897 *flags
|= ENV_MOD_MACHINE
;
5907 ERR("Missing environment variable\n");
5908 return ERROR_FUNCTION_FAILED
;
5913 LPCWSTR ptr
= *value
;
5914 if (!strncmpW(ptr
, prefix
, prefix_len
))
5916 if (ptr
[prefix_len
] == szSemiColon
[0])
5918 *flags
|= ENV_MOD_APPEND
;
5919 *value
+= lstrlenW(prefix
);
5926 else if (lstrlenW(*value
) >= prefix_len
)
5928 ptr
+= lstrlenW(ptr
) - prefix_len
;
5929 if (!lstrcmpW(ptr
, prefix
))
5931 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
5933 *flags
|= ENV_MOD_PREFIX
;
5934 /* the "[~]" will be removed by deformat_string */;
5944 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5945 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5946 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5947 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5949 ERR("Invalid flags: %08x\n", *flags
);
5950 return ERROR_FUNCTION_FAILED
;
5954 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
5956 return ERROR_SUCCESS
;
5959 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
5961 static const WCHAR user_env
[] =
5962 {'E','n','v','i','r','o','n','m','e','n','t',0};
5963 static const WCHAR machine_env
[] =
5964 {'S','y','s','t','e','m','\\',
5965 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5966 'C','o','n','t','r','o','l','\\',
5967 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5968 'E','n','v','i','r','o','n','m','e','n','t',0};
5973 if (flags
& ENV_MOD_MACHINE
)
5976 root
= HKEY_LOCAL_MACHINE
;
5981 root
= HKEY_CURRENT_USER
;
5984 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
5985 if (res
!= ERROR_SUCCESS
)
5987 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
5988 return ERROR_FUNCTION_FAILED
;
5991 return ERROR_SUCCESS
;
5994 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5996 MSIPACKAGE
*package
= param
;
5997 LPCWSTR name
, value
, component
;
5998 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
5999 DWORD flags
, type
, size
;
6006 component
= MSI_RecordGetString(rec
, 4);
6007 comp
= get_loaded_component(package
, component
);
6009 return ERROR_SUCCESS
;
6011 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6013 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6014 comp
->Action
= comp
->Installed
;
6015 return ERROR_SUCCESS
;
6017 comp
->Action
= INSTALLSTATE_LOCAL
;
6019 name
= MSI_RecordGetString(rec
, 2);
6020 value
= MSI_RecordGetString(rec
, 3);
6022 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6024 res
= env_parse_flags(&name
, &value
, &flags
);
6025 if (res
!= ERROR_SUCCESS
|| !value
)
6028 if (value
&& !deformat_string(package
, value
, &deformatted
))
6030 res
= ERROR_OUTOFMEMORY
;
6034 value
= deformatted
;
6036 res
= open_env_key( flags
, &env
);
6037 if (res
!= ERROR_SUCCESS
)
6040 if (flags
& ENV_MOD_MACHINE
)
6041 action
|= 0x20000000;
6045 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
6046 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
6047 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
6050 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
6054 /* Nothing to do. */
6057 res
= ERROR_SUCCESS
;
6061 /* If we are appending but the string was empty, strip ; */
6062 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
6064 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
6065 newval
= strdupW(value
);
6068 res
= ERROR_OUTOFMEMORY
;
6076 /* Contrary to MSDN, +-variable to [~];path works */
6077 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
6079 res
= ERROR_SUCCESS
;
6083 data
= msi_alloc(size
);
6087 return ERROR_OUTOFMEMORY
;
6090 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
6091 if (res
!= ERROR_SUCCESS
)
6094 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
6097 res
= RegDeleteValueW(env
, name
);
6098 if (res
!= ERROR_SUCCESS
)
6099 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
6103 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
6104 if (flags
& ENV_MOD_MASK
)
6108 if (flags
& ENV_MOD_APPEND
) multiplier
++;
6109 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
6110 mod_size
= lstrlenW(value
) * multiplier
;
6111 size
+= mod_size
* sizeof(WCHAR
);
6114 newval
= msi_alloc(size
);
6118 res
= ERROR_OUTOFMEMORY
;
6122 if (flags
& ENV_MOD_PREFIX
)
6124 lstrcpyW(newval
, value
);
6125 ptr
= newval
+ lstrlenW(value
);
6126 action
|= 0x80000000;
6129 lstrcpyW(ptr
, data
);
6131 if (flags
& ENV_MOD_APPEND
)
6133 lstrcatW(newval
, value
);
6134 action
|= 0x40000000;
6137 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
6138 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
6141 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
6145 uirow
= MSI_CreateRecord( 3 );
6146 MSI_RecordSetStringW( uirow
, 1, name
);
6147 MSI_RecordSetStringW( uirow
, 2, newval
);
6148 MSI_RecordSetInteger( uirow
, 3, action
);
6149 ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
6150 msiobj_release( &uirow
->hdr
);
6152 if (env
) RegCloseKey(env
);
6153 msi_free(deformatted
);
6159 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
6163 static const WCHAR ExecSeqQuery
[] =
6164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6165 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6166 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6167 if (rc
!= ERROR_SUCCESS
)
6168 return ERROR_SUCCESS
;
6170 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
6171 msiobj_release(&view
->hdr
);
6176 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6178 MSIPACKAGE
*package
= param
;
6179 LPCWSTR name
, value
, component
;
6180 LPWSTR deformatted
= NULL
;
6189 component
= MSI_RecordGetString( rec
, 4 );
6190 comp
= get_loaded_component( package
, component
);
6192 return ERROR_SUCCESS
;
6194 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6196 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6197 comp
->Action
= comp
->Installed
;
6198 return ERROR_SUCCESS
;
6200 comp
->Action
= INSTALLSTATE_ABSENT
;
6202 name
= MSI_RecordGetString( rec
, 2 );
6203 value
= MSI_RecordGetString( rec
, 3 );
6205 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6207 r
= env_parse_flags( &name
, &value
, &flags
);
6208 if (r
!= ERROR_SUCCESS
)
6211 if (!(flags
& ENV_ACT_REMOVE
))
6213 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
6214 return ERROR_SUCCESS
;
6217 if (value
&& !deformat_string( package
, value
, &deformatted
))
6218 return ERROR_OUTOFMEMORY
;
6220 value
= deformatted
;
6222 r
= open_env_key( flags
, &env
);
6223 if (r
!= ERROR_SUCCESS
)
6229 if (flags
& ENV_MOD_MACHINE
)
6230 action
|= 0x20000000;
6232 TRACE("Removing %s\n", debugstr_w(name
));
6234 res
= RegDeleteValueW( env
, name
);
6235 if (res
!= ERROR_SUCCESS
)
6237 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
6242 uirow
= MSI_CreateRecord( 3 );
6243 MSI_RecordSetStringW( uirow
, 1, name
);
6244 MSI_RecordSetStringW( uirow
, 2, value
);
6245 MSI_RecordSetInteger( uirow
, 3, action
);
6246 ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
6247 msiobj_release( &uirow
->hdr
);
6249 if (env
) RegCloseKey( env
);
6250 msi_free( deformatted
);
6254 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6258 static const WCHAR query
[] =
6259 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6260 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6262 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6263 if (rc
!= ERROR_SUCCESS
)
6264 return ERROR_SUCCESS
;
6266 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
6267 msiobj_release( &view
->hdr
);
6272 typedef struct tagMSIASSEMBLY
6275 MSICOMPONENT
*component
;
6276 MSIFEATURE
*feature
;
6280 LPWSTR display_name
;
6285 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
6287 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
6288 LPVOID pvReserved
, HMODULE
*phModDll
);
6290 static BOOL
init_functionpointers(void)
6296 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
6298 hmscoree
= LoadLibraryA("mscoree.dll");
6301 WARN("mscoree.dll not available\n");
6305 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
6306 if (!pLoadLibraryShim
)
6308 WARN("LoadLibraryShim not available\n");
6309 FreeLibrary(hmscoree
);
6313 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
6316 WARN("fusion.dll not available\n");
6317 FreeLibrary(hmscoree
);
6321 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
6323 FreeLibrary(hmscoree
);
6327 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
6330 IAssemblyCache
*cache
;
6333 UINT r
= ERROR_FUNCTION_FAILED
;
6335 TRACE("installing assembly: %s\n", debugstr_w(path
));
6337 uirow
= MSI_CreateRecord( 2 );
6338 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
6339 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
6340 msiobj_release( &uirow
->hdr
);
6342 if (assembly
->feature
)
6343 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
6345 if (assembly
->manifest
)
6346 FIXME("Manifest unhandled\n");
6348 if (assembly
->application
)
6350 FIXME("Assembly should be privately installed\n");
6351 return ERROR_SUCCESS
;
6354 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
6356 FIXME("Win32 assemblies not handled\n");
6357 return ERROR_SUCCESS
;
6360 hr
= pCreateAssemblyCache(&cache
, 0);
6364 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
6366 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
6371 IAssemblyCache_Release(cache
);
6375 typedef struct tagASSEMBLY_LIST
6377 MSIPACKAGE
*package
;
6378 IAssemblyCache
*cache
;
6379 struct list
*assemblies
;
6382 typedef struct tagASSEMBLY_NAME
6390 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
6392 ASSEMBLY_NAME
*asmname
= param
;
6393 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
6394 LPWSTR val
= msi_dup_record_field(rec
, 3);
6396 static const WCHAR Name
[] = {'N','a','m','e',0};
6397 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
6398 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
6399 static const WCHAR PublicKeyToken
[] = {
6400 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6402 if (!strcmpiW(name
, Name
))
6403 asmname
->name
= val
;
6404 else if (!strcmpiW(name
, Version
))
6405 asmname
->version
= val
;
6406 else if (!strcmpiW(name
, Culture
))
6407 asmname
->culture
= val
;
6408 else if (!strcmpiW(name
, PublicKeyToken
))
6409 asmname
->pubkeytoken
= val
;
6413 return ERROR_SUCCESS
;
6416 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
6420 *size
= lstrlenW(append
) + 1;
6421 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
6422 lstrcpyW(*str
, append
);
6426 (*size
) += lstrlenW(append
);
6427 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6428 lstrcatW(*str
, append
);
6431 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, MSICOMPONENT
*comp
)
6433 static const WCHAR separator
[] = {',',' ',0};
6434 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
6435 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
6436 static const WCHAR PublicKeyToken
[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6437 static const WCHAR query
[] = {
6438 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6439 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6440 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6441 '=','\'','%','s','\'',0};
6444 LPWSTR display_name
;
6448 display_name
= NULL
;
6449 memset( &name
, 0, sizeof(ASSEMBLY_NAME
) );
6451 r
= MSI_OpenQuery( db
, &view
, query
, comp
->Component
);
6452 if (r
!= ERROR_SUCCESS
)
6455 MSI_IterateRecords( view
, NULL
, parse_assembly_name
, &name
);
6456 msiobj_release( &view
->hdr
);
6460 ERR("No assembly name specified!\n");
6464 append_str( &display_name
, &size
, name
.name
);
6468 append_str( &display_name
, &size
, separator
);
6469 append_str( &display_name
, &size
, Version
);
6470 append_str( &display_name
, &size
, name
.version
);
6474 append_str( &display_name
, &size
, separator
);
6475 append_str( &display_name
, &size
, Culture
);
6476 append_str( &display_name
, &size
, name
.culture
);
6478 if (name
.pubkeytoken
)
6480 append_str( &display_name
, &size
, separator
);
6481 append_str( &display_name
, &size
, PublicKeyToken
);
6482 append_str( &display_name
, &size
, name
.pubkeytoken
);
6485 msi_free( name
.name
);
6486 msi_free( name
.version
);
6487 msi_free( name
.culture
);
6488 msi_free( name
.pubkeytoken
);
6490 return display_name
;
6493 static BOOL
check_assembly_installed( MSIDATABASE
*db
, IAssemblyCache
*cache
, MSICOMPONENT
*comp
)
6495 ASSEMBLY_INFO asminfo
;
6500 disp
= get_assembly_display_name( db
, comp
);
6504 memset( &asminfo
, 0, sizeof(ASSEMBLY_INFO
) );
6505 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6507 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, disp
, &asminfo
);
6509 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6515 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6517 ASSEMBLY_LIST
*list
= param
;
6518 MSIASSEMBLY
*assembly
;
6521 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6523 return ERROR_OUTOFMEMORY
;
6525 component
= MSI_RecordGetString(rec
, 1);
6526 assembly
->component
= get_loaded_component(list
->package
, component
);
6527 if (!assembly
->component
)
6528 return ERROR_SUCCESS
;
6530 if (assembly
->component
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6531 assembly
->component
->ActionRequest
!= INSTALLSTATE_SOURCE
)
6533 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6534 assembly
->component
->Action
= assembly
->component
->Installed
;
6535 return ERROR_SUCCESS
;
6537 assembly
->component
->Action
= assembly
->component
->ActionRequest
;
6539 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6540 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6542 if (!assembly
->file
)
6544 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6545 return ERROR_FUNCTION_FAILED
;
6548 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6549 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6550 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6552 if (assembly
->application
)
6555 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6557 /* FIXME: we should probably check the manifest file here */
6559 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6560 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6562 assembly
->installed
= TRUE
;
6566 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6568 assembly
->component
);
6570 list_add_head(list
->assemblies
, &assembly
->entry
);
6571 return ERROR_SUCCESS
;
6574 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6576 IAssemblyCache
*cache
= NULL
;
6582 static const WCHAR query
[] =
6583 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6584 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6586 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6587 if (r
!= ERROR_SUCCESS
)
6588 return ERROR_SUCCESS
;
6590 hr
= pCreateAssemblyCache(&cache
, 0);
6592 return ERROR_FUNCTION_FAILED
;
6594 list
.package
= package
;
6596 list
.assemblies
= assemblies
;
6598 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6599 msiobj_release(&view
->hdr
);
6601 IAssemblyCache_Release(cache
);
6606 static void free_assemblies(struct list
*assemblies
)
6608 struct list
*item
, *cursor
;
6610 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6612 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6614 list_remove(&assembly
->entry
);
6615 msi_free(assembly
->application
);
6616 msi_free(assembly
->manifest
);
6617 msi_free(assembly
->display_name
);
6622 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6624 MSIASSEMBLY
*assembly
;
6626 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6628 if (!lstrcmpW(assembly
->file
->File
, file
))
6638 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6639 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6641 MSIASSEMBLY
*assembly
;
6642 WCHAR temppath
[MAX_PATH
];
6643 struct list
*assemblies
= user
;
6646 if (!find_assembly(assemblies
, file
, &assembly
))
6649 GetTempPathW(MAX_PATH
, temppath
);
6650 PathAddBackslashW(temppath
);
6651 lstrcatW(temppath
, assembly
->file
->FileName
);
6653 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6655 if (assembly
->installed
)
6658 *path
= strdupW(temppath
);
6659 *attrs
= assembly
->file
->Attributes
;
6661 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6663 assembly
->installed
= TRUE
;
6665 r
= install_assembly(package
, assembly
, temppath
);
6666 if (r
!= ERROR_SUCCESS
)
6667 ERR("Failed to install assembly\n");
6673 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6676 struct list assemblies
= LIST_INIT(assemblies
);
6677 MSIASSEMBLY
*assembly
;
6680 if (!init_functionpointers() || !pCreateAssemblyCache
)
6681 return ERROR_FUNCTION_FAILED
;
6683 r
= load_assemblies(package
, &assemblies
);
6684 if (r
!= ERROR_SUCCESS
)
6687 if (list_empty(&assemblies
))
6690 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6693 r
= ERROR_OUTOFMEMORY
;
6697 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6699 if (assembly
->installed
&& !mi
->is_continuous
)
6702 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6703 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6707 r
= ready_media(package
, assembly
->file
, mi
);
6708 if (r
!= ERROR_SUCCESS
)
6710 ERR("Failed to ready media\n");
6715 data
.package
= package
;
6716 data
.cb
= installassembly_cb
;
6717 data
.user
= &assemblies
;
6719 if (assembly
->file
->IsCompressed
&&
6720 !msi_cabextract(package
, mi
, &data
))
6722 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6723 r
= ERROR_FUNCTION_FAILED
;
6728 if (!assembly
->file
->IsCompressed
)
6730 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6732 r
= install_assembly(package
, assembly
, source
);
6733 if (r
!= ERROR_SUCCESS
)
6734 ERR("Failed to install assembly\n");
6739 /* FIXME: write Installer assembly reg values */
6743 free_assemblies(&assemblies
);
6747 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6749 LPWSTR key
, template, id
;
6750 UINT r
= ERROR_SUCCESS
;
6752 id
= msi_dup_property( package
, szProductID
);
6756 return ERROR_SUCCESS
;
6758 template = msi_dup_property( package
, szPIDTemplate
);
6759 key
= msi_dup_property( package
, szPIDKEY
);
6761 if (key
&& template)
6763 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6764 r
= MSI_SetPropertyW( package
, szProductID
, key
);
6766 msi_free( template );
6771 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6774 package
->need_reboot
= 1;
6775 return ERROR_SUCCESS
;
6778 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6780 static const WCHAR szAvailableFreeReg
[] =
6781 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6783 int space
= msi_get_property_int( package
, szAvailableFreeReg
, 0 );
6785 TRACE("%p %d kilobytes\n", package
, space
);
6787 uirow
= MSI_CreateRecord( 1 );
6788 MSI_RecordSetInteger( uirow
, 1, space
);
6789 ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
6790 msiobj_release( &uirow
->hdr
);
6792 return ERROR_SUCCESS
;
6795 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6797 FIXME("%p\n", package
);
6798 return ERROR_SUCCESS
;
6801 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6803 FIXME("%p\n", package
);
6804 return ERROR_SUCCESS
;
6807 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6808 LPCSTR action
, LPCWSTR table
)
6810 static const WCHAR query
[] = {
6811 'S','E','L','E','C','T',' ','*',' ',
6812 'F','R','O','M',' ','`','%','s','`',0 };
6813 MSIQUERY
*view
= NULL
;
6817 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6818 if (r
== ERROR_SUCCESS
)
6820 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6821 msiobj_release(&view
->hdr
);
6825 FIXME("%s -> %u ignored %s table values\n",
6826 action
, count
, debugstr_w(table
));
6828 return ERROR_SUCCESS
;
6831 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6833 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6834 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6837 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6839 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6840 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6843 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6845 static const WCHAR table
[] = {
6846 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6847 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6850 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6852 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6853 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6856 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6858 static const WCHAR table
[] = {
6859 'M','s','i','A','s','s','e','m','b','l','y',0 };
6860 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6863 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6865 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6866 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6869 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6871 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6872 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6875 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6877 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6878 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6881 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6883 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6884 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6887 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6889 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6890 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6893 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6895 static const WCHAR table
[] = { 'D','i','r','e','c','t','o','r','y',0 };
6896 return msi_unimplemented_action_stub( package
, "SetODBCFolders", table
);
6899 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6901 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6902 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6905 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6907 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6908 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6911 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6913 static const WCHAR table
[] = { 'M','I','M','E',0 };
6914 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6917 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6919 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6920 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6923 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6927 const WCHAR
*action
;
6928 UINT (*handler
)(MSIPACKAGE
*);
6932 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6933 { szAppSearch
, ACTION_AppSearch
},
6934 { szBindImage
, ACTION_BindImage
},
6935 { szCCPSearch
, ACTION_CCPSearch
},
6936 { szCostFinalize
, ACTION_CostFinalize
},
6937 { szCostInitialize
, ACTION_CostInitialize
},
6938 { szCreateFolders
, ACTION_CreateFolders
},
6939 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6940 { szDeleteServices
, ACTION_DeleteServices
},
6941 { szDisableRollback
, ACTION_DisableRollback
},
6942 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6943 { szExecuteAction
, ACTION_ExecuteAction
},
6944 { szFileCost
, ACTION_FileCost
},
6945 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6946 { szForceReboot
, ACTION_ForceReboot
},
6947 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
6948 { szInstallExecute
, ACTION_InstallExecute
},
6949 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6950 { szInstallFiles
, ACTION_InstallFiles
},
6951 { szInstallFinalize
, ACTION_InstallFinalize
},
6952 { szInstallInitialize
, ACTION_InstallInitialize
},
6953 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6954 { szInstallValidate
, ACTION_InstallValidate
},
6955 { szIsolateComponents
, ACTION_IsolateComponents
},
6956 { szLaunchConditions
, ACTION_LaunchConditions
},
6957 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6958 { szMoveFiles
, ACTION_MoveFiles
},
6959 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6960 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6961 { szInstallODBC
, ACTION_InstallODBC
},
6962 { szInstallServices
, ACTION_InstallServices
},
6963 { szPatchFiles
, ACTION_PatchFiles
},
6964 { szProcessComponents
, ACTION_ProcessComponents
},
6965 { szPublishComponents
, ACTION_PublishComponents
},
6966 { szPublishFeatures
, ACTION_PublishFeatures
},
6967 { szPublishProduct
, ACTION_PublishProduct
},
6968 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6969 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6970 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6971 { szRegisterFonts
, ACTION_RegisterFonts
},
6972 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6973 { szRegisterProduct
, ACTION_RegisterProduct
},
6974 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6975 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6976 { szRegisterUser
, ACTION_RegisterUser
},
6977 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6978 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6979 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6980 { szRemoveFiles
, ACTION_RemoveFiles
},
6981 { szRemoveFolders
, ACTION_RemoveFolders
},
6982 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6983 { szRemoveODBC
, ACTION_RemoveODBC
},
6984 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6985 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6986 { szResolveSource
, ACTION_ResolveSource
},
6987 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6988 { szScheduleReboot
, ACTION_ScheduleReboot
},
6989 { szSelfRegModules
, ACTION_SelfRegModules
},
6990 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6991 { szSetODBCFolders
, ACTION_SetODBCFolders
},
6992 { szStartServices
, ACTION_StartServices
},
6993 { szStopServices
, ACTION_StopServices
},
6994 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6995 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6996 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6997 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6998 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6999 { szUnregisterFonts
, ACTION_UnregisterFonts
},
7000 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
7001 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
7002 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
7003 { szValidateProductID
, ACTION_ValidateProductID
},
7004 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
7005 { szWriteIniValues
, ACTION_WriteIniValues
},
7006 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
7010 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
7011 UINT
* rc
, BOOL force
)
7017 if (!run
&& !package
->script
->CurrentlyScripting
)
7022 if (strcmpW(action
,szInstallFinalize
) == 0 ||
7023 strcmpW(action
,szInstallExecute
) == 0 ||
7024 strcmpW(action
,szInstallExecuteAgain
) == 0)
7029 while (StandardActions
[i
].action
!= NULL
)
7031 if (strcmpW(StandardActions
[i
].action
, action
)==0)
7035 ui_actioninfo(package
, action
, TRUE
, 0);
7036 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
7037 ui_actioninfo(package
, action
, FALSE
, *rc
);
7041 ui_actionstart(package
, action
);
7042 if (StandardActions
[i
].handler
)
7044 *rc
= StandardActions
[i
].handler(package
);
7048 FIXME("unhandled standard action %s\n",debugstr_w(action
));
7049 *rc
= ERROR_SUCCESS
;
7060 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
7062 UINT rc
= ERROR_SUCCESS
;
7065 TRACE("Performing action (%s)\n", debugstr_w(action
));
7067 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
7070 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
7074 WARN("unhandled msi action %s\n", debugstr_w(action
));
7075 rc
= ERROR_FUNCTION_NOT_CALLED
;
7081 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
7083 UINT rc
= ERROR_SUCCESS
;
7084 BOOL handled
= FALSE
;
7086 TRACE("Performing action (%s)\n", debugstr_w(action
));
7088 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
7091 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
7093 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
7098 WARN("unhandled msi action %s\n", debugstr_w(action
));
7099 rc
= ERROR_FUNCTION_NOT_CALLED
;
7105 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
7107 UINT rc
= ERROR_SUCCESS
;
7110 static const WCHAR ExecSeqQuery
[] =
7111 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7112 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7113 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7114 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7115 static const WCHAR UISeqQuery
[] =
7116 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7117 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7118 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7119 ' ', '=',' ','%','i',0};
7121 if (needs_ui_sequence(package
))
7122 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
7124 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
7128 LPCWSTR action
, cond
;
7130 TRACE("Running the actions\n");
7132 /* check conditions */
7133 cond
= MSI_RecordGetString(row
, 2);
7135 /* this is a hack to skip errors in the condition code */
7136 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
7138 msiobj_release(&row
->hdr
);
7139 return ERROR_SUCCESS
;
7142 action
= MSI_RecordGetString(row
, 1);
7145 ERR("failed to fetch action\n");
7146 msiobj_release(&row
->hdr
);
7147 return ERROR_FUNCTION_FAILED
;
7150 if (needs_ui_sequence(package
))
7151 rc
= ACTION_PerformUIAction(package
, action
, -1);
7153 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
7155 msiobj_release(&row
->hdr
);
7161 /****************************************************
7162 * TOP level entry points
7163 *****************************************************/
7165 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
7166 LPCWSTR szCommandLine
)
7171 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
7172 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
7174 MSI_SetPropertyW(package
, szAction
, szInstall
);
7176 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
7183 dir
= strdupW(szPackagePath
);
7184 p
= strrchrW(dir
, '\\');
7188 file
= szPackagePath
+ (p
- dir
);
7193 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
7194 GetCurrentDirectoryW(MAX_PATH
, dir
);
7195 lstrcatW(dir
, szBackSlash
);
7196 file
= szPackagePath
;
7199 msi_free( package
->PackagePath
);
7200 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
7201 if (!package
->PackagePath
)
7204 return ERROR_OUTOFMEMORY
;
7207 lstrcpyW(package
->PackagePath
, dir
);
7208 lstrcatW(package
->PackagePath
, file
);
7211 msi_set_sourcedir_props(package
, FALSE
);
7214 msi_parse_command_line( package
, szCommandLine
, FALSE
);
7216 msi_apply_transforms( package
);
7217 msi_apply_patches( package
);
7219 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
7221 TRACE("setting reinstall property\n");
7222 MSI_SetPropertyW( package
, szReinstall
, szAll
);
7225 /* properties may have been added by a transform */
7226 msi_clone_properties( package
);
7227 msi_set_context( package
);
7229 if (needs_ui_sequence( package
))
7231 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
7232 rc
= ACTION_ProcessUISequence(package
);
7233 ui_exists
= ui_sequence_exists(package
);
7234 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
7236 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
7237 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
7241 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
7243 package
->script
->CurrentlyScripting
= FALSE
;
7245 /* process the ending type action */
7246 if (rc
== ERROR_SUCCESS
)
7247 ACTION_PerformActionSequence(package
, -1);
7248 else if (rc
== ERROR_INSTALL_USEREXIT
)
7249 ACTION_PerformActionSequence(package
, -2);
7250 else if (rc
== ERROR_INSTALL_SUSPEND
)
7251 ACTION_PerformActionSequence(package
, -4);
7253 ACTION_PerformActionSequence(package
, -3);
7255 /* finish up running custom actions */
7256 ACTION_FinishCustomActions(package
);
7258 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
7259 return ERROR_SUCCESS_REBOOT_REQUIRED
;