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 szDeleteServices
[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback
[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction
[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage
[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile
[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents
[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates
[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies
[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies
[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC
[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices
[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles
[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents
[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus
[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser
[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings
[] =
130 {'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};
131 static const WCHAR szRemoveExistingProducts
[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders
[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues
[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC
[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues
[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts
[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch
[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot
[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules
[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders
[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices
[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices
[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents
[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures
[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus
[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterMIMEInfo
[] =
162 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
163 static const WCHAR szUnregisterTypeLibraries
[] =
164 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
165 static const WCHAR szValidateProductID
[] =
166 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
167 static const WCHAR szWriteEnvironmentStrings
[] =
168 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
170 /********************************************************
172 ********************************************************/
174 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
176 static const WCHAR Query_t
[] =
177 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
178 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
179 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
180 ' ','\'','%','s','\'',0};
183 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
186 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
187 msiobj_release(&row
->hdr
);
190 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
194 static const WCHAR template_s
[]=
195 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
197 static const WCHAR template_e
[]=
198 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
199 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
201 static const WCHAR format
[] =
202 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
206 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
208 sprintfW(message
,template_s
,timet
,action
);
210 sprintfW(message
,template_e
,timet
,action
,rc
);
212 row
= MSI_CreateRecord(1);
213 MSI_RecordSetStringW(row
,1,message
);
215 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
216 msiobj_release(&row
->hdr
);
219 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
225 LPWSTR prop
= NULL
, val
= NULL
;
228 return ERROR_SUCCESS
;
240 TRACE("Looking at %s\n",debugstr_w(ptr
));
242 ptr2
= strchrW(ptr
,'=');
245 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
252 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
253 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
263 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
276 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
277 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
280 if (lstrlenW(prop
) > 0)
282 TRACE("Found commandline property (%s) = (%s)\n",
283 debugstr_w(prop
), debugstr_w(val
));
284 MSI_SetPropertyW(package
,prop
,val
);
290 return ERROR_SUCCESS
;
294 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
297 LPWSTR p
, *ret
= NULL
;
303 /* count the number of substrings */
304 for ( pc
= str
, count
= 0; pc
; count
++ )
306 pc
= strchrW( pc
, sep
);
311 /* allocate space for an array of substring pointers and the substrings */
312 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
313 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
317 /* copy the string and set the pointers */
318 p
= (LPWSTR
) &ret
[count
+1];
320 for( count
= 0; (ret
[count
] = p
); count
++ )
322 p
= strchrW( p
, sep
);
330 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
332 static const WCHAR szSystemLanguageID
[] =
333 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
335 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
336 UINT ret
= ERROR_FUNCTION_FAILED
;
338 prod_code
= msi_dup_property( package
, szProductCode
);
339 patch_product
= msi_get_suminfo_product( patch
);
341 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
343 if ( strstrW( patch_product
, prod_code
) )
348 si
= MSI_GetSummaryInformationW( patch
, 0 );
351 ERR("no summary information!\n");
355 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
358 ERR("no template property!\n");
359 msiobj_release( &si
->hdr
);
366 msiobj_release( &si
->hdr
);
370 langid
= msi_dup_property( package
, szSystemLanguageID
);
373 msiobj_release( &si
->hdr
);
377 p
= strchrW( template, ';' );
378 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, szZero
)))
380 TRACE("applicable transform\n");
384 /* FIXME: check platform */
386 msiobj_release( &si
->hdr
);
390 msi_free( patch_product
);
391 msi_free( prod_code
);
392 msi_free( template );
398 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
399 MSIDATABASE
*patch_db
, LPCWSTR name
)
401 UINT ret
= ERROR_FUNCTION_FAILED
;
402 IStorage
*stg
= NULL
;
405 TRACE("%p %s\n", package
, debugstr_w(name
) );
409 ERR("expected a colon in %s\n", debugstr_w(name
));
410 return ERROR_FUNCTION_FAILED
;
413 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
416 ret
= msi_check_transform_applicable( package
, stg
);
417 if (ret
== ERROR_SUCCESS
)
418 msi_table_apply_transform( package
->db
, stg
);
420 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
421 IStorage_Release( stg
);
424 ERR("failed to open substorage %s\n", debugstr_w(name
));
426 return ERROR_SUCCESS
;
429 UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
431 LPWSTR guid_list
, *guids
, product_code
;
432 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
434 product_code
= msi_dup_property( package
, szProductCode
);
437 /* FIXME: the property ProductCode should be written into the DB somewhere */
438 ERR("no product code to check\n");
439 return ERROR_SUCCESS
;
442 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
443 guids
= msi_split_string( guid_list
, ';' );
444 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
446 if (!lstrcmpW( guids
[i
], product_code
))
450 msi_free( guid_list
);
451 msi_free( product_code
);
456 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
459 MSIRECORD
*rec
= NULL
;
464 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
465 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
466 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
467 '`','S','o','u','r','c','e','`',' ','I','S',' ',
468 'N','O','T',' ','N','U','L','L',0};
470 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
471 if (r
!= ERROR_SUCCESS
)
474 r
= MSI_ViewExecute(view
, 0);
475 if (r
!= ERROR_SUCCESS
)
478 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
480 prop
= MSI_RecordGetString(rec
, 1);
481 patch
= msi_dup_property(package
, szPatch
);
482 MSI_SetPropertyW(package
, prop
, patch
);
487 if (rec
) msiobj_release(&rec
->hdr
);
488 msiobj_release(&view
->hdr
);
493 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
496 LPWSTR str
, *substorage
;
497 UINT i
, r
= ERROR_SUCCESS
;
499 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
501 return ERROR_FUNCTION_FAILED
;
503 if (msi_check_patch_applicable( package
, si
) != ERROR_SUCCESS
)
505 TRACE("Patch not applicable\n");
506 return ERROR_SUCCESS
;
509 package
->patch
= msi_alloc(sizeof(MSIPATCHINFO
));
511 return ERROR_OUTOFMEMORY
;
513 package
->patch
->patchcode
= msi_suminfo_dup_string(si
, PID_REVNUMBER
);
514 if (!package
->patch
->patchcode
)
515 return ERROR_OUTOFMEMORY
;
517 /* enumerate the substorage */
518 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
519 package
->patch
->transforms
= str
;
521 substorage
= msi_split_string( str
, ';' );
522 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
523 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
525 msi_free( substorage
);
526 msiobj_release( &si
->hdr
);
528 msi_set_media_source_prop(package
);
533 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
535 MSIDATABASE
*patch_db
= NULL
;
538 TRACE("%p %s\n", package
, debugstr_w( file
) );
541 * We probably want to make sure we only open a patch collection here.
542 * Patch collections (.msp) and databases (.msi) have different GUIDs
543 * but currently MSI_OpenDatabaseW will accept both.
545 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
546 if ( r
!= ERROR_SUCCESS
)
548 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
552 msi_parse_patch_summary( package
, patch_db
);
555 * There might be a CAB file in the patch package,
556 * so append it to the list of storage to search for streams.
558 append_storage_to_db( package
->db
, patch_db
->storage
);
560 msiobj_release( &patch_db
->hdr
);
562 return ERROR_SUCCESS
;
565 /* get the PATCH property, and apply all the patches it specifies */
566 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
568 LPWSTR patch_list
, *patches
;
569 UINT i
, r
= ERROR_SUCCESS
;
571 patch_list
= msi_dup_property( package
, szPatch
);
573 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
575 patches
= msi_split_string( patch_list
, ';' );
576 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
577 r
= msi_apply_patch_package( package
, patches
[i
] );
580 msi_free( patch_list
);
585 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
587 static const WCHAR szTransforms
[] = {
588 'T','R','A','N','S','F','O','R','M','S',0 };
589 LPWSTR xform_list
, *xforms
;
590 UINT i
, r
= ERROR_SUCCESS
;
592 xform_list
= msi_dup_property( package
, szTransforms
);
593 xforms
= msi_split_string( xform_list
, ';' );
595 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
597 if (xforms
[i
][0] == ':')
598 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
600 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
604 msi_free( xform_list
);
609 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
614 static const WCHAR ExecSeqQuery
[] =
615 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
616 '`','I','n','s','t','a','l','l',
617 'U','I','S','e','q','u','e','n','c','e','`',
618 ' ','W','H','E','R','E',' ',
619 '`','S','e','q','u','e','n','c','e','`',' ',
620 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
621 '`','S','e','q','u','e','n','c','e','`',0};
623 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
624 if (rc
== ERROR_SUCCESS
)
626 msiobj_release(&view
->hdr
);
633 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
636 LPWSTR source
, check
;
639 static const WCHAR szOriginalDatabase
[] =
640 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
642 db
= msi_dup_property( package
, szOriginalDatabase
);
644 return ERROR_OUTOFMEMORY
;
646 p
= strrchrW( db
, '\\' );
649 p
= strrchrW( db
, '/' );
653 return ERROR_SUCCESS
;
658 source
= msi_alloc( len
* sizeof(WCHAR
) );
659 lstrcpynW( source
, db
, len
);
661 check
= msi_dup_property( package
, cszSourceDir
);
662 if (!check
|| replace
)
663 MSI_SetPropertyW( package
, cszSourceDir
, source
);
667 check
= msi_dup_property( package
, cszSOURCEDIR
);
668 if (!check
|| replace
)
669 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
675 return ERROR_SUCCESS
;
678 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
680 INT level
= msi_get_property_int(package
, szUILevel
, 0);
681 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
684 static UINT
msi_set_context(MSIPACKAGE
*package
)
691 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
693 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
694 if (r
== ERROR_SUCCESS
)
697 if (num
== 1 || num
== 2)
698 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
701 return ERROR_SUCCESS
;
704 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
707 LPCWSTR cond
, action
;
708 MSIPACKAGE
*package
= param
;
710 action
= MSI_RecordGetString(row
,1);
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED
;
717 /* check conditions */
718 cond
= MSI_RecordGetString(row
,2);
720 /* this is a hack to skip errors in the condition code */
721 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
723 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
724 return ERROR_SUCCESS
;
727 if (needs_ui_sequence(package
))
728 rc
= ACTION_PerformUIAction(package
, action
, -1);
730 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
732 msi_dialog_check_messages( NULL
);
734 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
735 rc
= package
->CurrentInstallState
;
737 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
740 if (rc
!= ERROR_SUCCESS
)
741 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
746 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
750 static const WCHAR query
[] =
751 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
753 ' ','W','H','E','R','E',' ',
754 '`','S','e','q','u','e','n','c','e','`',' ',
755 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
756 '`','S','e','q','u','e','n','c','e','`',0};
758 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
760 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
761 if (r
== ERROR_SUCCESS
)
763 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
764 msiobj_release(&view
->hdr
);
770 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
774 static const WCHAR ExecSeqQuery
[] =
775 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
776 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
777 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
778 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
779 'O','R','D','E','R',' ', 'B','Y',' ',
780 '`','S','e','q','u','e','n','c','e','`',0 };
781 static const WCHAR IVQuery
[] =
782 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
783 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
784 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
785 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
786 ' ','\'', 'I','n','s','t','a','l','l',
787 'V','a','l','i','d','a','t','e','\'', 0};
790 if (package
->script
->ExecuteSequenceRun
)
792 TRACE("Execute Sequence already Run\n");
793 return ERROR_SUCCESS
;
796 package
->script
->ExecuteSequenceRun
= TRUE
;
798 /* get the sequence number */
801 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
803 return ERROR_FUNCTION_FAILED
;
804 seq
= MSI_RecordGetInteger(row
,1);
805 msiobj_release(&row
->hdr
);
808 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
809 if (rc
== ERROR_SUCCESS
)
811 TRACE("Running the actions\n");
813 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
814 msiobj_release(&view
->hdr
);
820 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
824 static const WCHAR ExecSeqQuery
[] =
825 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
826 '`','I','n','s','t','a','l','l',
827 'U','I','S','e','q','u','e','n','c','e','`',
828 ' ','W','H','E','R','E',' ',
829 '`','S','e','q','u','e','n','c','e','`',' ',
830 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
831 '`','S','e','q','u','e','n','c','e','`',0};
833 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
834 if (rc
== ERROR_SUCCESS
)
836 TRACE("Running the actions\n");
838 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
839 msiobj_release(&view
->hdr
);
845 /********************************************************
846 * ACTION helper functions and functions that perform the actions
847 *******************************************************/
848 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
849 UINT
* rc
, UINT script
, BOOL force
)
854 arc
= ACTION_CustomAction(package
, action
, script
, force
);
856 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
865 * Actual Action Handlers
868 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
870 MSIPACKAGE
*package
= param
;
871 LPCWSTR dir
, component
;
877 component
= MSI_RecordGetString(row
, 2);
878 comp
= get_loaded_component(package
, component
);
880 return ERROR_SUCCESS
;
882 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
884 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
885 comp
->Action
= comp
->Installed
;
886 return ERROR_SUCCESS
;
888 comp
->Action
= INSTALLSTATE_LOCAL
;
890 dir
= MSI_RecordGetString(row
,1);
893 ERR("Unable to get folder id\n");
894 return ERROR_SUCCESS
;
897 uirow
= MSI_CreateRecord(1);
898 MSI_RecordSetStringW(uirow
, 1, dir
);
899 ui_actiondata(package
, szCreateFolders
, uirow
);
900 msiobj_release(&uirow
->hdr
);
902 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
905 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
906 return ERROR_SUCCESS
;
909 TRACE("Folder is %s\n",debugstr_w(full_path
));
911 if (folder
->State
== 0)
912 create_full_pathW(full_path
);
917 return ERROR_SUCCESS
;
920 /* FIXME: probably should merge this with the above function */
921 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
923 UINT rc
= ERROR_SUCCESS
;
927 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
929 return ERROR_FUNCTION_FAILED
;
931 /* create the path */
932 if (folder
->State
== 0)
934 create_full_pathW(install_path
);
937 msi_free(install_path
);
942 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
946 /* create all the folders required by the components are going to install */
947 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
949 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
951 msi_create_directory( package
, comp
->Directory
);
954 return ERROR_SUCCESS
;
957 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
959 static const WCHAR ExecSeqQuery
[] =
960 {'S','E','L','E','C','T',' ',
961 '`','D','i','r','e','c','t','o','r','y','_','`',
962 ' ','F','R','O','M',' ',
963 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
967 /* create all the empty folders specified in the CreateFolder table */
968 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
969 if (rc
!= ERROR_SUCCESS
)
970 return ERROR_SUCCESS
;
972 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
973 msiobj_release(&view
->hdr
);
978 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
980 MSIPACKAGE
*package
= param
;
981 LPCWSTR dir
, component
;
987 component
= MSI_RecordGetString(row
, 2);
988 comp
= get_loaded_component(package
, component
);
990 return ERROR_SUCCESS
;
992 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
994 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
995 comp
->Action
= comp
->Installed
;
996 return ERROR_SUCCESS
;
998 comp
->Action
= INSTALLSTATE_ABSENT
;
1000 dir
= MSI_RecordGetString( row
, 1 );
1003 ERR("Unable to get folder id\n");
1004 return ERROR_SUCCESS
;
1007 full_path
= resolve_folder( package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1010 ERR("Unable to resolve folder id %s\n", debugstr_w(dir
));
1011 return ERROR_SUCCESS
;
1014 TRACE("folder is %s\n", debugstr_w(full_path
));
1016 uirow
= MSI_CreateRecord( 1 );
1017 MSI_RecordSetStringW( uirow
, 1, full_path
);
1018 ui_actiondata( package
, szRemoveFolders
, uirow
);
1019 msiobj_release( &uirow
->hdr
);
1021 RemoveDirectoryW( full_path
);
1024 msi_free( full_path
);
1025 return ERROR_SUCCESS
;
1028 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1030 static const WCHAR query
[] =
1031 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1032 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1037 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1038 if (rc
!= ERROR_SUCCESS
)
1039 return ERROR_SUCCESS
;
1041 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1042 msiobj_release( &view
->hdr
);
1047 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1049 MSIPACKAGE
*package
= param
;
1052 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1054 return ERROR_FUNCTION_FAILED
;
1056 list_add_tail( &package
->components
, &comp
->entry
);
1058 /* fill in the data */
1059 comp
->Component
= msi_dup_record_field( row
, 1 );
1061 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1063 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1064 comp
->Directory
= msi_dup_record_field( row
, 3 );
1065 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1066 comp
->Condition
= msi_dup_record_field( row
, 5 );
1067 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1069 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1070 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1072 return ERROR_SUCCESS
;
1075 static UINT
load_all_components( MSIPACKAGE
*package
)
1077 static const WCHAR query
[] = {
1078 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1079 '`','C','o','m','p','o','n','e','n','t','`',0 };
1083 if (!list_empty(&package
->components
))
1084 return ERROR_SUCCESS
;
1086 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1087 if (r
!= ERROR_SUCCESS
)
1090 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1091 msiobj_release(&view
->hdr
);
1096 MSIPACKAGE
*package
;
1097 MSIFEATURE
*feature
;
1100 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1104 cl
= msi_alloc( sizeof (*cl
) );
1106 return ERROR_NOT_ENOUGH_MEMORY
;
1107 cl
->component
= comp
;
1108 list_add_tail( &feature
->Components
, &cl
->entry
);
1110 return ERROR_SUCCESS
;
1113 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1117 fl
= msi_alloc( sizeof(*fl
) );
1119 return ERROR_NOT_ENOUGH_MEMORY
;
1120 fl
->feature
= child
;
1121 list_add_tail( &parent
->Children
, &fl
->entry
);
1123 return ERROR_SUCCESS
;
1126 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1128 _ilfs
* ilfs
= param
;
1132 component
= MSI_RecordGetString(row
,1);
1134 /* check to see if the component is already loaded */
1135 comp
= get_loaded_component( ilfs
->package
, component
);
1138 ERR("unknown component %s\n", debugstr_w(component
));
1139 return ERROR_FUNCTION_FAILED
;
1142 add_feature_component( ilfs
->feature
, comp
);
1143 comp
->Enabled
= TRUE
;
1145 return ERROR_SUCCESS
;
1148 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1150 MSIFEATURE
*feature
;
1155 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1157 if ( !lstrcmpW( feature
->Feature
, name
) )
1164 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1166 MSIPACKAGE
* package
= param
;
1167 MSIFEATURE
* feature
;
1168 static const WCHAR Query1
[] =
1169 {'S','E','L','E','C','T',' ',
1170 '`','C','o','m','p','o','n','e','n','t','_','`',
1171 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1172 'C','o','m','p','o','n','e','n','t','s','`',' ',
1173 'W','H','E','R','E',' ',
1174 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1179 /* fill in the data */
1181 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1183 return ERROR_NOT_ENOUGH_MEMORY
;
1185 list_init( &feature
->Children
);
1186 list_init( &feature
->Components
);
1188 feature
->Feature
= msi_dup_record_field( row
, 1 );
1190 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1192 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1193 feature
->Title
= msi_dup_record_field( row
, 3 );
1194 feature
->Description
= msi_dup_record_field( row
, 4 );
1196 if (!MSI_RecordIsNull(row
,5))
1197 feature
->Display
= MSI_RecordGetInteger(row
,5);
1199 feature
->Level
= MSI_RecordGetInteger(row
,6);
1200 feature
->Directory
= msi_dup_record_field( row
, 7 );
1201 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1203 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1204 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1206 list_add_tail( &package
->features
, &feature
->entry
);
1208 /* load feature components */
1210 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1211 if (rc
!= ERROR_SUCCESS
)
1212 return ERROR_SUCCESS
;
1214 ilfs
.package
= package
;
1215 ilfs
.feature
= feature
;
1217 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1218 msiobj_release(&view
->hdr
);
1220 return ERROR_SUCCESS
;
1223 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1225 MSIPACKAGE
* package
= param
;
1226 MSIFEATURE
*parent
, *child
;
1228 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1230 return ERROR_FUNCTION_FAILED
;
1232 if (!child
->Feature_Parent
)
1233 return ERROR_SUCCESS
;
1235 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1237 return ERROR_FUNCTION_FAILED
;
1239 add_feature_child( parent
, child
);
1240 return ERROR_SUCCESS
;
1243 static UINT
load_all_features( MSIPACKAGE
*package
)
1245 static const WCHAR query
[] = {
1246 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1247 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1248 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1252 if (!list_empty(&package
->features
))
1253 return ERROR_SUCCESS
;
1255 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1256 if (r
!= ERROR_SUCCESS
)
1259 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1260 if (r
!= ERROR_SUCCESS
)
1263 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1264 msiobj_release( &view
->hdr
);
1269 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1280 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1282 static const WCHAR query
[] = {
1283 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1284 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1285 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1286 MSIQUERY
*view
= NULL
;
1287 MSIRECORD
*row
= NULL
;
1290 TRACE("%s\n", debugstr_w(file
->File
));
1292 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1293 if (r
!= ERROR_SUCCESS
)
1296 r
= MSI_ViewExecute(view
, NULL
);
1297 if (r
!= ERROR_SUCCESS
)
1300 r
= MSI_ViewFetch(view
, &row
);
1301 if (r
!= ERROR_SUCCESS
)
1304 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1305 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1306 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1307 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1308 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1311 if (view
) msiobj_release(&view
->hdr
);
1312 if (row
) msiobj_release(&row
->hdr
);
1316 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1318 MSIPACKAGE
* package
= param
;
1322 /* fill in the data */
1324 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1326 return ERROR_NOT_ENOUGH_MEMORY
;
1328 file
->File
= msi_dup_record_field( row
, 1 );
1330 component
= MSI_RecordGetString( row
, 2 );
1331 file
->Component
= get_loaded_component( package
, component
);
1333 if (!file
->Component
)
1335 WARN("Component not found: %s\n", debugstr_w(component
));
1336 msi_free(file
->File
);
1338 return ERROR_SUCCESS
;
1341 file
->FileName
= msi_dup_record_field( row
, 3 );
1342 reduce_to_longfilename( file
->FileName
);
1344 file
->ShortName
= msi_dup_record_field( row
, 3 );
1345 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1347 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1348 file
->Version
= msi_dup_record_field( row
, 5 );
1349 file
->Language
= msi_dup_record_field( row
, 6 );
1350 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1351 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1353 file
->state
= msifs_invalid
;
1355 /* if the compressed bits are not set in the file attributes,
1356 * then read the information from the package word count property
1358 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1360 file
->IsCompressed
= FALSE
;
1362 else if (file
->Attributes
&
1363 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1365 file
->IsCompressed
= TRUE
;
1367 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1369 file
->IsCompressed
= FALSE
;
1373 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1376 load_file_hash(package
, file
);
1378 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1380 list_add_tail( &package
->files
, &file
->entry
);
1382 return ERROR_SUCCESS
;
1385 static UINT
load_all_files(MSIPACKAGE
*package
)
1389 static const WCHAR Query
[] =
1390 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1391 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1392 '`','S','e','q','u','e','n','c','e','`', 0};
1394 if (!list_empty(&package
->files
))
1395 return ERROR_SUCCESS
;
1397 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1398 if (rc
!= ERROR_SUCCESS
)
1399 return ERROR_SUCCESS
;
1401 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1402 msiobj_release(&view
->hdr
);
1404 return ERROR_SUCCESS
;
1407 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1409 MSIPACKAGE
*package
= param
;
1410 static WCHAR szEmpty
[] = { 0 };
1411 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1414 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1416 return ERROR_NOT_ENOUGH_MEMORY
;
1418 folder
->Directory
= msi_dup_record_field( row
, 1 );
1420 TRACE("%s\n", debugstr_w(folder
->Directory
));
1422 p
= msi_dup_record_field(row
, 3);
1424 /* split src and target dir */
1426 src_short
= folder_split_path( p
, ':' );
1428 /* split the long and short paths */
1429 tgt_long
= folder_split_path( tgt_short
, '|' );
1430 src_long
= folder_split_path( src_short
, '|' );
1432 /* check for no-op dirs */
1433 if (!lstrcmpW(szDot
, tgt_short
))
1434 tgt_short
= szEmpty
;
1435 if (!lstrcmpW(szDot
, src_short
))
1436 src_short
= szEmpty
;
1439 tgt_long
= tgt_short
;
1442 src_short
= tgt_short
;
1443 src_long
= tgt_long
;
1447 src_long
= src_short
;
1449 /* FIXME: use the target short path too */
1450 folder
->TargetDefault
= strdupW(tgt_long
);
1451 folder
->SourceShortPath
= strdupW(src_short
);
1452 folder
->SourceLongPath
= strdupW(src_long
);
1455 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1456 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1457 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1459 folder
->Parent
= msi_dup_record_field( row
, 2 );
1461 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1463 list_add_tail( &package
->folders
, &folder
->entry
);
1465 TRACE("returning %p\n", folder
);
1467 return ERROR_SUCCESS
;
1470 static UINT
load_all_folders( MSIPACKAGE
*package
)
1472 static const WCHAR query
[] = {
1473 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1474 '`','D','i','r','e','c','t','o','r','y','`',0 };
1478 if (!list_empty(&package
->folders
))
1479 return ERROR_SUCCESS
;
1481 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1482 if (r
!= ERROR_SUCCESS
)
1485 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1486 msiobj_release(&view
->hdr
);
1491 * I am not doing any of the costing functionality yet.
1492 * Mostly looking at doing the Component and Feature loading
1494 * The native MSI does A LOT of modification to tables here. Mostly adding
1495 * a lot of temporary columns to the Feature and Component tables.
1497 * note: Native msi also tracks the short filename. But I am only going to
1498 * track the long ones. Also looking at this directory table
1499 * it appears that the directory table does not get the parents
1500 * resolved base on property only based on their entries in the
1503 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1505 static const WCHAR szCosting
[] =
1506 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1508 MSI_SetPropertyW(package
, szCosting
, szZero
);
1509 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1511 load_all_folders( package
);
1512 load_all_components( package
);
1513 load_all_features( package
);
1514 load_all_files( package
);
1516 return ERROR_SUCCESS
;
1519 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1522 UINT rc
= ERROR_SUCCESS
;
1524 TRACE("Executing Script %i\n",script
);
1526 if (!package
->script
)
1528 ERR("no script!\n");
1529 return ERROR_FUNCTION_FAILED
;
1532 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1535 action
= package
->script
->Actions
[script
][i
];
1536 ui_actionstart(package
, action
);
1537 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1538 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1539 if (rc
!= ERROR_SUCCESS
)
1542 msi_free_action_script(package
, script
);
1546 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1548 return ERROR_SUCCESS
;
1551 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1557 state
= MsiQueryProductStateW(package
->ProductCode
);
1559 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1561 if (!comp
->ComponentId
)
1564 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1565 comp
->Installed
= INSTALLSTATE_ABSENT
;
1568 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1569 package
->Context
, comp
->ComponentId
,
1571 if (r
!= ERROR_SUCCESS
)
1572 comp
->Installed
= INSTALLSTATE_ABSENT
;
1577 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1579 MSIFEATURE
*feature
;
1582 state
= MsiQueryProductStateW(package
->ProductCode
);
1584 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1586 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1587 feature
->Installed
= INSTALLSTATE_ABSENT
;
1590 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1596 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1597 LPCWSTR property
, INSTALLSTATE state
)
1600 MSIFEATURE
*feature
;
1602 override
= msi_dup_property( package
, property
);
1606 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1608 if (lstrcmpW(property
, szRemove
) &&
1609 (feature
->Level
<= 0 || feature
->Level
> level
))
1612 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1614 if (strcmpiW(override
, szAll
)==0)
1615 msi_feature_set_state(package
, feature
, state
);
1618 LPWSTR ptr
= override
;
1619 LPWSTR ptr2
= strchrW(override
,',');
1623 int len
= ptr2
- ptr
;
1625 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1626 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1628 msi_feature_set_state(package
, feature
, state
);
1634 ptr2
= strchrW(ptr
,',');
1646 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
1648 static const WCHAR szAddLocal
[] =
1649 {'A','D','D','L','O','C','A','L',0};
1650 static const WCHAR szAddSource
[] =
1651 {'A','D','D','S','O','U','R','C','E',0};
1652 static const WCHAR szAdvertise
[] =
1653 {'A','D','V','E','R','T','I','S','E',0};
1656 /* all these activation/deactivation things happen in order and things
1657 * later on the list override things earlier on the list.
1659 * 0 INSTALLLEVEL processing
1672 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1673 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1674 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1675 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1676 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1679 MSI_SetPropertyW( package
, szPreselected
, szOne
);
1684 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1687 static const WCHAR szlevel
[] =
1688 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1689 MSICOMPONENT
* component
;
1690 MSIFEATURE
*feature
;
1692 TRACE("Checking Install Level\n");
1694 level
= msi_get_property_int(package
, szlevel
, 1);
1696 if (!msi_get_property_int( package
, szPreselected
, 0 ))
1698 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1700 BOOL feature_state
= ((feature
->Level
> 0) &&
1701 (feature
->Level
<= level
));
1703 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1705 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1706 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1707 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1708 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1710 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1714 /* disable child features of unselected parent features */
1715 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1719 if (feature
->Level
> 0 && feature
->Level
<= level
)
1722 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1723 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1728 * now we want to enable or disable components base on feature
1731 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1735 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1736 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1738 if (!feature
->Level
)
1741 /* features with components that have compressed files are made local */
1742 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1744 if (cl
->component
->Enabled
&&
1745 cl
->component
->ForceLocalState
&&
1746 feature
->Action
== INSTALLSTATE_SOURCE
)
1748 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1753 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1755 component
= cl
->component
;
1757 if (!component
->Enabled
)
1760 switch (feature
->Action
)
1762 case INSTALLSTATE_ABSENT
:
1763 component
->anyAbsent
= 1;
1765 case INSTALLSTATE_ADVERTISED
:
1766 component
->hasAdvertiseFeature
= 1;
1768 case INSTALLSTATE_SOURCE
:
1769 component
->hasSourceFeature
= 1;
1771 case INSTALLSTATE_LOCAL
:
1772 component
->hasLocalFeature
= 1;
1774 case INSTALLSTATE_DEFAULT
:
1775 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1776 component
->hasAdvertiseFeature
= 1;
1777 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1778 component
->hasSourceFeature
= 1;
1780 component
->hasLocalFeature
= 1;
1788 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1790 /* if the component isn't enabled, leave it alone */
1791 if (!component
->Enabled
)
1794 /* check if it's local or source */
1795 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1796 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1798 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1799 !component
->ForceLocalState
)
1800 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1802 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1806 /* if any feature is local, the component must be local too */
1807 if (component
->hasLocalFeature
)
1809 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1813 if (component
->hasSourceFeature
)
1815 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1819 if (component
->hasAdvertiseFeature
)
1821 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1825 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1826 if (component
->anyAbsent
)
1827 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1830 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1832 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1834 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1835 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1838 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1839 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1843 return ERROR_SUCCESS
;
1846 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1848 MSIPACKAGE
*package
= param
;
1853 name
= MSI_RecordGetString(row
,1);
1855 f
= get_loaded_folder(package
, name
);
1856 if (!f
) return ERROR_SUCCESS
;
1858 /* reset the ResolvedTarget */
1859 msi_free(f
->ResolvedTarget
);
1860 f
->ResolvedTarget
= NULL
;
1862 /* This helper function now does ALL the work */
1863 TRACE("Dir %s ...\n",debugstr_w(name
));
1864 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1865 TRACE("resolves to %s\n",debugstr_w(path
));
1868 return ERROR_SUCCESS
;
1871 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1873 MSIPACKAGE
*package
= param
;
1875 MSIFEATURE
*feature
;
1877 name
= MSI_RecordGetString( row
, 1 );
1879 feature
= get_loaded_feature( package
, name
);
1881 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1885 Condition
= MSI_RecordGetString(row
,3);
1887 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1889 int level
= MSI_RecordGetInteger(row
,2);
1890 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1891 feature
->Level
= level
;
1894 return ERROR_SUCCESS
;
1897 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1899 static const WCHAR name_fmt
[] =
1900 {'%','u','.','%','u','.','%','u','.','%','u',0};
1901 static const WCHAR name
[] = {'\\',0};
1902 VS_FIXEDFILEINFO
*lpVer
;
1903 WCHAR filever
[0x100];
1909 TRACE("%s\n", debugstr_w(filename
));
1911 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1915 version
= msi_alloc( versize
);
1916 GetFileVersionInfoW( filename
, 0, versize
, version
);
1918 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1920 msi_free( version
);
1924 sprintfW( filever
, name_fmt
,
1925 HIWORD(lpVer
->dwFileVersionMS
),
1926 LOWORD(lpVer
->dwFileVersionMS
),
1927 HIWORD(lpVer
->dwFileVersionLS
),
1928 LOWORD(lpVer
->dwFileVersionLS
));
1930 msi_free( version
);
1932 return strdupW( filever
);
1935 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1937 LPWSTR file_version
;
1940 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1942 MSICOMPONENT
* comp
= file
->Component
;
1948 if (file
->IsCompressed
)
1949 comp
->ForceLocalState
= TRUE
;
1951 /* calculate target */
1952 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
1954 msi_free(file
->TargetPath
);
1956 TRACE("file %s is named %s\n",
1957 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
1959 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1963 TRACE("file %s resolves to %s\n",
1964 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
1966 /* don't check files of components that aren't installed */
1967 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
1968 comp
->Installed
== INSTALLSTATE_ABSENT
)
1970 file
->state
= msifs_missing
; /* assume files are missing */
1974 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1976 file
->state
= msifs_missing
;
1977 comp
->Cost
+= file
->FileSize
;
1981 if (file
->Version
&&
1982 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
1984 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1985 debugstr_w(file_version
));
1986 /* FIXME: seems like a bad way to compare version numbers */
1987 if (lstrcmpiW(file_version
, file
->Version
)<0)
1989 file
->state
= msifs_overwrite
;
1990 comp
->Cost
+= file
->FileSize
;
1993 file
->state
= msifs_present
;
1994 msi_free( file_version
);
1997 file
->state
= msifs_present
;
2000 return ERROR_SUCCESS
;
2004 * A lot is done in this function aside from just the costing.
2005 * The costing needs to be implemented at some point but for now I am going
2006 * to focus on the directory building
2009 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2011 static const WCHAR ExecSeqQuery
[] =
2012 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2013 '`','D','i','r','e','c','t','o','r','y','`',0};
2014 static const WCHAR ConditionQuery
[] =
2015 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2016 '`','C','o','n','d','i','t','i','o','n','`',0};
2017 static const WCHAR szCosting
[] =
2018 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2019 static const WCHAR szlevel
[] =
2020 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2021 static const WCHAR szOutOfDiskSpace
[] =
2022 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2024 UINT rc
= ERROR_SUCCESS
;
2028 TRACE("Building Directory properties\n");
2030 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2031 if (rc
== ERROR_SUCCESS
)
2033 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2035 msiobj_release(&view
->hdr
);
2038 /* read components states from the registry */
2039 ACTION_GetComponentInstallStates(package
);
2040 ACTION_GetFeatureInstallStates(package
);
2042 TRACE("File calculations\n");
2043 msi_check_file_install_states( package
);
2045 if (!process_overrides( package
, msi_get_property_int( package
, szlevel
, 1 ) ))
2047 TRACE("Evaluating Condition Table\n");
2049 rc
= MSI_DatabaseOpenViewW( package
->db
, ConditionQuery
, &view
);
2050 if (rc
== ERROR_SUCCESS
)
2052 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
2053 msiobj_release( &view
->hdr
);
2056 TRACE("Enabling or Disabling Components\n");
2057 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2059 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
2061 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2062 comp
->Enabled
= FALSE
;
2065 comp
->Enabled
= TRUE
;
2069 MSI_SetPropertyW(package
,szCosting
,szOne
);
2070 /* set default run level if not set */
2071 level
= msi_dup_property( package
, szlevel
);
2073 MSI_SetPropertyW(package
,szlevel
, szOne
);
2076 /* FIXME: check volume disk space */
2077 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2079 return MSI_SetFeatureStates(package
);
2082 /* OK this value is "interpreted" and then formatted based on the
2083 first few characters */
2084 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2089 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2095 LPWSTR deformated
= NULL
;
2098 deformat_string(package
, &value
[2], &deformated
);
2100 /* binary value type */
2104 *size
= (strlenW(ptr
)/2)+1;
2106 *size
= strlenW(ptr
)/2;
2108 data
= msi_alloc(*size
);
2114 /* if uneven pad with a zero in front */
2120 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2122 TRACE("Uneven byte count\n");
2130 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2133 msi_free(deformated
);
2135 TRACE("Data %i bytes(%i)\n",*size
,count
);
2142 deformat_string(package
, &value
[1], &deformated
);
2145 *size
= sizeof(DWORD
);
2146 data
= msi_alloc(*size
);
2152 if ( (*p
< '0') || (*p
> '9') )
2158 if (deformated
[0] == '-')
2161 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2163 msi_free(deformated
);
2168 static const WCHAR szMulti
[] = {'[','~',']',0};
2177 *type
=REG_EXPAND_SZ
;
2185 if (strstrW(value
,szMulti
))
2186 *type
= REG_MULTI_SZ
;
2188 /* remove initial delimiter */
2189 if (!strncmpW(value
, szMulti
, 3))
2192 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2194 /* add double NULL terminator */
2195 if (*type
== REG_MULTI_SZ
)
2197 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2198 data
= msi_realloc_zero(data
, *size
);
2204 static const WCHAR
*get_root_key( MSIPACKAGE
*package
, INT root
, HKEY
*root_key
)
2211 if (msi_get_property_int( package
, szAllUsers
, 0 ))
2213 *root_key
= HKEY_LOCAL_MACHINE
;
2218 *root_key
= HKEY_CURRENT_USER
;
2223 *root_key
= HKEY_CLASSES_ROOT
;
2227 *root_key
= HKEY_CURRENT_USER
;
2231 *root_key
= HKEY_LOCAL_MACHINE
;
2235 *root_key
= HKEY_USERS
;
2239 ERR("Unknown root %i\n", root
);
2246 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2248 MSIPACKAGE
*package
= param
;
2249 LPSTR value_data
= NULL
;
2250 HKEY root_key
, hkey
;
2253 LPCWSTR szRoot
, component
, name
, key
, value
;
2258 BOOL check_first
= FALSE
;
2261 ui_progress(package
,2,0,0,0);
2268 component
= MSI_RecordGetString(row
, 6);
2269 comp
= get_loaded_component(package
,component
);
2271 return ERROR_SUCCESS
;
2273 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2275 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2276 comp
->Action
= comp
->Installed
;
2277 return ERROR_SUCCESS
;
2279 comp
->Action
= INSTALLSTATE_LOCAL
;
2281 name
= MSI_RecordGetString(row
, 4);
2282 if( MSI_RecordIsNull(row
,5) && name
)
2284 /* null values can have special meanings */
2285 if (name
[0]=='-' && name
[1] == 0)
2286 return ERROR_SUCCESS
;
2287 else if ((name
[0]=='+' && name
[1] == 0) ||
2288 (name
[0] == '*' && name
[1] == 0))
2293 root
= MSI_RecordGetInteger(row
,2);
2294 key
= MSI_RecordGetString(row
, 3);
2296 szRoot
= get_root_key( package
, root
, &root_key
);
2298 return ERROR_SUCCESS
;
2300 deformat_string(package
, key
, &deformated
);
2301 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2302 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2303 strcpyW(uikey
,szRoot
);
2304 strcatW(uikey
,deformated
);
2306 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2308 ERR("Could not create key %s\n",debugstr_w(deformated
));
2309 msi_free(deformated
);
2311 return ERROR_SUCCESS
;
2313 msi_free(deformated
);
2315 value
= MSI_RecordGetString(row
,5);
2317 value_data
= parse_value(package
, value
, &type
, &size
);
2320 value_data
= (LPSTR
)strdupW(szEmpty
);
2321 size
= sizeof(szEmpty
);
2325 deformat_string(package
, name
, &deformated
);
2329 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2331 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2336 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2337 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2339 TRACE("value %s of %s checked already exists\n",
2340 debugstr_w(deformated
), debugstr_w(uikey
));
2344 TRACE("Checked and setting value %s of %s\n",
2345 debugstr_w(deformated
), debugstr_w(uikey
));
2346 if (deformated
|| size
)
2347 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2352 uirow
= MSI_CreateRecord(3);
2353 MSI_RecordSetStringW(uirow
,2,deformated
);
2354 MSI_RecordSetStringW(uirow
,1,uikey
);
2355 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
)
2356 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2357 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2358 msiobj_release( &uirow
->hdr
);
2360 msi_free(value_data
);
2361 msi_free(deformated
);
2364 return ERROR_SUCCESS
;
2367 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2371 static const WCHAR ExecSeqQuery
[] =
2372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2373 '`','R','e','g','i','s','t','r','y','`',0 };
2375 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2376 if (rc
!= ERROR_SUCCESS
)
2377 return ERROR_SUCCESS
;
2379 /* increment progress bar each time action data is sent */
2380 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2382 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2384 msiobj_release(&view
->hdr
);
2388 static void delete_reg_key_or_value( HKEY hkey_root
, LPCWSTR key
, LPCWSTR value
, BOOL delete_key
)
2392 DWORD num_subkeys
, num_values
;
2396 if ((res
= RegDeleteTreeW( hkey_root
, key
)))
2398 WARN("Failed to delete key %s (%d)\n", debugstr_w(key
), res
);
2403 if (!(res
= RegOpenKeyW( hkey_root
, key
, &hkey
)))
2405 if ((res
= RegDeleteValueW( hkey
, value
)))
2407 WARN("Failed to delete value %s (%d)\n", debugstr_w(value
), res
);
2409 res
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
, NULL
, &num_values
,
2410 NULL
, NULL
, NULL
, NULL
);
2411 RegCloseKey( hkey
);
2413 if (!res
&& !num_subkeys
&& !num_values
)
2415 TRACE("Removing empty key %s\n", debugstr_w(key
));
2416 RegDeleteKeyW( hkey_root
, key
);
2420 WARN("Failed to open key %s (%d)\n", debugstr_w(key
), res
);
2424 static UINT
ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
2426 MSIPACKAGE
*package
= param
;
2427 LPCWSTR component
, name
, key_str
, root_key_str
;
2428 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2431 BOOL delete_key
= FALSE
;
2436 ui_progress( package
, 2, 0, 0, 0 );
2438 component
= MSI_RecordGetString( row
, 6 );
2439 comp
= get_loaded_component( package
, component
);
2441 return ERROR_SUCCESS
;
2443 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2445 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
2446 comp
->Action
= comp
->Installed
;
2447 return ERROR_SUCCESS
;
2449 comp
->Action
= INSTALLSTATE_ABSENT
;
2451 name
= MSI_RecordGetString( row
, 4 );
2452 if (MSI_RecordIsNull( row
, 5 ) && name
)
2454 if (name
[0] == '+' && !name
[1])
2455 return ERROR_SUCCESS
;
2456 else if ((name
[0] == '-' && !name
[1]) || (name
[0] == '*' && !name
[1]))
2463 root
= MSI_RecordGetInteger( row
, 2 );
2464 key_str
= MSI_RecordGetString( row
, 3 );
2466 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2468 return ERROR_SUCCESS
;
2470 deformat_string( package
, key_str
, &deformated_key
);
2471 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2472 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2473 strcpyW( ui_key_str
, root_key_str
);
2474 strcatW( ui_key_str
, deformated_key
);
2476 deformat_string( package
, name
, &deformated_name
);
2478 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2479 msi_free( deformated_key
);
2481 uirow
= MSI_CreateRecord( 2 );
2482 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2483 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2485 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2486 msiobj_release( &uirow
->hdr
);
2488 msi_free( ui_key_str
);
2489 msi_free( deformated_name
);
2490 return ERROR_SUCCESS
;
2493 static UINT
ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
2495 MSIPACKAGE
*package
= param
;
2496 LPCWSTR component
, name
, key_str
, root_key_str
;
2497 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2500 BOOL delete_key
= FALSE
;
2505 ui_progress( package
, 2, 0, 0, 0 );
2507 component
= MSI_RecordGetString( row
, 5 );
2508 comp
= get_loaded_component( package
, component
);
2510 return ERROR_SUCCESS
;
2512 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2514 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2515 comp
->Action
= comp
->Installed
;
2516 return ERROR_SUCCESS
;
2518 comp
->Action
= INSTALLSTATE_LOCAL
;
2520 if ((name
= MSI_RecordGetString( row
, 4 )))
2522 if (name
[0] == '-' && !name
[1])
2529 root
= MSI_RecordGetInteger( row
, 2 );
2530 key_str
= MSI_RecordGetString( row
, 3 );
2532 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2534 return ERROR_SUCCESS
;
2536 deformat_string( package
, key_str
, &deformated_key
);
2537 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2538 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2539 strcpyW( ui_key_str
, root_key_str
);
2540 strcatW( ui_key_str
, deformated_key
);
2542 deformat_string( package
, name
, &deformated_name
);
2544 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2545 msi_free( deformated_key
);
2547 uirow
= MSI_CreateRecord( 2 );
2548 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2549 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2551 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2552 msiobj_release( &uirow
->hdr
);
2554 msi_free( ui_key_str
);
2555 msi_free( deformated_name
);
2556 return ERROR_SUCCESS
;
2559 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
2563 static const WCHAR registry_query
[] =
2564 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2565 '`','R','e','g','i','s','t','r','y','`',0 };
2566 static const WCHAR remove_registry_query
[] =
2567 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2568 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2570 /* increment progress bar each time action data is sent */
2571 ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
2573 rc
= MSI_DatabaseOpenViewW( package
->db
, registry_query
, &view
);
2574 if (rc
== ERROR_SUCCESS
)
2576 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnUninstall
, package
);
2577 msiobj_release( &view
->hdr
);
2578 if (rc
!= ERROR_SUCCESS
)
2582 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_registry_query
, &view
);
2583 if (rc
== ERROR_SUCCESS
)
2585 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnInstall
, package
);
2586 msiobj_release( &view
->hdr
);
2587 if (rc
!= ERROR_SUCCESS
)
2591 return ERROR_SUCCESS
;
2594 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2596 package
->script
->CurrentlyScripting
= TRUE
;
2598 return ERROR_SUCCESS
;
2602 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2607 static const WCHAR q1
[]=
2608 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2609 '`','R','e','g','i','s','t','r','y','`',0};
2612 MSIFEATURE
*feature
;
2615 TRACE("InstallValidate\n");
2617 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2618 if (rc
== ERROR_SUCCESS
)
2620 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2621 msiobj_release( &view
->hdr
);
2622 total
+= progress
* REG_PROGRESS_VALUE
;
2625 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2626 total
+= COMPONENT_PROGRESS_VALUE
;
2628 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2629 total
+= file
->FileSize
;
2631 ui_progress(package
,0,total
,0,0);
2633 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2635 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2636 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2637 feature
->ActionRequest
);
2640 return ERROR_SUCCESS
;
2643 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2645 MSIPACKAGE
* package
= param
;
2646 LPCWSTR cond
= NULL
;
2647 LPCWSTR message
= NULL
;
2650 static const WCHAR title
[]=
2651 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2653 cond
= MSI_RecordGetString(row
,1);
2655 r
= MSI_EvaluateConditionW(package
,cond
);
2656 if (r
== MSICONDITION_FALSE
)
2658 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2661 message
= MSI_RecordGetString(row
,2);
2662 deformat_string(package
,message
,&deformated
);
2663 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2664 msi_free(deformated
);
2667 return ERROR_INSTALL_FAILURE
;
2670 return ERROR_SUCCESS
;
2673 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2676 MSIQUERY
* view
= NULL
;
2677 static const WCHAR ExecSeqQuery
[] =
2678 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2679 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2681 TRACE("Checking launch conditions\n");
2683 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2684 if (rc
!= ERROR_SUCCESS
)
2685 return ERROR_SUCCESS
;
2687 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2688 msiobj_release(&view
->hdr
);
2693 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2697 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2699 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2701 MSIRECORD
* row
= 0;
2703 LPWSTR deformated
,buffer
,deformated_name
;
2705 static const WCHAR ExecSeqQuery
[] =
2706 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2707 '`','R','e','g','i','s','t','r','y','`',' ',
2708 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2709 ' ','=',' ' ,'\'','%','s','\'',0 };
2710 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2711 static const WCHAR fmt2
[]=
2712 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2714 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2718 root
= MSI_RecordGetInteger(row
,2);
2719 key
= MSI_RecordGetString(row
, 3);
2720 name
= MSI_RecordGetString(row
, 4);
2721 deformat_string(package
, key
, &deformated
);
2722 deformat_string(package
, name
, &deformated_name
);
2724 len
= strlenW(deformated
) + 6;
2725 if (deformated_name
)
2726 len
+=strlenW(deformated_name
);
2728 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2730 if (deformated_name
)
2731 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2733 sprintfW(buffer
,fmt
,root
,deformated
);
2735 msi_free(deformated
);
2736 msi_free(deformated_name
);
2737 msiobj_release(&row
->hdr
);
2741 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2743 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2748 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2751 return strdupW( file
->TargetPath
);
2756 static HKEY
openSharedDLLsKey(void)
2759 static const WCHAR path
[] =
2760 {'S','o','f','t','w','a','r','e','\\',
2761 'M','i','c','r','o','s','o','f','t','\\',
2762 'W','i','n','d','o','w','s','\\',
2763 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2764 'S','h','a','r','e','d','D','L','L','s',0};
2766 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2770 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2775 DWORD sz
= sizeof(count
);
2778 hkey
= openSharedDLLsKey();
2779 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2780 if (rc
!= ERROR_SUCCESS
)
2786 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2790 hkey
= openSharedDLLsKey();
2792 msi_reg_set_val_dword( hkey
, path
, count
);
2794 RegDeleteValueW(hkey
,path
);
2800 * Return TRUE if the count should be written out and FALSE if not
2802 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2804 MSIFEATURE
*feature
;
2808 /* only refcount DLLs */
2809 if (comp
->KeyPath
== NULL
||
2810 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2811 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2815 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2816 write
= (count
> 0);
2818 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2822 /* increment counts */
2823 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2827 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2830 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2832 if ( cl
->component
== comp
)
2837 /* decrement counts */
2838 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2842 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2845 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2847 if ( cl
->component
== comp
)
2852 /* ref count all the files in the component */
2857 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2859 if (file
->Component
== comp
)
2860 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2864 /* add a count for permanent */
2865 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2868 comp
->RefCount
= count
;
2871 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2874 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2876 WCHAR squished_pc
[GUID_SIZE
];
2877 WCHAR squished_cc
[GUID_SIZE
];
2884 squash_guid(package
->ProductCode
,squished_pc
);
2885 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2887 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2891 ui_progress(package
,2,0,0,0);
2892 if (!comp
->ComponentId
)
2895 squash_guid(comp
->ComponentId
,squished_cc
);
2897 msi_free(comp
->FullKeypath
);
2898 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2900 ACTION_RefCountComponent( package
, comp
);
2902 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2903 debugstr_w(comp
->Component
),
2904 debugstr_w(squished_cc
),
2905 debugstr_w(comp
->FullKeypath
),
2908 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
||
2909 comp
->ActionRequest
== INSTALLSTATE_SOURCE
)
2911 if (!comp
->FullKeypath
)
2914 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2915 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2918 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2921 if (rc
!= ERROR_SUCCESS
)
2924 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2926 static const WCHAR szPermKey
[] =
2927 { '0','0','0','0','0','0','0','0','0','0','0','0',
2928 '0','0','0','0','0','0','0','0','0','0','0','0',
2929 '0','0','0','0','0','0','0','0',0 };
2931 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2934 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2935 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2941 WCHAR source
[MAX_PATH
];
2942 WCHAR base
[MAX_PATH
];
2945 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2946 static const WCHAR query
[] = {
2947 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2948 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2949 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2950 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2951 '`','D','i','s','k','I','d','`',0};
2953 file
= get_loaded_file(package
, comp
->KeyPath
);
2957 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2958 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2959 ptr2
= strrchrW(source
, '\\') + 1;
2960 msiobj_release(&row
->hdr
);
2962 lstrcpyW(base
, package
->PackagePath
);
2963 ptr
= strrchrW(base
, '\\');
2966 sourcepath
= resolve_file_source(package
, file
);
2967 ptr
= sourcepath
+ lstrlenW(base
);
2968 lstrcpyW(ptr2
, ptr
);
2969 msi_free(sourcepath
);
2971 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2975 else if (comp
->ActionRequest
== INSTALLSTATE_ABSENT
)
2977 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2978 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
2980 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
2982 comp
->Action
= comp
->ActionRequest
;
2985 uirow
= MSI_CreateRecord(3);
2986 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2987 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2988 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2989 ui_actiondata(package
,szProcessComponents
,uirow
);
2990 msiobj_release( &uirow
->hdr
);
2993 return ERROR_SUCCESS
;
3004 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
3005 LPWSTR lpszName
, LONG_PTR lParam
)
3008 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
3009 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
3013 if (!IS_INTRESOURCE(lpszName
))
3015 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
3019 sz
= strlenW(tl_struct
->source
)+4;
3020 sz
*= sizeof(WCHAR
);
3022 if ((INT_PTR
)lpszName
== 1)
3023 tl_struct
->path
= strdupW(tl_struct
->source
);
3026 tl_struct
->path
= msi_alloc(sz
);
3027 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
3030 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
3031 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
3034 msi_free(tl_struct
->path
);
3035 tl_struct
->path
= NULL
;
3040 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
3041 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
3043 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3047 msi_free(tl_struct
->path
);
3048 tl_struct
->path
= NULL
;
3050 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3051 ITypeLib_Release(tl_struct
->ptLib
);
3056 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3058 MSIPACKAGE
* package
= param
;
3062 typelib_struct tl_struct
;
3067 component
= MSI_RecordGetString(row
,3);
3068 comp
= get_loaded_component(package
,component
);
3070 return ERROR_SUCCESS
;
3072 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3074 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3075 comp
->Action
= comp
->Installed
;
3076 return ERROR_SUCCESS
;
3078 comp
->Action
= INSTALLSTATE_LOCAL
;
3080 file
= get_loaded_file( package
, comp
->KeyPath
);
3082 return ERROR_SUCCESS
;
3084 ui_actiondata( package
, szRegisterTypeLibraries
, row
);
3086 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3090 guid
= MSI_RecordGetString(row
,1);
3091 CLSIDFromString((LPCWSTR
)guid
, &tl_struct
.clsid
);
3092 tl_struct
.source
= strdupW( file
->TargetPath
);
3093 tl_struct
.path
= NULL
;
3095 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3096 (LONG_PTR
)&tl_struct
);
3104 helpid
= MSI_RecordGetString(row
,6);
3107 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3108 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3112 ERR("Failed to register type library %s\n",
3113 debugstr_w(tl_struct
.path
));
3115 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3117 ITypeLib_Release(tl_struct
.ptLib
);
3118 msi_free(tl_struct
.path
);
3121 ERR("Failed to load type library %s\n",
3122 debugstr_w(tl_struct
.source
));
3124 FreeLibrary(module
);
3125 msi_free(tl_struct
.source
);
3129 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3132 ERR("Failed to load type library: %08x\n", hr
);
3133 return ERROR_INSTALL_FAILURE
;
3136 ITypeLib_Release(tlib
);
3139 return ERROR_SUCCESS
;
3142 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3145 * OK this is a bit confusing.. I am given a _Component key and I believe
3146 * that the file that is being registered as a type library is the "key file
3147 * of that component" which I interpret to mean "The file in the KeyPath of
3152 static const WCHAR Query
[] =
3153 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3154 '`','T','y','p','e','L','i','b','`',0};
3156 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3157 if (rc
!= ERROR_SUCCESS
)
3158 return ERROR_SUCCESS
;
3160 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3161 msiobj_release(&view
->hdr
);
3165 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
3167 MSIPACKAGE
*package
= param
;
3168 LPCWSTR component
, guid
;
3176 component
= MSI_RecordGetString( row
, 3 );
3177 comp
= get_loaded_component( package
, component
);
3179 return ERROR_SUCCESS
;
3181 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3183 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3184 comp
->Action
= comp
->Installed
;
3185 return ERROR_SUCCESS
;
3187 comp
->Action
= INSTALLSTATE_ABSENT
;
3189 ui_actiondata( package
, szUnregisterTypeLibraries
, row
);
3191 guid
= MSI_RecordGetString( row
, 1 );
3192 CLSIDFromString( (LPCWSTR
)guid
, &libid
);
3193 version
= MSI_RecordGetInteger( row
, 4 );
3194 language
= MSI_RecordGetInteger( row
, 2 );
3197 syskind
= SYS_WIN64
;
3199 syskind
= SYS_WIN32
;
3202 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
3205 WARN("Failed to unregister typelib: %08x\n", hr
);
3208 return ERROR_SUCCESS
;
3211 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
3215 static const WCHAR query
[] =
3216 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3217 '`','T','y','p','e','L','i','b','`',0};
3219 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3220 if (rc
!= ERROR_SUCCESS
)
3221 return ERROR_SUCCESS
;
3223 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
3224 msiobj_release( &view
->hdr
);
3228 static WCHAR
*get_link_file( MSIPACKAGE
*package
, MSIRECORD
*row
)
3230 static const WCHAR szlnk
[] = {'.','l','n','k',0};
3231 LPCWSTR directory
, extension
;
3232 LPWSTR link_folder
, link_file
, filename
;
3234 directory
= MSI_RecordGetString( row
, 2 );
3235 link_folder
= resolve_folder( package
, directory
, FALSE
, FALSE
, TRUE
, NULL
);
3237 /* may be needed because of a bug somewhere else */
3238 create_full_pathW( link_folder
);
3240 filename
= msi_dup_record_field( row
, 3 );
3241 reduce_to_longfilename( filename
);
3243 extension
= strchrW( filename
, '.' );
3244 if (!extension
|| strcmpiW( extension
, szlnk
))
3246 int len
= strlenW( filename
);
3247 filename
= msi_realloc( filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
) );
3248 memcpy( filename
+ len
, szlnk
, sizeof(szlnk
) );
3250 link_file
= build_directory_name( 2, link_folder
, filename
);
3251 msi_free( link_folder
);
3252 msi_free( filename
);
3257 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3259 MSIPACKAGE
*package
= param
;
3260 LPWSTR link_file
, deformated
, path
;
3261 LPCWSTR component
, target
;
3263 IShellLinkW
*sl
= NULL
;
3264 IPersistFile
*pf
= NULL
;
3267 component
= MSI_RecordGetString(row
, 4);
3268 comp
= get_loaded_component(package
, component
);
3270 return ERROR_SUCCESS
;
3272 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3274 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3275 comp
->Action
= comp
->Installed
;
3276 return ERROR_SUCCESS
;
3278 comp
->Action
= INSTALLSTATE_LOCAL
;
3280 ui_actiondata(package
,szCreateShortcuts
,row
);
3282 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3283 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3287 ERR("CLSID_ShellLink not available\n");
3291 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3294 ERR("QueryInterface(IID_IPersistFile) failed\n");
3298 target
= MSI_RecordGetString(row
, 5);
3299 if (strchrW(target
, '['))
3301 deformat_string(package
, target
, &deformated
);
3302 IShellLinkW_SetPath(sl
,deformated
);
3303 msi_free(deformated
);
3307 FIXME("poorly handled shortcut format, advertised shortcut\n");
3308 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3311 if (!MSI_RecordIsNull(row
,6))
3313 LPCWSTR arguments
= MSI_RecordGetString(row
, 6);
3314 deformat_string(package
, arguments
, &deformated
);
3315 IShellLinkW_SetArguments(sl
,deformated
);
3316 msi_free(deformated
);
3319 if (!MSI_RecordIsNull(row
,7))
3321 LPCWSTR description
= MSI_RecordGetString(row
, 7);
3322 IShellLinkW_SetDescription(sl
, description
);
3325 if (!MSI_RecordIsNull(row
,8))
3326 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3328 if (!MSI_RecordIsNull(row
,9))
3331 LPCWSTR icon
= MSI_RecordGetString(row
, 9);
3333 path
= build_icon_path(package
, icon
);
3334 index
= MSI_RecordGetInteger(row
,10);
3336 /* no value means 0 */
3337 if (index
== MSI_NULL_INTEGER
)
3340 IShellLinkW_SetIconLocation(sl
, path
, index
);
3344 if (!MSI_RecordIsNull(row
,11))
3345 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3347 if (!MSI_RecordIsNull(row
,12))
3349 LPCWSTR wkdir
= MSI_RecordGetString(row
, 12);
3350 path
= resolve_folder(package
, wkdir
, FALSE
, FALSE
, TRUE
, NULL
);
3352 IShellLinkW_SetWorkingDirectory(sl
, path
);
3356 link_file
= get_link_file(package
, row
);
3358 TRACE("Writing shortcut to %s\n", debugstr_w(link_file
));
3359 IPersistFile_Save(pf
, link_file
, FALSE
);
3361 msi_free(link_file
);
3365 IPersistFile_Release( pf
);
3367 IShellLinkW_Release( sl
);
3369 return ERROR_SUCCESS
;
3372 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3377 static const WCHAR Query
[] =
3378 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3379 '`','S','h','o','r','t','c','u','t','`',0};
3381 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3382 if (rc
!= ERROR_SUCCESS
)
3383 return ERROR_SUCCESS
;
3385 res
= CoInitialize( NULL
);
3387 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3388 msiobj_release(&view
->hdr
);
3396 static UINT
ITERATE_RemoveShortcuts( MSIRECORD
*row
, LPVOID param
)
3398 MSIPACKAGE
*package
= param
;
3403 component
= MSI_RecordGetString( row
, 4 );
3404 comp
= get_loaded_component( package
, component
);
3406 return ERROR_SUCCESS
;
3408 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3410 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3411 comp
->Action
= comp
->Installed
;
3412 return ERROR_SUCCESS
;
3414 comp
->Action
= INSTALLSTATE_ABSENT
;
3416 ui_actiondata( package
, szRemoveShortcuts
, row
);
3418 link_file
= get_link_file( package
, row
);
3420 TRACE("Removing shortcut file %s\n", debugstr_w( link_file
));
3421 if (!DeleteFileW( link_file
))
3423 WARN("Failed to remove shortcut file %u\n", GetLastError());
3425 msi_free( link_file
);
3427 return ERROR_SUCCESS
;
3430 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
3434 static const WCHAR query
[] =
3435 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3436 '`','S','h','o','r','t','c','u','t','`',0};
3438 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3439 if (rc
!= ERROR_SUCCESS
)
3440 return ERROR_SUCCESS
;
3442 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveShortcuts
, package
);
3443 msiobj_release( &view
->hdr
);
3448 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3450 MSIPACKAGE
* package
= param
;
3458 FileName
= MSI_RecordGetString(row
,1);
3461 ERR("Unable to get FileName\n");
3462 return ERROR_SUCCESS
;
3465 FilePath
= build_icon_path(package
,FileName
);
3467 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3469 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3470 FILE_ATTRIBUTE_NORMAL
, NULL
);
3472 if (the_file
== INVALID_HANDLE_VALUE
)
3474 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3476 return ERROR_SUCCESS
;
3483 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3484 if (rc
!= ERROR_SUCCESS
)
3486 ERR("Failed to get stream\n");
3487 CloseHandle(the_file
);
3488 DeleteFileW(FilePath
);
3491 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3492 } while (sz
== 1024);
3495 CloseHandle(the_file
);
3497 return ERROR_SUCCESS
;
3500 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3505 static const WCHAR query
[]= {
3506 'S','E','L','E','C','T',' ','*',' ',
3507 'F','R','O','M',' ','`','I','c','o','n','`',0};
3509 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3510 if (r
== ERROR_SUCCESS
)
3512 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3513 msiobj_release(&view
->hdr
);
3516 return ERROR_SUCCESS
;
3519 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3525 MSISOURCELISTINFO
*info
;
3527 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3528 if (r
!= ERROR_SUCCESS
)
3531 RegCloseKey(source
);
3533 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3534 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3535 package
->Context
, MSICODE_PRODUCT
,
3536 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3537 if (r
!= ERROR_SUCCESS
)
3540 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3541 package
->Context
, MSICODE_PRODUCT
,
3542 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3543 if (r
!= ERROR_SUCCESS
)
3546 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3547 package
->Context
, MSICODE_PRODUCT
,
3548 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3549 if (r
!= ERROR_SUCCESS
)
3552 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3554 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3555 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3556 info
->options
, info
->value
);
3558 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3559 info
->context
, info
->options
,
3560 info
->property
, info
->value
);
3563 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3565 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3566 disk
->context
, disk
->options
,
3567 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3570 return ERROR_SUCCESS
;
3573 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3575 MSIHANDLE hdb
, suminfo
;
3576 WCHAR guids
[MAX_PATH
];
3577 WCHAR packcode
[SQUISH_GUID_SIZE
];
3584 static const WCHAR szProductLanguage
[] =
3585 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3586 static const WCHAR szARPProductIcon
[] =
3587 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3588 static const WCHAR szProductVersion
[] =
3589 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3590 static const WCHAR szAssignment
[] =
3591 {'A','s','s','i','g','n','m','e','n','t',0};
3592 static const WCHAR szAdvertiseFlags
[] =
3593 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3594 static const WCHAR szClients
[] =
3595 {'C','l','i','e','n','t','s',0};
3596 static const WCHAR szColon
[] = {':',0};
3598 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3599 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3602 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3603 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3606 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3608 buffer
= msi_dup_property(package
, szARPProductIcon
);
3611 LPWSTR path
= build_icon_path(package
,buffer
);
3612 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3617 buffer
= msi_dup_property(package
, szProductVersion
);
3620 DWORD verdword
= msi_version_str_to_dword(buffer
);
3621 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3625 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3626 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3627 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3628 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3630 hdb
= alloc_msihandle(&package
->db
->hdr
);
3632 return ERROR_NOT_ENOUGH_MEMORY
;
3634 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3635 MsiCloseHandle(hdb
);
3636 if (r
!= ERROR_SUCCESS
)
3640 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3641 NULL
, guids
, &size
);
3642 if (r
!= ERROR_SUCCESS
)
3645 ptr
= strchrW(guids
, ';');
3647 squash_guid(guids
, packcode
);
3648 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3651 MsiCloseHandle(suminfo
);
3652 return ERROR_SUCCESS
;
3655 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3660 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3662 static const WCHAR szUpgradeCode
[] =
3663 {'U','p','g','r','a','d','e','C','o','d','e',0};
3665 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3667 return ERROR_SUCCESS
;
3669 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3671 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3672 if (r
!= ERROR_SUCCESS
)
3677 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3678 if (r
!= ERROR_SUCCESS
)
3682 squash_guid(package
->ProductCode
, squashed_pc
);
3683 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3692 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3694 MSIFEATURE
*feature
;
3696 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3698 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3705 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3707 MSIFEATURE
*feature
;
3709 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3711 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3718 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3720 WCHAR patch_squashed
[GUID_SIZE
];
3723 UINT r
= ERROR_FUNCTION_FAILED
;
3725 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3727 if (res
!= ERROR_SUCCESS
)
3728 return ERROR_FUNCTION_FAILED
;
3730 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3732 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3733 (const BYTE
*)patch_squashed
,
3734 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3735 if (res
!= ERROR_SUCCESS
)
3738 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3739 (const BYTE
*)package
->patch
->transforms
,
3740 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3741 if (res
== ERROR_SUCCESS
)
3745 RegCloseKey(patches
);
3750 * 99% of the work done here is only done for
3751 * advertised installs. However this is where the
3752 * Icon table is processed and written out
3753 * so that is what I am going to do here.
3755 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3758 HKEY hukey
= NULL
, hudkey
= NULL
;
3761 /* FIXME: also need to publish if the product is in advertise mode */
3762 if (!msi_check_publish(package
))
3763 return ERROR_SUCCESS
;
3765 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3767 if (rc
!= ERROR_SUCCESS
)
3770 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3771 NULL
, &hudkey
, TRUE
);
3772 if (rc
!= ERROR_SUCCESS
)
3775 rc
= msi_publish_upgrade_code(package
);
3776 if (rc
!= ERROR_SUCCESS
)
3781 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3782 if (rc
!= ERROR_SUCCESS
)
3786 rc
= msi_publish_product_properties(package
, hukey
);
3787 if (rc
!= ERROR_SUCCESS
)
3790 rc
= msi_publish_sourcelist(package
, hukey
);
3791 if (rc
!= ERROR_SUCCESS
)
3794 rc
= msi_publish_icons(package
);
3797 uirow
= MSI_CreateRecord( 1 );
3798 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
3799 ui_actiondata( package
, szPublishProduct
, uirow
);
3800 msiobj_release( &uirow
->hdr
);
3803 RegCloseKey(hudkey
);
3808 static WCHAR
*get_ini_file_name( MSIPACKAGE
*package
, MSIRECORD
*row
)
3810 WCHAR
*filename
, *ptr
, *folder
, *ret
;
3811 const WCHAR
*dirprop
;
3813 filename
= msi_dup_record_field( row
, 2 );
3814 if (filename
&& (ptr
= strchrW( filename
, '|' )))
3819 dirprop
= MSI_RecordGetString( row
, 3 );
3822 folder
= resolve_folder( package
, dirprop
, FALSE
, FALSE
, TRUE
, NULL
);
3824 folder
= msi_dup_property( package
, dirprop
);
3827 folder
= msi_dup_property( package
, szWindowsFolder
);
3831 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop
));
3832 msi_free( filename
);
3836 ret
= build_directory_name( 2, folder
, ptr
);
3838 msi_free( filename
);
3843 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3845 MSIPACKAGE
*package
= param
;
3846 LPCWSTR component
, section
, key
, value
, identifier
;
3847 LPWSTR deformated_section
, deformated_key
, deformated_value
, fullname
;
3852 component
= MSI_RecordGetString(row
, 8);
3853 comp
= get_loaded_component(package
,component
);
3855 return ERROR_SUCCESS
;
3857 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3859 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3860 comp
->Action
= comp
->Installed
;
3861 return ERROR_SUCCESS
;
3863 comp
->Action
= INSTALLSTATE_LOCAL
;
3865 identifier
= MSI_RecordGetString(row
,1);
3866 section
= MSI_RecordGetString(row
,4);
3867 key
= MSI_RecordGetString(row
,5);
3868 value
= MSI_RecordGetString(row
,6);
3869 action
= MSI_RecordGetInteger(row
,7);
3871 deformat_string(package
,section
,&deformated_section
);
3872 deformat_string(package
,key
,&deformated_key
);
3873 deformat_string(package
,value
,&deformated_value
);
3875 fullname
= get_ini_file_name(package
, row
);
3879 TRACE("Adding value %s to section %s in %s\n",
3880 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3881 debugstr_w(fullname
));
3882 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3883 deformated_value
, fullname
);
3885 else if (action
== 1)
3888 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3889 returned
, 10, fullname
);
3890 if (returned
[0] == 0)
3892 TRACE("Adding value %s to section %s in %s\n",
3893 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3894 debugstr_w(fullname
));
3896 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3897 deformated_value
, fullname
);
3900 else if (action
== 3)
3901 FIXME("Append to existing section not yet implemented\n");
3903 uirow
= MSI_CreateRecord(4);
3904 MSI_RecordSetStringW(uirow
,1,identifier
);
3905 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3906 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3907 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3908 ui_actiondata(package
,szWriteIniValues
,uirow
);
3909 msiobj_release( &uirow
->hdr
);
3912 msi_free(deformated_key
);
3913 msi_free(deformated_value
);
3914 msi_free(deformated_section
);
3915 return ERROR_SUCCESS
;
3918 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3922 static const WCHAR ExecSeqQuery
[] =
3923 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3924 '`','I','n','i','F','i','l','e','`',0};
3926 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3927 if (rc
!= ERROR_SUCCESS
)
3929 TRACE("no IniFile table\n");
3930 return ERROR_SUCCESS
;
3933 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3934 msiobj_release(&view
->hdr
);
3938 static UINT
ITERATE_RemoveIniValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
3940 MSIPACKAGE
*package
= param
;
3941 LPCWSTR component
, section
, key
, value
, identifier
;
3942 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
3947 component
= MSI_RecordGetString( row
, 8 );
3948 comp
= get_loaded_component( package
, component
);
3950 return ERROR_SUCCESS
;
3952 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3954 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3955 comp
->Action
= comp
->Installed
;
3956 return ERROR_SUCCESS
;
3958 comp
->Action
= INSTALLSTATE_ABSENT
;
3960 identifier
= MSI_RecordGetString( row
, 1 );
3961 section
= MSI_RecordGetString( row
, 4 );
3962 key
= MSI_RecordGetString( row
, 5 );
3963 value
= MSI_RecordGetString( row
, 6 );
3964 action
= MSI_RecordGetInteger( row
, 7 );
3966 deformat_string( package
, section
, &deformated_section
);
3967 deformat_string( package
, key
, &deformated_key
);
3968 deformat_string( package
, value
, &deformated_value
);
3970 if (action
== msidbIniFileActionAddLine
|| action
== msidbIniFileActionCreateLine
)
3972 filename
= get_ini_file_name( package
, row
);
3974 TRACE("Removing key %s from section %s in %s\n",
3975 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
3977 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
3979 WARN("Unable to remove key %u\n", GetLastError());
3981 msi_free( filename
);
3984 FIXME("Unsupported action %d\n", action
);
3987 uirow
= MSI_CreateRecord( 4 );
3988 MSI_RecordSetStringW( uirow
, 1, identifier
);
3989 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
3990 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
3991 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
3992 ui_actiondata( package
, szRemoveIniValues
, uirow
);
3993 msiobj_release( &uirow
->hdr
);
3995 msi_free( deformated_key
);
3996 msi_free( deformated_value
);
3997 msi_free( deformated_section
);
3998 return ERROR_SUCCESS
;
4001 static UINT
ITERATE_RemoveIniValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
4003 MSIPACKAGE
*package
= param
;
4004 LPCWSTR component
, section
, key
, value
, identifier
;
4005 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
4010 component
= MSI_RecordGetString( row
, 8 );
4011 comp
= get_loaded_component( package
, component
);
4013 return ERROR_SUCCESS
;
4015 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4017 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
4018 comp
->Action
= comp
->Installed
;
4019 return ERROR_SUCCESS
;
4021 comp
->Action
= INSTALLSTATE_LOCAL
;
4023 identifier
= MSI_RecordGetString( row
, 1 );
4024 section
= MSI_RecordGetString( row
, 4 );
4025 key
= MSI_RecordGetString( row
, 5 );
4026 value
= MSI_RecordGetString( row
, 6 );
4027 action
= MSI_RecordGetInteger( row
, 7 );
4029 deformat_string( package
, section
, &deformated_section
);
4030 deformat_string( package
, key
, &deformated_key
);
4031 deformat_string( package
, value
, &deformated_value
);
4033 if (action
== msidbIniFileActionRemoveLine
)
4035 filename
= get_ini_file_name( package
, row
);
4037 TRACE("Removing key %s from section %s in %s\n",
4038 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
4040 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
4042 WARN("Unable to remove key %u\n", GetLastError());
4044 msi_free( filename
);
4047 FIXME("Unsupported action %d\n", action
);
4049 uirow
= MSI_CreateRecord( 4 );
4050 MSI_RecordSetStringW( uirow
, 1, identifier
);
4051 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4052 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4053 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4054 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4055 msiobj_release( &uirow
->hdr
);
4057 msi_free( deformated_key
);
4058 msi_free( deformated_value
);
4059 msi_free( deformated_section
);
4060 return ERROR_SUCCESS
;
4063 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4067 static const WCHAR query
[] =
4068 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4069 '`','I','n','i','F','i','l','e','`',0};
4070 static const WCHAR remove_query
[] =
4071 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4072 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4074 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4075 if (rc
== ERROR_SUCCESS
)
4077 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnUninstall
, package
);
4078 msiobj_release( &view
->hdr
);
4079 if (rc
!= ERROR_SUCCESS
)
4083 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_query
, &view
);
4084 if (rc
== ERROR_SUCCESS
)
4086 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnInstall
, package
);
4087 msiobj_release( &view
->hdr
);
4088 if (rc
!= ERROR_SUCCESS
)
4092 return ERROR_SUCCESS
;
4095 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
4097 MSIPACKAGE
*package
= param
;
4102 static const WCHAR ExeStr
[] =
4103 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4104 static const WCHAR close
[] = {'\"',0};
4106 PROCESS_INFORMATION info
;
4111 memset(&si
,0,sizeof(STARTUPINFOW
));
4113 filename
= MSI_RecordGetString(row
,1);
4114 file
= get_loaded_file( package
, filename
);
4118 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4119 return ERROR_SUCCESS
;
4122 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
4124 FullName
= msi_alloc(len
*sizeof(WCHAR
));
4125 strcpyW(FullName
,ExeStr
);
4126 strcatW( FullName
, file
->TargetPath
);
4127 strcatW(FullName
,close
);
4129 TRACE("Registering %s\n",debugstr_w(FullName
));
4130 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
4135 CloseHandle(info
.hThread
);
4136 msi_dialog_check_messages(info
.hProcess
);
4137 CloseHandle(info
.hProcess
);
4140 uirow
= MSI_CreateRecord( 2 );
4141 MSI_RecordSetStringW( uirow
, 1, filename
);
4142 uipath
= strdupW( file
->TargetPath
);
4143 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4144 MSI_RecordSetStringW( uirow
, 2, uipath
);
4145 ui_actiondata( package
, szSelfRegModules
, uirow
);
4146 msiobj_release( &uirow
->hdr
);
4148 msi_free( FullName
);
4150 return ERROR_SUCCESS
;
4153 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4157 static const WCHAR ExecSeqQuery
[] =
4158 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4159 '`','S','e','l','f','R','e','g','`',0};
4161 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4162 if (rc
!= ERROR_SUCCESS
)
4164 TRACE("no SelfReg table\n");
4165 return ERROR_SUCCESS
;
4168 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
4169 msiobj_release(&view
->hdr
);
4171 return ERROR_SUCCESS
;
4174 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
4176 static const WCHAR regsvr32
[] =
4177 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4178 static const WCHAR close
[] = {'\"',0};
4179 MSIPACKAGE
*package
= param
;
4185 PROCESS_INFORMATION pi
;
4190 memset( &si
, 0, sizeof(STARTUPINFOW
) );
4192 filename
= MSI_RecordGetString( row
, 1 );
4193 file
= get_loaded_file( package
, filename
);
4197 ERR("Unable to find file id %s\n", debugstr_w(filename
));
4198 return ERROR_SUCCESS
;
4201 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
4203 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
4204 strcpyW( cmdline
, regsvr32
);
4205 strcatW( cmdline
, file
->TargetPath
);
4206 strcatW( cmdline
, close
);
4208 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
4210 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
4213 CloseHandle( pi
.hThread
);
4214 msi_dialog_check_messages( pi
.hProcess
);
4215 CloseHandle( pi
.hProcess
);
4218 uirow
= MSI_CreateRecord( 2 );
4219 MSI_RecordSetStringW( uirow
, 1, filename
);
4220 uipath
= strdupW( file
->TargetPath
);
4221 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4222 MSI_RecordSetStringW( uirow
, 2, uipath
);
4223 ui_actiondata( package
, szSelfUnregModules
, uirow
);
4224 msiobj_release( &uirow
->hdr
);
4226 msi_free( cmdline
);
4228 return ERROR_SUCCESS
;
4231 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4235 static const WCHAR query
[] =
4236 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4237 '`','S','e','l','f','R','e','g','`',0};
4239 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4240 if (rc
!= ERROR_SUCCESS
)
4242 TRACE("no SelfReg table\n");
4243 return ERROR_SUCCESS
;
4246 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
4247 msiobj_release( &view
->hdr
);
4249 return ERROR_SUCCESS
;
4252 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4254 MSIFEATURE
*feature
;
4256 HKEY hkey
= NULL
, userdata
= NULL
;
4258 if (!msi_check_publish(package
))
4259 return ERROR_SUCCESS
;
4261 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4263 if (rc
!= ERROR_SUCCESS
)
4266 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4268 if (rc
!= ERROR_SUCCESS
)
4271 /* here the guids are base 85 encoded */
4272 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
4278 BOOL absent
= FALSE
;
4281 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4282 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4283 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
4286 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4290 if (feature
->Feature_Parent
)
4291 size
+= strlenW( feature
->Feature_Parent
)+2;
4293 data
= msi_alloc(size
* sizeof(WCHAR
));
4296 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4298 MSICOMPONENT
* component
= cl
->component
;
4302 if (component
->ComponentId
)
4304 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4305 CLSIDFromString(component
->ComponentId
, &clsid
);
4306 encode_base85_guid(&clsid
,buf
);
4307 TRACE("to %s\n",debugstr_w(buf
));
4312 if (feature
->Feature_Parent
)
4314 static const WCHAR sep
[] = {'\2',0};
4316 strcatW(data
,feature
->Feature_Parent
);
4319 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4323 if (feature
->Feature_Parent
)
4324 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4327 size
+= sizeof(WCHAR
);
4328 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4329 (const BYTE
*)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
4333 size
+= 2*sizeof(WCHAR
);
4334 data
= msi_alloc(size
);
4337 if (feature
->Feature_Parent
)
4338 strcpyW( &data
[1], feature
->Feature_Parent
);
4339 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4345 uirow
= MSI_CreateRecord( 1 );
4346 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4347 ui_actiondata( package
, szPublishFeatures
, uirow
);
4348 msiobj_release( &uirow
->hdr
);
4349 /* FIXME: call ui_progress? */
4354 RegCloseKey(userdata
);
4358 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4364 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4366 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4368 if (r
== ERROR_SUCCESS
)
4370 RegDeleteValueW(hkey
, feature
->Feature
);
4374 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4376 if (r
== ERROR_SUCCESS
)
4378 RegDeleteValueW(hkey
, feature
->Feature
);
4382 uirow
= MSI_CreateRecord( 1 );
4383 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4384 ui_actiondata( package
, szUnpublishFeatures
, uirow
);
4385 msiobj_release( &uirow
->hdr
);
4387 return ERROR_SUCCESS
;
4390 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4392 MSIFEATURE
*feature
;
4394 if (!msi_check_unpublish(package
))
4395 return ERROR_SUCCESS
;
4397 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4399 msi_unpublish_feature(package
, feature
);
4402 return ERROR_SUCCESS
;
4405 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4407 LPWSTR prop
, val
, key
;
4413 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4414 static const WCHAR szWindowsInstaller
[] =
4415 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4416 static const WCHAR modpath_fmt
[] =
4417 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4418 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4419 static const WCHAR szModifyPath
[] =
4420 {'M','o','d','i','f','y','P','a','t','h',0};
4421 static const WCHAR szUninstallString
[] =
4422 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4423 static const WCHAR szEstimatedSize
[] =
4424 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4425 static const WCHAR szProductLanguage
[] =
4426 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4427 static const WCHAR szProductVersion
[] =
4428 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4429 static const WCHAR szProductName
[] =
4430 {'P','r','o','d','u','c','t','N','a','m','e',0};
4431 static const WCHAR szDisplayName
[] =
4432 {'D','i','s','p','l','a','y','N','a','m','e',0};
4433 static const WCHAR szDisplayVersion
[] =
4434 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4435 static const WCHAR szManufacturer
[] =
4436 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4438 static const LPCSTR propval
[] = {
4439 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4440 "ARPCONTACT", "Contact",
4441 "ARPCOMMENTS", "Comments",
4442 "ProductName", "DisplayName",
4443 "ProductVersion", "DisplayVersion",
4444 "ARPHELPLINK", "HelpLink",
4445 "ARPHELPTELEPHONE", "HelpTelephone",
4446 "ARPINSTALLLOCATION", "InstallLocation",
4447 "SourceDir", "InstallSource",
4448 "Manufacturer", "Publisher",
4449 "ARPREADME", "Readme",
4451 "ARPURLINFOABOUT", "URLInfoAbout",
4452 "ARPURLUPDATEINFO", "URLUpdateInfo",
4455 const LPCSTR
*p
= propval
;
4459 prop
= strdupAtoW(*p
++);
4460 key
= strdupAtoW(*p
++);
4461 val
= msi_dup_property(package
, prop
);
4462 msi_reg_set_val_str(hkey
, key
, val
);
4468 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4470 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4471 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4472 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4475 /* FIXME: Write real Estimated Size when we have it */
4476 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4478 buffer
= msi_dup_property(package
, szProductName
);
4479 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4482 buffer
= msi_dup_property(package
, cszSourceDir
);
4483 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4486 buffer
= msi_dup_property(package
, szManufacturer
);
4487 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4490 GetLocalTime(&systime
);
4491 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4492 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4494 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4495 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4497 buffer
= msi_dup_property(package
, szProductVersion
);
4498 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4501 DWORD verdword
= msi_version_str_to_dword(buffer
);
4503 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4504 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4505 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4509 return ERROR_SUCCESS
;
4512 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4514 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4516 LPWSTR upgrade_code
;
4521 static const WCHAR szUpgradeCode
[] = {
4522 'U','p','g','r','a','d','e','C','o','d','e',0};
4524 /* FIXME: also need to publish if the product is in advertise mode */
4525 if (!msi_check_publish(package
))
4526 return ERROR_SUCCESS
;
4528 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4529 if (rc
!= ERROR_SUCCESS
)
4532 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4533 NULL
, &props
, TRUE
);
4534 if (rc
!= ERROR_SUCCESS
)
4537 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4538 msi_free( package
->db
->localfile
);
4539 package
->db
->localfile
= NULL
;
4541 rc
= msi_publish_install_properties(package
, hkey
);
4542 if (rc
!= ERROR_SUCCESS
)
4545 rc
= msi_publish_install_properties(package
, props
);
4546 if (rc
!= ERROR_SUCCESS
)
4549 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4552 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4553 squash_guid(package
->ProductCode
, squashed_pc
);
4554 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4555 RegCloseKey(upgrade
);
4556 msi_free(upgrade_code
);
4560 uirow
= MSI_CreateRecord( 1 );
4561 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4562 ui_actiondata( package
, szRegisterProduct
, uirow
);
4563 msiobj_release( &uirow
->hdr
);
4566 return ERROR_SUCCESS
;
4569 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4571 return execute_script(package
,INSTALL_SCRIPT
);
4574 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4577 LPWSTR remove
= NULL
;
4578 LPWSTR
*features
= NULL
;
4579 BOOL full_uninstall
= TRUE
;
4580 MSIFEATURE
*feature
;
4582 static const WCHAR szUpgradeCode
[] =
4583 {'U','p','g','r','a','d','e','C','o','d','e',0};
4585 remove
= msi_dup_property(package
, szRemove
);
4587 return ERROR_SUCCESS
;
4589 features
= msi_split_string(remove
, ',');
4593 ERR("REMOVE feature list is empty!\n");
4594 return ERROR_FUNCTION_FAILED
;
4597 if (!lstrcmpW(features
[0], szAll
))
4598 full_uninstall
= TRUE
;
4601 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4603 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4604 full_uninstall
= FALSE
;
4608 if (!full_uninstall
)
4611 MSIREG_DeleteProductKey(package
->ProductCode
);
4612 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4613 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4615 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4617 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4618 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4622 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4623 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4626 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4629 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4636 return ERROR_SUCCESS
;
4639 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4643 rc
= msi_unpublish_product(package
);
4644 if (rc
!= ERROR_SUCCESS
)
4647 /* turn off scheduling */
4648 package
->script
->CurrentlyScripting
= FALSE
;
4650 /* first do the same as an InstallExecute */
4651 rc
= ACTION_InstallExecute(package
);
4652 if (rc
!= ERROR_SUCCESS
)
4655 /* then handle Commit Actions */
4656 rc
= execute_script(package
,COMMIT_SCRIPT
);
4661 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4663 static const WCHAR RunOnce
[] = {
4664 'S','o','f','t','w','a','r','e','\\',
4665 'M','i','c','r','o','s','o','f','t','\\',
4666 'W','i','n','d','o','w','s','\\',
4667 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4668 'R','u','n','O','n','c','e',0};
4669 static const WCHAR InstallRunOnce
[] = {
4670 'S','o','f','t','w','a','r','e','\\',
4671 'M','i','c','r','o','s','o','f','t','\\',
4672 'W','i','n','d','o','w','s','\\',
4673 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4674 'I','n','s','t','a','l','l','e','r','\\',
4675 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4677 static const WCHAR msiexec_fmt
[] = {
4679 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4680 '\"','%','s','\"',0};
4681 static const WCHAR install_fmt
[] = {
4682 '/','I',' ','\"','%','s','\"',' ',
4683 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4684 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4685 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4687 WCHAR squished_pc
[100];
4689 squash_guid(package
->ProductCode
,squished_pc
);
4691 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4692 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4693 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4696 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4699 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4701 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4702 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4704 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4707 return ERROR_INSTALL_SUSPEND
;
4710 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4716 * We are currently doing what should be done here in the top level Install
4717 * however for Administrative and uninstalls this step will be needed
4719 if (!package
->PackagePath
)
4720 return ERROR_SUCCESS
;
4722 msi_set_sourcedir_props(package
, TRUE
);
4724 attrib
= GetFileAttributesW(package
->db
->path
);
4725 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4731 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4732 package
->Context
, MSICODE_PRODUCT
,
4733 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4734 if (rc
== ERROR_MORE_DATA
)
4736 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4737 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4738 package
->Context
, MSICODE_PRODUCT
,
4739 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4742 prompt
= strdupW(package
->db
->path
);
4744 msg
= generate_error_string(package
,1302,1,prompt
);
4745 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4747 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4750 rc
= ERROR_INSTALL_USEREXIT
;
4753 attrib
= GetFileAttributesW(package
->db
->path
);
4759 return ERROR_SUCCESS
;
4764 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4767 LPWSTR buffer
, productid
= NULL
;
4768 UINT i
, rc
= ERROR_SUCCESS
;
4771 static const WCHAR szPropKeys
[][80] =
4773 {'P','r','o','d','u','c','t','I','D',0},
4774 {'U','S','E','R','N','A','M','E',0},
4775 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4779 static const WCHAR szRegKeys
[][80] =
4781 {'P','r','o','d','u','c','t','I','D',0},
4782 {'R','e','g','O','w','n','e','r',0},
4783 {'R','e','g','C','o','m','p','a','n','y',0},
4787 if (msi_check_unpublish(package
))
4789 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4793 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4797 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4799 if (rc
!= ERROR_SUCCESS
)
4802 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4804 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4805 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4810 uirow
= MSI_CreateRecord( 1 );
4811 MSI_RecordSetStringW( uirow
, 1, productid
);
4812 ui_actiondata( package
, szRegisterUser
, uirow
);
4813 msiobj_release( &uirow
->hdr
);
4815 msi_free(productid
);
4821 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4825 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4826 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4831 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4833 MSIPACKAGE
*package
= param
;
4834 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
4835 LPWSTR advertise
= NULL
, output
= NULL
;
4843 feature
= MSI_RecordGetString(rec
, 5);
4844 feat
= get_loaded_feature(package
, feature
);
4846 return ERROR_SUCCESS
;
4848 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4849 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4850 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
4852 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
4853 feat
->Action
= feat
->Installed
;
4854 return ERROR_SUCCESS
;
4857 component
= MSI_RecordGetString(rec
, 3);
4858 comp
= get_loaded_component(package
, component
);
4860 return ERROR_SUCCESS
;
4862 compgroupid
= MSI_RecordGetString(rec
,1);
4863 qualifier
= MSI_RecordGetString(rec
,2);
4865 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4866 if (rc
!= ERROR_SUCCESS
)
4869 text
= MSI_RecordGetString(rec
,4);
4870 advertise
= create_component_advertise_string(package
, comp
, feature
);
4872 sz
= strlenW(advertise
);
4875 sz
+= lstrlenW(text
);
4878 sz
*= sizeof(WCHAR
);
4880 output
= msi_alloc_zero(sz
);
4881 strcpyW(output
,advertise
);
4882 msi_free(advertise
);
4885 strcatW(output
,text
);
4887 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4894 uirow
= MSI_CreateRecord( 2 );
4895 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4896 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4897 ui_actiondata( package
, szPublishComponents
, uirow
);
4898 msiobj_release( &uirow
->hdr
);
4899 /* FIXME: call ui_progress? */
4905 * At present I am ignorning the advertised components part of this and only
4906 * focusing on the qualified component sets
4908 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4912 static const WCHAR ExecSeqQuery
[] =
4913 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4914 '`','P','u','b','l','i','s','h',
4915 'C','o','m','p','o','n','e','n','t','`',0};
4917 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4918 if (rc
!= ERROR_SUCCESS
)
4919 return ERROR_SUCCESS
;
4921 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4922 msiobj_release(&view
->hdr
);
4927 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
4929 static const WCHAR szInstallerComponents
[] = {
4930 'S','o','f','t','w','a','r','e','\\',
4931 'M','i','c','r','o','s','o','f','t','\\',
4932 'I','n','s','t','a','l','l','e','r','\\',
4933 'C','o','m','p','o','n','e','n','t','s','\\',0};
4935 MSIPACKAGE
*package
= param
;
4936 LPCWSTR compgroupid
, component
, feature
, qualifier
;
4940 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
4943 feature
= MSI_RecordGetString( rec
, 5 );
4944 feat
= get_loaded_feature( package
, feature
);
4946 return ERROR_SUCCESS
;
4948 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4950 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
4951 feat
->Action
= feat
->Installed
;
4952 return ERROR_SUCCESS
;
4955 component
= MSI_RecordGetString( rec
, 3 );
4956 comp
= get_loaded_component( package
, component
);
4958 return ERROR_SUCCESS
;
4960 compgroupid
= MSI_RecordGetString( rec
, 1 );
4961 qualifier
= MSI_RecordGetString( rec
, 2 );
4963 squash_guid( compgroupid
, squashed
);
4964 strcpyW( keypath
, szInstallerComponents
);
4965 strcatW( keypath
, squashed
);
4967 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
4968 if (res
!= ERROR_SUCCESS
)
4970 WARN("Unable to delete component key %d\n", res
);
4973 uirow
= MSI_CreateRecord( 2 );
4974 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4975 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4976 ui_actiondata( package
, szUnpublishComponents
, uirow
);
4977 msiobj_release( &uirow
->hdr
);
4979 return ERROR_SUCCESS
;
4982 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
4986 static const WCHAR query
[] =
4987 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4988 '`','P','u','b','l','i','s','h',
4989 'C','o','m','p','o','n','e','n','t','`',0};
4991 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4992 if (rc
!= ERROR_SUCCESS
)
4993 return ERROR_SUCCESS
;
4995 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
4996 msiobj_release( &view
->hdr
);
5001 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
5003 MSIPACKAGE
*package
= param
;
5006 SC_HANDLE hscm
, service
= NULL
;
5007 LPCWSTR comp
, depends
, pass
;
5008 LPWSTR name
= NULL
, disp
= NULL
;
5009 LPCWSTR load_order
, serv_name
, key
;
5010 DWORD serv_type
, start_type
;
5013 static const WCHAR query
[] =
5014 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5015 '`','C','o','m','p','o','n','e','n','t','`',' ',
5016 'W','H','E','R','E',' ',
5017 '`','C','o','m','p','o','n','e','n','t','`',' ',
5018 '=','\'','%','s','\'',0};
5020 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
5023 ERR("Failed to open the SC Manager!\n");
5027 start_type
= MSI_RecordGetInteger(rec
, 5);
5028 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
5031 depends
= MSI_RecordGetString(rec
, 8);
5032 if (depends
&& *depends
)
5033 FIXME("Dependency list unhandled!\n");
5035 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5036 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
5037 serv_type
= MSI_RecordGetInteger(rec
, 4);
5038 err_control
= MSI_RecordGetInteger(rec
, 6);
5039 load_order
= MSI_RecordGetString(rec
, 7);
5040 serv_name
= MSI_RecordGetString(rec
, 9);
5041 pass
= MSI_RecordGetString(rec
, 10);
5042 comp
= MSI_RecordGetString(rec
, 12);
5044 /* fetch the service path */
5045 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
5048 ERR("Control query failed!\n");
5052 key
= MSI_RecordGetString(row
, 6);
5054 file
= get_loaded_file(package
, key
);
5055 msiobj_release(&row
->hdr
);
5058 ERR("Failed to load the service file\n");
5062 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
5063 start_type
, err_control
, file
->TargetPath
,
5064 load_order
, NULL
, NULL
, serv_name
, pass
);
5067 if (GetLastError() != ERROR_SERVICE_EXISTS
)
5068 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
5072 CloseServiceHandle(service
);
5073 CloseServiceHandle(hscm
);
5077 return ERROR_SUCCESS
;
5080 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
5084 static const WCHAR ExecSeqQuery
[] =
5085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5086 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5088 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5089 if (rc
!= ERROR_SUCCESS
)
5090 return ERROR_SUCCESS
;
5092 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
5093 msiobj_release(&view
->hdr
);
5098 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5099 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
5101 LPCWSTR
*vector
, *temp_vector
;
5105 static const WCHAR separator
[] = {'[','~',']',0};
5108 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
5113 vector
= msi_alloc(sizeof(LPWSTR
));
5121 vector
[*numargs
- 1] = p
;
5123 if ((q
= strstrW(p
, separator
)))
5127 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
5133 vector
= temp_vector
;
5142 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
5144 MSIPACKAGE
*package
= param
;
5147 SC_HANDLE scm
= NULL
, service
= NULL
;
5148 LPCWSTR component
, *vector
= NULL
;
5149 LPWSTR name
, args
, display_name
= NULL
;
5150 DWORD event
, numargs
, len
;
5151 UINT r
= ERROR_FUNCTION_FAILED
;
5153 component
= MSI_RecordGetString(rec
, 6);
5154 comp
= get_loaded_component(package
, component
);
5156 return ERROR_SUCCESS
;
5158 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5160 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
5161 comp
->Action
= comp
->Installed
;
5162 return ERROR_SUCCESS
;
5164 comp
->Action
= INSTALLSTATE_LOCAL
;
5166 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5167 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
5168 event
= MSI_RecordGetInteger(rec
, 3);
5170 if (!(event
& msidbServiceControlEventStart
))
5176 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
5179 ERR("Failed to open the service control manager\n");
5184 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5185 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5187 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5188 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5191 service
= OpenServiceW(scm
, name
, SERVICE_START
);
5194 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
5198 vector
= msi_service_args_to_vector(args
, &numargs
);
5200 if (!StartServiceW(service
, numargs
, vector
) &&
5201 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
5203 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
5210 uirow
= MSI_CreateRecord( 2 );
5211 MSI_RecordSetStringW( uirow
, 1, display_name
);
5212 MSI_RecordSetStringW( uirow
, 2, name
);
5213 ui_actiondata( package
, szStartServices
, uirow
);
5214 msiobj_release( &uirow
->hdr
);
5216 CloseServiceHandle(service
);
5217 CloseServiceHandle(scm
);
5222 msi_free(display_name
);
5226 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
5231 static const WCHAR query
[] = {
5232 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5233 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5235 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5236 if (rc
!= ERROR_SUCCESS
)
5237 return ERROR_SUCCESS
;
5239 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
5240 msiobj_release(&view
->hdr
);
5245 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
5247 DWORD i
, needed
, count
;
5248 ENUM_SERVICE_STATUSW
*dependencies
;
5252 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
5253 0, &needed
, &count
))
5256 if (GetLastError() != ERROR_MORE_DATA
)
5259 dependencies
= msi_alloc(needed
);
5263 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
5264 needed
, &needed
, &count
))
5267 for (i
= 0; i
< count
; i
++)
5269 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
5270 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
5274 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
5281 msi_free(dependencies
);
5285 static UINT
stop_service( LPCWSTR name
)
5287 SC_HANDLE scm
= NULL
, service
= NULL
;
5288 SERVICE_STATUS status
;
5289 SERVICE_STATUS_PROCESS ssp
;
5292 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5295 WARN("Failed to open the SCM: %d\n", GetLastError());
5299 service
= OpenServiceW(scm
, name
,
5301 SERVICE_QUERY_STATUS
|
5302 SERVICE_ENUMERATE_DEPENDENTS
);
5305 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
5309 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
5310 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
5312 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
5316 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
5319 stop_service_dependents(scm
, service
);
5321 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5322 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5325 CloseServiceHandle(service
);
5326 CloseServiceHandle(scm
);
5328 return ERROR_SUCCESS
;
5331 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
5333 MSIPACKAGE
*package
= param
;
5337 LPWSTR name
= NULL
, display_name
= NULL
;
5341 event
= MSI_RecordGetInteger( rec
, 3 );
5342 if (!(event
& msidbServiceControlEventStop
))
5343 return ERROR_SUCCESS
;
5345 component
= MSI_RecordGetString( rec
, 6 );
5346 comp
= get_loaded_component( package
, component
);
5348 return ERROR_SUCCESS
;
5350 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5352 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5353 comp
->Action
= comp
->Installed
;
5354 return ERROR_SUCCESS
;
5356 comp
->Action
= INSTALLSTATE_ABSENT
;
5358 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
5361 ERR("Failed to open the service control manager\n");
5366 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5367 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5369 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5370 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5372 CloseServiceHandle( scm
);
5374 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
5375 stop_service( name
);
5378 uirow
= MSI_CreateRecord( 2 );
5379 MSI_RecordSetStringW( uirow
, 1, display_name
);
5380 MSI_RecordSetStringW( uirow
, 2, name
);
5381 ui_actiondata( package
, szStopServices
, uirow
);
5382 msiobj_release( &uirow
->hdr
);
5385 msi_free( display_name
);
5386 return ERROR_SUCCESS
;
5389 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5394 static const WCHAR query
[] = {
5395 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5396 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5398 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5399 if (rc
!= ERROR_SUCCESS
)
5400 return ERROR_SUCCESS
;
5402 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5403 msiobj_release(&view
->hdr
);
5408 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
5410 MSIPACKAGE
*package
= param
;
5414 LPWSTR name
= NULL
, display_name
= NULL
;
5416 SC_HANDLE scm
= NULL
, service
= NULL
;
5418 event
= MSI_RecordGetInteger( rec
, 3 );
5419 if (!(event
& msidbServiceControlEventDelete
))
5420 return ERROR_SUCCESS
;
5422 component
= MSI_RecordGetString(rec
, 6);
5423 comp
= get_loaded_component(package
, component
);
5425 return ERROR_SUCCESS
;
5427 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5429 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5430 comp
->Action
= comp
->Installed
;
5431 return ERROR_SUCCESS
;
5433 comp
->Action
= INSTALLSTATE_ABSENT
;
5435 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
5436 stop_service( name
);
5438 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5441 WARN("Failed to open the SCM: %d\n", GetLastError());
5446 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5447 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5449 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5450 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5453 service
= OpenServiceW( scm
, name
, DELETE
);
5456 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
5460 if (!DeleteService( service
))
5461 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
5464 uirow
= MSI_CreateRecord( 2 );
5465 MSI_RecordSetStringW( uirow
, 1, display_name
);
5466 MSI_RecordSetStringW( uirow
, 2, name
);
5467 ui_actiondata( package
, szDeleteServices
, uirow
);
5468 msiobj_release( &uirow
->hdr
);
5470 CloseServiceHandle( service
);
5471 CloseServiceHandle( scm
);
5473 msi_free( display_name
);
5475 return ERROR_SUCCESS
;
5478 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5483 static const WCHAR query
[] = {
5484 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5485 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5487 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5488 if (rc
!= ERROR_SUCCESS
)
5489 return ERROR_SUCCESS
;
5491 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
5492 msiobj_release( &view
->hdr
);
5497 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5501 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5503 if (!lstrcmpW(file
->File
, filename
))
5510 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5512 MSIPACKAGE
*package
= param
;
5513 LPWSTR driver
, driver_path
, ptr
;
5514 WCHAR outpath
[MAX_PATH
];
5515 MSIFILE
*driver_file
, *setup_file
;
5519 UINT r
= ERROR_SUCCESS
;
5521 static const WCHAR driver_fmt
[] = {
5522 'D','r','i','v','e','r','=','%','s',0};
5523 static const WCHAR setup_fmt
[] = {
5524 'S','e','t','u','p','=','%','s',0};
5525 static const WCHAR usage_fmt
[] = {
5526 'F','i','l','e','U','s','a','g','e','=','1',0};
5528 desc
= MSI_RecordGetString(rec
, 3);
5530 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5531 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5535 ERR("ODBC Driver entry not found!\n");
5536 return ERROR_FUNCTION_FAILED
;
5539 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
5541 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5542 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
5544 driver
= msi_alloc(len
* sizeof(WCHAR
));
5546 return ERROR_OUTOFMEMORY
;
5549 lstrcpyW(ptr
, desc
);
5550 ptr
+= lstrlenW(ptr
) + 1;
5552 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5557 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5561 lstrcpyW(ptr
, usage_fmt
);
5562 ptr
+= lstrlenW(ptr
) + 1;
5565 driver_path
= strdupW(driver_file
->TargetPath
);
5566 ptr
= strrchrW(driver_path
, '\\');
5567 if (ptr
) *ptr
= '\0';
5569 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5570 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5572 ERR("Failed to install SQL driver!\n");
5573 r
= ERROR_FUNCTION_FAILED
;
5576 uirow
= MSI_CreateRecord( 5 );
5577 MSI_RecordSetStringW( uirow
, 1, desc
);
5578 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5579 MSI_RecordSetStringW( uirow
, 3, driver_path
);
5580 ui_actiondata( package
, szInstallODBC
, uirow
);
5581 msiobj_release( &uirow
->hdr
);
5584 msi_free(driver_path
);
5589 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5591 MSIPACKAGE
*package
= param
;
5592 LPWSTR translator
, translator_path
, ptr
;
5593 WCHAR outpath
[MAX_PATH
];
5594 MSIFILE
*translator_file
, *setup_file
;
5598 UINT r
= ERROR_SUCCESS
;
5600 static const WCHAR translator_fmt
[] = {
5601 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5602 static const WCHAR setup_fmt
[] = {
5603 'S','e','t','u','p','=','%','s',0};
5605 desc
= MSI_RecordGetString(rec
, 3);
5607 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5608 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5610 if (!translator_file
)
5612 ERR("ODBC Translator entry not found!\n");
5613 return ERROR_FUNCTION_FAILED
;
5616 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
5618 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5620 translator
= msi_alloc(len
* sizeof(WCHAR
));
5622 return ERROR_OUTOFMEMORY
;
5625 lstrcpyW(ptr
, desc
);
5626 ptr
+= lstrlenW(ptr
) + 1;
5628 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5633 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5638 translator_path
= strdupW(translator_file
->TargetPath
);
5639 ptr
= strrchrW(translator_path
, '\\');
5640 if (ptr
) *ptr
= '\0';
5642 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5643 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5645 ERR("Failed to install SQL translator!\n");
5646 r
= ERROR_FUNCTION_FAILED
;
5649 uirow
= MSI_CreateRecord( 5 );
5650 MSI_RecordSetStringW( uirow
, 1, desc
);
5651 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5652 MSI_RecordSetStringW( uirow
, 3, translator_path
);
5653 ui_actiondata( package
, szInstallODBC
, uirow
);
5654 msiobj_release( &uirow
->hdr
);
5656 msi_free(translator
);
5657 msi_free(translator_path
);
5662 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5664 MSIPACKAGE
*package
= param
;
5666 LPCWSTR desc
, driver
;
5667 WORD request
= ODBC_ADD_SYS_DSN
;
5670 UINT r
= ERROR_SUCCESS
;
5673 static const WCHAR attrs_fmt
[] = {
5674 'D','S','N','=','%','s',0 };
5676 desc
= MSI_RecordGetString(rec
, 3);
5677 driver
= MSI_RecordGetString(rec
, 4);
5678 registration
= MSI_RecordGetInteger(rec
, 5);
5680 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5681 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5683 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
5684 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5686 return ERROR_OUTOFMEMORY
;
5688 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5691 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5693 ERR("Failed to install SQL data source!\n");
5694 r
= ERROR_FUNCTION_FAILED
;
5697 uirow
= MSI_CreateRecord( 5 );
5698 MSI_RecordSetStringW( uirow
, 1, desc
);
5699 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5700 MSI_RecordSetInteger( uirow
, 3, request
);
5701 ui_actiondata( package
, szInstallODBC
, uirow
);
5702 msiobj_release( &uirow
->hdr
);
5709 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5714 static const WCHAR driver_query
[] = {
5715 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5716 'O','D','B','C','D','r','i','v','e','r',0 };
5718 static const WCHAR translator_query
[] = {
5719 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5720 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5722 static const WCHAR source_query
[] = {
5723 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5724 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5726 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5727 if (rc
!= ERROR_SUCCESS
)
5728 return ERROR_SUCCESS
;
5730 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5731 msiobj_release(&view
->hdr
);
5733 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5734 if (rc
!= ERROR_SUCCESS
)
5735 return ERROR_SUCCESS
;
5737 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5738 msiobj_release(&view
->hdr
);
5740 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5741 if (rc
!= ERROR_SUCCESS
)
5742 return ERROR_SUCCESS
;
5744 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5745 msiobj_release(&view
->hdr
);
5750 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5752 MSIPACKAGE
*package
= param
;
5757 desc
= MSI_RecordGetString( rec
, 3 );
5758 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5760 WARN("Failed to remove ODBC driver\n");
5764 FIXME("Usage count reached 0\n");
5767 uirow
= MSI_CreateRecord( 2 );
5768 MSI_RecordSetStringW( uirow
, 1, desc
);
5769 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5770 ui_actiondata( package
, szRemoveODBC
, uirow
);
5771 msiobj_release( &uirow
->hdr
);
5773 return ERROR_SUCCESS
;
5776 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5778 MSIPACKAGE
*package
= param
;
5783 desc
= MSI_RecordGetString( rec
, 3 );
5784 if (!SQLRemoveTranslatorW( desc
, &usage
))
5786 WARN("Failed to remove ODBC translator\n");
5790 FIXME("Usage count reached 0\n");
5793 uirow
= MSI_CreateRecord( 2 );
5794 MSI_RecordSetStringW( uirow
, 1, desc
);
5795 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5796 ui_actiondata( package
, szRemoveODBC
, uirow
);
5797 msiobj_release( &uirow
->hdr
);
5799 return ERROR_SUCCESS
;
5802 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5804 MSIPACKAGE
*package
= param
;
5807 LPCWSTR desc
, driver
;
5808 WORD request
= ODBC_REMOVE_SYS_DSN
;
5812 static const WCHAR attrs_fmt
[] = {
5813 'D','S','N','=','%','s',0 };
5815 desc
= MSI_RecordGetString( rec
, 3 );
5816 driver
= MSI_RecordGetString( rec
, 4 );
5817 registration
= MSI_RecordGetInteger( rec
, 5 );
5819 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5820 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5822 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
5823 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5825 return ERROR_OUTOFMEMORY
;
5827 FIXME("Use ODBCSourceAttribute table\n");
5829 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5832 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5834 WARN("Failed to remove ODBC data source\n");
5838 uirow
= MSI_CreateRecord( 3 );
5839 MSI_RecordSetStringW( uirow
, 1, desc
);
5840 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5841 MSI_RecordSetInteger( uirow
, 3, request
);
5842 ui_actiondata( package
, szRemoveODBC
, uirow
);
5843 msiobj_release( &uirow
->hdr
);
5845 return ERROR_SUCCESS
;
5848 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5853 static const WCHAR driver_query
[] = {
5854 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5855 'O','D','B','C','D','r','i','v','e','r',0 };
5857 static const WCHAR translator_query
[] = {
5858 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5859 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5861 static const WCHAR source_query
[] = {
5862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5863 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5865 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
5866 if (rc
!= ERROR_SUCCESS
)
5867 return ERROR_SUCCESS
;
5869 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
5870 msiobj_release( &view
->hdr
);
5872 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
5873 if (rc
!= ERROR_SUCCESS
)
5874 return ERROR_SUCCESS
;
5876 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
5877 msiobj_release( &view
->hdr
);
5879 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
5880 if (rc
!= ERROR_SUCCESS
)
5881 return ERROR_SUCCESS
;
5883 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
5884 msiobj_release( &view
->hdr
);
5889 #define ENV_ACT_SETALWAYS 0x1
5890 #define ENV_ACT_SETABSENT 0x2
5891 #define ENV_ACT_REMOVE 0x4
5892 #define ENV_ACT_REMOVEMATCH 0x8
5894 #define ENV_MOD_MACHINE 0x20000000
5895 #define ENV_MOD_APPEND 0x40000000
5896 #define ENV_MOD_PREFIX 0x80000000
5897 #define ENV_MOD_MASK 0xC0000000
5899 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5901 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5903 LPCWSTR cptr
= *name
;
5905 static const WCHAR prefix
[] = {'[','~',']',0};
5906 static const int prefix_len
= 3;
5912 *flags
|= ENV_ACT_SETALWAYS
;
5913 else if (*cptr
== '+')
5914 *flags
|= ENV_ACT_SETABSENT
;
5915 else if (*cptr
== '-')
5916 *flags
|= ENV_ACT_REMOVE
;
5917 else if (*cptr
== '!')
5918 *flags
|= ENV_ACT_REMOVEMATCH
;
5919 else if (*cptr
== '*')
5920 *flags
|= ENV_MOD_MACHINE
;
5930 ERR("Missing environment variable\n");
5931 return ERROR_FUNCTION_FAILED
;
5936 LPCWSTR ptr
= *value
;
5937 if (!strncmpW(ptr
, prefix
, prefix_len
))
5939 if (ptr
[prefix_len
] == szSemiColon
[0])
5941 *flags
|= ENV_MOD_APPEND
;
5942 *value
+= lstrlenW(prefix
);
5949 else if (lstrlenW(*value
) >= prefix_len
)
5951 ptr
+= lstrlenW(ptr
) - prefix_len
;
5952 if (!lstrcmpW(ptr
, prefix
))
5954 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
5956 *flags
|= ENV_MOD_PREFIX
;
5957 /* the "[~]" will be removed by deformat_string */;
5967 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5968 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5969 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5970 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5972 ERR("Invalid flags: %08x\n", *flags
);
5973 return ERROR_FUNCTION_FAILED
;
5977 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
5979 return ERROR_SUCCESS
;
5982 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
5984 static const WCHAR user_env
[] =
5985 {'E','n','v','i','r','o','n','m','e','n','t',0};
5986 static const WCHAR machine_env
[] =
5987 {'S','y','s','t','e','m','\\',
5988 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5989 'C','o','n','t','r','o','l','\\',
5990 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5991 'E','n','v','i','r','o','n','m','e','n','t',0};
5996 if (flags
& ENV_MOD_MACHINE
)
5999 root
= HKEY_LOCAL_MACHINE
;
6004 root
= HKEY_CURRENT_USER
;
6007 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
6008 if (res
!= ERROR_SUCCESS
)
6010 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
6011 return ERROR_FUNCTION_FAILED
;
6014 return ERROR_SUCCESS
;
6017 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6019 MSIPACKAGE
*package
= param
;
6020 LPCWSTR name
, value
, component
;
6021 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
6022 DWORD flags
, type
, size
;
6029 component
= MSI_RecordGetString(rec
, 4);
6030 comp
= get_loaded_component(package
, component
);
6032 return ERROR_SUCCESS
;
6034 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6036 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6037 comp
->Action
= comp
->Installed
;
6038 return ERROR_SUCCESS
;
6040 comp
->Action
= INSTALLSTATE_LOCAL
;
6042 name
= MSI_RecordGetString(rec
, 2);
6043 value
= MSI_RecordGetString(rec
, 3);
6045 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6047 res
= env_parse_flags(&name
, &value
, &flags
);
6048 if (res
!= ERROR_SUCCESS
|| !value
)
6051 if (value
&& !deformat_string(package
, value
, &deformatted
))
6053 res
= ERROR_OUTOFMEMORY
;
6057 value
= deformatted
;
6059 res
= open_env_key( flags
, &env
);
6060 if (res
!= ERROR_SUCCESS
)
6063 if (flags
& ENV_MOD_MACHINE
)
6064 action
|= 0x20000000;
6068 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
6069 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
6070 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
6073 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
6077 /* Nothing to do. */
6080 res
= ERROR_SUCCESS
;
6084 /* If we are appending but the string was empty, strip ; */
6085 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
6087 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
6088 newval
= strdupW(value
);
6091 res
= ERROR_OUTOFMEMORY
;
6099 /* Contrary to MSDN, +-variable to [~];path works */
6100 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
6102 res
= ERROR_SUCCESS
;
6106 data
= msi_alloc(size
);
6110 return ERROR_OUTOFMEMORY
;
6113 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
6114 if (res
!= ERROR_SUCCESS
)
6117 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
6120 res
= RegDeleteValueW(env
, name
);
6121 if (res
!= ERROR_SUCCESS
)
6122 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
6126 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
6127 if (flags
& ENV_MOD_MASK
)
6131 if (flags
& ENV_MOD_APPEND
) multiplier
++;
6132 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
6133 mod_size
= lstrlenW(value
) * multiplier
;
6134 size
+= mod_size
* sizeof(WCHAR
);
6137 newval
= msi_alloc(size
);
6141 res
= ERROR_OUTOFMEMORY
;
6145 if (flags
& ENV_MOD_PREFIX
)
6147 lstrcpyW(newval
, value
);
6148 ptr
= newval
+ lstrlenW(value
);
6149 action
|= 0x80000000;
6152 lstrcpyW(ptr
, data
);
6154 if (flags
& ENV_MOD_APPEND
)
6156 lstrcatW(newval
, value
);
6157 action
|= 0x40000000;
6160 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
6161 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
6164 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
6168 uirow
= MSI_CreateRecord( 3 );
6169 MSI_RecordSetStringW( uirow
, 1, name
);
6170 MSI_RecordSetStringW( uirow
, 2, newval
);
6171 MSI_RecordSetInteger( uirow
, 3, action
);
6172 ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
6173 msiobj_release( &uirow
->hdr
);
6175 if (env
) RegCloseKey(env
);
6176 msi_free(deformatted
);
6182 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
6186 static const WCHAR ExecSeqQuery
[] =
6187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6188 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6189 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6190 if (rc
!= ERROR_SUCCESS
)
6191 return ERROR_SUCCESS
;
6193 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
6194 msiobj_release(&view
->hdr
);
6199 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6201 MSIPACKAGE
*package
= param
;
6202 LPCWSTR name
, value
, component
;
6203 LPWSTR deformatted
= NULL
;
6212 component
= MSI_RecordGetString( rec
, 4 );
6213 comp
= get_loaded_component( package
, component
);
6215 return ERROR_SUCCESS
;
6217 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6219 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6220 comp
->Action
= comp
->Installed
;
6221 return ERROR_SUCCESS
;
6223 comp
->Action
= INSTALLSTATE_ABSENT
;
6225 name
= MSI_RecordGetString( rec
, 2 );
6226 value
= MSI_RecordGetString( rec
, 3 );
6228 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6230 r
= env_parse_flags( &name
, &value
, &flags
);
6231 if (r
!= ERROR_SUCCESS
)
6234 if (!(flags
& ENV_ACT_REMOVE
))
6236 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
6237 return ERROR_SUCCESS
;
6240 if (value
&& !deformat_string( package
, value
, &deformatted
))
6241 return ERROR_OUTOFMEMORY
;
6243 value
= deformatted
;
6245 r
= open_env_key( flags
, &env
);
6246 if (r
!= ERROR_SUCCESS
)
6252 if (flags
& ENV_MOD_MACHINE
)
6253 action
|= 0x20000000;
6255 TRACE("Removing %s\n", debugstr_w(name
));
6257 res
= RegDeleteValueW( env
, name
);
6258 if (res
!= ERROR_SUCCESS
)
6260 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
6265 uirow
= MSI_CreateRecord( 3 );
6266 MSI_RecordSetStringW( uirow
, 1, name
);
6267 MSI_RecordSetStringW( uirow
, 2, value
);
6268 MSI_RecordSetInteger( uirow
, 3, action
);
6269 ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
6270 msiobj_release( &uirow
->hdr
);
6272 if (env
) RegCloseKey( env
);
6273 msi_free( deformatted
);
6277 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6281 static const WCHAR query
[] =
6282 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6283 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6285 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6286 if (rc
!= ERROR_SUCCESS
)
6287 return ERROR_SUCCESS
;
6289 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
6290 msiobj_release( &view
->hdr
);
6295 typedef struct tagMSIASSEMBLY
6298 MSICOMPONENT
*component
;
6299 MSIFEATURE
*feature
;
6303 LPWSTR display_name
;
6308 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
6310 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
6311 LPVOID pvReserved
, HMODULE
*phModDll
);
6313 static BOOL
init_functionpointers(void)
6319 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
6321 hmscoree
= LoadLibraryA("mscoree.dll");
6324 WARN("mscoree.dll not available\n");
6328 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
6329 if (!pLoadLibraryShim
)
6331 WARN("LoadLibraryShim not available\n");
6332 FreeLibrary(hmscoree
);
6336 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
6339 WARN("fusion.dll not available\n");
6340 FreeLibrary(hmscoree
);
6344 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
6346 FreeLibrary(hmscoree
);
6350 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
6353 IAssemblyCache
*cache
;
6356 UINT r
= ERROR_FUNCTION_FAILED
;
6358 TRACE("installing assembly: %s\n", debugstr_w(path
));
6360 uirow
= MSI_CreateRecord( 2 );
6361 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
6362 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
6363 msiobj_release( &uirow
->hdr
);
6365 if (assembly
->feature
)
6366 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
6368 if (assembly
->manifest
)
6369 FIXME("Manifest unhandled\n");
6371 if (assembly
->application
)
6373 FIXME("Assembly should be privately installed\n");
6374 return ERROR_SUCCESS
;
6377 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
6379 FIXME("Win32 assemblies not handled\n");
6380 return ERROR_SUCCESS
;
6383 hr
= pCreateAssemblyCache(&cache
, 0);
6387 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
6389 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
6394 IAssemblyCache_Release(cache
);
6398 typedef struct tagASSEMBLY_LIST
6400 MSIPACKAGE
*package
;
6401 IAssemblyCache
*cache
;
6402 struct list
*assemblies
;
6405 typedef struct tagASSEMBLY_NAME
6413 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
6415 ASSEMBLY_NAME
*asmname
= param
;
6416 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
6417 LPWSTR val
= msi_dup_record_field(rec
, 3);
6419 static const WCHAR Name
[] = {'N','a','m','e',0};
6420 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
6421 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
6422 static const WCHAR PublicKeyToken
[] = {
6423 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6425 if (!strcmpiW(name
, Name
))
6426 asmname
->name
= val
;
6427 else if (!strcmpiW(name
, Version
))
6428 asmname
->version
= val
;
6429 else if (!strcmpiW(name
, Culture
))
6430 asmname
->culture
= val
;
6431 else if (!strcmpiW(name
, PublicKeyToken
))
6432 asmname
->pubkeytoken
= val
;
6436 return ERROR_SUCCESS
;
6439 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
6443 *size
= lstrlenW(append
) + 1;
6444 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
6445 lstrcpyW(*str
, append
);
6449 (*size
) += lstrlenW(append
);
6450 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6451 lstrcatW(*str
, append
);
6454 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, MSICOMPONENT
*comp
)
6456 static const WCHAR separator
[] = {',',' ',0};
6457 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
6458 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
6459 static const WCHAR PublicKeyToken
[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6460 static const WCHAR query
[] = {
6461 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6462 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6463 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6464 '=','\'','%','s','\'',0};
6467 LPWSTR display_name
;
6471 display_name
= NULL
;
6472 memset( &name
, 0, sizeof(ASSEMBLY_NAME
) );
6474 r
= MSI_OpenQuery( db
, &view
, query
, comp
->Component
);
6475 if (r
!= ERROR_SUCCESS
)
6478 MSI_IterateRecords( view
, NULL
, parse_assembly_name
, &name
);
6479 msiobj_release( &view
->hdr
);
6483 ERR("No assembly name specified!\n");
6487 append_str( &display_name
, &size
, name
.name
);
6491 append_str( &display_name
, &size
, separator
);
6492 append_str( &display_name
, &size
, Version
);
6493 append_str( &display_name
, &size
, name
.version
);
6497 append_str( &display_name
, &size
, separator
);
6498 append_str( &display_name
, &size
, Culture
);
6499 append_str( &display_name
, &size
, name
.culture
);
6501 if (name
.pubkeytoken
)
6503 append_str( &display_name
, &size
, separator
);
6504 append_str( &display_name
, &size
, PublicKeyToken
);
6505 append_str( &display_name
, &size
, name
.pubkeytoken
);
6508 msi_free( name
.name
);
6509 msi_free( name
.version
);
6510 msi_free( name
.culture
);
6511 msi_free( name
.pubkeytoken
);
6513 return display_name
;
6516 static BOOL
check_assembly_installed( MSIDATABASE
*db
, IAssemblyCache
*cache
, MSICOMPONENT
*comp
)
6518 ASSEMBLY_INFO asminfo
;
6523 disp
= get_assembly_display_name( db
, comp
);
6527 memset( &asminfo
, 0, sizeof(ASSEMBLY_INFO
) );
6528 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6530 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, disp
, &asminfo
);
6532 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6538 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6540 ASSEMBLY_LIST
*list
= param
;
6541 MSIASSEMBLY
*assembly
;
6544 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6546 return ERROR_OUTOFMEMORY
;
6548 component
= MSI_RecordGetString(rec
, 1);
6549 assembly
->component
= get_loaded_component(list
->package
, component
);
6550 if (!assembly
->component
)
6551 return ERROR_SUCCESS
;
6553 if (assembly
->component
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6554 assembly
->component
->ActionRequest
!= INSTALLSTATE_SOURCE
)
6556 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6557 assembly
->component
->Action
= assembly
->component
->Installed
;
6558 return ERROR_SUCCESS
;
6560 assembly
->component
->Action
= assembly
->component
->ActionRequest
;
6562 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6563 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6565 if (!assembly
->file
)
6567 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6568 return ERROR_FUNCTION_FAILED
;
6571 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6572 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6573 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6575 if (assembly
->application
)
6578 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6580 /* FIXME: we should probably check the manifest file here */
6582 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6583 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6585 assembly
->installed
= TRUE
;
6589 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6591 assembly
->component
);
6593 list_add_head(list
->assemblies
, &assembly
->entry
);
6594 return ERROR_SUCCESS
;
6597 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6599 IAssemblyCache
*cache
= NULL
;
6605 static const WCHAR query
[] =
6606 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6607 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6609 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6610 if (r
!= ERROR_SUCCESS
)
6611 return ERROR_SUCCESS
;
6613 hr
= pCreateAssemblyCache(&cache
, 0);
6615 return ERROR_FUNCTION_FAILED
;
6617 list
.package
= package
;
6619 list
.assemblies
= assemblies
;
6621 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6622 msiobj_release(&view
->hdr
);
6624 IAssemblyCache_Release(cache
);
6629 static void free_assemblies(struct list
*assemblies
)
6631 struct list
*item
, *cursor
;
6633 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6635 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6637 list_remove(&assembly
->entry
);
6638 msi_free(assembly
->application
);
6639 msi_free(assembly
->manifest
);
6640 msi_free(assembly
->display_name
);
6645 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6647 MSIASSEMBLY
*assembly
;
6649 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6651 if (!lstrcmpW(assembly
->file
->File
, file
))
6661 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6662 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6664 MSIASSEMBLY
*assembly
;
6665 WCHAR temppath
[MAX_PATH
];
6666 struct list
*assemblies
= user
;
6669 if (!find_assembly(assemblies
, file
, &assembly
))
6672 GetTempPathW(MAX_PATH
, temppath
);
6673 PathAddBackslashW(temppath
);
6674 lstrcatW(temppath
, assembly
->file
->FileName
);
6676 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6678 if (assembly
->installed
)
6681 *path
= strdupW(temppath
);
6682 *attrs
= assembly
->file
->Attributes
;
6684 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6686 assembly
->installed
= TRUE
;
6688 r
= install_assembly(package
, assembly
, temppath
);
6689 if (r
!= ERROR_SUCCESS
)
6690 ERR("Failed to install assembly\n");
6696 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6699 struct list assemblies
= LIST_INIT(assemblies
);
6700 MSIASSEMBLY
*assembly
;
6703 if (!init_functionpointers() || !pCreateAssemblyCache
)
6704 return ERROR_FUNCTION_FAILED
;
6706 r
= load_assemblies(package
, &assemblies
);
6707 if (r
!= ERROR_SUCCESS
)
6710 if (list_empty(&assemblies
))
6713 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6716 r
= ERROR_OUTOFMEMORY
;
6720 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6722 if (assembly
->installed
&& !mi
->is_continuous
)
6725 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6726 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6730 r
= ready_media(package
, assembly
->file
, mi
);
6731 if (r
!= ERROR_SUCCESS
)
6733 ERR("Failed to ready media\n");
6738 data
.package
= package
;
6739 data
.cb
= installassembly_cb
;
6740 data
.user
= &assemblies
;
6742 if (assembly
->file
->IsCompressed
&&
6743 !msi_cabextract(package
, mi
, &data
))
6745 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6746 r
= ERROR_FUNCTION_FAILED
;
6751 if (!assembly
->file
->IsCompressed
)
6753 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6755 r
= install_assembly(package
, assembly
, source
);
6756 if (r
!= ERROR_SUCCESS
)
6757 ERR("Failed to install assembly\n");
6762 /* FIXME: write Installer assembly reg values */
6766 free_assemblies(&assemblies
);
6770 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6772 LPWSTR key
, template, id
;
6773 UINT r
= ERROR_SUCCESS
;
6775 id
= msi_dup_property( package
, szProductID
);
6779 return ERROR_SUCCESS
;
6781 template = msi_dup_property( package
, szPIDTemplate
);
6782 key
= msi_dup_property( package
, szPIDKEY
);
6784 if (key
&& template)
6786 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6787 r
= MSI_SetPropertyW( package
, szProductID
, key
);
6789 msi_free( template );
6794 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6797 package
->need_reboot
= 1;
6798 return ERROR_SUCCESS
;
6801 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6803 static const WCHAR szAvailableFreeReg
[] =
6804 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6806 int space
= msi_get_property_int( package
, szAvailableFreeReg
, 0 );
6808 TRACE("%p %d kilobytes\n", package
, space
);
6810 uirow
= MSI_CreateRecord( 1 );
6811 MSI_RecordSetInteger( uirow
, 1, space
);
6812 ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
6813 msiobj_release( &uirow
->hdr
);
6815 return ERROR_SUCCESS
;
6818 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6820 FIXME("%p\n", package
);
6821 return ERROR_SUCCESS
;
6824 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6826 FIXME("%p\n", package
);
6827 return ERROR_SUCCESS
;
6830 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6835 static const WCHAR driver_query
[] = {
6836 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6837 'O','D','B','C','D','r','i','v','e','r',0 };
6839 static const WCHAR translator_query
[] = {
6840 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6841 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6843 r
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
6844 if (r
== ERROR_SUCCESS
)
6847 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
6848 msiobj_release( &view
->hdr
);
6849 if (count
) FIXME("ignored %u rows in ODBCDriver table\n", count
);
6852 r
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
6853 if (r
== ERROR_SUCCESS
)
6856 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
6857 msiobj_release( &view
->hdr
);
6858 if (count
) FIXME("ignored %u rows in ODBCTranslator table\n", count
);
6861 return ERROR_SUCCESS
;
6864 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6865 LPCSTR action
, LPCWSTR table
)
6867 static const WCHAR query
[] = {
6868 'S','E','L','E','C','T',' ','*',' ',
6869 'F','R','O','M',' ','`','%','s','`',0 };
6870 MSIQUERY
*view
= NULL
;
6874 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6875 if (r
== ERROR_SUCCESS
)
6877 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6878 msiobj_release(&view
->hdr
);
6882 FIXME("%s -> %u ignored %s table values\n",
6883 action
, count
, debugstr_w(table
));
6885 return ERROR_SUCCESS
;
6888 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6890 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6891 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6894 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6896 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6897 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6900 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6902 static const WCHAR table
[] = {
6903 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6904 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6907 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6909 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6910 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6913 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6915 static const WCHAR table
[] = {
6916 'M','s','i','A','s','s','e','m','b','l','y',0 };
6917 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6920 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6922 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6923 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6926 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6928 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6929 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6932 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6934 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6935 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6938 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6940 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6941 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6944 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6946 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6947 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6950 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6952 static const WCHAR table
[] = { 'M','I','M','E',0 };
6953 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6956 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6960 const WCHAR
*action
;
6961 UINT (*handler
)(MSIPACKAGE
*);
6965 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6966 { szAppSearch
, ACTION_AppSearch
},
6967 { szBindImage
, ACTION_BindImage
},
6968 { szCCPSearch
, ACTION_CCPSearch
},
6969 { szCostFinalize
, ACTION_CostFinalize
},
6970 { szCostInitialize
, ACTION_CostInitialize
},
6971 { szCreateFolders
, ACTION_CreateFolders
},
6972 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6973 { szDeleteServices
, ACTION_DeleteServices
},
6974 { szDisableRollback
, ACTION_DisableRollback
},
6975 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6976 { szExecuteAction
, ACTION_ExecuteAction
},
6977 { szFileCost
, ACTION_FileCost
},
6978 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6979 { szForceReboot
, ACTION_ForceReboot
},
6980 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
6981 { szInstallExecute
, ACTION_InstallExecute
},
6982 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6983 { szInstallFiles
, ACTION_InstallFiles
},
6984 { szInstallFinalize
, ACTION_InstallFinalize
},
6985 { szInstallInitialize
, ACTION_InstallInitialize
},
6986 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6987 { szInstallValidate
, ACTION_InstallValidate
},
6988 { szIsolateComponents
, ACTION_IsolateComponents
},
6989 { szLaunchConditions
, ACTION_LaunchConditions
},
6990 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6991 { szMoveFiles
, ACTION_MoveFiles
},
6992 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6993 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6994 { szInstallODBC
, ACTION_InstallODBC
},
6995 { szInstallServices
, ACTION_InstallServices
},
6996 { szPatchFiles
, ACTION_PatchFiles
},
6997 { szProcessComponents
, ACTION_ProcessComponents
},
6998 { szPublishComponents
, ACTION_PublishComponents
},
6999 { szPublishFeatures
, ACTION_PublishFeatures
},
7000 { szPublishProduct
, ACTION_PublishProduct
},
7001 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
7002 { szRegisterComPlus
, ACTION_RegisterComPlus
},
7003 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
7004 { szRegisterFonts
, ACTION_RegisterFonts
},
7005 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
7006 { szRegisterProduct
, ACTION_RegisterProduct
},
7007 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
7008 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
7009 { szRegisterUser
, ACTION_RegisterUser
},
7010 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
7011 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
7012 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
7013 { szRemoveFiles
, ACTION_RemoveFiles
},
7014 { szRemoveFolders
, ACTION_RemoveFolders
},
7015 { szRemoveIniValues
, ACTION_RemoveIniValues
},
7016 { szRemoveODBC
, ACTION_RemoveODBC
},
7017 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
7018 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
7019 { szResolveSource
, ACTION_ResolveSource
},
7020 { szRMCCPSearch
, ACTION_RMCCPSearch
},
7021 { szScheduleReboot
, ACTION_ScheduleReboot
},
7022 { szSelfRegModules
, ACTION_SelfRegModules
},
7023 { szSelfUnregModules
, ACTION_SelfUnregModules
},
7024 { szSetODBCFolders
, ACTION_SetODBCFolders
},
7025 { szStartServices
, ACTION_StartServices
},
7026 { szStopServices
, ACTION_StopServices
},
7027 { szUnpublishComponents
, ACTION_UnpublishComponents
},
7028 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
7029 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
7030 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
7031 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
7032 { szUnregisterFonts
, ACTION_UnregisterFonts
},
7033 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
7034 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
7035 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
7036 { szValidateProductID
, ACTION_ValidateProductID
},
7037 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
7038 { szWriteIniValues
, ACTION_WriteIniValues
},
7039 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
7043 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
7044 UINT
* rc
, BOOL force
)
7050 if (!run
&& !package
->script
->CurrentlyScripting
)
7055 if (strcmpW(action
,szInstallFinalize
) == 0 ||
7056 strcmpW(action
,szInstallExecute
) == 0 ||
7057 strcmpW(action
,szInstallExecuteAgain
) == 0)
7062 while (StandardActions
[i
].action
!= NULL
)
7064 if (strcmpW(StandardActions
[i
].action
, action
)==0)
7068 ui_actioninfo(package
, action
, TRUE
, 0);
7069 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
7070 ui_actioninfo(package
, action
, FALSE
, *rc
);
7074 ui_actionstart(package
, action
);
7075 if (StandardActions
[i
].handler
)
7077 *rc
= StandardActions
[i
].handler(package
);
7081 FIXME("unhandled standard action %s\n",debugstr_w(action
));
7082 *rc
= ERROR_SUCCESS
;
7093 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
7095 UINT rc
= ERROR_SUCCESS
;
7098 TRACE("Performing action (%s)\n", debugstr_w(action
));
7100 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
7103 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
7107 WARN("unhandled msi action %s\n", debugstr_w(action
));
7108 rc
= ERROR_FUNCTION_NOT_CALLED
;
7114 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
7116 UINT rc
= ERROR_SUCCESS
;
7117 BOOL handled
= FALSE
;
7119 TRACE("Performing action (%s)\n", debugstr_w(action
));
7121 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
7124 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
7126 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
7131 WARN("unhandled msi action %s\n", debugstr_w(action
));
7132 rc
= ERROR_FUNCTION_NOT_CALLED
;
7138 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
7140 UINT rc
= ERROR_SUCCESS
;
7143 static const WCHAR ExecSeqQuery
[] =
7144 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7145 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7146 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7147 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7148 static const WCHAR UISeqQuery
[] =
7149 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7150 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7151 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7152 ' ', '=',' ','%','i',0};
7154 if (needs_ui_sequence(package
))
7155 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
7157 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
7161 LPCWSTR action
, cond
;
7163 TRACE("Running the actions\n");
7165 /* check conditions */
7166 cond
= MSI_RecordGetString(row
, 2);
7168 /* this is a hack to skip errors in the condition code */
7169 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
7171 msiobj_release(&row
->hdr
);
7172 return ERROR_SUCCESS
;
7175 action
= MSI_RecordGetString(row
, 1);
7178 ERR("failed to fetch action\n");
7179 msiobj_release(&row
->hdr
);
7180 return ERROR_FUNCTION_FAILED
;
7183 if (needs_ui_sequence(package
))
7184 rc
= ACTION_PerformUIAction(package
, action
, -1);
7186 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
7188 msiobj_release(&row
->hdr
);
7194 /****************************************************
7195 * TOP level entry points
7196 *****************************************************/
7198 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
7199 LPCWSTR szCommandLine
)
7204 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
7205 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
7207 MSI_SetPropertyW(package
, szAction
, szInstall
);
7209 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
7216 dir
= strdupW(szPackagePath
);
7217 p
= strrchrW(dir
, '\\');
7221 file
= szPackagePath
+ (p
- dir
);
7226 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
7227 GetCurrentDirectoryW(MAX_PATH
, dir
);
7228 lstrcatW(dir
, szBackSlash
);
7229 file
= szPackagePath
;
7232 msi_free( package
->PackagePath
);
7233 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
7234 if (!package
->PackagePath
)
7237 return ERROR_OUTOFMEMORY
;
7240 lstrcpyW(package
->PackagePath
, dir
);
7241 lstrcatW(package
->PackagePath
, file
);
7244 msi_set_sourcedir_props(package
, FALSE
);
7247 msi_parse_command_line( package
, szCommandLine
, FALSE
);
7249 msi_apply_transforms( package
);
7250 msi_apply_patches( package
);
7252 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
7254 TRACE("setting reinstall property\n");
7255 MSI_SetPropertyW( package
, szReinstall
, szAll
);
7258 /* properties may have been added by a transform */
7259 msi_clone_properties( package
);
7260 msi_set_context( package
);
7262 if (needs_ui_sequence( package
))
7264 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
7265 rc
= ACTION_ProcessUISequence(package
);
7266 ui_exists
= ui_sequence_exists(package
);
7267 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
7269 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
7270 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
7274 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
7276 package
->script
->CurrentlyScripting
= FALSE
;
7278 /* process the ending type action */
7279 if (rc
== ERROR_SUCCESS
)
7280 ACTION_PerformActionSequence(package
, -1);
7281 else if (rc
== ERROR_INSTALL_USEREXIT
)
7282 ACTION_PerformActionSequence(package
, -2);
7283 else if (rc
== ERROR_INSTALL_SUSPEND
)
7284 ACTION_PerformActionSequence(package
, -4);
7286 ACTION_PerformActionSequence(package
, -3);
7288 /* finish up running custom actions */
7289 ACTION_FinishCustomActions(package
);
7291 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
7292 return ERROR_SUCCESS_REBOOT_REQUIRED
;