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"
39 #include "wine/unicode.h"
42 #define REG_PROGRESS_VALUE 13200
43 #define COMPONENT_PROGRESS_VALUE 24000
45 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
47 static const WCHAR szCreateFolders
[] =
48 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
49 static const WCHAR szCostFinalize
[] =
50 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
51 static const WCHAR szWriteRegistryValues
[] =
52 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
53 static const WCHAR szFileCost
[] =
54 {'F','i','l','e','C','o','s','t',0};
55 static const WCHAR szInstallInitialize
[] =
56 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
57 static const WCHAR szInstallValidate
[] =
58 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
59 static const WCHAR szLaunchConditions
[] =
60 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
61 static const WCHAR szProcessComponents
[] =
62 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
63 static const WCHAR szRegisterTypeLibraries
[] =
64 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
65 static const WCHAR szCreateShortcuts
[] =
66 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
67 static const WCHAR szPublishProduct
[] =
68 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
69 static const WCHAR szWriteIniValues
[] =
70 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
71 static const WCHAR szSelfRegModules
[] =
72 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
73 static const WCHAR szPublishFeatures
[] =
74 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
75 static const WCHAR szRegisterProduct
[] =
76 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
77 static const WCHAR szInstallExecute
[] =
78 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
79 static const WCHAR szInstallExecuteAgain
[] =
80 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
81 static const WCHAR szInstallFinalize
[] =
82 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
83 static const WCHAR szForceReboot
[] =
84 {'F','o','r','c','e','R','e','b','o','o','t',0};
85 static const WCHAR szResolveSource
[] =
86 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
87 static const WCHAR szAllocateRegistrySpace
[] =
88 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
89 static const WCHAR szBindImage
[] =
90 {'B','i','n','d','I','m','a','g','e',0};
91 static const WCHAR szDeleteServices
[] =
92 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
93 static const WCHAR szDisableRollback
[] =
94 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
95 static const WCHAR szExecuteAction
[] =
96 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
97 static const WCHAR szInstallAdminPackage
[] =
98 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
99 static const WCHAR szInstallSFPCatalogFile
[] =
100 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
101 static const WCHAR szIsolateComponents
[] =
102 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
103 static const WCHAR szMigrateFeatureStates
[] =
104 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
105 static const WCHAR szMsiUnpublishAssemblies
[] =
106 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
107 static const WCHAR szInstallODBC
[] =
108 {'I','n','s','t','a','l','l','O','D','B','C',0};
109 static const WCHAR szInstallServices
[] =
110 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
111 static const WCHAR szPublishComponents
[] =
112 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
113 static const WCHAR szRegisterComPlus
[] =
114 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
115 static const WCHAR szRegisterUser
[] =
116 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
117 static const WCHAR szRemoveEnvironmentStrings
[] =
118 {'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};
119 static const WCHAR szRemoveExistingProducts
[] =
120 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
121 static const WCHAR szRemoveFolders
[] =
122 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
123 static const WCHAR szRemoveIniValues
[] =
124 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
125 static const WCHAR szRemoveODBC
[] =
126 {'R','e','m','o','v','e','O','D','B','C',0};
127 static const WCHAR szRemoveRegistryValues
[] =
128 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
129 static const WCHAR szRemoveShortcuts
[] =
130 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
131 static const WCHAR szRMCCPSearch
[] =
132 {'R','M','C','C','P','S','e','a','r','c','h',0};
133 static const WCHAR szScheduleReboot
[] =
134 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
135 static const WCHAR szSelfUnregModules
[] =
136 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
137 static const WCHAR szSetODBCFolders
[] =
138 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
139 static const WCHAR szStartServices
[] =
140 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
141 static const WCHAR szStopServices
[] =
142 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
143 static const WCHAR szUnpublishComponents
[] =
144 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
145 static const WCHAR szUnpublishFeatures
[] =
146 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
147 static const WCHAR szUnregisterComPlus
[] =
148 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
149 static const WCHAR szUnregisterTypeLibraries
[] =
150 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
151 static const WCHAR szValidateProductID
[] =
152 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
153 static const WCHAR szWriteEnvironmentStrings
[] =
154 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
156 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
158 static const WCHAR Query_t
[] =
159 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
160 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
161 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
162 ' ','\'','%','s','\'',0};
165 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
168 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
169 msiobj_release(&row
->hdr
);
172 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
176 static const WCHAR template_s
[]=
177 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
179 static const WCHAR template_e
[]=
180 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
181 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
183 static const WCHAR format
[] =
184 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
188 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
190 sprintfW(message
,template_s
,timet
,action
);
192 sprintfW(message
,template_e
,timet
,action
,rc
);
194 row
= MSI_CreateRecord(1);
195 MSI_RecordSetStringW(row
,1,message
);
197 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
198 msiobj_release(&row
->hdr
);
208 static int parse_prop( const WCHAR
*str
, WCHAR
*value
, int *quotes
)
210 enum parse_state state
= state_quote
;
213 int ignore
, in_quotes
= 0, count
= 0, len
= 0;
215 for (p
= str
; *p
; p
++)
220 case state_whitespace
:
224 if (!count
) goto done
;
231 if (in_quotes
) count
--;
236 if (!count
) in_quotes
= 0;
248 if (in_quotes
) count
--;
252 state
= state_whitespace
;
253 if (!count
) goto done
;
258 if (!count
) in_quotes
= 0;
269 if (in_quotes
) count
--;
273 state
= state_whitespace
;
274 if (!count
|| (count
> 1 && !len
)) goto done
;
280 if (!count
) in_quotes
= 0;
289 if (!ignore
) *out
++ = *p
;
293 if (!len
) *value
= 0;
300 static void remove_quotes( WCHAR
*str
)
303 int len
= strlenW( str
);
305 while ((p
= strchrW( p
, '"' )))
307 memmove( p
, p
+ 1, (len
- (p
- str
)) * sizeof(WCHAR
) );
312 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
322 return ERROR_SUCCESS
;
327 while (*ptr
== ' ') ptr
++;
330 ptr2
= strchrW( ptr
, '=' );
331 if (!ptr2
) return ERROR_INVALID_COMMAND_LINE
;
334 if (!len
) return ERROR_INVALID_COMMAND_LINE
;
336 prop
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) );
337 memcpy( prop
, ptr
, len
* sizeof(WCHAR
) );
339 if (!preserve_case
) struprW( prop
);
342 while (*ptr2
== ' ') ptr2
++;
345 val
= msi_alloc( (strlenW( ptr2
) + 1) * sizeof(WCHAR
) );
346 len
= parse_prop( ptr2
, val
, &num_quotes
);
349 WARN("unbalanced quotes\n");
352 return ERROR_INVALID_COMMAND_LINE
;
354 remove_quotes( val
);
355 TRACE("Found commandline property %s = %s\n", debugstr_w(prop
), debugstr_w(val
));
357 r
= msi_set_property( package
->db
, prop
, val
);
358 if (r
== ERROR_SUCCESS
&& !strcmpW( prop
, szSourceDir
))
359 msi_reset_folders( package
, TRUE
);
367 return ERROR_SUCCESS
;
370 WCHAR
**msi_split_string( const WCHAR
*str
, WCHAR sep
)
373 LPWSTR p
, *ret
= NULL
;
379 /* count the number of substrings */
380 for ( pc
= str
, count
= 0; pc
; count
++ )
382 pc
= strchrW( pc
, sep
);
387 /* allocate space for an array of substring pointers and the substrings */
388 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
389 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
393 /* copy the string and set the pointers */
394 p
= (LPWSTR
) &ret
[count
+1];
396 for( count
= 0; (ret
[count
] = p
); count
++ )
398 p
= strchrW( p
, sep
);
406 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
408 static const WCHAR szSystemLanguageID
[] =
409 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
411 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
412 UINT ret
= ERROR_FUNCTION_FAILED
;
414 prod_code
= msi_dup_property( package
->db
, szProductCode
);
415 patch_product
= msi_get_suminfo_product( patch
);
417 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
419 if ( strstrW( patch_product
, prod_code
) )
424 si
= MSI_GetSummaryInformationW( patch
, 0 );
427 ERR("no summary information!\n");
431 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
434 ERR("no template property!\n");
435 msiobj_release( &si
->hdr
);
442 msiobj_release( &si
->hdr
);
446 langid
= msi_dup_property( package
->db
, szSystemLanguageID
);
449 msiobj_release( &si
->hdr
);
453 p
= strchrW( template, ';' );
454 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, szZero
)))
456 TRACE("applicable transform\n");
460 /* FIXME: check platform */
462 msiobj_release( &si
->hdr
);
466 msi_free( patch_product
);
467 msi_free( prod_code
);
468 msi_free( template );
474 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
475 MSIDATABASE
*patch_db
, LPCWSTR name
)
477 UINT ret
= ERROR_FUNCTION_FAILED
;
478 IStorage
*stg
= NULL
;
481 TRACE("%p %s\n", package
, debugstr_w(name
) );
485 ERR("expected a colon in %s\n", debugstr_w(name
));
486 return ERROR_FUNCTION_FAILED
;
489 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
492 ret
= msi_check_transform_applicable( package
, stg
);
493 if (ret
== ERROR_SUCCESS
)
494 msi_table_apply_transform( package
->db
, stg
);
496 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
497 IStorage_Release( stg
);
500 ERR("failed to open substorage %s\n", debugstr_w(name
));
502 return ERROR_SUCCESS
;
505 UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
507 LPWSTR guid_list
, *guids
, product_code
;
508 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
510 product_code
= msi_dup_property( package
->db
, szProductCode
);
513 /* FIXME: the property ProductCode should be written into the DB somewhere */
514 ERR("no product code to check\n");
515 return ERROR_SUCCESS
;
518 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
519 guids
= msi_split_string( guid_list
, ';' );
520 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
522 if (!strcmpW( guids
[i
], product_code
))
526 msi_free( guid_list
);
527 msi_free( product_code
);
532 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
535 MSIRECORD
*rec
= NULL
;
540 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
541 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
542 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
543 '`','S','o','u','r','c','e','`',' ','I','S',' ',
544 'N','O','T',' ','N','U','L','L',0};
546 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
547 if (r
!= ERROR_SUCCESS
)
550 r
= MSI_ViewExecute(view
, 0);
551 if (r
!= ERROR_SUCCESS
)
554 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
556 prop
= MSI_RecordGetString(rec
, 1);
557 patch
= msi_dup_property(package
->db
, szPatch
);
558 msi_set_property(package
->db
, prop
, patch
);
563 if (rec
) msiobj_release(&rec
->hdr
);
564 msiobj_release(&view
->hdr
);
569 UINT
msi_parse_patch_summary( MSISUMMARYINFO
*si
, MSIPATCHINFO
**patch
)
572 UINT r
= ERROR_SUCCESS
;
575 pi
= msi_alloc_zero( sizeof(MSIPATCHINFO
) );
577 return ERROR_OUTOFMEMORY
;
579 pi
->patchcode
= msi_suminfo_dup_string( si
, PID_REVNUMBER
);
583 return ERROR_OUTOFMEMORY
;
589 msi_free( pi
->patchcode
);
591 return ERROR_PATCH_PACKAGE_INVALID
;
594 p
= strchrW( p
+ 1, '}' );
597 msi_free( pi
->patchcode
);
599 return ERROR_PATCH_PACKAGE_INVALID
;
604 FIXME("patch obsoletes %s\n", debugstr_w(p
+ 1));
608 TRACE("patch code %s\n", debugstr_w(pi
->patchcode
));
610 pi
->transforms
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
613 msi_free( pi
->patchcode
);
615 return ERROR_OUTOFMEMORY
;
622 struct msi_patch_offset
629 struct msi_patch_offset_list
632 UINT count
, min
, max
;
633 UINT offset_to_apply
;
636 static struct msi_patch_offset_list
*msi_patch_offset_list_create(void)
638 struct msi_patch_offset_list
*pos
= msi_alloc(sizeof(struct msi_patch_offset_list
));
639 list_init( &pos
->files
);
640 pos
->count
= pos
->max
= 0;
646 static void msi_patch_offset_list_free(struct msi_patch_offset_list
*pos
)
648 struct msi_patch_offset
*po
, *po2
;
650 LIST_FOR_EACH_ENTRY_SAFE( po
, po2
, &pos
->files
, struct msi_patch_offset
, entry
)
652 msi_free( po
->Name
);
659 static void msi_patch_offset_get_patches(MSIDATABASE
*db
, UINT last_sequence
, struct msi_patch_offset_list
*pos
)
664 static const WCHAR query_patch
[] = {
665 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
666 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
667 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
669 r
= MSI_DatabaseOpenViewW( db
, query_patch
, &view
);
670 if (r
!= ERROR_SUCCESS
)
673 rec
= MSI_CreateRecord( 1 );
674 MSI_RecordSetInteger(rec
, 1, last_sequence
);
676 r
= MSI_ViewExecute( view
, rec
);
677 msiobj_release( &rec
->hdr
);
678 if (r
!= ERROR_SUCCESS
)
681 while (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
683 UINT sequence
= MSI_RecordGetInteger( rec
, 2 );
686 * We only use the max/min sequence numbers for now.
689 pos
->min
= min(pos
->min
, sequence
);
690 pos
->max
= max(pos
->max
, sequence
);
693 msiobj_release( &rec
->hdr
);
696 msiobj_release( &view
->hdr
);
699 static void msi_patch_offset_get_files(MSIDATABASE
*db
, UINT last_sequence
, struct msi_patch_offset_list
*pos
)
704 static const WCHAR query_files
[] = {
705 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
706 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
707 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
709 r
= MSI_DatabaseOpenViewW( db
, query_files
, &view
);
710 if (r
!= ERROR_SUCCESS
)
713 rec
= MSI_CreateRecord( 1 );
714 MSI_RecordSetInteger(rec
, 1, last_sequence
);
716 r
= MSI_ViewExecute( view
, rec
);
717 msiobj_release( &rec
->hdr
);
718 if (r
!= ERROR_SUCCESS
)
721 while (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
723 UINT attributes
= MSI_RecordGetInteger( rec
, 7 );
724 if (attributes
& msidbFileAttributesPatchAdded
)
726 struct msi_patch_offset
*po
= msi_alloc(sizeof(struct msi_patch_offset
));
728 po
->Name
= msi_dup_record_field( rec
, 1 );
729 po
->Sequence
= MSI_RecordGetInteger( rec
, 8 );
731 pos
->min
= min(pos
->min
, po
->Sequence
);
732 pos
->max
= max(pos
->max
, po
->Sequence
);
734 list_add_tail( &pos
->files
, &po
->entry
);
737 msiobj_release( &rec
->hdr
);
740 msiobj_release( &view
->hdr
);
743 static UINT
msi_patch_offset_modify_db(MSIDATABASE
*db
, struct msi_patch_offset_list
*pos
)
745 static const WCHAR query_files
[] =
746 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
747 'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
748 'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
749 'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
750 struct msi_patch_offset
*po
;
755 r
= MSI_DatabaseOpenViewW( db
, query_files
, &view
);
756 if (r
!= ERROR_SUCCESS
)
757 return ERROR_SUCCESS
;
759 rec
= MSI_CreateRecord( 2 );
760 MSI_RecordSetInteger( rec
, 1, pos
->min
);
761 MSI_RecordSetInteger( rec
, 2, pos
->max
);
763 r
= MSI_ViewExecute( view
, rec
);
764 msiobj_release( &rec
->hdr
);
765 if (r
!= ERROR_SUCCESS
)
768 LIST_FOR_EACH_ENTRY( po
, &pos
->files
, struct msi_patch_offset
, entry
)
771 while ( (r_fetch
= MSI_ViewFetch( view
, &rec
)) == ERROR_SUCCESS
)
773 LPCWSTR file
= MSI_RecordGetString( rec
, 1 );
776 if (!strcmpiW(file
, po
->Name
))
779 seq
= MSI_RecordGetInteger( rec
, 8 );
780 MSI_RecordSetInteger( rec
, 8, seq
+ pos
->offset_to_apply
);
781 r
= MSI_ViewModify( view
, MSIMODIFY_UPDATE
, rec
);
782 if (r
!= ERROR_SUCCESS
)
783 ERR("Failed to update offset for file %s.\n", debugstr_w(file
));
785 msiobj_release( &rec
->hdr
);
789 msiobj_release( &rec
->hdr
);
792 if (r_fetch
!= ERROR_SUCCESS
)
797 msiobj_release( &view
->hdr
);
799 return ERROR_SUCCESS
;
802 static const WCHAR patch_media_query
[] = {
803 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
804 'W','H','E','R','E',' ','`','S','o','u','r','c','e','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
805 'A','N','D',' ','`','C','a','b','i','n','e','t','`',' ','I','S',' ','N','O','T',' ','N','U','L','L',' ',
806 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
819 static UINT
msi_add_patch_media( MSIPACKAGE
*package
, IStorage
*patch
)
821 static const WCHAR delete_query
[] = {
822 'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
823 'W','H','E','R','E',' ','`','D','i','s','k','I','d','`','=','?',0};
824 static const WCHAR insert_query
[] = {
825 'I','N','S','E','R','T',' ','I','N','T','O',' ','`','M','e','d','i','a','`',' ',
826 '(','`','D','i','s','k','I','d','`',',','`','L','a','s','t','S','e','q','u','e','n','c','e','`',',',
827 '`','D','i','s','k','P','r','o','m','p','t','`',',','`','C','a','b','i','n','e','t','`',',',
828 '`','V','o','l','u','m','e','L','a','b','e','l','`',',','`','S','o','u','r','c','e','`',')',' ',
829 'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
831 MSIRECORD
*rec
= NULL
;
833 struct list media_list
;
834 struct patch_media
*media
, *next
;
836 r
= MSI_DatabaseOpenViewW( package
->db
, patch_media_query
, &view
);
837 if (r
!= ERROR_SUCCESS
) return r
;
839 r
= MSI_ViewExecute( view
, 0 );
840 if (r
!= ERROR_SUCCESS
)
842 msiobj_release( &view
->hdr
);
843 TRACE("query failed %u\n", r
);
847 list_init( &media_list
);
848 while (MSI_ViewFetch( view
, &rec
) == ERROR_SUCCESS
)
850 disk_id
= MSI_RecordGetInteger( rec
, 1 );
851 TRACE("disk_id %u\n", disk_id
);
852 if (disk_id
>= MSI_INITIAL_MEDIA_TRANSFORM_DISKID
)
854 msiobj_release( &rec
->hdr
);
857 if (!(media
= msi_alloc( sizeof( *media
)))) goto done
;
858 media
->disk_id
= disk_id
;
859 media
->last_sequence
= MSI_RecordGetInteger( rec
, 2 );
860 media
->prompt
= msi_dup_record_field( rec
, 3 );
861 media
->cabinet
= msi_dup_record_field( rec
, 4 );
862 media
->volume
= msi_dup_record_field( rec
, 5 );
863 media
->source
= msi_dup_record_field( rec
, 6 );
865 list_add_tail( &media_list
, &media
->entry
);
866 msiobj_release( &rec
->hdr
);
868 LIST_FOR_EACH_ENTRY( media
, &media_list
, struct patch_media
, entry
)
870 MSIQUERY
*delete_view
, *insert_view
;
872 r
= MSI_DatabaseOpenViewW( package
->db
, delete_query
, &delete_view
);
873 if (r
!= ERROR_SUCCESS
) goto done
;
875 rec
= MSI_CreateRecord( 1 );
876 MSI_RecordSetInteger( rec
, 1, media
->disk_id
);
878 r
= MSI_ViewExecute( delete_view
, rec
);
879 msiobj_release( &delete_view
->hdr
);
880 msiobj_release( &rec
->hdr
);
881 if (r
!= ERROR_SUCCESS
) goto done
;
883 r
= MSI_DatabaseOpenViewW( package
->db
, insert_query
, &insert_view
);
884 if (r
!= ERROR_SUCCESS
) goto done
;
886 disk_id
= package
->db
->media_transform_disk_id
;
887 TRACE("disk id %u\n", disk_id
);
888 TRACE("last sequence %u\n", media
->last_sequence
);
889 TRACE("prompt %s\n", debugstr_w(media
->prompt
));
890 TRACE("cabinet %s\n", debugstr_w(media
->cabinet
));
891 TRACE("volume %s\n", debugstr_w(media
->volume
));
892 TRACE("source %s\n", debugstr_w(media
->source
));
894 rec
= MSI_CreateRecord( 6 );
895 MSI_RecordSetInteger( rec
, 1, disk_id
);
896 MSI_RecordSetInteger( rec
, 2, media
->last_sequence
);
897 MSI_RecordSetStringW( rec
, 3, media
->prompt
);
898 MSI_RecordSetStringW( rec
, 4, media
->cabinet
);
899 MSI_RecordSetStringW( rec
, 5, media
->volume
);
900 MSI_RecordSetStringW( rec
, 6, media
->source
);
902 r
= MSI_ViewExecute( insert_view
, rec
);
903 msiobj_release( &insert_view
->hdr
);
904 msiobj_release( &rec
->hdr
);
905 if (r
!= ERROR_SUCCESS
) goto done
;
907 r
= msi_add_cabinet_stream( package
, disk_id
, patch
, media
->cabinet
);
908 if (r
!= ERROR_SUCCESS
) WARN("failed to add cabinet stream %u\n", r
);
909 package
->db
->media_transform_disk_id
++;
913 msiobj_release( &view
->hdr
);
914 LIST_FOR_EACH_ENTRY_SAFE( media
, next
, &media_list
, struct patch_media
, entry
)
916 list_remove( &media
->entry
);
917 msi_free( media
->prompt
);
918 msi_free( media
->cabinet
);
919 msi_free( media
->volume
);
920 msi_free( media
->source
);
926 static UINT
msi_set_patch_offsets(MSIDATABASE
*db
)
929 MSIRECORD
*rec
= NULL
;
932 r
= MSI_DatabaseOpenViewW( db
, patch_media_query
, &view
);
933 if (r
!= ERROR_SUCCESS
)
936 r
= MSI_ViewExecute( view
, 0 );
937 if (r
!= ERROR_SUCCESS
)
940 while (MSI_ViewFetch( view
, &rec
) == ERROR_SUCCESS
)
942 UINT last_sequence
= MSI_RecordGetInteger( rec
, 2 );
943 struct msi_patch_offset_list
*pos
;
945 /* FIXME: Set/Check Source field instead? */
946 if (last_sequence
>= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
)
948 msiobj_release( &rec
->hdr
);
952 pos
= msi_patch_offset_list_create();
954 msi_patch_offset_get_files( db
, last_sequence
, pos
);
955 msi_patch_offset_get_patches( db
, last_sequence
, pos
);
959 UINT offset
= db
->media_transform_offset
- pos
->min
;
960 last_sequence
= offset
+ pos
->max
;
963 * This is for the patch table, which is not yet properly transformed.
965 last_sequence
+= pos
->min
;
967 pos
->offset_to_apply
= offset
;
968 msi_patch_offset_modify_db( db
, pos
);
970 MSI_RecordSetInteger( rec
, 2, last_sequence
);
971 r
= MSI_ViewModify( view
, MSIMODIFY_UPDATE
, rec
);
972 if (r
!= ERROR_SUCCESS
)
973 ERR("Failed to update Media table entry, expect breakage (%u).\n", r
);
975 db
->media_transform_offset
= last_sequence
+ 1;
978 msi_patch_offset_list_free( pos
);
979 msiobj_release( &rec
->hdr
);
983 msiobj_release( &view
->hdr
);
987 UINT
msi_apply_patch_db( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
, MSIPATCHINFO
*patch
)
989 UINT i
, r
= ERROR_SUCCESS
;
992 /* apply substorage transforms */
993 substorage
= msi_split_string( patch
->transforms
, ';' );
994 for (i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++)
996 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
997 if (r
== ERROR_SUCCESS
)
999 msi_add_patch_media( package
, patch_db
->storage
);
1000 msi_set_patch_offsets( package
->db
);
1004 msi_free( substorage
);
1005 if (r
!= ERROR_SUCCESS
)
1008 msi_set_media_source_prop( package
);
1010 patch
->state
= MSIPATCHSTATE_APPLIED
;
1011 list_add_tail( &package
->patches
, &patch
->entry
);
1012 return ERROR_SUCCESS
;
1015 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
1017 static const WCHAR dotmsp
[] = {'.','m','s','p',0};
1018 MSIDATABASE
*patch_db
= NULL
;
1019 WCHAR localfile
[MAX_PATH
];
1021 MSIPATCHINFO
*patch
= NULL
;
1022 UINT r
= ERROR_SUCCESS
;
1024 TRACE("%p %s\n", package
, debugstr_w( file
) );
1026 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &patch_db
);
1027 if ( r
!= ERROR_SUCCESS
)
1029 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
1033 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
1036 msiobj_release( &patch_db
->hdr
);
1037 return ERROR_FUNCTION_FAILED
;
1040 r
= msi_check_patch_applicable( package
, si
);
1041 if (r
!= ERROR_SUCCESS
)
1043 TRACE("patch not applicable\n");
1048 r
= msi_parse_patch_summary( si
, &patch
);
1049 if ( r
!= ERROR_SUCCESS
)
1052 r
= msi_get_local_package_name( localfile
, dotmsp
);
1053 if ( r
!= ERROR_SUCCESS
)
1056 TRACE("copying to local package %s\n", debugstr_w(localfile
));
1058 if (!CopyFileW( file
, localfile
, FALSE
))
1060 ERR("Unable to copy package (%s -> %s) (error %u)\n",
1061 debugstr_w(file
), debugstr_w(localfile
), GetLastError());
1065 patch
->localfile
= strdupW( localfile
);
1067 r
= msi_apply_patch_db( package
, patch_db
, patch
);
1068 if ( r
!= ERROR_SUCCESS
)
1069 WARN("patch failed to apply %u\n", r
);
1072 msiobj_release( &si
->hdr
);
1073 msiobj_release( &patch_db
->hdr
);
1074 if (patch
&& r
!= ERROR_SUCCESS
)
1076 if (patch
->localfile
)
1077 DeleteFileW( patch
->localfile
);
1079 msi_free( patch
->patchcode
);
1080 msi_free( patch
->transforms
);
1081 msi_free( patch
->localfile
);
1087 /* get the PATCH property, and apply all the patches it specifies */
1088 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
1090 LPWSTR patch_list
, *patches
;
1091 UINT i
, r
= ERROR_SUCCESS
;
1093 patch_list
= msi_dup_property( package
->db
, szPatch
);
1095 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
1097 patches
= msi_split_string( patch_list
, ';' );
1098 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
1099 r
= msi_apply_patch_package( package
, patches
[i
] );
1101 msi_free( patches
);
1102 msi_free( patch_list
);
1107 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
1109 static const WCHAR szTransforms
[] = {
1110 'T','R','A','N','S','F','O','R','M','S',0 };
1111 LPWSTR xform_list
, *xforms
;
1112 UINT i
, r
= ERROR_SUCCESS
;
1114 xform_list
= msi_dup_property( package
->db
, szTransforms
);
1115 xforms
= msi_split_string( xform_list
, ';' );
1117 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
1119 if (xforms
[i
][0] == ':')
1120 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
1125 if (!PathIsRelativeW( xforms
[i
] )) transform
= xforms
[i
];
1128 WCHAR
*p
= strrchrW( package
->PackagePath
, '\\' );
1129 DWORD len
= p
- package
->PackagePath
+ 1;
1131 if (!(transform
= msi_alloc( (len
+ strlenW( xforms
[i
] ) + 1) * sizeof(WCHAR
)) ))
1134 msi_free( xform_list
);
1135 return ERROR_OUTOFMEMORY
;
1137 memcpy( transform
, package
->PackagePath
, len
* sizeof(WCHAR
) );
1138 memcpy( transform
+ len
, xforms
[i
], (strlenW( xforms
[i
] ) + 1) * sizeof(WCHAR
) );
1140 r
= MSI_DatabaseApplyTransformW( package
->db
, transform
, 0 );
1141 if (transform
!= xforms
[i
]) msi_free( transform
);
1146 msi_free( xform_list
);
1151 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
1156 static const WCHAR ExecSeqQuery
[] =
1157 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1158 '`','I','n','s','t','a','l','l',
1159 'U','I','S','e','q','u','e','n','c','e','`',
1160 ' ','W','H','E','R','E',' ',
1161 '`','S','e','q','u','e','n','c','e','`',' ',
1162 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1163 '`','S','e','q','u','e','n','c','e','`',0};
1165 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1166 if (rc
== ERROR_SUCCESS
)
1168 msiobj_release(&view
->hdr
);
1175 UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
1177 LPWSTR source
, check
;
1179 if (msi_get_property_int( package
->db
, szInstalled
, 0 ))
1183 MSIREG_OpenInstallProps( package
->ProductCode
, package
->Context
, NULL
, &hkey
, FALSE
);
1184 source
= msi_reg_get_val_str( hkey
, INSTALLPROPERTY_INSTALLSOURCEW
);
1185 RegCloseKey( hkey
);
1192 db
= msi_dup_property( package
->db
, szOriginalDatabase
);
1194 return ERROR_OUTOFMEMORY
;
1196 p
= strrchrW( db
, '\\' );
1199 p
= strrchrW( db
, '/' );
1203 return ERROR_SUCCESS
;
1208 source
= msi_alloc( len
* sizeof(WCHAR
) );
1209 lstrcpynW( source
, db
, len
);
1213 check
= msi_dup_property( package
->db
, szSourceDir
);
1214 if (!check
|| replace
)
1216 UINT r
= msi_set_property( package
->db
, szSourceDir
, source
);
1217 if (r
== ERROR_SUCCESS
)
1218 msi_reset_folders( package
, TRUE
);
1222 check
= msi_dup_property( package
->db
, szSOURCEDIR
);
1223 if (!check
|| replace
)
1224 msi_set_property( package
->db
, szSOURCEDIR
, source
);
1229 return ERROR_SUCCESS
;
1232 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
1234 INT level
= msi_get_property_int(package
->db
, szUILevel
, 0);
1235 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
1238 UINT
msi_set_context(MSIPACKAGE
*package
)
1242 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
1244 num
= msi_get_property_int(package
->db
, szAllUsers
, 0);
1245 if (num
== 1 || num
== 2)
1246 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
1248 return ERROR_SUCCESS
;
1251 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
1254 LPCWSTR cond
, action
;
1255 MSIPACKAGE
*package
= param
;
1257 action
= MSI_RecordGetString(row
,1);
1260 ERR("Error is retrieving action name\n");
1261 return ERROR_FUNCTION_FAILED
;
1264 /* check conditions */
1265 cond
= MSI_RecordGetString(row
,2);
1267 /* this is a hack to skip errors in the condition code */
1268 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
1270 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
1271 return ERROR_SUCCESS
;
1274 if (needs_ui_sequence(package
))
1275 rc
= ACTION_PerformUIAction(package
, action
, -1);
1277 rc
= ACTION_PerformAction(package
, action
, -1);
1279 msi_dialog_check_messages( NULL
);
1281 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
1282 rc
= package
->CurrentInstallState
;
1284 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1287 if (rc
!= ERROR_SUCCESS
)
1288 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
1293 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
1297 static const WCHAR query
[] =
1298 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1300 ' ','W','H','E','R','E',' ',
1301 '`','S','e','q','u','e','n','c','e','`',' ',
1302 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1303 '`','S','e','q','u','e','n','c','e','`',0};
1305 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
1307 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
1308 if (r
== ERROR_SUCCESS
)
1310 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
1311 msiobj_release(&view
->hdr
);
1317 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
1321 static const WCHAR ExecSeqQuery
[] =
1322 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1323 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1324 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1325 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1326 'O','R','D','E','R',' ', 'B','Y',' ',
1327 '`','S','e','q','u','e','n','c','e','`',0 };
1328 static const WCHAR IVQuery
[] =
1329 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1330 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1331 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1332 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1333 ' ','\'', 'I','n','s','t','a','l','l',
1334 'V','a','l','i','d','a','t','e','\'', 0};
1337 if (package
->script
->ExecuteSequenceRun
)
1339 TRACE("Execute Sequence already Run\n");
1340 return ERROR_SUCCESS
;
1343 package
->script
->ExecuteSequenceRun
= TRUE
;
1345 /* get the sequence number */
1348 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
1350 return ERROR_FUNCTION_FAILED
;
1351 seq
= MSI_RecordGetInteger(row
,1);
1352 msiobj_release(&row
->hdr
);
1355 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
1356 if (rc
== ERROR_SUCCESS
)
1358 TRACE("Running the actions\n");
1360 msi_set_property(package
->db
, szSourceDir
, NULL
);
1362 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
1363 msiobj_release(&view
->hdr
);
1369 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
1373 static const WCHAR ExecSeqQuery
[] =
1374 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1375 '`','I','n','s','t','a','l','l',
1376 'U','I','S','e','q','u','e','n','c','e','`',
1377 ' ','W','H','E','R','E',' ',
1378 '`','S','e','q','u','e','n','c','e','`',' ',
1379 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1380 '`','S','e','q','u','e','n','c','e','`',0};
1382 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1383 if (rc
== ERROR_SUCCESS
)
1385 TRACE("Running the actions\n");
1387 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
1388 msiobj_release(&view
->hdr
);
1394 /********************************************************
1395 * ACTION helper functions and functions that perform the actions
1396 *******************************************************/
1397 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
1398 UINT
* rc
, UINT script
, BOOL force
)
1403 arc
= ACTION_CustomAction(package
, action
, script
, force
);
1405 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1413 MSICOMPONENT
*msi_get_loaded_component( MSIPACKAGE
*package
, const WCHAR
*Component
)
1417 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1419 if (!strcmpW( Component
, comp
->Component
)) return comp
;
1424 MSIFEATURE
*msi_get_loaded_feature(MSIPACKAGE
* package
, const WCHAR
*Feature
)
1426 MSIFEATURE
*feature
;
1428 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1430 if (!strcmpW( Feature
, feature
->Feature
)) return feature
;
1435 MSIFILE
*msi_get_loaded_file( MSIPACKAGE
*package
, const WCHAR
*key
)
1439 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1441 if (!strcmpW( key
, file
->File
)) return file
;
1446 MSIFILEPATCH
*msi_get_loaded_filepatch( MSIPACKAGE
*package
, const WCHAR
*key
)
1448 MSIFILEPATCH
*patch
;
1450 /* FIXME: There might be more than one patch */
1451 LIST_FOR_EACH_ENTRY( patch
, &package
->filepatches
, MSIFILEPATCH
, entry
)
1453 if (!strcmpW( key
, patch
->File
->File
)) return patch
;
1458 MSIFOLDER
*msi_get_loaded_folder( MSIPACKAGE
*package
, const WCHAR
*dir
)
1462 LIST_FOR_EACH_ENTRY( folder
, &package
->folders
, MSIFOLDER
, entry
)
1464 if (!strcmpW( dir
, folder
->Directory
)) return folder
;
1470 * Recursively create all directories in the path.
1471 * shamelessly stolen from setupapi/queue.c
1473 BOOL
msi_create_full_path( const WCHAR
*path
)
1479 new_path
= msi_alloc( (strlenW( path
) + 1) * sizeof(WCHAR
) );
1480 strcpyW( new_path
, path
);
1482 while ((len
= strlenW( new_path
)) && new_path
[len
- 1] == '\\')
1483 new_path
[len
- 1] = 0;
1485 while (!CreateDirectoryW( new_path
, NULL
))
1488 DWORD last_error
= GetLastError();
1489 if (last_error
== ERROR_ALREADY_EXISTS
) break;
1490 if (last_error
!= ERROR_PATH_NOT_FOUND
)
1495 if (!(slash
= strrchrW( new_path
, '\\' )))
1500 len
= slash
- new_path
;
1502 if (!msi_create_full_path( new_path
))
1507 new_path
[len
] = '\\';
1509 msi_free( new_path
);
1513 void msi_ui_progress( MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
1517 row
= MSI_CreateRecord( 4 );
1518 MSI_RecordSetInteger( row
, 1, a
);
1519 MSI_RecordSetInteger( row
, 2, b
);
1520 MSI_RecordSetInteger( row
, 3, c
);
1521 MSI_RecordSetInteger( row
, 4, d
);
1522 MSI_ProcessMessage( package
, INSTALLMESSAGE_PROGRESS
, row
);
1523 msiobj_release( &row
->hdr
);
1525 msi_dialog_check_messages( NULL
);
1528 void msi_ui_actiondata( MSIPACKAGE
*package
, const WCHAR
*action
, MSIRECORD
*record
)
1530 static const WCHAR query
[] =
1531 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1532 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
1533 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
1534 WCHAR message
[1024];
1538 if (!package
->LastAction
|| strcmpW( package
->LastAction
, action
))
1540 if (!(row
= MSI_QueryGetRecord( package
->db
, query
, action
))) return;
1542 if (MSI_RecordIsNull( row
, 3 ))
1544 msiobj_release( &row
->hdr
);
1547 /* update the cached action format */
1548 msi_free( package
->ActionFormat
);
1549 package
->ActionFormat
= msi_dup_record_field( row
, 3 );
1550 msi_free( package
->LastAction
);
1551 package
->LastAction
= strdupW( action
);
1552 msiobj_release( &row
->hdr
);
1555 MSI_RecordSetStringW( record
, 0, package
->ActionFormat
);
1556 MSI_FormatRecordW( package
, record
, message
, &size
);
1557 row
= MSI_CreateRecord( 1 );
1558 MSI_RecordSetStringW( row
, 1, message
);
1559 MSI_ProcessMessage( package
, INSTALLMESSAGE_ACTIONDATA
, row
);
1560 msiobj_release( &row
->hdr
);
1563 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1565 MSIPACKAGE
*package
= param
;
1566 LPCWSTR dir
, component
, full_path
;
1571 component
= MSI_RecordGetString(row
, 2);
1573 return ERROR_SUCCESS
;
1575 comp
= msi_get_loaded_component(package
, component
);
1577 return ERROR_SUCCESS
;
1581 TRACE("component is disabled\n");
1582 return ERROR_SUCCESS
;
1585 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
1587 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
1588 comp
->Action
= comp
->Installed
;
1589 return ERROR_SUCCESS
;
1591 comp
->Action
= INSTALLSTATE_LOCAL
;
1593 dir
= MSI_RecordGetString(row
,1);
1596 ERR("Unable to get folder id\n");
1597 return ERROR_SUCCESS
;
1600 uirow
= MSI_CreateRecord(1);
1601 MSI_RecordSetStringW(uirow
, 1, dir
);
1602 msi_ui_actiondata(package
, szCreateFolders
, uirow
);
1603 msiobj_release(&uirow
->hdr
);
1605 full_path
= msi_get_target_folder( package
, dir
);
1608 ERR("Unable to retrieve folder %s\n", debugstr_w(dir
));
1609 return ERROR_SUCCESS
;
1611 TRACE("folder is %s\n", debugstr_w(full_path
));
1613 folder
= msi_get_loaded_folder( package
, dir
);
1614 if (folder
->State
== 0) msi_create_full_path( full_path
);
1616 return ERROR_SUCCESS
;
1619 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1621 static const WCHAR query
[] =
1622 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1623 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1627 /* create all the empty folders specified in the CreateFolder table */
1628 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
1629 if (rc
!= ERROR_SUCCESS
)
1630 return ERROR_SUCCESS
;
1632 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1633 msiobj_release(&view
->hdr
);
1638 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
1640 MSIPACKAGE
*package
= param
;
1641 LPCWSTR dir
, component
, full_path
;
1646 component
= MSI_RecordGetString(row
, 2);
1648 return ERROR_SUCCESS
;
1650 comp
= msi_get_loaded_component(package
, component
);
1652 return ERROR_SUCCESS
;
1656 TRACE("component is disabled\n");
1657 return ERROR_SUCCESS
;
1660 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
1662 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
1663 comp
->Action
= comp
->Installed
;
1664 return ERROR_SUCCESS
;
1666 comp
->Action
= INSTALLSTATE_ABSENT
;
1668 dir
= MSI_RecordGetString( row
, 1 );
1671 ERR("Unable to get folder id\n");
1672 return ERROR_SUCCESS
;
1675 full_path
= msi_get_target_folder( package
, dir
);
1678 ERR("Unable to resolve folder %s\n", debugstr_w(dir
));
1679 return ERROR_SUCCESS
;
1681 TRACE("folder is %s\n", debugstr_w(full_path
));
1683 uirow
= MSI_CreateRecord( 1 );
1684 MSI_RecordSetStringW( uirow
, 1, dir
);
1685 msi_ui_actiondata( package
, szRemoveFolders
, uirow
);
1686 msiobj_release( &uirow
->hdr
);
1688 RemoveDirectoryW( full_path
);
1689 folder
= msi_get_loaded_folder( package
, dir
);
1691 return ERROR_SUCCESS
;
1694 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1696 static const WCHAR query
[] =
1697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1698 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1703 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1704 if (rc
!= ERROR_SUCCESS
)
1705 return ERROR_SUCCESS
;
1707 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1708 msiobj_release( &view
->hdr
);
1713 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1715 MSIPACKAGE
*package
= param
;
1718 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1720 return ERROR_FUNCTION_FAILED
;
1722 list_add_tail( &package
->components
, &comp
->entry
);
1724 /* fill in the data */
1725 comp
->Component
= msi_dup_record_field( row
, 1 );
1727 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1729 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1730 comp
->Directory
= msi_dup_record_field( row
, 3 );
1731 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1732 comp
->Condition
= msi_dup_record_field( row
, 5 );
1733 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1735 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1736 comp
->Action
= INSTALLSTATE_UNKNOWN
;
1737 comp
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1739 comp
->assembly
= msi_load_assembly( package
, comp
);
1740 return ERROR_SUCCESS
;
1743 static UINT
load_all_components( MSIPACKAGE
*package
)
1745 static const WCHAR query
[] = {
1746 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1747 '`','C','o','m','p','o','n','e','n','t','`',0 };
1751 if (!list_empty(&package
->components
))
1752 return ERROR_SUCCESS
;
1754 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1755 if (r
!= ERROR_SUCCESS
)
1758 if (!msi_init_assembly_caches( package
))
1760 ERR("can't initialize assembly caches\n");
1761 msiobj_release( &view
->hdr
);
1762 return ERROR_FUNCTION_FAILED
;
1765 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1766 msiobj_release(&view
->hdr
);
1768 msi_destroy_assembly_caches( package
);
1773 MSIPACKAGE
*package
;
1774 MSIFEATURE
*feature
;
1777 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1781 cl
= msi_alloc( sizeof (*cl
) );
1783 return ERROR_NOT_ENOUGH_MEMORY
;
1784 cl
->component
= comp
;
1785 list_add_tail( &feature
->Components
, &cl
->entry
);
1787 return ERROR_SUCCESS
;
1790 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1794 fl
= msi_alloc( sizeof(*fl
) );
1796 return ERROR_NOT_ENOUGH_MEMORY
;
1797 fl
->feature
= child
;
1798 list_add_tail( &parent
->Children
, &fl
->entry
);
1800 return ERROR_SUCCESS
;
1803 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1805 _ilfs
* ilfs
= param
;
1809 component
= MSI_RecordGetString(row
,1);
1811 /* check to see if the component is already loaded */
1812 comp
= msi_get_loaded_component( ilfs
->package
, component
);
1815 ERR("unknown component %s\n", debugstr_w(component
));
1816 return ERROR_FUNCTION_FAILED
;
1819 add_feature_component( ilfs
->feature
, comp
);
1820 comp
->Enabled
= TRUE
;
1822 return ERROR_SUCCESS
;
1825 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1827 MSIFEATURE
*feature
;
1832 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1834 if ( !strcmpW( feature
->Feature
, name
) )
1841 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1843 MSIPACKAGE
* package
= param
;
1844 MSIFEATURE
* feature
;
1845 static const WCHAR Query1
[] =
1846 {'S','E','L','E','C','T',' ',
1847 '`','C','o','m','p','o','n','e','n','t','_','`',
1848 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1849 'C','o','m','p','o','n','e','n','t','s','`',' ',
1850 'W','H','E','R','E',' ',
1851 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1856 /* fill in the data */
1858 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1860 return ERROR_NOT_ENOUGH_MEMORY
;
1862 list_init( &feature
->Children
);
1863 list_init( &feature
->Components
);
1865 feature
->Feature
= msi_dup_record_field( row
, 1 );
1867 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1869 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1870 feature
->Title
= msi_dup_record_field( row
, 3 );
1871 feature
->Description
= msi_dup_record_field( row
, 4 );
1873 if (!MSI_RecordIsNull(row
,5))
1874 feature
->Display
= MSI_RecordGetInteger(row
,5);
1876 feature
->Level
= MSI_RecordGetInteger(row
,6);
1877 feature
->Directory
= msi_dup_record_field( row
, 7 );
1878 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1880 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1881 feature
->Action
= INSTALLSTATE_UNKNOWN
;
1882 feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1884 list_add_tail( &package
->features
, &feature
->entry
);
1886 /* load feature components */
1888 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1889 if (rc
!= ERROR_SUCCESS
)
1890 return ERROR_SUCCESS
;
1892 ilfs
.package
= package
;
1893 ilfs
.feature
= feature
;
1895 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1896 msiobj_release(&view
->hdr
);
1898 return ERROR_SUCCESS
;
1901 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1903 MSIPACKAGE
* package
= param
;
1904 MSIFEATURE
*parent
, *child
;
1906 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1908 return ERROR_FUNCTION_FAILED
;
1910 if (!child
->Feature_Parent
)
1911 return ERROR_SUCCESS
;
1913 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1915 return ERROR_FUNCTION_FAILED
;
1917 add_feature_child( parent
, child
);
1918 return ERROR_SUCCESS
;
1921 static UINT
load_all_features( MSIPACKAGE
*package
)
1923 static const WCHAR query
[] = {
1924 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1925 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1926 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1930 if (!list_empty(&package
->features
))
1931 return ERROR_SUCCESS
;
1933 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1934 if (r
!= ERROR_SUCCESS
)
1937 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1938 if (r
!= ERROR_SUCCESS
)
1941 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1942 msiobj_release( &view
->hdr
);
1947 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1958 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1960 static const WCHAR query
[] = {
1961 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1962 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1963 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1964 MSIQUERY
*view
= NULL
;
1965 MSIRECORD
*row
= NULL
;
1968 TRACE("%s\n", debugstr_w(file
->File
));
1970 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1971 if (r
!= ERROR_SUCCESS
)
1974 r
= MSI_ViewExecute(view
, NULL
);
1975 if (r
!= ERROR_SUCCESS
)
1978 r
= MSI_ViewFetch(view
, &row
);
1979 if (r
!= ERROR_SUCCESS
)
1982 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1983 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1984 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1985 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1986 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1989 if (view
) msiobj_release(&view
->hdr
);
1990 if (row
) msiobj_release(&row
->hdr
);
1994 static UINT
load_file_disk_id( MSIPACKAGE
*package
, MSIFILE
*file
)
1997 static const WCHAR query
[] = {
1998 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1999 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2000 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
2002 row
= MSI_QueryGetRecord( package
->db
, query
, file
->Sequence
);
2005 WARN("query failed\n");
2006 return ERROR_FUNCTION_FAILED
;
2009 file
->disk_id
= MSI_RecordGetInteger( row
, 1 );
2010 msiobj_release( &row
->hdr
);
2011 return ERROR_SUCCESS
;
2014 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
2016 MSIPACKAGE
* package
= param
;
2020 /* fill in the data */
2022 file
= msi_alloc_zero( sizeof (MSIFILE
) );
2024 return ERROR_NOT_ENOUGH_MEMORY
;
2026 file
->File
= msi_dup_record_field( row
, 1 );
2028 component
= MSI_RecordGetString( row
, 2 );
2029 file
->Component
= msi_get_loaded_component( package
, component
);
2031 if (!file
->Component
)
2033 WARN("Component not found: %s\n", debugstr_w(component
));
2034 msi_free(file
->File
);
2036 return ERROR_SUCCESS
;
2039 file
->FileName
= msi_dup_record_field( row
, 3 );
2040 msi_reduce_to_long_filename( file
->FileName
);
2042 file
->ShortName
= msi_dup_record_field( row
, 3 );
2043 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
2045 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
2046 file
->Version
= msi_dup_record_field( row
, 5 );
2047 file
->Language
= msi_dup_record_field( row
, 6 );
2048 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
2049 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
2051 file
->state
= msifs_invalid
;
2053 /* if the compressed bits are not set in the file attributes,
2054 * then read the information from the package word count property
2056 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
2058 file
->IsCompressed
= FALSE
;
2060 else if (file
->Attributes
&
2061 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
2063 file
->IsCompressed
= TRUE
;
2065 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
2067 file
->IsCompressed
= FALSE
;
2071 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
2074 load_file_hash(package
, file
);
2075 load_file_disk_id(package
, file
);
2077 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
2079 list_add_tail( &package
->files
, &file
->entry
);
2081 return ERROR_SUCCESS
;
2084 static UINT
load_all_files(MSIPACKAGE
*package
)
2088 static const WCHAR Query
[] =
2089 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2090 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
2091 '`','S','e','q','u','e','n','c','e','`', 0};
2093 if (!list_empty(&package
->files
))
2094 return ERROR_SUCCESS
;
2096 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2097 if (rc
!= ERROR_SUCCESS
)
2098 return ERROR_SUCCESS
;
2100 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
2101 msiobj_release(&view
->hdr
);
2103 return ERROR_SUCCESS
;
2106 static UINT
load_media( MSIRECORD
*row
, LPVOID param
)
2108 MSIPACKAGE
*package
= param
;
2109 UINT disk_id
= MSI_RecordGetInteger( row
, 1 );
2110 const WCHAR
*cabinet
= MSI_RecordGetString( row
, 4 );
2112 /* FIXME: load external cabinets and directory sources too */
2113 if (!cabinet
|| cabinet
[0] != '#') return ERROR_SUCCESS
;
2114 msi_add_cabinet_stream( package
, disk_id
, package
->db
->storage
, cabinet
);
2115 return ERROR_SUCCESS
;
2118 static UINT
load_all_media( MSIPACKAGE
*package
)
2120 static const WCHAR query
[] =
2121 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
2122 'O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
2126 if (!list_empty( &package
->cabinet_streams
)) return ERROR_SUCCESS
;
2128 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
2129 if (r
!= ERROR_SUCCESS
) return ERROR_SUCCESS
;
2131 MSI_IterateRecords( view
, NULL
, load_media
, package
);
2132 msiobj_release( &view
->hdr
);
2133 return ERROR_SUCCESS
;
2136 static UINT
load_patch(MSIRECORD
*row
, LPVOID param
)
2138 MSIPACKAGE
*package
= param
;
2139 MSIFILEPATCH
*patch
;
2142 patch
= msi_alloc_zero( sizeof (MSIFILEPATCH
) );
2144 return ERROR_NOT_ENOUGH_MEMORY
;
2146 file_key
= msi_dup_record_field( row
, 1 );
2147 patch
->File
= msi_get_loaded_file( package
, file_key
);
2152 ERR("Failed to find target for patch in File table\n");
2154 return ERROR_FUNCTION_FAILED
;
2157 patch
->Sequence
= MSI_RecordGetInteger( row
, 2 );
2159 /* FIXME: The database should be properly transformed */
2160 patch
->Sequence
+= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
;
2162 patch
->PatchSize
= MSI_RecordGetInteger( row
, 3 );
2163 patch
->Attributes
= MSI_RecordGetInteger( row
, 4 );
2164 patch
->IsApplied
= FALSE
;
2167 * Header field - for patch validation.
2168 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
2171 TRACE("Patch Loaded (%s)\n", debugstr_w(patch
->File
->File
));
2173 list_add_tail( &package
->filepatches
, &patch
->entry
);
2175 return ERROR_SUCCESS
;
2178 static UINT
load_all_patches(MSIPACKAGE
*package
)
2182 static const WCHAR Query
[] =
2183 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2184 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
2185 '`','S','e','q','u','e','n','c','e','`',0};
2187 if (!list_empty(&package
->filepatches
))
2188 return ERROR_SUCCESS
;
2190 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2191 if (rc
!= ERROR_SUCCESS
)
2192 return ERROR_SUCCESS
;
2194 rc
= MSI_IterateRecords(view
, NULL
, load_patch
, package
);
2195 msiobj_release(&view
->hdr
);
2197 return ERROR_SUCCESS
;
2200 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
2202 MSIPACKAGE
*package
= param
;
2203 static WCHAR szEmpty
[] = { 0 };
2204 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
2207 if (!(folder
= msi_alloc_zero( sizeof(*folder
) ))) return ERROR_NOT_ENOUGH_MEMORY
;
2208 list_init( &folder
->children
);
2209 folder
->Directory
= msi_dup_record_field( row
, 1 );
2210 folder
->Parent
= msi_dup_record_field( row
, 2 );
2211 p
= msi_dup_record_field(row
, 3);
2213 TRACE("%s\n", debugstr_w(folder
->Directory
));
2215 /* split src and target dir */
2217 src_short
= folder_split_path( p
, ':' );
2219 /* split the long and short paths */
2220 tgt_long
= folder_split_path( tgt_short
, '|' );
2221 src_long
= folder_split_path( src_short
, '|' );
2223 /* check for no-op dirs */
2224 if (tgt_short
&& !strcmpW( szDot
, tgt_short
))
2225 tgt_short
= szEmpty
;
2226 if (src_short
&& !strcmpW( szDot
, src_short
))
2227 src_short
= szEmpty
;
2230 tgt_long
= tgt_short
;
2233 src_short
= tgt_short
;
2234 src_long
= tgt_long
;
2238 src_long
= src_short
;
2240 /* FIXME: use the target short path too */
2241 folder
->TargetDefault
= strdupW(tgt_long
);
2242 folder
->SourceShortPath
= strdupW(src_short
);
2243 folder
->SourceLongPath
= strdupW(src_long
);
2246 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
2247 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
2248 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
2250 list_add_tail( &package
->folders
, &folder
->entry
);
2251 return ERROR_SUCCESS
;
2254 static UINT
add_folder_child( MSIFOLDER
*parent
, MSIFOLDER
*child
)
2258 if (!(fl
= msi_alloc( sizeof(*fl
) ))) return ERROR_NOT_ENOUGH_MEMORY
;
2260 list_add_tail( &parent
->children
, &fl
->entry
);
2261 return ERROR_SUCCESS
;
2264 static UINT
find_folder_children( MSIRECORD
*row
, LPVOID param
)
2266 MSIPACKAGE
*package
= param
;
2267 MSIFOLDER
*parent
, *child
;
2269 if (!(child
= msi_get_loaded_folder( package
, MSI_RecordGetString( row
, 1 ) )))
2270 return ERROR_FUNCTION_FAILED
;
2272 if (!child
->Parent
) return ERROR_SUCCESS
;
2274 if (!(parent
= msi_get_loaded_folder( package
, child
->Parent
)))
2275 return ERROR_FUNCTION_FAILED
;
2277 return add_folder_child( parent
, child
);
2280 static UINT
load_all_folders( MSIPACKAGE
*package
)
2282 static const WCHAR query
[] = {
2283 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
2284 '`','D','i','r','e','c','t','o','r','y','`',0 };
2288 if (!list_empty(&package
->folders
))
2289 return ERROR_SUCCESS
;
2291 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
2292 if (r
!= ERROR_SUCCESS
)
2295 r
= MSI_IterateRecords( view
, NULL
, load_folder
, package
);
2296 if (r
!= ERROR_SUCCESS
)
2298 msiobj_release( &view
->hdr
);
2301 r
= MSI_IterateRecords( view
, NULL
, find_folder_children
, package
);
2302 msiobj_release( &view
->hdr
);
2306 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
2308 msi_set_property( package
->db
, szCostingComplete
, szZero
);
2309 msi_set_property( package
->db
, szRootDrive
, szCRoot
);
2311 load_all_folders( package
);
2312 load_all_components( package
);
2313 load_all_features( package
);
2314 load_all_files( package
);
2315 load_all_patches( package
);
2316 load_all_media( package
);
2318 return ERROR_SUCCESS
;
2321 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
2324 UINT rc
= ERROR_SUCCESS
;
2326 TRACE("Executing Script %i\n",script
);
2328 if (!package
->script
)
2330 ERR("no script!\n");
2331 return ERROR_FUNCTION_FAILED
;
2334 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
2337 action
= package
->script
->Actions
[script
][i
];
2338 ui_actionstart(package
, action
);
2339 TRACE("Executing Action (%s)\n",debugstr_w(action
));
2340 rc
= ACTION_PerformAction(package
, action
, script
);
2341 if (rc
!= ERROR_SUCCESS
)
2344 msi_free_action_script(package
, script
);
2348 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
2350 return ERROR_SUCCESS
;
2353 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
2358 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
2360 if (!comp
->ComponentId
) continue;
2362 r
= MsiQueryComponentStateW( package
->ProductCode
, NULL
,
2363 MSIINSTALLCONTEXT_USERMANAGED
, comp
->ComponentId
,
2365 if (r
!= ERROR_SUCCESS
)
2366 r
= MsiQueryComponentStateW( package
->ProductCode
, NULL
,
2367 MSIINSTALLCONTEXT_USERUNMANAGED
, comp
->ComponentId
,
2369 if (r
!= ERROR_SUCCESS
)
2370 r
= MsiQueryComponentStateW( package
->ProductCode
, NULL
,
2371 MSIINSTALLCONTEXT_MACHINE
, comp
->ComponentId
,
2373 if (r
!= ERROR_SUCCESS
)
2374 comp
->Installed
= INSTALLSTATE_ABSENT
;
2378 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
2380 MSIFEATURE
*feature
;
2382 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2384 INSTALLSTATE state
= MsiQueryFeatureStateW( package
->ProductCode
, feature
->Feature
);
2386 if (state
== INSTALLSTATE_UNKNOWN
|| state
== INSTALLSTATE_INVALIDARG
)
2387 feature
->Installed
= INSTALLSTATE_ABSENT
;
2389 feature
->Installed
= state
;
2393 static inline BOOL
is_feature_selected( MSIFEATURE
*feature
, INT level
)
2395 return (feature
->Level
> 0 && feature
->Level
<= level
);
2398 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
2399 LPCWSTR property
, INSTALLSTATE state
)
2402 MSIFEATURE
*feature
;
2404 override
= msi_dup_property( package
->db
, property
);
2408 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2410 if (strcmpW( property
, szRemove
) && !is_feature_selected( feature
, level
))
2413 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
2415 if (!strcmpiW( override
, szAll
))
2417 if (feature
->Installed
!= state
)
2419 feature
->Action
= state
;
2420 feature
->ActionRequest
= state
;
2425 LPWSTR ptr
= override
;
2426 LPWSTR ptr2
= strchrW(override
,',');
2430 int len
= ptr2
- ptr
;
2432 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
2433 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
2435 if (feature
->Installed
!= state
)
2437 feature
->Action
= state
;
2438 feature
->ActionRequest
= state
;
2445 ptr2
= strchrW(ptr
,',');
2456 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
2458 static const WCHAR szAddLocal
[] =
2459 {'A','D','D','L','O','C','A','L',0};
2460 static const WCHAR szAddSource
[] =
2461 {'A','D','D','S','O','U','R','C','E',0};
2462 static const WCHAR szAdvertise
[] =
2463 {'A','D','V','E','R','T','I','S','E',0};
2466 /* all these activation/deactivation things happen in order and things
2467 * later on the list override things earlier on the list.
2469 * 0 INSTALLLEVEL processing
2482 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
2483 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
2484 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
2485 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
2486 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
2489 msi_set_property( package
->db
, szPreselected
, szOne
);
2494 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
2497 MSICOMPONENT
* component
;
2498 MSIFEATURE
*feature
;
2500 TRACE("Checking Install Level\n");
2502 level
= msi_get_property_int(package
->db
, szInstallLevel
, 1);
2504 if (!msi_get_property_int( package
->db
, szPreselected
, 0 ))
2506 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2508 if (!is_feature_selected( feature
, level
)) continue;
2510 if (feature
->ActionRequest
== INSTALLSTATE_UNKNOWN
)
2512 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
2514 feature
->Action
= INSTALLSTATE_SOURCE
;
2515 feature
->ActionRequest
= INSTALLSTATE_SOURCE
;
2517 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
2519 feature
->Action
= INSTALLSTATE_ADVERTISED
;
2520 feature
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
2524 feature
->Action
= INSTALLSTATE_LOCAL
;
2525 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
2529 /* disable child features of unselected parent or follow parent */
2530 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2534 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
2536 if (!is_feature_selected( feature
, level
))
2538 fl
->feature
->Action
= INSTALLSTATE_UNKNOWN
;
2539 fl
->feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
2541 else if (fl
->feature
->Attributes
& msidbFeatureAttributesFollowParent
)
2543 fl
->feature
->Action
= feature
->Action
;
2544 fl
->feature
->ActionRequest
= feature
->ActionRequest
;
2549 else /* preselected */
2551 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2553 if (!is_feature_selected( feature
, level
)) continue;
2555 if (feature
->ActionRequest
== INSTALLSTATE_UNKNOWN
)
2557 if (feature
->Installed
== INSTALLSTATE_ABSENT
)
2559 feature
->Action
= INSTALLSTATE_UNKNOWN
;
2560 feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
2564 feature
->Action
= feature
->Installed
;
2565 feature
->ActionRequest
= feature
->Installed
;
2569 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2573 if (!is_feature_selected( feature
, level
)) continue;
2575 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
2577 if (fl
->feature
->Attributes
& msidbFeatureAttributesFollowParent
)
2579 fl
->feature
->Action
= feature
->Action
;
2580 fl
->feature
->ActionRequest
= feature
->ActionRequest
;
2586 /* now we want to set component state based based on feature state */
2587 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2591 TRACE("Examining Feature %s (Level %d Installed %d Request %d Action %d)\n",
2592 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
,
2593 feature
->ActionRequest
, feature
->Action
);
2595 if (!is_feature_selected( feature
, level
)) continue;
2597 /* features with components that have compressed files are made local */
2598 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2600 if (cl
->component
->ForceLocalState
&&
2601 feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
2603 feature
->Action
= INSTALLSTATE_LOCAL
;
2604 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
2609 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2611 component
= cl
->component
;
2613 switch (feature
->ActionRequest
)
2615 case INSTALLSTATE_ABSENT
:
2616 component
->anyAbsent
= 1;
2618 case INSTALLSTATE_ADVERTISED
:
2619 component
->hasAdvertiseFeature
= 1;
2621 case INSTALLSTATE_SOURCE
:
2622 component
->hasSourceFeature
= 1;
2624 case INSTALLSTATE_LOCAL
:
2625 component
->hasLocalFeature
= 1;
2627 case INSTALLSTATE_DEFAULT
:
2628 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
2629 component
->hasAdvertiseFeature
= 1;
2630 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
2631 component
->hasSourceFeature
= 1;
2633 component
->hasLocalFeature
= 1;
2641 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
2643 /* check if it's local or source */
2644 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
2645 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
2647 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
2648 !component
->ForceLocalState
)
2650 component
->Action
= INSTALLSTATE_SOURCE
;
2651 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
2655 component
->Action
= INSTALLSTATE_LOCAL
;
2656 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2661 /* if any feature is local, the component must be local too */
2662 if (component
->hasLocalFeature
)
2664 component
->Action
= INSTALLSTATE_LOCAL
;
2665 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2668 if (component
->hasSourceFeature
)
2670 component
->Action
= INSTALLSTATE_SOURCE
;
2671 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
2674 if (component
->hasAdvertiseFeature
)
2676 component
->Action
= INSTALLSTATE_ADVERTISED
;
2677 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
2680 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
2681 if (component
->anyAbsent
&&
2682 (component
->Installed
== INSTALLSTATE_LOCAL
|| component
->Installed
== INSTALLSTATE_SOURCE
))
2684 component
->Action
= INSTALLSTATE_ABSENT
;
2685 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
2689 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
2691 if (component
->ActionRequest
== INSTALLSTATE_DEFAULT
)
2693 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
2694 component
->Action
= INSTALLSTATE_LOCAL
;
2695 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2698 if (component
->ActionRequest
== INSTALLSTATE_SOURCE
&&
2699 component
->Installed
== INSTALLSTATE_SOURCE
&&
2700 component
->hasSourceFeature
)
2702 component
->Action
= INSTALLSTATE_UNKNOWN
;
2703 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
2706 TRACE("Result: Component %s (Installed %d Request %d Action %d)\n",
2707 debugstr_w(component
->Component
), component
->Installed
, component
->ActionRequest
, component
->Action
);
2710 return ERROR_SUCCESS
;
2713 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
2715 MSIPACKAGE
*package
= param
;
2717 MSIFEATURE
*feature
;
2719 name
= MSI_RecordGetString( row
, 1 );
2721 feature
= msi_get_loaded_feature( package
, name
);
2723 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
2727 Condition
= MSI_RecordGetString(row
,3);
2729 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
2731 int level
= MSI_RecordGetInteger(row
,2);
2732 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
2733 feature
->Level
= level
;
2736 return ERROR_SUCCESS
;
2739 VS_FIXEDFILEINFO
*msi_get_disk_file_version( LPCWSTR filename
)
2741 static const WCHAR name
[] = {'\\',0};
2742 VS_FIXEDFILEINFO
*ptr
, *ret
;
2744 DWORD versize
, handle
;
2747 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
2751 version
= msi_alloc( versize
);
2755 GetFileVersionInfoW( filename
, 0, versize
, version
);
2757 if (!VerQueryValueW( version
, name
, (LPVOID
*)&ptr
, &sz
))
2759 msi_free( version
);
2763 ret
= msi_alloc( sz
);
2764 memcpy( ret
, ptr
, sz
);
2766 msi_free( version
);
2770 int msi_compare_file_versions( VS_FIXEDFILEINFO
*fi
, const WCHAR
*version
)
2774 msi_parse_version_string( version
, &ms
, &ls
);
2776 if (fi
->dwFileVersionMS
> ms
) return 1;
2777 else if (fi
->dwFileVersionMS
< ms
) return -1;
2778 else if (fi
->dwFileVersionLS
> ls
) return 1;
2779 else if (fi
->dwFileVersionLS
< ls
) return -1;
2783 int msi_compare_font_versions( const WCHAR
*ver1
, const WCHAR
*ver2
)
2787 msi_parse_version_string( ver1
, &ms1
, NULL
);
2788 msi_parse_version_string( ver2
, &ms2
, NULL
);
2790 if (ms1
> ms2
) return 1;
2791 else if (ms1
< ms2
) return -1;
2795 DWORD
msi_get_disk_file_size( LPCWSTR filename
)
2800 file
= CreateFileW( filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
2801 if (file
== INVALID_HANDLE_VALUE
)
2802 return INVALID_FILE_SIZE
;
2804 size
= GetFileSize( file
, NULL
);
2805 TRACE("size is %u\n", size
);
2806 CloseHandle( file
);
2810 BOOL
msi_file_hash_matches( MSIFILE
*file
)
2813 MSIFILEHASHINFO hash
;
2815 hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
2816 r
= MsiGetFileHashW( file
->TargetPath
, 0, &hash
);
2817 if (r
!= ERROR_SUCCESS
)
2820 return !memcmp( &hash
, &file
->hash
, sizeof(MSIFILEHASHINFO
) );
2823 static WCHAR
*get_temp_dir( void )
2826 WCHAR tmp
[MAX_PATH
], dir
[MAX_PATH
];
2828 GetTempPathW( MAX_PATH
, tmp
);
2831 if (!GetTempFileNameW( tmp
, szMsi
, ++id
, dir
)) return NULL
;
2832 if (CreateDirectoryW( dir
, NULL
)) break;
2834 return strdupW( dir
);
2838 * msi_build_directory_name()
2840 * This function is to save messing round with directory names
2841 * It handles adding backslashes between path segments,
2842 * and can add \ at the end of the directory name if told to.
2844 * It takes a variable number of arguments.
2845 * It always allocates a new string for the result, so make sure
2846 * to free the return value when finished with it.
2848 * The first arg is the number of path segments that follow.
2849 * The arguments following count are a list of path segments.
2850 * A path segment may be NULL.
2852 * Path segments will be added with a \ separating them.
2853 * A \ will not be added after the last segment, however if the
2854 * last segment is NULL, then the last character will be a \
2856 WCHAR
*msi_build_directory_name( DWORD count
, ... )
2862 va_start( va
, count
);
2863 for (i
= 0; i
< count
; i
++)
2865 const WCHAR
*str
= va_arg( va
, const WCHAR
* );
2866 if (str
) sz
+= strlenW( str
) + 1;
2870 dir
= msi_alloc( sz
* sizeof(WCHAR
) );
2873 va_start( va
, count
);
2874 for (i
= 0; i
< count
; i
++)
2876 const WCHAR
*str
= va_arg( va
, const WCHAR
* );
2878 strcatW( dir
, str
);
2879 if ( i
+ 1 != count
&& dir
[strlenW( dir
) - 1] != '\\') strcatW( dir
, szBackSlash
);
2885 static void set_target_path( MSIPACKAGE
*package
, MSIFILE
*file
)
2887 MSIASSEMBLY
*assembly
= file
->Component
->assembly
;
2889 TRACE("file %s is named %s\n", debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2891 msi_free( file
->TargetPath
);
2892 if (assembly
&& !assembly
->application
)
2894 if (!assembly
->tempdir
) assembly
->tempdir
= get_temp_dir();
2895 file
->TargetPath
= msi_build_directory_name( 2, assembly
->tempdir
, file
->FileName
);
2896 msi_track_tempfile( package
, file
->TargetPath
);
2900 const WCHAR
*dir
= msi_get_target_folder( package
, file
->Component
->Directory
);
2901 file
->TargetPath
= msi_build_directory_name( 2, dir
, file
->FileName
);
2904 TRACE("resolves to %s\n", debugstr_w(file
->TargetPath
));
2907 static UINT
calculate_file_cost( MSIPACKAGE
*package
)
2909 VS_FIXEDFILEINFO
*file_version
;
2910 WCHAR
*font_version
;
2913 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2915 MSICOMPONENT
*comp
= file
->Component
;
2918 if (!comp
->Enabled
) continue;
2920 if (file
->IsCompressed
)
2921 comp
->ForceLocalState
= TRUE
;
2923 set_target_path( package
, file
);
2925 if ((comp
->assembly
&& !comp
->assembly
->installed
) ||
2926 GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2928 comp
->Cost
+= file
->FileSize
;
2931 file_size
= msi_get_disk_file_size( file
->TargetPath
);
2935 if ((file_version
= msi_get_disk_file_version( file
->TargetPath
)))
2937 if (msi_compare_file_versions( file_version
, file
->Version
) < 0)
2939 comp
->Cost
+= file
->FileSize
- file_size
;
2941 msi_free( file_version
);
2944 else if ((font_version
= font_version_from_file( file
->TargetPath
)))
2946 if (msi_compare_font_versions( font_version
, file
->Version
) < 0)
2948 comp
->Cost
+= file
->FileSize
- file_size
;
2950 msi_free( font_version
);
2954 if (file_size
!= file
->FileSize
)
2956 comp
->Cost
+= file
->FileSize
- file_size
;
2959 return ERROR_SUCCESS
;
2962 void msi_clean_path( WCHAR
*p
)
2969 /* copy until the end of the string or a space */
2970 while (*p
!= ' ' && (*q
= *p
))
2973 /* reduce many backslashes to one */
2974 if (*p
!= '\\' || *q
!= '\\')
2978 /* quit at the end of the string */
2982 /* count the number of spaces */
2987 /* if it's leading or trailing space, skip it */
2988 if ( len
== 0 || p
[-1] == '\\' || p
[n
] == '\\' )
2990 else /* copy n spaces */
2991 while (n
&& (*q
++ = *p
++)) n
--;
2995 void msi_resolve_target_folder( MSIPACKAGE
*package
, const WCHAR
*name
, BOOL load_prop
)
2998 MSIFOLDER
*folder
, *parent
, *child
;
3001 TRACE("resolving %s\n", debugstr_w(name
));
3003 if (!(folder
= msi_get_loaded_folder( package
, name
))) return;
3005 if (!strcmpW( folder
->Directory
, szTargetDir
)) /* special resolving for target root dir */
3007 if (!load_prop
|| !(path
= msi_dup_property( package
->db
, szTargetDir
)))
3009 path
= msi_dup_property( package
->db
, szRootDrive
);
3012 else if (!load_prop
|| !(path
= msi_dup_property( package
->db
, folder
->Directory
)))
3014 parent
= msi_get_loaded_folder( package
, folder
->Parent
);
3015 path
= msi_build_directory_name( 3, parent
->ResolvedTarget
, folder
->TargetDefault
, NULL
);
3017 msi_clean_path( path
);
3018 if (folder
->ResolvedTarget
&& !strcmpiW( path
, folder
->ResolvedTarget
))
3020 TRACE("%s already resolved to %s\n", debugstr_w(name
), debugstr_w(folder
->ResolvedTarget
));
3024 msi_set_property( package
->db
, folder
->Directory
, path
);
3025 msi_free( folder
->ResolvedTarget
);
3026 folder
->ResolvedTarget
= path
;
3028 LIST_FOR_EACH_ENTRY( fl
, &folder
->children
, FolderList
, entry
)
3031 msi_resolve_target_folder( package
, child
->Directory
, load_prop
);
3033 TRACE("%s resolves to %s\n", debugstr_w(name
), debugstr_w(folder
->ResolvedTarget
));
3036 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
3038 static const WCHAR condition_query
[] =
3039 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','C','o','n','d','i','t','i','o','n','`',0};
3040 static const WCHAR szOutOfDiskSpace
[] =
3041 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
3043 UINT rc
= ERROR_SUCCESS
;
3047 TRACE("Building directory properties\n");
3048 msi_resolve_target_folder( package
, szTargetDir
, TRUE
);
3050 TRACE("Evaluating component conditions\n");
3051 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
3053 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
3055 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
3056 comp
->Enabled
= FALSE
;
3059 comp
->Enabled
= TRUE
;
3062 /* read components states from the registry */
3063 ACTION_GetComponentInstallStates(package
);
3064 ACTION_GetFeatureInstallStates(package
);
3066 if (!process_overrides( package
, msi_get_property_int( package
->db
, szInstallLevel
, 1 ) ))
3068 TRACE("Evaluating feature conditions\n");
3070 rc
= MSI_DatabaseOpenViewW( package
->db
, condition_query
, &view
);
3071 if (rc
== ERROR_SUCCESS
)
3073 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
3074 msiobj_release( &view
->hdr
);
3078 TRACE("Calculating file cost\n");
3079 calculate_file_cost( package
);
3081 msi_set_property( package
->db
, szCostingComplete
, szOne
);
3082 /* set default run level if not set */
3083 level
= msi_dup_property( package
->db
, szInstallLevel
);
3085 msi_set_property( package
->db
, szInstallLevel
, szOne
);
3088 /* FIXME: check volume disk space */
3089 msi_set_property( package
->db
, szOutOfDiskSpace
, szZero
);
3091 return MSI_SetFeatureStates(package
);
3094 /* OK this value is "interpreted" and then formatted based on the
3095 first few characters */
3096 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
3101 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
3107 LPWSTR deformated
= NULL
;
3110 deformat_string(package
, &value
[2], &deformated
);
3112 /* binary value type */
3116 *size
= (strlenW(ptr
)/2)+1;
3118 *size
= strlenW(ptr
)/2;
3120 data
= msi_alloc(*size
);
3126 /* if uneven pad with a zero in front */
3132 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3134 TRACE("Uneven byte count\n");
3142 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3145 msi_free(deformated
);
3147 TRACE("Data %i bytes(%i)\n",*size
,count
);
3154 deformat_string(package
, &value
[1], &deformated
);
3157 *size
= sizeof(DWORD
);
3158 data
= msi_alloc(*size
);
3164 if ( (*p
< '0') || (*p
> '9') )
3170 if (deformated
[0] == '-')
3173 TRACE("DWORD %i\n",*(LPDWORD
)data
);
3175 msi_free(deformated
);
3180 static const WCHAR szMulti
[] = {'[','~',']',0};
3189 *type
=REG_EXPAND_SZ
;
3197 if (strstrW(value
, szMulti
))
3198 *type
= REG_MULTI_SZ
;
3200 /* remove initial delimiter */
3201 if (!strncmpW(value
, szMulti
, 3))
3204 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
3206 /* add double NULL terminator */
3207 if (*type
== REG_MULTI_SZ
)
3209 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
3210 data
= msi_realloc_zero(data
, *size
);
3216 static const WCHAR
*get_root_key( MSIPACKAGE
*package
, INT root
, HKEY
*root_key
)
3223 if (msi_get_property_int( package
->db
, szAllUsers
, 0 ))
3225 *root_key
= HKEY_LOCAL_MACHINE
;
3230 *root_key
= HKEY_CURRENT_USER
;
3235 *root_key
= HKEY_CLASSES_ROOT
;
3239 *root_key
= HKEY_CURRENT_USER
;
3243 *root_key
= HKEY_LOCAL_MACHINE
;
3247 *root_key
= HKEY_USERS
;
3251 ERR("Unknown root %i\n", root
);
3258 static WCHAR
*get_keypath( MSIPACKAGE
*package
, HKEY root
, const WCHAR
*path
)
3260 static const WCHAR prefixW
[] = {'S','O','F','T','W','A','R','E','\\'};
3261 static const UINT len
= sizeof(prefixW
) / sizeof(prefixW
[0]);
3263 if (is_64bit
&& package
->platform
== PLATFORM_INTEL
&&
3264 root
== HKEY_LOCAL_MACHINE
&& !strncmpiW( path
, prefixW
, len
))
3269 size
= (strlenW( path
) + strlenW( szWow6432Node
) + 2) * sizeof(WCHAR
);
3270 if (!(path_32node
= msi_alloc( size
))) return NULL
;
3272 memcpy( path_32node
, path
, len
* sizeof(WCHAR
) );
3273 strcpyW( path_32node
+ len
, szWow6432Node
);
3274 strcatW( path_32node
, szBackSlash
);
3275 strcatW( path_32node
, path
+ len
);
3279 return strdupW( path
);
3282 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
3284 MSIPACKAGE
*package
= param
;
3285 LPSTR value_data
= NULL
;
3286 HKEY root_key
, hkey
;
3288 LPWSTR deformated
, uikey
, keypath
;
3289 LPCWSTR szRoot
, component
, name
, key
, value
;
3293 BOOL check_first
= FALSE
;
3296 msi_ui_progress( package
, 2, 0, 0, 0 );
3298 component
= MSI_RecordGetString(row
, 6);
3299 comp
= msi_get_loaded_component(package
,component
);
3301 return ERROR_SUCCESS
;
3305 TRACE("component is disabled\n");
3306 return ERROR_SUCCESS
;
3309 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3311 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3312 comp
->Action
= comp
->Installed
;
3313 return ERROR_SUCCESS
;
3315 comp
->Action
= INSTALLSTATE_LOCAL
;
3317 name
= MSI_RecordGetString(row
, 4);
3318 if( MSI_RecordIsNull(row
,5) && name
)
3320 /* null values can have special meanings */
3321 if (name
[0]=='-' && name
[1] == 0)
3322 return ERROR_SUCCESS
;
3323 else if ((name
[0]=='+' && name
[1] == 0) ||
3324 (name
[0] == '*' && name
[1] == 0))
3329 root
= MSI_RecordGetInteger(row
,2);
3330 key
= MSI_RecordGetString(row
, 3);
3332 szRoot
= get_root_key( package
, root
, &root_key
);
3334 return ERROR_SUCCESS
;
3336 deformat_string(package
, key
, &deformated
);
3337 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
3338 uikey
= msi_alloc(size
*sizeof(WCHAR
));
3339 strcpyW(uikey
,szRoot
);
3340 strcatW(uikey
,deformated
);
3342 keypath
= get_keypath( package
, root_key
, deformated
);
3343 msi_free( deformated
);
3344 if (RegCreateKeyW( root_key
, keypath
, &hkey
))
3346 ERR("Could not create key %s\n", debugstr_w(keypath
));
3349 return ERROR_SUCCESS
;
3352 value
= MSI_RecordGetString(row
,5);
3354 value_data
= parse_value(package
, value
, &type
, &size
);
3357 value_data
= (LPSTR
)strdupW(szEmpty
);
3358 size
= sizeof(szEmpty
);
3362 deformat_string(package
, name
, &deformated
);
3366 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
3368 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
3373 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
3374 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
3376 TRACE("value %s of %s checked already exists\n",
3377 debugstr_w(deformated
), debugstr_w(uikey
));
3381 TRACE("Checked and setting value %s of %s\n",
3382 debugstr_w(deformated
), debugstr_w(uikey
));
3383 if (deformated
|| size
)
3384 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
3389 uirow
= MSI_CreateRecord(3);
3390 MSI_RecordSetStringW(uirow
,2,deformated
);
3391 MSI_RecordSetStringW(uirow
,1,uikey
);
3392 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
)
3393 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
3394 msi_ui_actiondata( package
, szWriteRegistryValues
, uirow
);
3395 msiobj_release( &uirow
->hdr
);
3397 msi_free(value_data
);
3398 msi_free(deformated
);
3402 return ERROR_SUCCESS
;
3405 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
3409 static const WCHAR ExecSeqQuery
[] =
3410 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3411 '`','R','e','g','i','s','t','r','y','`',0 };
3413 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3414 if (rc
!= ERROR_SUCCESS
)
3415 return ERROR_SUCCESS
;
3417 /* increment progress bar each time action data is sent */
3418 msi_ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
3420 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
3421 msiobj_release(&view
->hdr
);
3425 static void delete_reg_key_or_value( HKEY hkey_root
, LPCWSTR key
, LPCWSTR value
, BOOL delete_key
)
3429 DWORD num_subkeys
, num_values
;
3433 if ((res
= RegDeleteTreeW( hkey_root
, key
)))
3435 TRACE("Failed to delete key %s (%d)\n", debugstr_w(key
), res
);
3440 if (!(res
= RegOpenKeyW( hkey_root
, key
, &hkey
)))
3442 if ((res
= RegDeleteValueW( hkey
, value
)))
3444 TRACE("Failed to delete value %s (%d)\n", debugstr_w(value
), res
);
3446 res
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
, NULL
, &num_values
,
3447 NULL
, NULL
, NULL
, NULL
);
3448 RegCloseKey( hkey
);
3449 if (!res
&& !num_subkeys
&& !num_values
)
3451 TRACE("Removing empty key %s\n", debugstr_w(key
));
3452 RegDeleteKeyW( hkey_root
, key
);
3456 TRACE("Failed to open key %s (%d)\n", debugstr_w(key
), res
);
3460 static UINT
ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
3462 MSIPACKAGE
*package
= param
;
3463 LPCWSTR component
, name
, key_str
, root_key_str
;
3464 LPWSTR deformated_key
, deformated_name
, ui_key_str
, keypath
;
3467 BOOL delete_key
= FALSE
;
3472 msi_ui_progress( package
, 2, 0, 0, 0 );
3474 component
= MSI_RecordGetString( row
, 6 );
3475 comp
= msi_get_loaded_component( package
, component
);
3477 return ERROR_SUCCESS
;
3481 TRACE("component is disabled\n");
3482 return ERROR_SUCCESS
;
3485 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3487 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
3488 comp
->Action
= comp
->Installed
;
3489 return ERROR_SUCCESS
;
3491 comp
->Action
= INSTALLSTATE_ABSENT
;
3493 name
= MSI_RecordGetString( row
, 4 );
3494 if (MSI_RecordIsNull( row
, 5 ) && name
)
3496 if (name
[0] == '+' && !name
[1])
3497 return ERROR_SUCCESS
;
3498 else if ((name
[0] == '-' && !name
[1]) || (name
[0] == '*' && !name
[1]))
3505 root
= MSI_RecordGetInteger( row
, 2 );
3506 key_str
= MSI_RecordGetString( row
, 3 );
3508 root_key_str
= get_root_key( package
, root
, &hkey_root
);
3510 return ERROR_SUCCESS
;
3512 deformat_string( package
, key_str
, &deformated_key
);
3513 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
3514 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
3515 strcpyW( ui_key_str
, root_key_str
);
3516 strcatW( ui_key_str
, deformated_key
);
3518 deformat_string( package
, name
, &deformated_name
);
3520 keypath
= get_keypath( package
, hkey_root
, deformated_key
);
3521 msi_free( deformated_key
);
3522 delete_reg_key_or_value( hkey_root
, keypath
, deformated_name
, delete_key
);
3523 msi_free( keypath
);
3525 uirow
= MSI_CreateRecord( 2 );
3526 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
3527 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
3529 msi_ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
3530 msiobj_release( &uirow
->hdr
);
3532 msi_free( ui_key_str
);
3533 msi_free( deformated_name
);
3534 return ERROR_SUCCESS
;
3537 static UINT
ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
3539 MSIPACKAGE
*package
= param
;
3540 LPCWSTR component
, name
, key_str
, root_key_str
;
3541 LPWSTR deformated_key
, deformated_name
, ui_key_str
, keypath
;
3544 BOOL delete_key
= FALSE
;
3549 msi_ui_progress( package
, 2, 0, 0, 0 );
3551 component
= MSI_RecordGetString( row
, 5 );
3552 comp
= msi_get_loaded_component( package
, component
);
3554 return ERROR_SUCCESS
;
3558 TRACE("component is disabled\n");
3559 return ERROR_SUCCESS
;
3562 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3564 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3565 comp
->Action
= comp
->Installed
;
3566 return ERROR_SUCCESS
;
3568 comp
->Action
= INSTALLSTATE_LOCAL
;
3570 if ((name
= MSI_RecordGetString( row
, 4 )))
3572 if (name
[0] == '-' && !name
[1])
3579 root
= MSI_RecordGetInteger( row
, 2 );
3580 key_str
= MSI_RecordGetString( row
, 3 );
3582 root_key_str
= get_root_key( package
, root
, &hkey_root
);
3584 return ERROR_SUCCESS
;
3586 deformat_string( package
, key_str
, &deformated_key
);
3587 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
3588 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
3589 strcpyW( ui_key_str
, root_key_str
);
3590 strcatW( ui_key_str
, deformated_key
);
3592 deformat_string( package
, name
, &deformated_name
);
3594 keypath
= get_keypath( package
, hkey_root
, deformated_key
);
3595 msi_free( deformated_key
);
3596 delete_reg_key_or_value( hkey_root
, keypath
, deformated_name
, delete_key
);
3597 msi_free( keypath
);
3599 uirow
= MSI_CreateRecord( 2 );
3600 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
3601 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
3603 msi_ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
3604 msiobj_release( &uirow
->hdr
);
3606 msi_free( ui_key_str
);
3607 msi_free( deformated_name
);
3608 return ERROR_SUCCESS
;
3611 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
3615 static const WCHAR registry_query
[] =
3616 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3617 '`','R','e','g','i','s','t','r','y','`',0 };
3618 static const WCHAR remove_registry_query
[] =
3619 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3620 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
3622 /* increment progress bar each time action data is sent */
3623 msi_ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
3625 rc
= MSI_DatabaseOpenViewW( package
->db
, registry_query
, &view
);
3626 if (rc
== ERROR_SUCCESS
)
3628 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnUninstall
, package
);
3629 msiobj_release( &view
->hdr
);
3630 if (rc
!= ERROR_SUCCESS
)
3634 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_registry_query
, &view
);
3635 if (rc
== ERROR_SUCCESS
)
3637 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnInstall
, package
);
3638 msiobj_release( &view
->hdr
);
3639 if (rc
!= ERROR_SUCCESS
)
3643 return ERROR_SUCCESS
;
3646 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
3648 package
->script
->CurrentlyScripting
= TRUE
;
3650 return ERROR_SUCCESS
;
3654 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
3659 static const WCHAR q1
[]=
3660 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3661 '`','R','e','g','i','s','t','r','y','`',0};
3664 MSIFEATURE
*feature
;
3667 TRACE("InstallValidate\n");
3669 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3670 if (rc
== ERROR_SUCCESS
)
3672 MSI_IterateRecords( view
, &progress
, NULL
, package
);
3673 msiobj_release( &view
->hdr
);
3674 total
+= progress
* REG_PROGRESS_VALUE
;
3677 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
3678 total
+= COMPONENT_PROGRESS_VALUE
;
3680 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
3681 total
+= file
->FileSize
;
3683 msi_ui_progress( package
, 0, total
, 0, 0 );
3685 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3687 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3688 debugstr_w(feature
->Feature
), feature
->Installed
,
3689 feature
->ActionRequest
, feature
->Action
);
3692 return ERROR_SUCCESS
;
3695 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
3697 MSIPACKAGE
* package
= param
;
3698 LPCWSTR cond
= NULL
;
3699 LPCWSTR message
= NULL
;
3702 static const WCHAR title
[]=
3703 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3705 cond
= MSI_RecordGetString(row
,1);
3707 r
= MSI_EvaluateConditionW(package
,cond
);
3708 if (r
== MSICONDITION_FALSE
)
3710 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
3713 message
= MSI_RecordGetString(row
,2);
3714 deformat_string(package
,message
,&deformated
);
3715 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
3716 msi_free(deformated
);
3719 return ERROR_INSTALL_FAILURE
;
3722 return ERROR_SUCCESS
;
3725 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
3728 MSIQUERY
* view
= NULL
;
3729 static const WCHAR ExecSeqQuery
[] =
3730 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3731 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3733 TRACE("Checking launch conditions\n");
3735 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3736 if (rc
!= ERROR_SUCCESS
)
3737 return ERROR_SUCCESS
;
3739 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
3740 msiobj_release(&view
->hdr
);
3745 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
3749 return strdupW( msi_get_target_folder( package
, cmp
->Directory
) );
3751 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
3753 MSIRECORD
* row
= 0;
3755 LPWSTR deformated
,buffer
,deformated_name
;
3757 static const WCHAR ExecSeqQuery
[] =
3758 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3759 '`','R','e','g','i','s','t','r','y','`',' ',
3760 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3761 ' ','=',' ' ,'\'','%','s','\'',0 };
3762 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
3763 static const WCHAR fmt2
[]=
3764 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3766 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
3770 root
= MSI_RecordGetInteger(row
,2);
3771 key
= MSI_RecordGetString(row
, 3);
3772 name
= MSI_RecordGetString(row
, 4);
3773 deformat_string(package
, key
, &deformated
);
3774 deformat_string(package
, name
, &deformated_name
);
3776 len
= strlenW(deformated
) + 6;
3777 if (deformated_name
)
3778 len
+=strlenW(deformated_name
);
3780 buffer
= msi_alloc( len
*sizeof(WCHAR
));
3782 if (deformated_name
)
3783 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
3785 sprintfW(buffer
,fmt
,root
,deformated
);
3787 msi_free(deformated
);
3788 msi_free(deformated_name
);
3789 msiobj_release(&row
->hdr
);
3793 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
3795 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3800 MSIFILE
*file
= msi_get_loaded_file( package
, cmp
->KeyPath
);
3803 return strdupW( file
->TargetPath
);
3808 static HKEY
openSharedDLLsKey(void)
3811 static const WCHAR path
[] =
3812 {'S','o','f','t','w','a','r','e','\\',
3813 'M','i','c','r','o','s','o','f','t','\\',
3814 'W','i','n','d','o','w','s','\\',
3815 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3816 'S','h','a','r','e','d','D','L','L','s',0};
3818 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
3822 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
3827 DWORD sz
= sizeof(count
);
3830 hkey
= openSharedDLLsKey();
3831 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
3832 if (rc
!= ERROR_SUCCESS
)
3838 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
3842 hkey
= openSharedDLLsKey();
3844 msi_reg_set_val_dword( hkey
, path
, count
);
3846 RegDeleteValueW(hkey
,path
);
3851 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
3853 MSIFEATURE
*feature
;
3857 /* only refcount DLLs */
3858 if (comp
->KeyPath
== NULL
||
3860 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
3861 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
3865 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
3866 write
= (count
> 0);
3868 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
3872 /* increment counts */
3873 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3877 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3880 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3882 if ( cl
->component
== comp
)
3887 /* decrement counts */
3888 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3892 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3895 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3897 if ( cl
->component
== comp
)
3902 /* ref count all the files in the component */
3907 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
3909 if (file
->Component
== comp
)
3910 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
3914 /* add a count for permanent */
3915 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
3918 comp
->RefCount
= count
;
3921 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
3924 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
3926 WCHAR squished_pc
[GUID_SIZE
];
3927 WCHAR squished_cc
[GUID_SIZE
];
3934 squash_guid(package
->ProductCode
,squished_pc
);
3935 msi_ui_progress( package
, 1, COMPONENT_PROGRESS_VALUE
, 1, 0 );
3937 msi_set_sourcedir_props(package
, FALSE
);
3939 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
3943 msi_ui_progress( package
, 2, 0, 0, 0 );
3944 if (!comp
->ComponentId
)
3947 squash_guid(comp
->ComponentId
,squished_cc
);
3949 msi_free(comp
->FullKeypath
);
3952 const WCHAR prefixW
[] = {'<','\\',0};
3953 DWORD len
= strlenW( prefixW
) + strlenW( comp
->assembly
->display_name
);
3955 comp
->FullKeypath
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) );
3956 if (comp
->FullKeypath
)
3958 strcpyW( comp
->FullKeypath
, prefixW
);
3959 strcatW( comp
->FullKeypath
, comp
->assembly
->display_name
);
3962 else comp
->FullKeypath
= resolve_keypath( package
, comp
);
3964 ACTION_RefCountComponent( package
, comp
);
3966 TRACE("Component %s (%s), Keypath=%s, RefCount=%i Request=%u\n",
3967 debugstr_w(comp
->Component
),
3968 debugstr_w(squished_cc
),
3969 debugstr_w(comp
->FullKeypath
),
3971 comp
->ActionRequest
);
3973 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
||
3974 comp
->ActionRequest
== INSTALLSTATE_SOURCE
)
3976 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3977 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
, &hkey
, TRUE
);
3979 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
, &hkey
, TRUE
);
3981 if (rc
!= ERROR_SUCCESS
)
3984 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
3986 static const WCHAR szPermKey
[] =
3987 { '0','0','0','0','0','0','0','0','0','0','0','0',
3988 '0','0','0','0','0','0','0','0','0','0','0','0',
3989 '0','0','0','0','0','0','0','0',0 };
3991 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
3994 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
)
3995 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
4001 WCHAR source
[MAX_PATH
];
4002 WCHAR base
[MAX_PATH
];
4005 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
4006 static const WCHAR query
[] = {
4007 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
4008 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
4009 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
4010 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
4011 '`','D','i','s','k','I','d','`',0};
4013 if (!comp
->KeyPath
|| !(file
= msi_get_loaded_file(package
, comp
->KeyPath
)))
4016 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
4017 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
4018 ptr2
= strrchrW(source
, '\\') + 1;
4019 msiobj_release(&row
->hdr
);
4021 lstrcpyW(base
, package
->PackagePath
);
4022 ptr
= strrchrW(base
, '\\');
4025 sourcepath
= msi_resolve_file_source(package
, file
);
4026 ptr
= sourcepath
+ lstrlenW(base
);
4027 lstrcpyW(ptr2
, ptr
);
4028 msi_free(sourcepath
);
4030 msi_reg_set_val_str(hkey
, squished_pc
, source
);
4034 else if (comp
->ActionRequest
== INSTALLSTATE_ABSENT
)
4036 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4037 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
4039 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
4041 comp
->Action
= comp
->ActionRequest
;
4044 uirow
= MSI_CreateRecord(3);
4045 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
4046 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
4047 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
4048 msi_ui_actiondata( package
, szProcessComponents
, uirow
);
4049 msiobj_release( &uirow
->hdr
);
4052 return ERROR_SUCCESS
;
4063 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
4064 LPWSTR lpszName
, LONG_PTR lParam
)
4067 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
4068 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
4072 if (!IS_INTRESOURCE(lpszName
))
4074 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
4078 sz
= strlenW(tl_struct
->source
)+4;
4079 sz
*= sizeof(WCHAR
);
4081 if ((INT_PTR
)lpszName
== 1)
4082 tl_struct
->path
= strdupW(tl_struct
->source
);
4085 tl_struct
->path
= msi_alloc(sz
);
4086 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
4089 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
4090 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
4093 msi_free(tl_struct
->path
);
4094 tl_struct
->path
= NULL
;
4099 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
4100 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
4102 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
4106 msi_free(tl_struct
->path
);
4107 tl_struct
->path
= NULL
;
4109 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
4110 ITypeLib_Release(tl_struct
->ptLib
);
4115 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
4117 MSIPACKAGE
* package
= param
;
4121 typelib_struct tl_struct
;
4126 component
= MSI_RecordGetString(row
,3);
4127 comp
= msi_get_loaded_component(package
,component
);
4129 return ERROR_SUCCESS
;
4133 TRACE("component is disabled\n");
4134 return ERROR_SUCCESS
;
4137 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4139 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
4140 comp
->Action
= comp
->Installed
;
4141 return ERROR_SUCCESS
;
4143 comp
->Action
= INSTALLSTATE_LOCAL
;
4145 if (!comp
->KeyPath
|| !(file
= msi_get_loaded_file( package
, comp
->KeyPath
)))
4147 TRACE("component has no key path\n");
4148 return ERROR_SUCCESS
;
4150 msi_ui_actiondata( package
, szRegisterTypeLibraries
, row
);
4152 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
4156 guid
= MSI_RecordGetString(row
,1);
4157 CLSIDFromString((LPCWSTR
)guid
, &tl_struct
.clsid
);
4158 tl_struct
.source
= strdupW( file
->TargetPath
);
4159 tl_struct
.path
= NULL
;
4161 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
4162 (LONG_PTR
)&tl_struct
);
4166 LPCWSTR helpid
, help_path
= NULL
;
4169 helpid
= MSI_RecordGetString(row
,6);
4171 if (helpid
) help_path
= msi_get_target_folder( package
, helpid
);
4172 res
= RegisterTypeLib( tl_struct
.ptLib
, tl_struct
.path
, (OLECHAR
*)help_path
);
4175 ERR("Failed to register type library %s\n", debugstr_w(tl_struct
.path
));
4177 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
4179 ITypeLib_Release(tl_struct
.ptLib
);
4180 msi_free(tl_struct
.path
);
4182 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct
.source
));
4184 FreeLibrary(module
);
4185 msi_free(tl_struct
.source
);
4189 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
4192 ERR("Failed to load type library: %08x\n", hr
);
4193 return ERROR_INSTALL_FAILURE
;
4196 ITypeLib_Release(tlib
);
4199 return ERROR_SUCCESS
;
4202 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
4205 * OK this is a bit confusing.. I am given a _Component key and I believe
4206 * that the file that is being registered as a type library is the "key file
4207 * of that component" which I interpret to mean "The file in the KeyPath of
4212 static const WCHAR Query
[] =
4213 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4214 '`','T','y','p','e','L','i','b','`',0};
4216 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4217 if (rc
!= ERROR_SUCCESS
)
4218 return ERROR_SUCCESS
;
4220 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
4221 msiobj_release(&view
->hdr
);
4225 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
4227 MSIPACKAGE
*package
= param
;
4228 LPCWSTR component
, guid
;
4236 component
= MSI_RecordGetString( row
, 3 );
4237 comp
= msi_get_loaded_component( package
, component
);
4239 return ERROR_SUCCESS
;
4243 TRACE("component is disabled\n");
4244 return ERROR_SUCCESS
;
4247 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4249 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
4250 comp
->Action
= comp
->Installed
;
4251 return ERROR_SUCCESS
;
4253 comp
->Action
= INSTALLSTATE_ABSENT
;
4255 msi_ui_actiondata( package
, szUnregisterTypeLibraries
, row
);
4257 guid
= MSI_RecordGetString( row
, 1 );
4258 CLSIDFromString( (LPCWSTR
)guid
, &libid
);
4259 version
= MSI_RecordGetInteger( row
, 4 );
4260 language
= MSI_RecordGetInteger( row
, 2 );
4263 syskind
= SYS_WIN64
;
4265 syskind
= SYS_WIN32
;
4268 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
4271 WARN("Failed to unregister typelib: %08x\n", hr
);
4274 return ERROR_SUCCESS
;
4277 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
4281 static const WCHAR query
[] =
4282 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4283 '`','T','y','p','e','L','i','b','`',0};
4285 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4286 if (rc
!= ERROR_SUCCESS
)
4287 return ERROR_SUCCESS
;
4289 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
4290 msiobj_release( &view
->hdr
);
4294 static WCHAR
*get_link_file( MSIPACKAGE
*package
, MSIRECORD
*row
)
4296 static const WCHAR szlnk
[] = {'.','l','n','k',0};
4297 LPCWSTR directory
, extension
, link_folder
;
4298 LPWSTR link_file
, filename
;
4300 directory
= MSI_RecordGetString( row
, 2 );
4301 link_folder
= msi_get_target_folder( package
, directory
);
4303 /* may be needed because of a bug somewhere else */
4304 msi_create_full_path( link_folder
);
4306 filename
= msi_dup_record_field( row
, 3 );
4307 msi_reduce_to_long_filename( filename
);
4309 extension
= strchrW( filename
, '.' );
4310 if (!extension
|| strcmpiW( extension
, szlnk
))
4312 int len
= strlenW( filename
);
4313 filename
= msi_realloc( filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
) );
4314 memcpy( filename
+ len
, szlnk
, sizeof(szlnk
) );
4316 link_file
= msi_build_directory_name( 2, link_folder
, filename
);
4317 msi_free( filename
);
4322 WCHAR
*msi_build_icon_path( MSIPACKAGE
*package
, const WCHAR
*icon_name
)
4324 static const WCHAR szMicrosoft
[] = {'M','i','c','r','o','s','o','f','t','\\',0};
4325 static const WCHAR szInstaller
[] = {'I','n','s','t','a','l','l','e','r','\\',0};
4326 WCHAR
*folder
, *dest
, *path
;
4328 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4329 folder
= msi_dup_property( package
->db
, szWindowsFolder
);
4332 WCHAR
*appdata
= msi_dup_property( package
->db
, szAppDataFolder
);
4333 folder
= msi_build_directory_name( 2, appdata
, szMicrosoft
);
4334 msi_free( appdata
);
4336 dest
= msi_build_directory_name( 3, folder
, szInstaller
, package
->ProductCode
);
4337 msi_create_full_path( dest
);
4338 path
= msi_build_directory_name( 2, dest
, icon_name
);
4344 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
4346 MSIPACKAGE
*package
= param
;
4347 LPWSTR link_file
, deformated
, path
;
4348 LPCWSTR component
, target
;
4350 IShellLinkW
*sl
= NULL
;
4351 IPersistFile
*pf
= NULL
;
4354 component
= MSI_RecordGetString(row
, 4);
4355 comp
= msi_get_loaded_component(package
, component
);
4357 return ERROR_SUCCESS
;
4361 TRACE("component is disabled\n");
4362 return ERROR_SUCCESS
;
4365 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4367 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
4368 comp
->Action
= comp
->Installed
;
4369 return ERROR_SUCCESS
;
4371 comp
->Action
= INSTALLSTATE_LOCAL
;
4373 msi_ui_actiondata( package
, szCreateShortcuts
, row
);
4375 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
4376 &IID_IShellLinkW
, (LPVOID
*) &sl
);
4380 ERR("CLSID_ShellLink not available\n");
4384 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
4387 ERR("QueryInterface(IID_IPersistFile) failed\n");
4391 target
= MSI_RecordGetString(row
, 5);
4392 if (strchrW(target
, '['))
4394 deformat_string(package
, target
, &deformated
);
4395 IShellLinkW_SetPath(sl
,deformated
);
4396 msi_free(deformated
);
4400 FIXME("poorly handled shortcut format, advertised shortcut\n");
4401 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
4404 if (!MSI_RecordIsNull(row
,6))
4406 LPCWSTR arguments
= MSI_RecordGetString(row
, 6);
4407 deformat_string(package
, arguments
, &deformated
);
4408 IShellLinkW_SetArguments(sl
,deformated
);
4409 msi_free(deformated
);
4412 if (!MSI_RecordIsNull(row
,7))
4414 LPCWSTR description
= MSI_RecordGetString(row
, 7);
4415 IShellLinkW_SetDescription(sl
, description
);
4418 if (!MSI_RecordIsNull(row
,8))
4419 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
4421 if (!MSI_RecordIsNull(row
,9))
4424 LPCWSTR icon
= MSI_RecordGetString(row
, 9);
4426 path
= msi_build_icon_path(package
, icon
);
4427 index
= MSI_RecordGetInteger(row
,10);
4429 /* no value means 0 */
4430 if (index
== MSI_NULL_INTEGER
)
4433 IShellLinkW_SetIconLocation(sl
, path
, index
);
4437 if (!MSI_RecordIsNull(row
,11))
4438 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
4440 if (!MSI_RecordIsNull(row
,12))
4442 LPCWSTR full_path
, wkdir
= MSI_RecordGetString( row
, 12 );
4443 full_path
= msi_get_target_folder( package
, wkdir
);
4444 if (full_path
) IShellLinkW_SetWorkingDirectory( sl
, full_path
);
4446 link_file
= get_link_file(package
, row
);
4448 TRACE("Writing shortcut to %s\n", debugstr_w(link_file
));
4449 IPersistFile_Save(pf
, link_file
, FALSE
);
4450 msi_free(link_file
);
4454 IPersistFile_Release( pf
);
4456 IShellLinkW_Release( sl
);
4458 return ERROR_SUCCESS
;
4461 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
4466 static const WCHAR Query
[] =
4467 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4468 '`','S','h','o','r','t','c','u','t','`',0};
4470 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4471 if (rc
!= ERROR_SUCCESS
)
4472 return ERROR_SUCCESS
;
4474 res
= CoInitialize( NULL
);
4476 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
4477 msiobj_release(&view
->hdr
);
4485 static UINT
ITERATE_RemoveShortcuts( MSIRECORD
*row
, LPVOID param
)
4487 MSIPACKAGE
*package
= param
;
4492 component
= MSI_RecordGetString( row
, 4 );
4493 comp
= msi_get_loaded_component( package
, component
);
4495 return ERROR_SUCCESS
;
4499 TRACE("component is disabled\n");
4500 return ERROR_SUCCESS
;
4503 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4505 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
4506 comp
->Action
= comp
->Installed
;
4507 return ERROR_SUCCESS
;
4509 comp
->Action
= INSTALLSTATE_ABSENT
;
4511 msi_ui_actiondata( package
, szRemoveShortcuts
, row
);
4513 link_file
= get_link_file( package
, row
);
4515 TRACE("Removing shortcut file %s\n", debugstr_w( link_file
));
4516 if (!DeleteFileW( link_file
))
4518 WARN("Failed to remove shortcut file %u\n", GetLastError());
4520 msi_free( link_file
);
4522 return ERROR_SUCCESS
;
4525 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
4529 static const WCHAR query
[] =
4530 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4531 '`','S','h','o','r','t','c','u','t','`',0};
4533 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4534 if (rc
!= ERROR_SUCCESS
)
4535 return ERROR_SUCCESS
;
4537 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveShortcuts
, package
);
4538 msiobj_release( &view
->hdr
);
4543 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
4545 MSIPACKAGE
* package
= param
;
4553 FileName
= MSI_RecordGetString(row
,1);
4556 ERR("Unable to get FileName\n");
4557 return ERROR_SUCCESS
;
4560 FilePath
= msi_build_icon_path(package
, FileName
);
4562 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
4564 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
4565 FILE_ATTRIBUTE_NORMAL
, NULL
);
4567 if (the_file
== INVALID_HANDLE_VALUE
)
4569 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
4571 return ERROR_SUCCESS
;
4578 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
4579 if (rc
!= ERROR_SUCCESS
)
4581 ERR("Failed to get stream\n");
4582 CloseHandle(the_file
);
4583 DeleteFileW(FilePath
);
4586 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
4587 } while (sz
== 1024);
4590 CloseHandle(the_file
);
4592 return ERROR_SUCCESS
;
4595 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
4600 static const WCHAR query
[]= {
4601 'S','E','L','E','C','T',' ','*',' ',
4602 'F','R','O','M',' ','`','I','c','o','n','`',0};
4604 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
4605 if (r
== ERROR_SUCCESS
)
4607 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
4608 msiobj_release(&view
->hdr
);
4611 return ERROR_SUCCESS
;
4614 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
4620 MSISOURCELISTINFO
*info
;
4622 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
4623 if (r
!= ERROR_SUCCESS
)
4626 RegCloseKey(source
);
4628 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
4629 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
4630 package
->Context
, MSICODE_PRODUCT
,
4631 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
4632 if (r
!= ERROR_SUCCESS
)
4635 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
4636 package
->Context
, MSICODE_PRODUCT
,
4637 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
4638 if (r
!= ERROR_SUCCESS
)
4641 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
4642 package
->Context
, MSICODE_PRODUCT
,
4643 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
4644 if (r
!= ERROR_SUCCESS
)
4647 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
4649 if (!strcmpW( info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
4650 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
4651 info
->options
, info
->value
);
4653 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
4654 info
->context
, info
->options
,
4655 info
->property
, info
->value
);
4658 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
4660 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
4661 disk
->context
, disk
->options
,
4662 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
4665 return ERROR_SUCCESS
;
4668 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
4670 MSIHANDLE hdb
, suminfo
;
4671 WCHAR guids
[MAX_PATH
];
4672 WCHAR packcode
[SQUISH_GUID_SIZE
];
4679 static const WCHAR szARPProductIcon
[] =
4680 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
4681 static const WCHAR szAssignment
[] =
4682 {'A','s','s','i','g','n','m','e','n','t',0};
4683 static const WCHAR szAdvertiseFlags
[] =
4684 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
4685 static const WCHAR szClients
[] =
4686 {'C','l','i','e','n','t','s',0};
4687 static const WCHAR szColon
[] = {':',0};
4689 buffer
= msi_dup_property(package
->db
, INSTALLPROPERTY_PRODUCTNAMEW
);
4690 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
4693 langid
= msi_get_property_int(package
->db
, szProductLanguage
, 0);
4694 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4697 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
4699 buffer
= msi_dup_property(package
->db
, szARPProductIcon
);
4702 LPWSTR path
= msi_build_icon_path(package
, buffer
);
4703 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
4708 buffer
= msi_dup_property(package
->db
, szProductVersion
);
4711 DWORD verdword
= msi_version_str_to_dword(buffer
);
4712 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4716 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
4717 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
4718 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
4719 msi_reg_set_val_str(hkey
, szClients
, szColon
);
4721 hdb
= alloc_msihandle(&package
->db
->hdr
);
4723 return ERROR_NOT_ENOUGH_MEMORY
;
4725 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
4726 MsiCloseHandle(hdb
);
4727 if (r
!= ERROR_SUCCESS
)
4731 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
4732 NULL
, guids
, &size
);
4733 if (r
!= ERROR_SUCCESS
)
4736 ptr
= strchrW(guids
, ';');
4738 squash_guid(guids
, packcode
);
4739 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
4742 MsiCloseHandle(suminfo
);
4743 return ERROR_SUCCESS
;
4746 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
4751 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4753 upgrade
= msi_dup_property(package
->db
, szUpgradeCode
);
4755 return ERROR_SUCCESS
;
4757 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4758 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
4760 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
4762 if (r
!= ERROR_SUCCESS
)
4764 WARN("failed to open upgrade code key\n");
4766 return ERROR_SUCCESS
;
4768 squash_guid(package
->ProductCode
, squashed_pc
);
4769 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
4772 return ERROR_SUCCESS
;
4775 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
4777 MSIFEATURE
*feature
;
4779 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4781 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
4788 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
4790 MSIFEATURE
*feature
;
4792 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4794 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4801 static UINT
msi_publish_patches( MSIPACKAGE
*package
)
4803 static const WCHAR szAllPatches
[] = {'A','l','l','P','a','t','c','h','e','s',0};
4804 WCHAR patch_squashed
[GUID_SIZE
];
4805 HKEY patches_key
= NULL
, product_patches_key
= NULL
, product_key
;
4807 MSIPATCHINFO
*patch
;
4809 WCHAR
*p
, *all_patches
= NULL
;
4812 r
= MSIREG_OpenProductKey( package
->ProductCode
, NULL
, package
->Context
, &product_key
, TRUE
);
4813 if (r
!= ERROR_SUCCESS
)
4814 return ERROR_FUNCTION_FAILED
;
4816 res
= RegCreateKeyExW( product_key
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &patches_key
, NULL
);
4817 if (res
!= ERROR_SUCCESS
)
4819 r
= ERROR_FUNCTION_FAILED
;
4823 r
= MSIREG_OpenUserDataProductPatchesKey( package
->ProductCode
, package
->Context
, &product_patches_key
, TRUE
);
4824 if (r
!= ERROR_SUCCESS
)
4827 LIST_FOR_EACH_ENTRY( patch
, &package
->patches
, MSIPATCHINFO
, entry
)
4829 squash_guid( patch
->patchcode
, patch_squashed
);
4830 len
+= strlenW( patch_squashed
) + 1;
4833 p
= all_patches
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) );
4837 LIST_FOR_EACH_ENTRY( patch
, &package
->patches
, MSIPATCHINFO
, entry
)
4841 squash_guid( patch
->patchcode
, p
);
4842 p
+= strlenW( p
) + 1;
4844 res
= RegSetValueExW( patches_key
, patch_squashed
, 0, REG_SZ
,
4845 (const BYTE
*)patch
->transforms
,
4846 (strlenW(patch
->transforms
) + 1) * sizeof(WCHAR
) );
4847 if (res
!= ERROR_SUCCESS
)
4850 r
= MSIREG_OpenUserDataPatchKey( patch
->patchcode
, package
->Context
, &patch_key
, TRUE
);
4851 if (r
!= ERROR_SUCCESS
)
4854 res
= RegSetValueExW( patch_key
, szLocalPackage
, 0, REG_SZ
,
4855 (const BYTE
*)patch
->localfile
,
4856 (strlenW(patch
->localfile
) + 1) * sizeof(WCHAR
) );
4857 RegCloseKey( patch_key
);
4858 if (res
!= ERROR_SUCCESS
)
4861 res
= RegCreateKeyExW( product_patches_key
, patch_squashed
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &patch_key
, NULL
);
4862 if (res
!= ERROR_SUCCESS
)
4865 res
= RegSetValueExW( patch_key
, szState
, 0, REG_DWORD
, (const BYTE
*)&patch
->state
, sizeof(patch
->state
) );
4866 RegCloseKey( patch_key
);
4867 if (res
!= ERROR_SUCCESS
)
4871 all_patches
[len
] = 0;
4872 res
= RegSetValueExW( patches_key
, szPatches
, 0, REG_MULTI_SZ
,
4873 (const BYTE
*)all_patches
, (len
+ 1) * sizeof(WCHAR
) );
4874 if (res
!= ERROR_SUCCESS
)
4877 res
= RegSetValueExW( product_patches_key
, szAllPatches
, 0, REG_MULTI_SZ
,
4878 (const BYTE
*)all_patches
, (len
+ 1) * sizeof(WCHAR
) );
4879 if (res
!= ERROR_SUCCESS
)
4880 r
= ERROR_FUNCTION_FAILED
;
4883 RegCloseKey( product_patches_key
);
4884 RegCloseKey( patches_key
);
4885 RegCloseKey( product_key
);
4886 msi_free( all_patches
);
4891 * 99% of the work done here is only done for
4892 * advertised installs. However this is where the
4893 * Icon table is processed and written out
4894 * so that is what I am going to do here.
4896 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
4899 HKEY hukey
= NULL
, hudkey
= NULL
;
4902 if (!list_empty(&package
->patches
))
4904 rc
= msi_publish_patches(package
);
4905 if (rc
!= ERROR_SUCCESS
)
4909 /* FIXME: also need to publish if the product is in advertise mode */
4910 if (!msi_check_publish(package
))
4911 return ERROR_SUCCESS
;
4913 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
4915 if (rc
!= ERROR_SUCCESS
)
4918 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
4919 NULL
, &hudkey
, TRUE
);
4920 if (rc
!= ERROR_SUCCESS
)
4923 rc
= msi_publish_upgrade_code(package
);
4924 if (rc
!= ERROR_SUCCESS
)
4927 rc
= msi_publish_product_properties(package
, hukey
);
4928 if (rc
!= ERROR_SUCCESS
)
4931 rc
= msi_publish_sourcelist(package
, hukey
);
4932 if (rc
!= ERROR_SUCCESS
)
4935 rc
= msi_publish_icons(package
);
4938 uirow
= MSI_CreateRecord( 1 );
4939 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4940 msi_ui_actiondata( package
, szPublishProduct
, uirow
);
4941 msiobj_release( &uirow
->hdr
);
4944 RegCloseKey(hudkey
);
4949 static WCHAR
*get_ini_file_name( MSIPACKAGE
*package
, MSIRECORD
*row
)
4951 WCHAR
*filename
, *ptr
, *folder
, *ret
;
4952 const WCHAR
*dirprop
;
4954 filename
= msi_dup_record_field( row
, 2 );
4955 if (filename
&& (ptr
= strchrW( filename
, '|' )))
4960 dirprop
= MSI_RecordGetString( row
, 3 );
4963 folder
= strdupW( msi_get_target_folder( package
, dirprop
) );
4964 if (!folder
) folder
= msi_dup_property( package
->db
, dirprop
);
4967 folder
= msi_dup_property( package
->db
, szWindowsFolder
);
4971 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop
));
4972 msi_free( filename
);
4976 ret
= msi_build_directory_name( 2, folder
, ptr
);
4978 msi_free( filename
);
4983 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
4985 MSIPACKAGE
*package
= param
;
4986 LPCWSTR component
, section
, key
, value
, identifier
;
4987 LPWSTR deformated_section
, deformated_key
, deformated_value
, fullname
;
4992 component
= MSI_RecordGetString(row
, 8);
4993 comp
= msi_get_loaded_component(package
,component
);
4995 return ERROR_SUCCESS
;
4999 TRACE("component is disabled\n");
5000 return ERROR_SUCCESS
;
5003 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5005 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
5006 comp
->Action
= comp
->Installed
;
5007 return ERROR_SUCCESS
;
5009 comp
->Action
= INSTALLSTATE_LOCAL
;
5011 identifier
= MSI_RecordGetString(row
,1);
5012 section
= MSI_RecordGetString(row
,4);
5013 key
= MSI_RecordGetString(row
,5);
5014 value
= MSI_RecordGetString(row
,6);
5015 action
= MSI_RecordGetInteger(row
,7);
5017 deformat_string(package
,section
,&deformated_section
);
5018 deformat_string(package
,key
,&deformated_key
);
5019 deformat_string(package
,value
,&deformated_value
);
5021 fullname
= get_ini_file_name(package
, row
);
5025 TRACE("Adding value %s to section %s in %s\n",
5026 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
5027 debugstr_w(fullname
));
5028 WritePrivateProfileStringW(deformated_section
, deformated_key
,
5029 deformated_value
, fullname
);
5031 else if (action
== 1)
5034 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
5035 returned
, 10, fullname
);
5036 if (returned
[0] == 0)
5038 TRACE("Adding value %s to section %s in %s\n",
5039 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
5040 debugstr_w(fullname
));
5042 WritePrivateProfileStringW(deformated_section
, deformated_key
,
5043 deformated_value
, fullname
);
5046 else if (action
== 3)
5047 FIXME("Append to existing section not yet implemented\n");
5049 uirow
= MSI_CreateRecord(4);
5050 MSI_RecordSetStringW(uirow
,1,identifier
);
5051 MSI_RecordSetStringW(uirow
,2,deformated_section
);
5052 MSI_RecordSetStringW(uirow
,3,deformated_key
);
5053 MSI_RecordSetStringW(uirow
,4,deformated_value
);
5054 msi_ui_actiondata( package
, szWriteIniValues
, uirow
);
5055 msiobj_release( &uirow
->hdr
);
5058 msi_free(deformated_key
);
5059 msi_free(deformated_value
);
5060 msi_free(deformated_section
);
5061 return ERROR_SUCCESS
;
5064 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
5068 static const WCHAR ExecSeqQuery
[] =
5069 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5070 '`','I','n','i','F','i','l','e','`',0};
5072 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5073 if (rc
!= ERROR_SUCCESS
)
5075 TRACE("no IniFile table\n");
5076 return ERROR_SUCCESS
;
5079 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
5080 msiobj_release(&view
->hdr
);
5084 static UINT
ITERATE_RemoveIniValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
5086 MSIPACKAGE
*package
= param
;
5087 LPCWSTR component
, section
, key
, value
, identifier
;
5088 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
5093 component
= MSI_RecordGetString( row
, 8 );
5094 comp
= msi_get_loaded_component( package
, component
);
5096 return ERROR_SUCCESS
;
5100 TRACE("component is disabled\n");
5101 return ERROR_SUCCESS
;
5104 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5106 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
5107 comp
->Action
= comp
->Installed
;
5108 return ERROR_SUCCESS
;
5110 comp
->Action
= INSTALLSTATE_ABSENT
;
5112 identifier
= MSI_RecordGetString( row
, 1 );
5113 section
= MSI_RecordGetString( row
, 4 );
5114 key
= MSI_RecordGetString( row
, 5 );
5115 value
= MSI_RecordGetString( row
, 6 );
5116 action
= MSI_RecordGetInteger( row
, 7 );
5118 deformat_string( package
, section
, &deformated_section
);
5119 deformat_string( package
, key
, &deformated_key
);
5120 deformat_string( package
, value
, &deformated_value
);
5122 if (action
== msidbIniFileActionAddLine
|| action
== msidbIniFileActionCreateLine
)
5124 filename
= get_ini_file_name( package
, row
);
5126 TRACE("Removing key %s from section %s in %s\n",
5127 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
5129 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
5131 WARN("Unable to remove key %u\n", GetLastError());
5133 msi_free( filename
);
5136 FIXME("Unsupported action %d\n", action
);
5139 uirow
= MSI_CreateRecord( 4 );
5140 MSI_RecordSetStringW( uirow
, 1, identifier
);
5141 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
5142 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
5143 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
5144 msi_ui_actiondata( package
, szRemoveIniValues
, uirow
);
5145 msiobj_release( &uirow
->hdr
);
5147 msi_free( deformated_key
);
5148 msi_free( deformated_value
);
5149 msi_free( deformated_section
);
5150 return ERROR_SUCCESS
;
5153 static UINT
ITERATE_RemoveIniValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
5155 MSIPACKAGE
*package
= param
;
5156 LPCWSTR component
, section
, key
, value
, identifier
;
5157 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
5162 component
= MSI_RecordGetString( row
, 8 );
5163 comp
= msi_get_loaded_component( package
, component
);
5165 return ERROR_SUCCESS
;
5169 TRACE("component is disabled\n");
5170 return ERROR_SUCCESS
;
5173 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5175 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
5176 comp
->Action
= comp
->Installed
;
5177 return ERROR_SUCCESS
;
5179 comp
->Action
= INSTALLSTATE_LOCAL
;
5181 identifier
= MSI_RecordGetString( row
, 1 );
5182 section
= MSI_RecordGetString( row
, 4 );
5183 key
= MSI_RecordGetString( row
, 5 );
5184 value
= MSI_RecordGetString( row
, 6 );
5185 action
= MSI_RecordGetInteger( row
, 7 );
5187 deformat_string( package
, section
, &deformated_section
);
5188 deformat_string( package
, key
, &deformated_key
);
5189 deformat_string( package
, value
, &deformated_value
);
5191 if (action
== msidbIniFileActionRemoveLine
)
5193 filename
= get_ini_file_name( package
, row
);
5195 TRACE("Removing key %s from section %s in %s\n",
5196 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
5198 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
5200 WARN("Unable to remove key %u\n", GetLastError());
5202 msi_free( filename
);
5205 FIXME("Unsupported action %d\n", action
);
5207 uirow
= MSI_CreateRecord( 4 );
5208 MSI_RecordSetStringW( uirow
, 1, identifier
);
5209 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
5210 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
5211 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
5212 msi_ui_actiondata( package
, szRemoveIniValues
, uirow
);
5213 msiobj_release( &uirow
->hdr
);
5215 msi_free( deformated_key
);
5216 msi_free( deformated_value
);
5217 msi_free( deformated_section
);
5218 return ERROR_SUCCESS
;
5221 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
5225 static const WCHAR query
[] =
5226 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5227 '`','I','n','i','F','i','l','e','`',0};
5228 static const WCHAR remove_query
[] =
5229 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5230 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
5232 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5233 if (rc
== ERROR_SUCCESS
)
5235 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnUninstall
, package
);
5236 msiobj_release( &view
->hdr
);
5237 if (rc
!= ERROR_SUCCESS
)
5241 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_query
, &view
);
5242 if (rc
== ERROR_SUCCESS
)
5244 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnInstall
, package
);
5245 msiobj_release( &view
->hdr
);
5246 if (rc
!= ERROR_SUCCESS
)
5250 return ERROR_SUCCESS
;
5253 static void register_dll( const WCHAR
*dll
, BOOL unregister
)
5257 hmod
= LoadLibraryExW( dll
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
5260 HRESULT (WINAPI
*func_ptr
)( void );
5261 const char *func
= unregister
? "DllUnregisterServer" : "DllRegisterServer";
5263 func_ptr
= (void *)GetProcAddress( hmod
, func
);
5266 HRESULT hr
= func_ptr();
5268 WARN("failed to register dll 0x%08x\n", hr
);
5271 WARN("entry point %s not found\n", func
);
5272 FreeLibrary( hmod
);
5275 WARN("failed to load library %u\n", GetLastError());
5278 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
5280 MSIPACKAGE
*package
= param
;
5285 filename
= MSI_RecordGetString(row
,1);
5286 file
= msi_get_loaded_file( package
, filename
);
5290 ERR("Unable to find file id %s\n",debugstr_w(filename
));
5291 return ERROR_SUCCESS
;
5294 TRACE("Registering %s\n", debugstr_w( file
->TargetPath
));
5296 register_dll( file
->TargetPath
, FALSE
);
5298 uirow
= MSI_CreateRecord( 2 );
5299 MSI_RecordSetStringW( uirow
, 1, filename
);
5300 MSI_RecordSetStringW( uirow
, 2, file
->Component
->Directory
);
5301 msi_ui_actiondata( package
, szSelfRegModules
, uirow
);
5302 msiobj_release( &uirow
->hdr
);
5304 return ERROR_SUCCESS
;
5307 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
5311 static const WCHAR ExecSeqQuery
[] =
5312 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5313 '`','S','e','l','f','R','e','g','`',0};
5315 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5316 if (rc
!= ERROR_SUCCESS
)
5318 TRACE("no SelfReg table\n");
5319 return ERROR_SUCCESS
;
5322 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
5323 msiobj_release(&view
->hdr
);
5325 return ERROR_SUCCESS
;
5328 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
5330 MSIPACKAGE
*package
= param
;
5335 filename
= MSI_RecordGetString( row
, 1 );
5336 file
= msi_get_loaded_file( package
, filename
);
5340 ERR("Unable to find file id %s\n", debugstr_w(filename
));
5341 return ERROR_SUCCESS
;
5344 TRACE("Unregistering %s\n", debugstr_w( file
->TargetPath
));
5346 register_dll( file
->TargetPath
, TRUE
);
5348 uirow
= MSI_CreateRecord( 2 );
5349 MSI_RecordSetStringW( uirow
, 1, filename
);
5350 MSI_RecordSetStringW( uirow
, 2, file
->Component
->Directory
);
5351 msi_ui_actiondata( package
, szSelfUnregModules
, uirow
);
5352 msiobj_release( &uirow
->hdr
);
5354 return ERROR_SUCCESS
;
5357 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
5361 static const WCHAR query
[] =
5362 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5363 '`','S','e','l','f','R','e','g','`',0};
5365 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5366 if (rc
!= ERROR_SUCCESS
)
5368 TRACE("no SelfReg table\n");
5369 return ERROR_SUCCESS
;
5372 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
5373 msiobj_release( &view
->hdr
);
5375 return ERROR_SUCCESS
;
5378 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
5380 MSIFEATURE
*feature
;
5382 HKEY hkey
= NULL
, userdata
= NULL
;
5384 if (!msi_check_publish(package
))
5385 return ERROR_SUCCESS
;
5387 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
5389 if (rc
!= ERROR_SUCCESS
)
5392 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
5394 if (rc
!= ERROR_SUCCESS
)
5397 /* here the guids are base 85 encoded */
5398 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
5404 BOOL absent
= FALSE
;
5407 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
5408 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
5409 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
5412 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
5416 if (feature
->Feature_Parent
)
5417 size
+= strlenW( feature
->Feature_Parent
)+2;
5419 data
= msi_alloc(size
* sizeof(WCHAR
));
5422 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
5424 MSICOMPONENT
* component
= cl
->component
;
5428 if (component
->ComponentId
)
5430 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
5431 CLSIDFromString(component
->ComponentId
, &clsid
);
5432 encode_base85_guid(&clsid
,buf
);
5433 TRACE("to %s\n",debugstr_w(buf
));
5438 if (feature
->Feature_Parent
)
5440 static const WCHAR sep
[] = {'\2',0};
5442 strcatW(data
,feature
->Feature_Parent
);
5445 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
5449 if (feature
->Feature_Parent
)
5450 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
5453 size
+= sizeof(WCHAR
);
5454 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
5455 (const BYTE
*)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
5459 size
+= 2*sizeof(WCHAR
);
5460 data
= msi_alloc(size
);
5463 if (feature
->Feature_Parent
)
5464 strcpyW( &data
[1], feature
->Feature_Parent
);
5465 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
5471 uirow
= MSI_CreateRecord( 1 );
5472 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
5473 msi_ui_actiondata( package
, szPublishFeatures
, uirow
);
5474 msiobj_release( &uirow
->hdr
);
5475 /* FIXME: call msi_ui_progress? */
5480 RegCloseKey(userdata
);
5484 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
5490 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
5492 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
5494 if (r
== ERROR_SUCCESS
)
5496 RegDeleteValueW(hkey
, feature
->Feature
);
5500 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
5502 if (r
== ERROR_SUCCESS
)
5504 RegDeleteValueW(hkey
, feature
->Feature
);
5508 uirow
= MSI_CreateRecord( 1 );
5509 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
5510 msi_ui_actiondata( package
, szUnpublishFeatures
, uirow
);
5511 msiobj_release( &uirow
->hdr
);
5513 return ERROR_SUCCESS
;
5516 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
5518 MSIFEATURE
*feature
;
5520 if (!msi_check_unpublish(package
))
5521 return ERROR_SUCCESS
;
5523 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
5525 msi_unpublish_feature(package
, feature
);
5528 return ERROR_SUCCESS
;
5531 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
5535 WCHAR date
[9], *val
, *buffer
;
5536 const WCHAR
*prop
, *key
;
5538 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
5539 static const WCHAR modpath_fmt
[] =
5540 {'M','s','i','E','x','e','c','.','e','x','e',' ',
5541 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
5542 static const WCHAR szModifyPath
[] =
5543 {'M','o','d','i','f','y','P','a','t','h',0};
5544 static const WCHAR szUninstallString
[] =
5545 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
5546 static const WCHAR szEstimatedSize
[] =
5547 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
5548 static const WCHAR szDisplayVersion
[] =
5549 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
5550 static const WCHAR szInstallSource
[] =
5551 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
5552 static const WCHAR szARPAUTHORIZEDCDFPREFIX
[] =
5553 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
5554 static const WCHAR szAuthorizedCDFPrefix
[] =
5555 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
5556 static const WCHAR szARPCONTACT
[] =
5557 {'A','R','P','C','O','N','T','A','C','T',0};
5558 static const WCHAR szContact
[] =
5559 {'C','o','n','t','a','c','t',0};
5560 static const WCHAR szARPCOMMENTS
[] =
5561 {'A','R','P','C','O','M','M','E','N','T','S',0};
5562 static const WCHAR szComments
[] =
5563 {'C','o','m','m','e','n','t','s',0};
5564 static const WCHAR szProductName
[] =
5565 {'P','r','o','d','u','c','t','N','a','m','e',0};
5566 static const WCHAR szDisplayName
[] =
5567 {'D','i','s','p','l','a','y','N','a','m','e',0};
5568 static const WCHAR szARPHELPLINK
[] =
5569 {'A','R','P','H','E','L','P','L','I','N','K',0};
5570 static const WCHAR szHelpLink
[] =
5571 {'H','e','l','p','L','i','n','k',0};
5572 static const WCHAR szARPHELPTELEPHONE
[] =
5573 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
5574 static const WCHAR szHelpTelephone
[] =
5575 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
5576 static const WCHAR szARPINSTALLLOCATION
[] =
5577 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
5578 static const WCHAR szInstallLocation
[] =
5579 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
5580 static const WCHAR szManufacturer
[] =
5581 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
5582 static const WCHAR szPublisher
[] =
5583 {'P','u','b','l','i','s','h','e','r',0};
5584 static const WCHAR szARPREADME
[] =
5585 {'A','R','P','R','E','A','D','M','E',0};
5586 static const WCHAR szReadme
[] =
5587 {'R','e','a','d','M','e',0};
5588 static const WCHAR szARPSIZE
[] =
5589 {'A','R','P','S','I','Z','E',0};
5590 static const WCHAR szSize
[] =
5591 {'S','i','z','e',0};
5592 static const WCHAR szARPURLINFOABOUT
[] =
5593 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
5594 static const WCHAR szURLInfoAbout
[] =
5595 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
5596 static const WCHAR szARPURLUPDATEINFO
[] =
5597 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
5598 static const WCHAR szURLUpdateInfo
[] =
5599 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
5601 static const WCHAR
*propval
[] = {
5602 szARPAUTHORIZEDCDFPREFIX
, szAuthorizedCDFPrefix
,
5603 szARPCONTACT
, szContact
,
5604 szARPCOMMENTS
, szComments
,
5605 szProductName
, szDisplayName
,
5606 szARPHELPLINK
, szHelpLink
,
5607 szARPHELPTELEPHONE
, szHelpTelephone
,
5608 szARPINSTALLLOCATION
, szInstallLocation
,
5609 szSourceDir
, szInstallSource
,
5610 szManufacturer
, szPublisher
,
5611 szARPREADME
, szReadme
,
5613 szARPURLINFOABOUT
, szURLInfoAbout
,
5614 szARPURLUPDATEINFO
, szURLUpdateInfo
,
5617 const WCHAR
**p
= propval
;
5623 val
= msi_dup_property(package
->db
, prop
);
5624 msi_reg_set_val_str(hkey
, key
, val
);
5628 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
5630 size
= deformat_string(package
, modpath_fmt
, &buffer
);
5631 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
5632 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
5635 /* FIXME: Write real Estimated Size when we have it */
5636 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
5638 GetLocalTime(&systime
);
5639 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
5640 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
5642 langid
= msi_get_property_int(package
->db
, szProductLanguage
, 0);
5643 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
5645 buffer
= msi_dup_property(package
->db
, szProductVersion
);
5646 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
5649 DWORD verdword
= msi_version_str_to_dword(buffer
);
5651 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
5652 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
5653 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
5657 return ERROR_SUCCESS
;
5660 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
5662 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
5664 LPWSTR upgrade_code
;
5665 HKEY hkey
, props
, upgrade_key
;
5668 /* FIXME: also need to publish if the product is in advertise mode */
5669 if (!msi_check_publish(package
))
5670 return ERROR_SUCCESS
;
5672 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, package
->platform
, &hkey
, TRUE
);
5673 if (rc
!= ERROR_SUCCESS
)
5676 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
5677 NULL
, &props
, TRUE
);
5678 if (rc
!= ERROR_SUCCESS
)
5681 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
5682 msi_free( package
->db
->localfile
);
5683 package
->db
->localfile
= NULL
;
5685 rc
= msi_publish_install_properties(package
, hkey
);
5686 if (rc
!= ERROR_SUCCESS
)
5689 rc
= msi_publish_install_properties(package
, props
);
5690 if (rc
!= ERROR_SUCCESS
)
5693 upgrade_code
= msi_dup_property(package
->db
, szUpgradeCode
);
5696 rc
= MSIREG_OpenUpgradeCodesKey( upgrade_code
, &upgrade_key
, TRUE
);
5697 if (rc
== ERROR_SUCCESS
)
5699 squash_guid( package
->ProductCode
, squashed_pc
);
5700 msi_reg_set_val_str( upgrade_key
, squashed_pc
, NULL
);
5701 RegCloseKey( upgrade_key
);
5703 msi_free( upgrade_code
);
5707 uirow
= MSI_CreateRecord( 1 );
5708 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
5709 msi_ui_actiondata( package
, szRegisterProduct
, uirow
);
5710 msiobj_release( &uirow
->hdr
);
5713 return ERROR_SUCCESS
;
5716 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
5718 return execute_script(package
,INSTALL_SCRIPT
);
5721 static UINT
msi_unpublish_product(MSIPACKAGE
*package
, WCHAR
*remove
)
5723 WCHAR
*upgrade
, **features
;
5724 BOOL full_uninstall
= TRUE
;
5725 MSIFEATURE
*feature
;
5726 MSIPATCHINFO
*patch
;
5728 static const WCHAR szUpgradeCode
[] =
5729 {'U','p','g','r','a','d','e','C','o','d','e',0};
5731 features
= msi_split_string(remove
, ',');
5734 ERR("REMOVE feature list is empty!\n");
5735 return ERROR_FUNCTION_FAILED
;
5738 if (!strcmpW( features
[0], szAll
))
5739 full_uninstall
= TRUE
;
5742 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
5744 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
5745 full_uninstall
= FALSE
;
5750 if (!full_uninstall
)
5751 return ERROR_SUCCESS
;
5753 MSIREG_DeleteProductKey(package
->ProductCode
);
5754 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
5755 MSIREG_DeleteUninstallKey(package
->ProductCode
, package
->platform
);
5757 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
5758 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
5759 MSIREG_DeleteUserProductKey(package
->ProductCode
);
5760 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
5762 upgrade
= msi_dup_property(package
->db
, szUpgradeCode
);
5765 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
5766 MSIREG_DeleteClassesUpgradeCodesKey(upgrade
);
5770 LIST_FOR_EACH_ENTRY(patch
, &package
->patches
, MSIPATCHINFO
, entry
)
5772 MSIREG_DeleteUserDataPatchKey(patch
->patchcode
, package
->Context
);
5775 return ERROR_SUCCESS
;
5778 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
5783 /* turn off scheduling */
5784 package
->script
->CurrentlyScripting
= FALSE
;
5786 /* first do the same as an InstallExecute */
5787 rc
= ACTION_InstallExecute(package
);
5788 if (rc
!= ERROR_SUCCESS
)
5791 /* then handle Commit Actions */
5792 rc
= execute_script(package
,COMMIT_SCRIPT
);
5793 if (rc
!= ERROR_SUCCESS
)
5796 remove
= msi_dup_property(package
->db
, szRemove
);
5798 rc
= msi_unpublish_product(package
, remove
);
5804 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
5806 static const WCHAR RunOnce
[] = {
5807 'S','o','f','t','w','a','r','e','\\',
5808 'M','i','c','r','o','s','o','f','t','\\',
5809 'W','i','n','d','o','w','s','\\',
5810 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5811 'R','u','n','O','n','c','e',0};
5812 static const WCHAR InstallRunOnce
[] = {
5813 'S','o','f','t','w','a','r','e','\\',
5814 'M','i','c','r','o','s','o','f','t','\\',
5815 'W','i','n','d','o','w','s','\\',
5816 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5817 'I','n','s','t','a','l','l','e','r','\\',
5818 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5820 static const WCHAR msiexec_fmt
[] = {
5822 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5823 '\"','%','s','\"',0};
5824 static const WCHAR install_fmt
[] = {
5825 '/','I',' ','\"','%','s','\"',' ',
5826 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5827 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5828 WCHAR buffer
[256], sysdir
[MAX_PATH
];
5830 WCHAR squished_pc
[100];
5832 squash_guid(package
->ProductCode
,squished_pc
);
5834 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
5835 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
5836 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
5839 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
5842 TRACE("Reboot command %s\n",debugstr_w(buffer
));
5844 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
5845 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
5847 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
5850 return ERROR_INSTALL_SUSPEND
;
5853 WCHAR
*msi_build_error_string( MSIPACKAGE
*package
, UINT error
, DWORD count
, ... )
5855 static const WCHAR query
[] =
5856 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5857 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5858 '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5859 MSIRECORD
*rec
, *row
;
5865 if (!(row
= MSI_QueryGetRecord( package
->db
, query
, error
))) return 0;
5867 rec
= MSI_CreateRecord( count
+ 2 );
5868 str
= MSI_RecordGetString( row
, 1 );
5869 MSI_RecordSetStringW( rec
, 0, str
);
5870 msiobj_release( &row
->hdr
);
5871 MSI_RecordSetInteger( rec
, 1, error
);
5873 va_start( va
, count
);
5874 for (i
= 0; i
< count
; i
++)
5876 str
= va_arg( va
, const WCHAR
*);
5877 MSI_RecordSetStringW( rec
, i
+ 2, str
);
5881 MSI_FormatRecordW( package
, rec
, NULL
, &size
);
5883 data
= msi_alloc( size
* sizeof(WCHAR
) );
5884 if (size
> 1) MSI_FormatRecordW( package
, rec
, data
, &size
);
5886 msiobj_release( &rec
->hdr
);
5890 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
5896 * We are currently doing what should be done here in the top level Install
5897 * however for Administrative and uninstalls this step will be needed
5899 if (!package
->PackagePath
)
5900 return ERROR_SUCCESS
;
5902 msi_set_sourcedir_props(package
, TRUE
);
5904 attrib
= GetFileAttributesW(package
->db
->path
);
5905 if (attrib
== INVALID_FILE_ATTRIBUTES
)
5911 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
5912 package
->Context
, MSICODE_PRODUCT
,
5913 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
5914 if (rc
== ERROR_MORE_DATA
)
5916 prompt
= msi_alloc(size
* sizeof(WCHAR
));
5917 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
5918 package
->Context
, MSICODE_PRODUCT
,
5919 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
5922 prompt
= strdupW(package
->db
->path
);
5924 msg
= msi_build_error_string(package
, 1302, 1, prompt
);
5925 while(attrib
== INVALID_FILE_ATTRIBUTES
)
5927 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
5930 rc
= ERROR_INSTALL_USEREXIT
;
5933 attrib
= GetFileAttributesW(package
->db
->path
);
5939 return ERROR_SUCCESS
;
5944 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
5947 LPWSTR buffer
, productid
= NULL
;
5948 UINT i
, rc
= ERROR_SUCCESS
;
5951 static const WCHAR szPropKeys
[][80] =
5953 {'P','r','o','d','u','c','t','I','D',0},
5954 {'U','S','E','R','N','A','M','E',0},
5955 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5959 static const WCHAR szRegKeys
[][80] =
5961 {'P','r','o','d','u','c','t','I','D',0},
5962 {'R','e','g','O','w','n','e','r',0},
5963 {'R','e','g','C','o','m','p','a','n','y',0},
5967 if (msi_check_unpublish(package
))
5969 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
5973 productid
= msi_dup_property( package
->db
, INSTALLPROPERTY_PRODUCTIDW
);
5977 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
5979 if (rc
!= ERROR_SUCCESS
)
5982 for( i
= 0; szPropKeys
[i
][0]; i
++ )
5984 buffer
= msi_dup_property( package
->db
, szPropKeys
[i
] );
5985 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
5990 uirow
= MSI_CreateRecord( 1 );
5991 MSI_RecordSetStringW( uirow
, 1, productid
);
5992 msi_ui_actiondata( package
, szRegisterUser
, uirow
);
5993 msiobj_release( &uirow
->hdr
);
5995 msi_free(productid
);
6001 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
6005 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
6006 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
6010 WCHAR
*msi_create_component_advertise_string( MSIPACKAGE
*package
, MSICOMPONENT
*component
, const WCHAR
*feature
)
6012 static const WCHAR fmt
[] = {'%','s','%','s','%','c','%','s',0};
6013 WCHAR productid_85
[21], component_85
[21], *ret
;
6017 /* > is used if there is a component GUID and < if not. */
6019 productid_85
[0] = 0;
6020 component_85
[0] = 0;
6021 CLSIDFromString( package
->ProductCode
, &clsid
);
6023 encode_base85_guid( &clsid
, productid_85
);
6026 CLSIDFromString( component
->ComponentId
, &clsid
);
6027 encode_base85_guid( &clsid
, component_85
);
6030 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85
), debugstr_w(feature
),
6031 debugstr_w(component_85
));
6033 sz
= 20 + strlenW( feature
) + 20 + 3;
6034 ret
= msi_alloc_zero( sz
* sizeof(WCHAR
) );
6035 if (ret
) sprintfW( ret
, fmt
, productid_85
, feature
, component
? '>' : '<', component_85
);
6039 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
6041 MSIPACKAGE
*package
= param
;
6042 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
6043 LPWSTR advertise
= NULL
, output
= NULL
, existing
= NULL
, p
, q
;
6052 feature
= MSI_RecordGetString(rec
, 5);
6053 feat
= msi_get_loaded_feature(package
, feature
);
6055 return ERROR_SUCCESS
;
6057 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6058 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
6059 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
6061 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
6062 feat
->Action
= feat
->Installed
;
6063 return ERROR_SUCCESS
;
6066 component
= MSI_RecordGetString(rec
, 3);
6067 comp
= msi_get_loaded_component(package
, component
);
6069 return ERROR_SUCCESS
;
6071 compgroupid
= MSI_RecordGetString(rec
,1);
6072 qualifier
= MSI_RecordGetString(rec
,2);
6074 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
6075 if (rc
!= ERROR_SUCCESS
)
6078 advertise
= msi_create_component_advertise_string( package
, comp
, feature
);
6079 text
= MSI_RecordGetString( rec
, 4 );
6082 p
= msi_alloc( (strlenW( advertise
) + strlenW( text
) + 1) * sizeof(WCHAR
) );
6083 strcpyW( p
, advertise
);
6085 msi_free( advertise
);
6088 existing
= msi_reg_get_val_str( hkey
, qualifier
);
6090 sz
= strlenW( advertise
) + 1;
6093 for (p
= existing
; *p
; p
+= len
)
6095 len
= strlenW( p
) + 1;
6096 if (strcmpW( advertise
, p
)) sz
+= len
;
6099 if (!(output
= msi_alloc( (sz
+ 1) * sizeof(WCHAR
) )))
6101 rc
= ERROR_OUTOFMEMORY
;
6107 for (p
= existing
; *p
; p
+= len
)
6109 len
= strlenW( p
) + 1;
6110 if (strcmpW( advertise
, p
))
6112 memcpy( q
, p
, len
* sizeof(WCHAR
) );
6117 strcpyW( q
, advertise
);
6118 q
[strlenW( q
) + 1] = 0;
6120 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
6125 msi_free( advertise
);
6126 msi_free( existing
);
6129 uirow
= MSI_CreateRecord( 2 );
6130 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
6131 MSI_RecordSetStringW( uirow
, 2, qualifier
);
6132 msi_ui_actiondata( package
, szPublishComponents
, uirow
);
6133 msiobj_release( &uirow
->hdr
);
6134 /* FIXME: call ui_progress? */
6140 * At present I am ignorning the advertised components part of this and only
6141 * focusing on the qualified component sets
6143 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
6147 static const WCHAR ExecSeqQuery
[] =
6148 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6149 '`','P','u','b','l','i','s','h',
6150 'C','o','m','p','o','n','e','n','t','`',0};
6152 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6153 if (rc
!= ERROR_SUCCESS
)
6154 return ERROR_SUCCESS
;
6156 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
6157 msiobj_release(&view
->hdr
);
6162 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
6164 static const WCHAR szInstallerComponents
[] = {
6165 'S','o','f','t','w','a','r','e','\\',
6166 'M','i','c','r','o','s','o','f','t','\\',
6167 'I','n','s','t','a','l','l','e','r','\\',
6168 'C','o','m','p','o','n','e','n','t','s','\\',0};
6170 MSIPACKAGE
*package
= param
;
6171 LPCWSTR compgroupid
, component
, feature
, qualifier
;
6175 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
6178 feature
= MSI_RecordGetString( rec
, 5 );
6179 feat
= msi_get_loaded_feature( package
, feature
);
6181 return ERROR_SUCCESS
;
6183 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6185 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
6186 feat
->Action
= feat
->Installed
;
6187 return ERROR_SUCCESS
;
6190 component
= MSI_RecordGetString( rec
, 3 );
6191 comp
= msi_get_loaded_component( package
, component
);
6193 return ERROR_SUCCESS
;
6195 compgroupid
= MSI_RecordGetString( rec
, 1 );
6196 qualifier
= MSI_RecordGetString( rec
, 2 );
6198 squash_guid( compgroupid
, squashed
);
6199 strcpyW( keypath
, szInstallerComponents
);
6200 strcatW( keypath
, squashed
);
6202 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
6203 if (res
!= ERROR_SUCCESS
)
6205 WARN("Unable to delete component key %d\n", res
);
6208 uirow
= MSI_CreateRecord( 2 );
6209 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
6210 MSI_RecordSetStringW( uirow
, 2, qualifier
);
6211 msi_ui_actiondata( package
, szUnpublishComponents
, uirow
);
6212 msiobj_release( &uirow
->hdr
);
6214 return ERROR_SUCCESS
;
6217 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
6221 static const WCHAR query
[] =
6222 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6223 '`','P','u','b','l','i','s','h',
6224 'C','o','m','p','o','n','e','n','t','`',0};
6226 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6227 if (rc
!= ERROR_SUCCESS
)
6228 return ERROR_SUCCESS
;
6230 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
6231 msiobj_release( &view
->hdr
);
6236 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
6238 static const WCHAR query
[] =
6239 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6240 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
6241 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
6242 MSIPACKAGE
*package
= param
;
6243 MSICOMPONENT
*component
;
6246 SC_HANDLE hscm
= NULL
, service
= NULL
;
6248 LPWSTR name
= NULL
, disp
= NULL
, load_order
= NULL
, serv_name
= NULL
;
6249 LPWSTR depends
= NULL
, pass
= NULL
, args
= NULL
, image_path
= NULL
;
6250 DWORD serv_type
, start_type
, err_control
;
6251 SERVICE_DESCRIPTIONW sd
= {NULL
};
6253 comp
= MSI_RecordGetString( rec
, 12 );
6254 component
= msi_get_loaded_component( package
, comp
);
6257 WARN("service component not found\n");
6260 if (!component
->Enabled
)
6262 TRACE("service component disabled\n");
6265 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
6268 ERR("Failed to open the SC Manager!\n");
6272 start_type
= MSI_RecordGetInteger(rec
, 5);
6273 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
6276 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
6277 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
6278 serv_type
= MSI_RecordGetInteger(rec
, 4);
6279 err_control
= MSI_RecordGetInteger(rec
, 6);
6280 deformat_string(package
, MSI_RecordGetString(rec
, 7), &load_order
);
6281 deformat_string(package
, MSI_RecordGetString(rec
, 8), &depends
);
6282 deformat_string(package
, MSI_RecordGetString(rec
, 9), &serv_name
);
6283 deformat_string(package
, MSI_RecordGetString(rec
, 10), &pass
);
6284 deformat_string(package
, MSI_RecordGetString(rec
, 11), &args
);
6285 deformat_string(package
, MSI_RecordGetString(rec
, 13), &sd
.lpDescription
);
6287 /* fetch the service path */
6288 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
6291 ERR("Query failed\n");
6294 key
= MSI_RecordGetString(row
, 6);
6295 file
= msi_get_loaded_file(package
, key
);
6296 msiobj_release(&row
->hdr
);
6299 ERR("Failed to load the service file\n");
6303 if (!args
|| !args
[0]) image_path
= file
->TargetPath
;
6306 int len
= strlenW(file
->TargetPath
) + strlenW(args
) + 2;
6307 if (!(image_path
= msi_alloc(len
* sizeof(WCHAR
))))
6308 return ERROR_OUTOFMEMORY
;
6310 strcpyW(image_path
, file
->TargetPath
);
6311 strcatW(image_path
, szSpace
);
6312 strcatW(image_path
, args
);
6314 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
6315 start_type
, err_control
, image_path
, load_order
,
6316 NULL
, depends
, serv_name
, pass
);
6320 if (GetLastError() != ERROR_SERVICE_EXISTS
)
6321 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
6323 else if (sd
.lpDescription
)
6325 if (!ChangeServiceConfig2W(service
, SERVICE_CONFIG_DESCRIPTION
, &sd
))
6326 WARN("failed to set service description %u\n", GetLastError());
6329 if (image_path
!= file
->TargetPath
) msi_free(image_path
);
6331 CloseServiceHandle(service
);
6332 CloseServiceHandle(hscm
);
6335 msi_free(sd
.lpDescription
);
6336 msi_free(load_order
);
6337 msi_free(serv_name
);
6342 return ERROR_SUCCESS
;
6345 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
6349 static const WCHAR ExecSeqQuery
[] =
6350 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6351 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
6353 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6354 if (rc
!= ERROR_SUCCESS
)
6355 return ERROR_SUCCESS
;
6357 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
6358 msiobj_release(&view
->hdr
);
6363 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
6364 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
6366 LPCWSTR
*vector
, *temp_vector
;
6370 static const WCHAR separator
[] = {'[','~',']',0};
6373 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
6378 vector
= msi_alloc(sizeof(LPWSTR
));
6386 vector
[*numargs
- 1] = p
;
6388 if ((q
= strstrW(p
, separator
)))
6392 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
6398 vector
= temp_vector
;
6407 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
6409 MSIPACKAGE
*package
= param
;
6412 SC_HANDLE scm
= NULL
, service
= NULL
;
6413 LPCWSTR component
, *vector
= NULL
;
6414 LPWSTR name
, args
, display_name
= NULL
;
6415 DWORD event
, numargs
, len
;
6416 UINT r
= ERROR_FUNCTION_FAILED
;
6418 component
= MSI_RecordGetString(rec
, 6);
6419 comp
= msi_get_loaded_component(package
, component
);
6421 return ERROR_SUCCESS
;
6425 TRACE("component is disabled\n");
6426 return ERROR_SUCCESS
;
6429 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6431 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6432 comp
->Action
= comp
->Installed
;
6433 return ERROR_SUCCESS
;
6435 comp
->Action
= INSTALLSTATE_LOCAL
;
6437 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
6438 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
6439 event
= MSI_RecordGetInteger(rec
, 3);
6441 if (!(event
& msidbServiceControlEventStart
))
6447 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
6450 ERR("Failed to open the service control manager\n");
6455 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
6456 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
6458 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
6459 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
6462 service
= OpenServiceW(scm
, name
, SERVICE_START
);
6465 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
6469 vector
= msi_service_args_to_vector(args
, &numargs
);
6471 if (!StartServiceW(service
, numargs
, vector
) &&
6472 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
6474 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
6481 uirow
= MSI_CreateRecord( 2 );
6482 MSI_RecordSetStringW( uirow
, 1, display_name
);
6483 MSI_RecordSetStringW( uirow
, 2, name
);
6484 msi_ui_actiondata( package
, szStartServices
, uirow
);
6485 msiobj_release( &uirow
->hdr
);
6487 CloseServiceHandle(service
);
6488 CloseServiceHandle(scm
);
6493 msi_free(display_name
);
6497 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
6502 static const WCHAR query
[] = {
6503 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6504 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6506 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6507 if (rc
!= ERROR_SUCCESS
)
6508 return ERROR_SUCCESS
;
6510 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
6511 msiobj_release(&view
->hdr
);
6516 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
6518 DWORD i
, needed
, count
;
6519 ENUM_SERVICE_STATUSW
*dependencies
;
6523 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
6524 0, &needed
, &count
))
6527 if (GetLastError() != ERROR_MORE_DATA
)
6530 dependencies
= msi_alloc(needed
);
6534 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
6535 needed
, &needed
, &count
))
6538 for (i
= 0; i
< count
; i
++)
6540 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
6541 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
6545 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
6552 msi_free(dependencies
);
6556 static UINT
stop_service( LPCWSTR name
)
6558 SC_HANDLE scm
= NULL
, service
= NULL
;
6559 SERVICE_STATUS status
;
6560 SERVICE_STATUS_PROCESS ssp
;
6563 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
6566 WARN("Failed to open the SCM: %d\n", GetLastError());
6570 service
= OpenServiceW(scm
, name
,
6572 SERVICE_QUERY_STATUS
|
6573 SERVICE_ENUMERATE_DEPENDENTS
);
6576 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
6580 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
6581 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
6583 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
6587 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
6590 stop_service_dependents(scm
, service
);
6592 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
6593 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
6596 CloseServiceHandle(service
);
6597 CloseServiceHandle(scm
);
6599 return ERROR_SUCCESS
;
6602 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
6604 MSIPACKAGE
*package
= param
;
6608 LPWSTR name
= NULL
, display_name
= NULL
;
6612 event
= MSI_RecordGetInteger( rec
, 3 );
6613 if (!(event
& msidbServiceControlEventStop
))
6614 return ERROR_SUCCESS
;
6616 component
= MSI_RecordGetString( rec
, 6 );
6617 comp
= msi_get_loaded_component( package
, component
);
6619 return ERROR_SUCCESS
;
6623 TRACE("component is disabled\n");
6624 return ERROR_SUCCESS
;
6627 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6629 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6630 comp
->Action
= comp
->Installed
;
6631 return ERROR_SUCCESS
;
6633 comp
->Action
= INSTALLSTATE_ABSENT
;
6635 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
6638 ERR("Failed to open the service control manager\n");
6643 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
6644 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
6646 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
6647 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
6649 CloseServiceHandle( scm
);
6651 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
6652 stop_service( name
);
6655 uirow
= MSI_CreateRecord( 2 );
6656 MSI_RecordSetStringW( uirow
, 1, display_name
);
6657 MSI_RecordSetStringW( uirow
, 2, name
);
6658 msi_ui_actiondata( package
, szStopServices
, uirow
);
6659 msiobj_release( &uirow
->hdr
);
6662 msi_free( display_name
);
6663 return ERROR_SUCCESS
;
6666 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
6671 static const WCHAR query
[] = {
6672 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6673 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6675 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6676 if (rc
!= ERROR_SUCCESS
)
6677 return ERROR_SUCCESS
;
6679 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
6680 msiobj_release(&view
->hdr
);
6685 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
6687 MSIPACKAGE
*package
= param
;
6691 LPWSTR name
= NULL
, display_name
= NULL
;
6693 SC_HANDLE scm
= NULL
, service
= NULL
;
6695 event
= MSI_RecordGetInteger( rec
, 3 );
6696 if (!(event
& msidbServiceControlEventDelete
))
6697 return ERROR_SUCCESS
;
6699 component
= MSI_RecordGetString(rec
, 6);
6700 comp
= msi_get_loaded_component(package
, component
);
6702 return ERROR_SUCCESS
;
6706 TRACE("component is disabled\n");
6707 return ERROR_SUCCESS
;
6710 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6712 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6713 comp
->Action
= comp
->Installed
;
6714 return ERROR_SUCCESS
;
6716 comp
->Action
= INSTALLSTATE_ABSENT
;
6718 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
6719 stop_service( name
);
6721 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
6724 WARN("Failed to open the SCM: %d\n", GetLastError());
6729 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
6730 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
6732 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
6733 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
6736 service
= OpenServiceW( scm
, name
, DELETE
);
6739 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
6743 if (!DeleteService( service
))
6744 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
6747 uirow
= MSI_CreateRecord( 2 );
6748 MSI_RecordSetStringW( uirow
, 1, display_name
);
6749 MSI_RecordSetStringW( uirow
, 2, name
);
6750 msi_ui_actiondata( package
, szDeleteServices
, uirow
);
6751 msiobj_release( &uirow
->hdr
);
6753 CloseServiceHandle( service
);
6754 CloseServiceHandle( scm
);
6756 msi_free( display_name
);
6758 return ERROR_SUCCESS
;
6761 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
6766 static const WCHAR query
[] = {
6767 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6768 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6770 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6771 if (rc
!= ERROR_SUCCESS
)
6772 return ERROR_SUCCESS
;
6774 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
6775 msiobj_release( &view
->hdr
);
6780 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
6782 MSIPACKAGE
*package
= param
;
6783 LPWSTR driver
, driver_path
, ptr
;
6784 WCHAR outpath
[MAX_PATH
];
6785 MSIFILE
*driver_file
= NULL
, *setup_file
= NULL
;
6788 LPCWSTR desc
, file_key
, component
;
6790 UINT r
= ERROR_SUCCESS
;
6792 static const WCHAR driver_fmt
[] = {
6793 'D','r','i','v','e','r','=','%','s',0};
6794 static const WCHAR setup_fmt
[] = {
6795 'S','e','t','u','p','=','%','s',0};
6796 static const WCHAR usage_fmt
[] = {
6797 'F','i','l','e','U','s','a','g','e','=','1',0};
6799 component
= MSI_RecordGetString( rec
, 2 );
6800 comp
= msi_get_loaded_component( package
, component
);
6802 return ERROR_SUCCESS
;
6806 TRACE("component is disabled\n");
6807 return ERROR_SUCCESS
;
6810 desc
= MSI_RecordGetString(rec
, 3);
6812 file_key
= MSI_RecordGetString( rec
, 4 );
6813 if (file_key
) driver_file
= msi_get_loaded_file( package
, file_key
);
6815 file_key
= MSI_RecordGetString( rec
, 5 );
6816 if (file_key
) setup_file
= msi_get_loaded_file( package
, file_key
);
6820 ERR("ODBC Driver entry not found!\n");
6821 return ERROR_FUNCTION_FAILED
;
6824 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
6826 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
6827 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
6829 driver
= msi_alloc(len
* sizeof(WCHAR
));
6831 return ERROR_OUTOFMEMORY
;
6834 lstrcpyW(ptr
, desc
);
6835 ptr
+= lstrlenW(ptr
) + 1;
6837 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
6842 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
6846 lstrcpyW(ptr
, usage_fmt
);
6847 ptr
+= lstrlenW(ptr
) + 1;
6850 driver_path
= strdupW(driver_file
->TargetPath
);
6851 ptr
= strrchrW(driver_path
, '\\');
6852 if (ptr
) *ptr
= '\0';
6854 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
6855 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
6857 ERR("Failed to install SQL driver!\n");
6858 r
= ERROR_FUNCTION_FAILED
;
6861 uirow
= MSI_CreateRecord( 5 );
6862 MSI_RecordSetStringW( uirow
, 1, desc
);
6863 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
6864 MSI_RecordSetStringW( uirow
, 3, driver_file
->Component
->Directory
);
6865 msi_ui_actiondata( package
, szInstallODBC
, uirow
);
6866 msiobj_release( &uirow
->hdr
);
6869 msi_free(driver_path
);
6874 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
6876 MSIPACKAGE
*package
= param
;
6877 LPWSTR translator
, translator_path
, ptr
;
6878 WCHAR outpath
[MAX_PATH
];
6879 MSIFILE
*translator_file
= NULL
, *setup_file
= NULL
;
6882 LPCWSTR desc
, file_key
, component
;
6884 UINT r
= ERROR_SUCCESS
;
6886 static const WCHAR translator_fmt
[] = {
6887 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6888 static const WCHAR setup_fmt
[] = {
6889 'S','e','t','u','p','=','%','s',0};
6891 component
= MSI_RecordGetString( rec
, 2 );
6892 comp
= msi_get_loaded_component( package
, component
);
6894 return ERROR_SUCCESS
;
6898 TRACE("component is disabled\n");
6899 return ERROR_SUCCESS
;
6902 desc
= MSI_RecordGetString(rec
, 3);
6904 file_key
= MSI_RecordGetString( rec
, 4 );
6905 if (file_key
) translator_file
= msi_get_loaded_file( package
, file_key
);
6907 file_key
= MSI_RecordGetString( rec
, 5 );
6908 if (file_key
) setup_file
= msi_get_loaded_file( package
, file_key
);
6910 if (!translator_file
)
6912 ERR("ODBC Translator entry not found!\n");
6913 return ERROR_FUNCTION_FAILED
;
6916 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
6918 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
6920 translator
= msi_alloc(len
* sizeof(WCHAR
));
6922 return ERROR_OUTOFMEMORY
;
6925 lstrcpyW(ptr
, desc
);
6926 ptr
+= lstrlenW(ptr
) + 1;
6928 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
6933 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
6938 translator_path
= strdupW(translator_file
->TargetPath
);
6939 ptr
= strrchrW(translator_path
, '\\');
6940 if (ptr
) *ptr
= '\0';
6942 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
6943 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
6945 ERR("Failed to install SQL translator!\n");
6946 r
= ERROR_FUNCTION_FAILED
;
6949 uirow
= MSI_CreateRecord( 5 );
6950 MSI_RecordSetStringW( uirow
, 1, desc
);
6951 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
6952 MSI_RecordSetStringW( uirow
, 3, translator_file
->Component
->Directory
);
6953 msi_ui_actiondata( package
, szInstallODBC
, uirow
);
6954 msiobj_release( &uirow
->hdr
);
6956 msi_free(translator
);
6957 msi_free(translator_path
);
6962 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
6964 MSIPACKAGE
*package
= param
;
6967 LPCWSTR desc
, driver
, component
;
6968 WORD request
= ODBC_ADD_SYS_DSN
;
6971 UINT r
= ERROR_SUCCESS
;
6974 static const WCHAR attrs_fmt
[] = {
6975 'D','S','N','=','%','s',0 };
6977 component
= MSI_RecordGetString( rec
, 2 );
6978 comp
= msi_get_loaded_component( package
, component
);
6980 return ERROR_SUCCESS
;
6984 TRACE("component is disabled\n");
6985 return ERROR_SUCCESS
;
6988 desc
= MSI_RecordGetString(rec
, 3);
6989 driver
= MSI_RecordGetString(rec
, 4);
6990 registration
= MSI_RecordGetInteger(rec
, 5);
6992 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
6993 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
6995 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
6996 attrs
= msi_alloc(len
* sizeof(WCHAR
));
6998 return ERROR_OUTOFMEMORY
;
7000 len
= sprintfW(attrs
, attrs_fmt
, desc
);
7003 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
7005 ERR("Failed to install SQL data source!\n");
7006 r
= ERROR_FUNCTION_FAILED
;
7009 uirow
= MSI_CreateRecord( 5 );
7010 MSI_RecordSetStringW( uirow
, 1, desc
);
7011 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
7012 MSI_RecordSetInteger( uirow
, 3, request
);
7013 msi_ui_actiondata( package
, szInstallODBC
, uirow
);
7014 msiobj_release( &uirow
->hdr
);
7021 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
7026 static const WCHAR driver_query
[] = {
7027 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7028 'O','D','B','C','D','r','i','v','e','r',0 };
7030 static const WCHAR translator_query
[] = {
7031 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7032 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7034 static const WCHAR source_query
[] = {
7035 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7036 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
7038 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
7039 if (rc
!= ERROR_SUCCESS
)
7040 return ERROR_SUCCESS
;
7042 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
7043 msiobj_release(&view
->hdr
);
7045 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
7046 if (rc
!= ERROR_SUCCESS
)
7047 return ERROR_SUCCESS
;
7049 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
7050 msiobj_release(&view
->hdr
);
7052 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
7053 if (rc
!= ERROR_SUCCESS
)
7054 return ERROR_SUCCESS
;
7056 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
7057 msiobj_release(&view
->hdr
);
7062 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
7064 MSIPACKAGE
*package
= param
;
7068 LPCWSTR desc
, component
;
7070 component
= MSI_RecordGetString( rec
, 2 );
7071 comp
= msi_get_loaded_component( package
, component
);
7073 return ERROR_SUCCESS
;
7077 TRACE("component is disabled\n");
7078 return ERROR_SUCCESS
;
7081 desc
= MSI_RecordGetString( rec
, 3 );
7082 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
7084 WARN("Failed to remove ODBC driver\n");
7088 FIXME("Usage count reached 0\n");
7091 uirow
= MSI_CreateRecord( 2 );
7092 MSI_RecordSetStringW( uirow
, 1, desc
);
7093 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
7094 msi_ui_actiondata( package
, szRemoveODBC
, uirow
);
7095 msiobj_release( &uirow
->hdr
);
7097 return ERROR_SUCCESS
;
7100 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
7102 MSIPACKAGE
*package
= param
;
7106 LPCWSTR desc
, component
;
7108 component
= MSI_RecordGetString( rec
, 2 );
7109 comp
= msi_get_loaded_component( package
, component
);
7111 return ERROR_SUCCESS
;
7115 TRACE("component is disabled\n");
7116 return ERROR_SUCCESS
;
7119 desc
= MSI_RecordGetString( rec
, 3 );
7120 if (!SQLRemoveTranslatorW( desc
, &usage
))
7122 WARN("Failed to remove ODBC translator\n");
7126 FIXME("Usage count reached 0\n");
7129 uirow
= MSI_CreateRecord( 2 );
7130 MSI_RecordSetStringW( uirow
, 1, desc
);
7131 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
7132 msi_ui_actiondata( package
, szRemoveODBC
, uirow
);
7133 msiobj_release( &uirow
->hdr
);
7135 return ERROR_SUCCESS
;
7138 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
7140 MSIPACKAGE
*package
= param
;
7144 LPCWSTR desc
, driver
, component
;
7145 WORD request
= ODBC_REMOVE_SYS_DSN
;
7149 static const WCHAR attrs_fmt
[] = {
7150 'D','S','N','=','%','s',0 };
7152 component
= MSI_RecordGetString( rec
, 2 );
7153 comp
= msi_get_loaded_component( package
, component
);
7155 return ERROR_SUCCESS
;
7159 TRACE("component is disabled\n");
7160 return ERROR_SUCCESS
;
7163 desc
= MSI_RecordGetString( rec
, 3 );
7164 driver
= MSI_RecordGetString( rec
, 4 );
7165 registration
= MSI_RecordGetInteger( rec
, 5 );
7167 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
7168 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
7170 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
7171 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
7173 return ERROR_OUTOFMEMORY
;
7175 FIXME("Use ODBCSourceAttribute table\n");
7177 len
= sprintfW( attrs
, attrs_fmt
, desc
);
7180 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
7182 WARN("Failed to remove ODBC data source\n");
7186 uirow
= MSI_CreateRecord( 3 );
7187 MSI_RecordSetStringW( uirow
, 1, desc
);
7188 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
7189 MSI_RecordSetInteger( uirow
, 3, request
);
7190 msi_ui_actiondata( package
, szRemoveODBC
, uirow
);
7191 msiobj_release( &uirow
->hdr
);
7193 return ERROR_SUCCESS
;
7196 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
7201 static const WCHAR driver_query
[] = {
7202 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7203 'O','D','B','C','D','r','i','v','e','r',0 };
7205 static const WCHAR translator_query
[] = {
7206 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7207 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7209 static const WCHAR source_query
[] = {
7210 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7211 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
7213 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
7214 if (rc
!= ERROR_SUCCESS
)
7215 return ERROR_SUCCESS
;
7217 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
7218 msiobj_release( &view
->hdr
);
7220 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
7221 if (rc
!= ERROR_SUCCESS
)
7222 return ERROR_SUCCESS
;
7224 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
7225 msiobj_release( &view
->hdr
);
7227 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
7228 if (rc
!= ERROR_SUCCESS
)
7229 return ERROR_SUCCESS
;
7231 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
7232 msiobj_release( &view
->hdr
);
7237 #define ENV_ACT_SETALWAYS 0x1
7238 #define ENV_ACT_SETABSENT 0x2
7239 #define ENV_ACT_REMOVE 0x4
7240 #define ENV_ACT_REMOVEMATCH 0x8
7242 #define ENV_MOD_MACHINE 0x20000000
7243 #define ENV_MOD_APPEND 0x40000000
7244 #define ENV_MOD_PREFIX 0x80000000
7245 #define ENV_MOD_MASK 0xC0000000
7247 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
7249 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
7251 LPCWSTR cptr
= *name
;
7253 static const WCHAR prefix
[] = {'[','~',']',0};
7254 static const int prefix_len
= 3;
7260 *flags
|= ENV_ACT_SETALWAYS
;
7261 else if (*cptr
== '+')
7262 *flags
|= ENV_ACT_SETABSENT
;
7263 else if (*cptr
== '-')
7264 *flags
|= ENV_ACT_REMOVE
;
7265 else if (*cptr
== '!')
7266 *flags
|= ENV_ACT_REMOVEMATCH
;
7267 else if (*cptr
== '*')
7268 *flags
|= ENV_MOD_MACHINE
;
7278 ERR("Missing environment variable\n");
7279 return ERROR_FUNCTION_FAILED
;
7284 LPCWSTR ptr
= *value
;
7285 if (!strncmpW(ptr
, prefix
, prefix_len
))
7287 if (ptr
[prefix_len
] == szSemiColon
[0])
7289 *flags
|= ENV_MOD_APPEND
;
7290 *value
+= lstrlenW(prefix
);
7297 else if (lstrlenW(*value
) >= prefix_len
)
7299 ptr
+= lstrlenW(ptr
) - prefix_len
;
7300 if (!strcmpW( ptr
, prefix
))
7302 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
7304 *flags
|= ENV_MOD_PREFIX
;
7305 /* the "[~]" will be removed by deformat_string */;
7315 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
7316 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
7317 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
7318 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
7320 ERR("Invalid flags: %08x\n", *flags
);
7321 return ERROR_FUNCTION_FAILED
;
7325 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
7327 return ERROR_SUCCESS
;
7330 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
7332 static const WCHAR user_env
[] =
7333 {'E','n','v','i','r','o','n','m','e','n','t',0};
7334 static const WCHAR machine_env
[] =
7335 {'S','y','s','t','e','m','\\',
7336 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
7337 'C','o','n','t','r','o','l','\\',
7338 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
7339 'E','n','v','i','r','o','n','m','e','n','t',0};
7344 if (flags
& ENV_MOD_MACHINE
)
7347 root
= HKEY_LOCAL_MACHINE
;
7352 root
= HKEY_CURRENT_USER
;
7355 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
7356 if (res
!= ERROR_SUCCESS
)
7358 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
7359 return ERROR_FUNCTION_FAILED
;
7362 return ERROR_SUCCESS
;
7365 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
7367 MSIPACKAGE
*package
= param
;
7368 LPCWSTR name
, value
, component
;
7369 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
7370 DWORD flags
, type
, size
;
7377 component
= MSI_RecordGetString(rec
, 4);
7378 comp
= msi_get_loaded_component(package
, component
);
7380 return ERROR_SUCCESS
;
7384 TRACE("component is disabled\n");
7385 return ERROR_SUCCESS
;
7388 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
7390 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
7391 comp
->Action
= comp
->Installed
;
7392 return ERROR_SUCCESS
;
7394 comp
->Action
= INSTALLSTATE_LOCAL
;
7396 name
= MSI_RecordGetString(rec
, 2);
7397 value
= MSI_RecordGetString(rec
, 3);
7399 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
7401 res
= env_parse_flags(&name
, &value
, &flags
);
7402 if (res
!= ERROR_SUCCESS
|| !value
)
7405 if (value
&& !deformat_string(package
, value
, &deformatted
))
7407 res
= ERROR_OUTOFMEMORY
;
7411 value
= deformatted
;
7413 res
= open_env_key( flags
, &env
);
7414 if (res
!= ERROR_SUCCESS
)
7417 if (flags
& ENV_MOD_MACHINE
)
7418 action
|= 0x20000000;
7422 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
7423 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
7424 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
7427 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
7431 /* Nothing to do. */
7434 res
= ERROR_SUCCESS
;
7438 /* If we are appending but the string was empty, strip ; */
7439 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
7441 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
7442 newval
= strdupW(value
);
7445 res
= ERROR_OUTOFMEMORY
;
7453 /* Contrary to MSDN, +-variable to [~];path works */
7454 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
7456 res
= ERROR_SUCCESS
;
7460 data
= msi_alloc(size
);
7464 return ERROR_OUTOFMEMORY
;
7467 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
7468 if (res
!= ERROR_SUCCESS
)
7471 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !strcmpW( data
, value
)))
7474 res
= RegDeleteValueW(env
, name
);
7475 if (res
!= ERROR_SUCCESS
)
7476 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
7480 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
7481 if (flags
& ENV_MOD_MASK
)
7485 if (flags
& ENV_MOD_APPEND
) multiplier
++;
7486 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
7487 mod_size
= lstrlenW(value
) * multiplier
;
7488 size
+= mod_size
* sizeof(WCHAR
);
7491 newval
= msi_alloc(size
);
7495 res
= ERROR_OUTOFMEMORY
;
7499 if (flags
& ENV_MOD_PREFIX
)
7501 lstrcpyW(newval
, value
);
7502 ptr
= newval
+ lstrlenW(value
);
7503 action
|= 0x80000000;
7506 lstrcpyW(ptr
, data
);
7508 if (flags
& ENV_MOD_APPEND
)
7510 lstrcatW(newval
, value
);
7511 action
|= 0x40000000;
7514 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
7515 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
7518 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
7522 uirow
= MSI_CreateRecord( 3 );
7523 MSI_RecordSetStringW( uirow
, 1, name
);
7524 MSI_RecordSetStringW( uirow
, 2, newval
);
7525 MSI_RecordSetInteger( uirow
, 3, action
);
7526 msi_ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
7527 msiobj_release( &uirow
->hdr
);
7529 if (env
) RegCloseKey(env
);
7530 msi_free(deformatted
);
7536 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
7540 static const WCHAR ExecSeqQuery
[] =
7541 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7542 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7543 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
7544 if (rc
!= ERROR_SUCCESS
)
7545 return ERROR_SUCCESS
;
7547 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
7548 msiobj_release(&view
->hdr
);
7553 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
7555 MSIPACKAGE
*package
= param
;
7556 LPCWSTR name
, value
, component
;
7557 LPWSTR deformatted
= NULL
;
7566 component
= MSI_RecordGetString( rec
, 4 );
7567 comp
= msi_get_loaded_component( package
, component
);
7569 return ERROR_SUCCESS
;
7573 TRACE("component is disabled\n");
7574 return ERROR_SUCCESS
;
7577 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
7579 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
7580 comp
->Action
= comp
->Installed
;
7581 return ERROR_SUCCESS
;
7583 comp
->Action
= INSTALLSTATE_ABSENT
;
7585 name
= MSI_RecordGetString( rec
, 2 );
7586 value
= MSI_RecordGetString( rec
, 3 );
7588 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
7590 r
= env_parse_flags( &name
, &value
, &flags
);
7591 if (r
!= ERROR_SUCCESS
)
7594 if (!(flags
& ENV_ACT_REMOVE
))
7596 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
7597 return ERROR_SUCCESS
;
7600 if (value
&& !deformat_string( package
, value
, &deformatted
))
7601 return ERROR_OUTOFMEMORY
;
7603 value
= deformatted
;
7605 r
= open_env_key( flags
, &env
);
7606 if (r
!= ERROR_SUCCESS
)
7612 if (flags
& ENV_MOD_MACHINE
)
7613 action
|= 0x20000000;
7615 TRACE("Removing %s\n", debugstr_w(name
));
7617 res
= RegDeleteValueW( env
, name
);
7618 if (res
!= ERROR_SUCCESS
)
7620 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
7625 uirow
= MSI_CreateRecord( 3 );
7626 MSI_RecordSetStringW( uirow
, 1, name
);
7627 MSI_RecordSetStringW( uirow
, 2, value
);
7628 MSI_RecordSetInteger( uirow
, 3, action
);
7629 msi_ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
7630 msiobj_release( &uirow
->hdr
);
7632 if (env
) RegCloseKey( env
);
7633 msi_free( deformatted
);
7637 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
7641 static const WCHAR query
[] =
7642 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7643 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
7645 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
7646 if (rc
!= ERROR_SUCCESS
)
7647 return ERROR_SUCCESS
;
7649 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
7650 msiobj_release( &view
->hdr
);
7655 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
7657 LPWSTR key
, template, id
;
7658 UINT r
= ERROR_SUCCESS
;
7660 id
= msi_dup_property( package
->db
, szProductID
);
7664 return ERROR_SUCCESS
;
7666 template = msi_dup_property( package
->db
, szPIDTemplate
);
7667 key
= msi_dup_property( package
->db
, szPIDKEY
);
7669 if (key
&& template)
7671 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
7672 r
= msi_set_property( package
->db
, szProductID
, key
);
7674 msi_free( template );
7679 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
7682 package
->need_reboot
= 1;
7683 return ERROR_SUCCESS
;
7686 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
7688 static const WCHAR szAvailableFreeReg
[] =
7689 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
7691 int space
= msi_get_property_int( package
->db
, szAvailableFreeReg
, 0 );
7693 TRACE("%p %d kilobytes\n", package
, space
);
7695 uirow
= MSI_CreateRecord( 1 );
7696 MSI_RecordSetInteger( uirow
, 1, space
);
7697 msi_ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
7698 msiobj_release( &uirow
->hdr
);
7700 return ERROR_SUCCESS
;
7703 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
7705 FIXME("%p\n", package
);
7706 return ERROR_SUCCESS
;
7709 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
7711 FIXME("%p\n", package
);
7712 return ERROR_SUCCESS
;
7715 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
7720 static const WCHAR driver_query
[] = {
7721 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7722 'O','D','B','C','D','r','i','v','e','r',0 };
7724 static const WCHAR translator_query
[] = {
7725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7726 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7728 r
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
7729 if (r
== ERROR_SUCCESS
)
7732 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
7733 msiobj_release( &view
->hdr
);
7734 if (count
) FIXME("ignored %u rows in ODBCDriver table\n", count
);
7737 r
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
7738 if (r
== ERROR_SUCCESS
)
7741 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
7742 msiobj_release( &view
->hdr
);
7743 if (count
) FIXME("ignored %u rows in ODBCTranslator table\n", count
);
7746 return ERROR_SUCCESS
;
7749 static UINT
ITERATE_RemoveExistingProducts( MSIRECORD
*rec
, LPVOID param
)
7751 MSIPACKAGE
*package
= param
;
7752 const WCHAR
*property
= MSI_RecordGetString( rec
, 1 );
7755 if ((value
= msi_dup_property( package
->db
, property
)))
7757 FIXME("remove %s\n", debugstr_w(value
));
7760 return ERROR_SUCCESS
;
7763 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
7768 static const WCHAR query
[] =
7769 {'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',
7770 ' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7772 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
7773 if (r
== ERROR_SUCCESS
)
7775 r
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveExistingProducts
, package
);
7776 msiobj_release( &view
->hdr
);
7778 return ERROR_SUCCESS
;
7781 static UINT
ITERATE_MigrateFeatureStates( MSIRECORD
*rec
, LPVOID param
)
7783 MSIPACKAGE
*package
= param
;
7784 int attributes
= MSI_RecordGetInteger( rec
, 5 );
7786 if (attributes
& msidbUpgradeAttributesMigrateFeatures
)
7788 const WCHAR
*upgrade_code
= MSI_RecordGetString( rec
, 1 );
7789 const WCHAR
*version_min
= MSI_RecordGetString( rec
, 2 );
7790 const WCHAR
*version_max
= MSI_RecordGetString( rec
, 3 );
7791 const WCHAR
*language
= MSI_RecordGetString( rec
, 4 );
7795 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
7797 r
= MSIREG_OpenClassesUpgradeCodesKey( upgrade_code
, &hkey
, FALSE
);
7798 if (r
!= ERROR_SUCCESS
)
7799 return ERROR_SUCCESS
;
7803 r
= MSIREG_OpenUserUpgradeCodesKey( upgrade_code
, &hkey
, FALSE
);
7804 if (r
!= ERROR_SUCCESS
)
7805 return ERROR_SUCCESS
;
7807 RegCloseKey( hkey
);
7809 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7810 debugstr_w(upgrade_code
), debugstr_w(version_min
),
7811 debugstr_w(version_max
), debugstr_w(language
));
7813 return ERROR_SUCCESS
;
7816 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
7821 static const WCHAR query
[] =
7822 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
7824 if (msi_get_property_int( package
->db
, szInstalled
, 0 ))
7826 TRACE("product is installed, skipping action\n");
7827 return ERROR_SUCCESS
;
7829 if (msi_get_property_int( package
->db
, szPreselected
, 0 ))
7831 TRACE("Preselected property is set, not migrating feature states\n");
7832 return ERROR_SUCCESS
;
7835 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
7836 if (r
== ERROR_SUCCESS
)
7838 r
= MSI_IterateRecords( view
, NULL
, ITERATE_MigrateFeatureStates
, package
);
7839 msiobj_release( &view
->hdr
);
7841 return ERROR_SUCCESS
;
7844 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
7845 LPCSTR action
, LPCWSTR table
)
7847 static const WCHAR query
[] = {
7848 'S','E','L','E','C','T',' ','*',' ',
7849 'F','R','O','M',' ','`','%','s','`',0 };
7850 MSIQUERY
*view
= NULL
;
7854 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
7855 if (r
== ERROR_SUCCESS
)
7857 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
7858 msiobj_release(&view
->hdr
);
7862 FIXME("%s -> %u ignored %s table values\n",
7863 action
, count
, debugstr_w(table
));
7865 return ERROR_SUCCESS
;
7868 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
7870 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
7871 return msi_unimplemented_action_stub( package
, "BindImage", table
);
7874 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
7876 static const WCHAR table
[] = {
7877 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7878 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
7881 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
7883 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
7884 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
7887 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
7889 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
7890 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
7893 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
7895 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
7896 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
7899 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
7901 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7902 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
7905 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
7909 const WCHAR
*action
;
7910 UINT (*handler
)(MSIPACKAGE
*);
7914 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
7915 { szAppSearch
, ACTION_AppSearch
},
7916 { szBindImage
, ACTION_BindImage
},
7917 { szCCPSearch
, ACTION_CCPSearch
},
7918 { szCostFinalize
, ACTION_CostFinalize
},
7919 { szCostInitialize
, ACTION_CostInitialize
},
7920 { szCreateFolders
, ACTION_CreateFolders
},
7921 { szCreateShortcuts
, ACTION_CreateShortcuts
},
7922 { szDeleteServices
, ACTION_DeleteServices
},
7923 { szDisableRollback
, ACTION_DisableRollback
},
7924 { szDuplicateFiles
, ACTION_DuplicateFiles
},
7925 { szExecuteAction
, ACTION_ExecuteAction
},
7926 { szFileCost
, ACTION_FileCost
},
7927 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
7928 { szForceReboot
, ACTION_ForceReboot
},
7929 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
7930 { szInstallExecute
, ACTION_InstallExecute
},
7931 { szInstallExecuteAgain
, ACTION_InstallExecute
},
7932 { szInstallFiles
, ACTION_InstallFiles
},
7933 { szInstallFinalize
, ACTION_InstallFinalize
},
7934 { szInstallInitialize
, ACTION_InstallInitialize
},
7935 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
7936 { szInstallValidate
, ACTION_InstallValidate
},
7937 { szIsolateComponents
, ACTION_IsolateComponents
},
7938 { szLaunchConditions
, ACTION_LaunchConditions
},
7939 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
7940 { szMoveFiles
, ACTION_MoveFiles
},
7941 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
7942 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
7943 { szInstallODBC
, ACTION_InstallODBC
},
7944 { szInstallServices
, ACTION_InstallServices
},
7945 { szPatchFiles
, ACTION_PatchFiles
},
7946 { szProcessComponents
, ACTION_ProcessComponents
},
7947 { szPublishComponents
, ACTION_PublishComponents
},
7948 { szPublishFeatures
, ACTION_PublishFeatures
},
7949 { szPublishProduct
, ACTION_PublishProduct
},
7950 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
7951 { szRegisterComPlus
, ACTION_RegisterComPlus
},
7952 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
7953 { szRegisterFonts
, ACTION_RegisterFonts
},
7954 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
7955 { szRegisterProduct
, ACTION_RegisterProduct
},
7956 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
7957 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
7958 { szRegisterUser
, ACTION_RegisterUser
},
7959 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
7960 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
7961 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
7962 { szRemoveFiles
, ACTION_RemoveFiles
},
7963 { szRemoveFolders
, ACTION_RemoveFolders
},
7964 { szRemoveIniValues
, ACTION_RemoveIniValues
},
7965 { szRemoveODBC
, ACTION_RemoveODBC
},
7966 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
7967 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
7968 { szResolveSource
, ACTION_ResolveSource
},
7969 { szRMCCPSearch
, ACTION_RMCCPSearch
},
7970 { szScheduleReboot
, ACTION_ScheduleReboot
},
7971 { szSelfRegModules
, ACTION_SelfRegModules
},
7972 { szSelfUnregModules
, ACTION_SelfUnregModules
},
7973 { szSetODBCFolders
, ACTION_SetODBCFolders
},
7974 { szStartServices
, ACTION_StartServices
},
7975 { szStopServices
, ACTION_StopServices
},
7976 { szUnpublishComponents
, ACTION_UnpublishComponents
},
7977 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
7978 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
7979 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
7980 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
7981 { szUnregisterFonts
, ACTION_UnregisterFonts
},
7982 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
7983 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
7984 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
7985 { szValidateProductID
, ACTION_ValidateProductID
},
7986 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
7987 { szWriteIniValues
, ACTION_WriteIniValues
},
7988 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
7992 static BOOL
ACTION_HandleStandardAction( MSIPACKAGE
*package
, LPCWSTR action
, UINT
*rc
)
7998 while (StandardActions
[i
].action
!= NULL
)
8000 if (!strcmpW( StandardActions
[i
].action
, action
))
8002 ui_actionstart( package
, action
);
8003 if (StandardActions
[i
].handler
)
8005 ui_actioninfo( package
, action
, TRUE
, 0 );
8006 *rc
= StandardActions
[i
].handler( package
);
8007 ui_actioninfo( package
, action
, FALSE
, *rc
);
8011 FIXME("unhandled standard action %s\n", debugstr_w(action
));
8012 *rc
= ERROR_SUCCESS
;
8022 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
8024 UINT rc
= ERROR_SUCCESS
;
8027 TRACE("Performing action (%s)\n", debugstr_w(action
));
8029 handled
= ACTION_HandleStandardAction(package
, action
, &rc
);
8032 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, TRUE
);
8036 WARN("unhandled msi action %s\n", debugstr_w(action
));
8037 rc
= ERROR_FUNCTION_NOT_CALLED
;
8043 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
8045 UINT rc
= ERROR_SUCCESS
;
8046 BOOL handled
= FALSE
;
8048 TRACE("Performing action (%s)\n", debugstr_w(action
));
8050 handled
= ACTION_HandleStandardAction(package
, action
, &rc
);
8053 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
8055 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
8060 WARN("unhandled msi action %s\n", debugstr_w(action
));
8061 rc
= ERROR_FUNCTION_NOT_CALLED
;
8067 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
8069 UINT rc
= ERROR_SUCCESS
;
8072 static const WCHAR ExecSeqQuery
[] =
8073 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
8074 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
8075 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
8076 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
8077 static const WCHAR UISeqQuery
[] =
8078 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
8079 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
8080 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
8081 ' ', '=',' ','%','i',0};
8083 if (needs_ui_sequence(package
))
8084 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
8086 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
8090 LPCWSTR action
, cond
;
8092 TRACE("Running the actions\n");
8094 /* check conditions */
8095 cond
= MSI_RecordGetString(row
, 2);
8097 /* this is a hack to skip errors in the condition code */
8098 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
8100 msiobj_release(&row
->hdr
);
8101 return ERROR_SUCCESS
;
8104 action
= MSI_RecordGetString(row
, 1);
8107 ERR("failed to fetch action\n");
8108 msiobj_release(&row
->hdr
);
8109 return ERROR_FUNCTION_FAILED
;
8112 if (needs_ui_sequence(package
))
8113 rc
= ACTION_PerformUIAction(package
, action
, -1);
8115 rc
= ACTION_PerformAction(package
, action
, -1);
8117 msiobj_release(&row
->hdr
);
8123 /****************************************************
8124 * TOP level entry points
8125 *****************************************************/
8127 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
8128 LPCWSTR szCommandLine
)
8133 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
8134 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
8136 msi_set_property( package
->db
, szAction
, szInstall
);
8138 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
8145 dir
= strdupW(szPackagePath
);
8146 p
= strrchrW(dir
, '\\');
8150 file
= szPackagePath
+ (p
- dir
);
8155 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
8156 GetCurrentDirectoryW(MAX_PATH
, dir
);
8157 lstrcatW(dir
, szBackSlash
);
8158 file
= szPackagePath
;
8161 msi_free( package
->PackagePath
);
8162 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
8163 if (!package
->PackagePath
)
8166 return ERROR_OUTOFMEMORY
;
8169 lstrcpyW(package
->PackagePath
, dir
);
8170 lstrcatW(package
->PackagePath
, file
);
8173 msi_set_sourcedir_props(package
, FALSE
);
8176 rc
= msi_parse_command_line( package
, szCommandLine
, FALSE
);
8177 if (rc
!= ERROR_SUCCESS
)
8180 msi_apply_transforms( package
);
8181 msi_apply_patches( package
);
8183 if (!szCommandLine
&& msi_get_property_int( package
->db
, szInstalled
, 0 ))
8185 TRACE("setting reinstall property\n");
8186 msi_set_property( package
->db
, szReinstall
, szAll
);
8189 /* properties may have been added by a transform */
8190 msi_clone_properties( package
);
8192 msi_parse_command_line( package
, szCommandLine
, FALSE
);
8193 msi_adjust_privilege_properties( package
);
8194 msi_set_context( package
);
8196 if (needs_ui_sequence( package
))
8198 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
8199 rc
= ACTION_ProcessUISequence(package
);
8200 ui_exists
= ui_sequence_exists(package
);
8201 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
8203 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
8204 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
8208 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
8210 package
->script
->CurrentlyScripting
= FALSE
;
8212 /* process the ending type action */
8213 if (rc
== ERROR_SUCCESS
)
8214 ACTION_PerformActionSequence(package
, -1);
8215 else if (rc
== ERROR_INSTALL_USEREXIT
)
8216 ACTION_PerformActionSequence(package
, -2);
8217 else if (rc
== ERROR_INSTALL_SUSPEND
)
8218 ACTION_PerformActionSequence(package
, -4);
8220 ACTION_PerformActionSequence(package
, -3);
8222 /* finish up running custom actions */
8223 ACTION_FinishCustomActions(package
);
8225 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
8226 return ERROR_SUCCESS_REBOOT_REQUIRED
;