2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
40 #include "wine/unicode.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
49 * consts and values used
51 static const WCHAR c_colon
[] = {'C',':','\\',0};
53 static const WCHAR szCreateFolders
[] =
54 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
55 static const WCHAR szCostFinalize
[] =
56 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
57 static const WCHAR szWriteRegistryValues
[] =
58 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
59 static const WCHAR szCostInitialize
[] =
60 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
61 static const WCHAR szFileCost
[] =
62 {'F','i','l','e','C','o','s','t',0};
63 static const WCHAR szInstallInitialize
[] =
64 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
65 static const WCHAR szInstallValidate
[] =
66 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
67 static const WCHAR szLaunchConditions
[] =
68 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
69 static const WCHAR szProcessComponents
[] =
70 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
71 static const WCHAR szRegisterTypeLibraries
[] =
72 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
73 static const WCHAR szCreateShortcuts
[] =
74 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
75 static const WCHAR szPublishProduct
[] =
76 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
77 static const WCHAR szWriteIniValues
[] =
78 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
79 static const WCHAR szSelfRegModules
[] =
80 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
81 static const WCHAR szPublishFeatures
[] =
82 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
83 static const WCHAR szRegisterProduct
[] =
84 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
85 static const WCHAR szInstallExecute
[] =
86 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
87 static const WCHAR szInstallExecuteAgain
[] =
88 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
89 static const WCHAR szInstallFinalize
[] =
90 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
91 static const WCHAR szForceReboot
[] =
92 {'F','o','r','c','e','R','e','b','o','o','t',0};
93 static const WCHAR szResolveSource
[] =
94 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
95 static const WCHAR szAllocateRegistrySpace
[] =
96 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
97 static const WCHAR szBindImage
[] =
98 {'B','i','n','d','I','m','a','g','e',0};
99 static const WCHAR szDeleteServices
[] =
100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
101 static const WCHAR szDisableRollback
[] =
102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
103 static const WCHAR szExecuteAction
[] =
104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
105 static const WCHAR szInstallAdminPackage
[] =
106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
107 static const WCHAR szInstallSFPCatalogFile
[] =
108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
109 static const WCHAR szIsolateComponents
[] =
110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
111 static const WCHAR szMigrateFeatureStates
[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
113 static const WCHAR szMsiPublishAssemblies
[] =
114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
115 static const WCHAR szMsiUnpublishAssemblies
[] =
116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
117 static const WCHAR szInstallODBC
[] =
118 {'I','n','s','t','a','l','l','O','D','B','C',0};
119 static const WCHAR szInstallServices
[] =
120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szPatchFiles
[] =
122 {'P','a','t','c','h','F','i','l','e','s',0};
123 static const WCHAR szPublishComponents
[] =
124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
125 static const WCHAR szRegisterComPlus
[] =
126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
127 static const WCHAR szRegisterUser
[] =
128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
129 static const WCHAR szRemoveEnvironmentStrings
[] =
130 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
131 static const WCHAR szRemoveExistingProducts
[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
133 static const WCHAR szRemoveFolders
[] =
134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
135 static const WCHAR szRemoveIniValues
[] =
136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
137 static const WCHAR szRemoveODBC
[] =
138 {'R','e','m','o','v','e','O','D','B','C',0};
139 static const WCHAR szRemoveRegistryValues
[] =
140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
141 static const WCHAR szRemoveShortcuts
[] =
142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
143 static const WCHAR szRMCCPSearch
[] =
144 {'R','M','C','C','P','S','e','a','r','c','h',0};
145 static const WCHAR szScheduleReboot
[] =
146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
147 static const WCHAR szSelfUnregModules
[] =
148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
149 static const WCHAR szSetODBCFolders
[] =
150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
151 static const WCHAR szStartServices
[] =
152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
153 static const WCHAR szStopServices
[] =
154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szUnpublishComponents
[] =
156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
157 static const WCHAR szUnpublishFeatures
[] =
158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
159 static const WCHAR szUnregisterComPlus
[] =
160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 static const WCHAR szUnregisterTypeLibraries
[] =
162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
163 static const WCHAR szValidateProductID
[] =
164 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
165 static const WCHAR szWriteEnvironmentStrings
[] =
166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
168 /********************************************************
170 ********************************************************/
172 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
174 static const WCHAR Query_t
[] =
175 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
176 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
177 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
178 ' ','\'','%','s','\'',0};
181 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
184 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
185 msiobj_release(&row
->hdr
);
188 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
192 static const WCHAR template_s
[]=
193 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
195 static const WCHAR template_e
[]=
196 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
197 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
199 static const WCHAR format
[] =
200 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
204 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
206 sprintfW(message
,template_s
,timet
,action
);
208 sprintfW(message
,template_e
,timet
,action
,rc
);
210 row
= MSI_CreateRecord(1);
211 MSI_RecordSetStringW(row
,1,message
);
213 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
214 msiobj_release(&row
->hdr
);
217 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
223 LPWSTR prop
= NULL
, val
= NULL
;
226 return ERROR_SUCCESS
;
238 TRACE("Looking at %s\n",debugstr_w(ptr
));
240 ptr2
= strchrW(ptr
,'=');
243 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
250 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
251 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
261 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
274 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
275 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
278 if (lstrlenW(prop
) > 0)
280 UINT r
= msi_set_property( package
->db
, prop
, val
);
282 TRACE("Found commandline property (%s) = (%s)\n",
283 debugstr_w(prop
), debugstr_w(val
));
285 if (r
== ERROR_SUCCESS
&& !strcmpW( prop
, cszSourceDir
))
286 msi_reset_folders( package
, TRUE
);
292 return ERROR_SUCCESS
;
296 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
299 LPWSTR p
, *ret
= NULL
;
305 /* count the number of substrings */
306 for ( pc
= str
, count
= 0; pc
; count
++ )
308 pc
= strchrW( pc
, sep
);
313 /* allocate space for an array of substring pointers and the substrings */
314 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
315 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
319 /* copy the string and set the pointers */
320 p
= (LPWSTR
) &ret
[count
+1];
322 for( count
= 0; (ret
[count
] = p
); count
++ )
324 p
= strchrW( p
, sep
);
332 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
334 static const WCHAR szSystemLanguageID
[] =
335 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
337 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
338 UINT ret
= ERROR_FUNCTION_FAILED
;
340 prod_code
= msi_dup_property( package
->db
, szProductCode
);
341 patch_product
= msi_get_suminfo_product( patch
);
343 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
345 if ( strstrW( patch_product
, prod_code
) )
350 si
= MSI_GetSummaryInformationW( patch
, 0 );
353 ERR("no summary information!\n");
357 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
360 ERR("no template property!\n");
361 msiobj_release( &si
->hdr
);
368 msiobj_release( &si
->hdr
);
372 langid
= msi_dup_property( package
->db
, szSystemLanguageID
);
375 msiobj_release( &si
->hdr
);
379 p
= strchrW( template, ';' );
380 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, szZero
)))
382 TRACE("applicable transform\n");
386 /* FIXME: check platform */
388 msiobj_release( &si
->hdr
);
392 msi_free( patch_product
);
393 msi_free( prod_code
);
394 msi_free( template );
400 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
401 MSIDATABASE
*patch_db
, LPCWSTR name
)
403 UINT ret
= ERROR_FUNCTION_FAILED
;
404 IStorage
*stg
= NULL
;
407 TRACE("%p %s\n", package
, debugstr_w(name
) );
411 ERR("expected a colon in %s\n", debugstr_w(name
));
412 return ERROR_FUNCTION_FAILED
;
415 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
418 ret
= msi_check_transform_applicable( package
, stg
);
419 if (ret
== ERROR_SUCCESS
)
420 msi_table_apply_transform( package
->db
, stg
);
422 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
423 IStorage_Release( stg
);
426 ERR("failed to open substorage %s\n", debugstr_w(name
));
428 return ERROR_SUCCESS
;
431 UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
433 LPWSTR guid_list
, *guids
, product_code
;
434 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
436 product_code
= msi_dup_property( package
->db
, szProductCode
);
439 /* FIXME: the property ProductCode should be written into the DB somewhere */
440 ERR("no product code to check\n");
441 return ERROR_SUCCESS
;
444 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
445 guids
= msi_split_string( guid_list
, ';' );
446 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
448 if (!lstrcmpW( guids
[i
], product_code
))
452 msi_free( guid_list
);
453 msi_free( product_code
);
458 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
461 MSIRECORD
*rec
= NULL
;
466 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
467 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
468 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
469 '`','S','o','u','r','c','e','`',' ','I','S',' ',
470 'N','O','T',' ','N','U','L','L',0};
472 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
473 if (r
!= ERROR_SUCCESS
)
476 r
= MSI_ViewExecute(view
, 0);
477 if (r
!= ERROR_SUCCESS
)
480 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
482 prop
= MSI_RecordGetString(rec
, 1);
483 patch
= msi_dup_property(package
->db
, szPatch
);
484 msi_set_property(package
->db
, prop
, patch
);
489 if (rec
) msiobj_release(&rec
->hdr
);
490 msiobj_release(&view
->hdr
);
495 UINT
msi_parse_patch_summary( MSISUMMARYINFO
*si
, MSIPATCHINFO
**patch
)
498 UINT r
= ERROR_SUCCESS
;
500 pi
= msi_alloc_zero( sizeof(MSIPATCHINFO
) );
502 return ERROR_OUTOFMEMORY
;
504 pi
->patchcode
= msi_suminfo_dup_string( si
, PID_REVNUMBER
);
508 return ERROR_OUTOFMEMORY
;
511 pi
->transforms
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
514 msi_free( pi
->patchcode
);
516 return ERROR_OUTOFMEMORY
;
523 UINT
msi_apply_patch_db( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
, MSIPATCHINFO
*patch
)
525 UINT i
, r
= ERROR_SUCCESS
;
528 /* apply substorage transforms */
529 substorage
= msi_split_string( patch
->transforms
, ';' );
530 for (i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++)
531 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
533 msi_free( substorage
);
534 if (r
!= ERROR_SUCCESS
)
537 msi_set_media_source_prop( package
);
540 * There might be a CAB file in the patch package,
541 * so append it to the list of storages to search for streams.
543 append_storage_to_db( package
->db
, patch_db
->storage
);
545 list_add_tail( &package
->patches
, &patch
->entry
);
546 return ERROR_SUCCESS
;
549 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
551 static const WCHAR dotmsp
[] = {'.','m','s','p',0};
552 MSIDATABASE
*patch_db
= NULL
;
553 WCHAR localfile
[MAX_PATH
];
555 MSIPATCHINFO
*patch
= NULL
;
556 UINT r
= ERROR_SUCCESS
;
558 TRACE("%p %s\n", package
, debugstr_w( file
) );
560 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &patch_db
);
561 if ( r
!= ERROR_SUCCESS
)
563 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
567 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
570 msiobj_release( &patch_db
->hdr
);
571 return ERROR_FUNCTION_FAILED
;
574 r
= msi_check_patch_applicable( package
, si
);
575 if (r
!= ERROR_SUCCESS
)
577 TRACE("patch not applicable\n");
582 r
= msi_parse_patch_summary( si
, &patch
);
583 if ( r
!= ERROR_SUCCESS
)
586 r
= msi_get_local_package_name( localfile
, dotmsp
);
587 if ( r
!= ERROR_SUCCESS
)
590 TRACE("copying to local package %s\n", debugstr_w(localfile
));
592 if (!CopyFileW( file
, localfile
, FALSE
))
594 ERR("Unable to copy package (%s -> %s) (error %u)\n",
595 debugstr_w(file
), debugstr_w(localfile
), GetLastError());
599 patch
->localfile
= strdupW( localfile
);
601 r
= msi_apply_patch_db( package
, patch_db
, patch
);
602 if ( r
!= ERROR_SUCCESS
)
603 WARN("patch failed to apply %u\n", r
);
606 msiobj_release( &si
->hdr
);
607 msiobj_release( &patch_db
->hdr
);
608 if (patch
&& r
!= ERROR_SUCCESS
)
610 if (patch
->localfile
)
611 DeleteFileW( patch
->localfile
);
613 msi_free( patch
->patchcode
);
614 msi_free( patch
->transforms
);
615 msi_free( patch
->localfile
);
621 /* get the PATCH property, and apply all the patches it specifies */
622 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
624 LPWSTR patch_list
, *patches
;
625 UINT i
, r
= ERROR_SUCCESS
;
627 patch_list
= msi_dup_property( package
->db
, szPatch
);
629 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
631 patches
= msi_split_string( patch_list
, ';' );
632 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
633 r
= msi_apply_patch_package( package
, patches
[i
] );
636 msi_free( patch_list
);
641 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
643 static const WCHAR szTransforms
[] = {
644 'T','R','A','N','S','F','O','R','M','S',0 };
645 LPWSTR xform_list
, *xforms
;
646 UINT i
, r
= ERROR_SUCCESS
;
648 xform_list
= msi_dup_property( package
->db
, szTransforms
);
649 xforms
= msi_split_string( xform_list
, ';' );
651 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
653 if (xforms
[i
][0] == ':')
654 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
656 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
660 msi_free( xform_list
);
665 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
670 static const WCHAR ExecSeqQuery
[] =
671 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
672 '`','I','n','s','t','a','l','l',
673 'U','I','S','e','q','u','e','n','c','e','`',
674 ' ','W','H','E','R','E',' ',
675 '`','S','e','q','u','e','n','c','e','`',' ',
676 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
677 '`','S','e','q','u','e','n','c','e','`',0};
679 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
680 if (rc
== ERROR_SUCCESS
)
682 msiobj_release(&view
->hdr
);
689 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
692 LPWSTR source
, check
;
695 static const WCHAR szOriginalDatabase
[] =
696 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
698 db
= msi_dup_property( package
->db
, szOriginalDatabase
);
700 return ERROR_OUTOFMEMORY
;
702 p
= strrchrW( db
, '\\' );
705 p
= strrchrW( db
, '/' );
709 return ERROR_SUCCESS
;
714 source
= msi_alloc( len
* sizeof(WCHAR
) );
715 lstrcpynW( source
, db
, len
);
717 check
= msi_dup_property( package
->db
, cszSourceDir
);
718 if (!check
|| replace
)
720 UINT r
= msi_set_property( package
->db
, cszSourceDir
, source
);
721 if (r
== ERROR_SUCCESS
)
722 msi_reset_folders( package
, TRUE
);
726 check
= msi_dup_property( package
->db
, cszSOURCEDIR
);
727 if (!check
|| replace
)
728 msi_set_property( package
->db
, cszSOURCEDIR
, source
);
734 return ERROR_SUCCESS
;
737 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
739 INT level
= msi_get_property_int(package
->db
, szUILevel
, 0);
740 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
743 UINT
msi_set_context(MSIPACKAGE
*package
)
747 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
749 num
= msi_get_property_int(package
->db
, szAllUsers
, 0);
750 if (num
== 1 || num
== 2)
751 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
753 return ERROR_SUCCESS
;
756 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
759 LPCWSTR cond
, action
;
760 MSIPACKAGE
*package
= param
;
762 action
= MSI_RecordGetString(row
,1);
765 ERR("Error is retrieving action name\n");
766 return ERROR_FUNCTION_FAILED
;
769 /* check conditions */
770 cond
= MSI_RecordGetString(row
,2);
772 /* this is a hack to skip errors in the condition code */
773 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
775 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
776 return ERROR_SUCCESS
;
779 if (needs_ui_sequence(package
))
780 rc
= ACTION_PerformUIAction(package
, action
, -1);
782 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
784 msi_dialog_check_messages( NULL
);
786 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
787 rc
= package
->CurrentInstallState
;
789 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
792 if (rc
!= ERROR_SUCCESS
)
793 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
798 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
802 static const WCHAR query
[] =
803 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
805 ' ','W','H','E','R','E',' ',
806 '`','S','e','q','u','e','n','c','e','`',' ',
807 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
808 '`','S','e','q','u','e','n','c','e','`',0};
810 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
812 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
813 if (r
== ERROR_SUCCESS
)
815 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
816 msiobj_release(&view
->hdr
);
822 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
826 static const WCHAR ExecSeqQuery
[] =
827 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
828 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
829 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
830 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
831 'O','R','D','E','R',' ', 'B','Y',' ',
832 '`','S','e','q','u','e','n','c','e','`',0 };
833 static const WCHAR IVQuery
[] =
834 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
835 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
836 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
837 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
838 ' ','\'', 'I','n','s','t','a','l','l',
839 'V','a','l','i','d','a','t','e','\'', 0};
842 if (package
->script
->ExecuteSequenceRun
)
844 TRACE("Execute Sequence already Run\n");
845 return ERROR_SUCCESS
;
848 package
->script
->ExecuteSequenceRun
= TRUE
;
850 /* get the sequence number */
853 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
855 return ERROR_FUNCTION_FAILED
;
856 seq
= MSI_RecordGetInteger(row
,1);
857 msiobj_release(&row
->hdr
);
860 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
861 if (rc
== ERROR_SUCCESS
)
863 TRACE("Running the actions\n");
865 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
866 msiobj_release(&view
->hdr
);
872 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
876 static const WCHAR ExecSeqQuery
[] =
877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
878 '`','I','n','s','t','a','l','l',
879 'U','I','S','e','q','u','e','n','c','e','`',
880 ' ','W','H','E','R','E',' ',
881 '`','S','e','q','u','e','n','c','e','`',' ',
882 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
883 '`','S','e','q','u','e','n','c','e','`',0};
885 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
886 if (rc
== ERROR_SUCCESS
)
888 TRACE("Running the actions\n");
890 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
891 msiobj_release(&view
->hdr
);
897 /********************************************************
898 * ACTION helper functions and functions that perform the actions
899 *******************************************************/
900 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
901 UINT
* rc
, UINT script
, BOOL force
)
906 arc
= ACTION_CustomAction(package
, action
, script
, force
);
908 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
917 * Actual Action Handlers
920 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
922 MSIPACKAGE
*package
= param
;
923 LPCWSTR dir
, component
;
929 component
= MSI_RecordGetString(row
, 2);
930 comp
= get_loaded_component(package
, component
);
932 return ERROR_SUCCESS
;
934 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
936 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
937 comp
->Action
= comp
->Installed
;
938 return ERROR_SUCCESS
;
940 comp
->Action
= INSTALLSTATE_LOCAL
;
942 dir
= MSI_RecordGetString(row
,1);
945 ERR("Unable to get folder id\n");
946 return ERROR_SUCCESS
;
949 uirow
= MSI_CreateRecord(1);
950 MSI_RecordSetStringW(uirow
, 1, dir
);
951 ui_actiondata(package
, szCreateFolders
, uirow
);
952 msiobj_release(&uirow
->hdr
);
954 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
957 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
958 return ERROR_SUCCESS
;
961 TRACE("Folder is %s\n",debugstr_w(full_path
));
963 if (folder
->State
== 0)
964 create_full_pathW(full_path
);
969 return ERROR_SUCCESS
;
972 /* FIXME: probably should merge this with the above function */
973 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
975 UINT rc
= ERROR_SUCCESS
;
979 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
981 return ERROR_FUNCTION_FAILED
;
983 /* create the path */
984 if (folder
->State
== 0)
986 create_full_pathW(install_path
);
989 msi_free(install_path
);
994 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
998 /* create all the folders required by the components are going to install */
999 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1001 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
1003 msi_create_directory( package
, comp
->Directory
);
1006 return ERROR_SUCCESS
;
1009 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1011 static const WCHAR ExecSeqQuery
[] =
1012 {'S','E','L','E','C','T',' ',
1013 '`','D','i','r','e','c','t','o','r','y','_','`',
1014 ' ','F','R','O','M',' ',
1015 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1019 /* create all the empty folders specified in the CreateFolder table */
1020 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1021 if (rc
!= ERROR_SUCCESS
)
1022 return ERROR_SUCCESS
;
1024 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1025 msiobj_release(&view
->hdr
);
1030 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
1032 MSIPACKAGE
*package
= param
;
1033 LPCWSTR dir
, component
;
1039 component
= MSI_RecordGetString(row
, 2);
1040 comp
= get_loaded_component(package
, component
);
1042 return ERROR_SUCCESS
;
1044 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
1046 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
1047 comp
->Action
= comp
->Installed
;
1048 return ERROR_SUCCESS
;
1050 comp
->Action
= INSTALLSTATE_ABSENT
;
1052 dir
= MSI_RecordGetString( row
, 1 );
1055 ERR("Unable to get folder id\n");
1056 return ERROR_SUCCESS
;
1059 full_path
= resolve_folder( package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1062 ERR("Unable to resolve folder id %s\n", debugstr_w(dir
));
1063 return ERROR_SUCCESS
;
1066 TRACE("folder is %s\n", debugstr_w(full_path
));
1068 uirow
= MSI_CreateRecord( 1 );
1069 MSI_RecordSetStringW( uirow
, 1, full_path
);
1070 ui_actiondata( package
, szRemoveFolders
, uirow
);
1071 msiobj_release( &uirow
->hdr
);
1073 RemoveDirectoryW( full_path
);
1076 msi_free( full_path
);
1077 return ERROR_SUCCESS
;
1080 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1082 static const WCHAR query
[] =
1083 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1084 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1089 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1090 if (rc
!= ERROR_SUCCESS
)
1091 return ERROR_SUCCESS
;
1093 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1094 msiobj_release( &view
->hdr
);
1099 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1101 MSIPACKAGE
*package
= param
;
1104 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1106 return ERROR_FUNCTION_FAILED
;
1108 list_add_tail( &package
->components
, &comp
->entry
);
1110 /* fill in the data */
1111 comp
->Component
= msi_dup_record_field( row
, 1 );
1113 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1115 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1116 comp
->Directory
= msi_dup_record_field( row
, 3 );
1117 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1118 comp
->Condition
= msi_dup_record_field( row
, 5 );
1119 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1121 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1122 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1124 return ERROR_SUCCESS
;
1127 static UINT
load_all_components( MSIPACKAGE
*package
)
1129 static const WCHAR query
[] = {
1130 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1131 '`','C','o','m','p','o','n','e','n','t','`',0 };
1135 if (!list_empty(&package
->components
))
1136 return ERROR_SUCCESS
;
1138 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1139 if (r
!= ERROR_SUCCESS
)
1142 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1143 msiobj_release(&view
->hdr
);
1148 MSIPACKAGE
*package
;
1149 MSIFEATURE
*feature
;
1152 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1156 cl
= msi_alloc( sizeof (*cl
) );
1158 return ERROR_NOT_ENOUGH_MEMORY
;
1159 cl
->component
= comp
;
1160 list_add_tail( &feature
->Components
, &cl
->entry
);
1162 return ERROR_SUCCESS
;
1165 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1169 fl
= msi_alloc( sizeof(*fl
) );
1171 return ERROR_NOT_ENOUGH_MEMORY
;
1172 fl
->feature
= child
;
1173 list_add_tail( &parent
->Children
, &fl
->entry
);
1175 return ERROR_SUCCESS
;
1178 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1180 _ilfs
* ilfs
= param
;
1184 component
= MSI_RecordGetString(row
,1);
1186 /* check to see if the component is already loaded */
1187 comp
= get_loaded_component( ilfs
->package
, component
);
1190 ERR("unknown component %s\n", debugstr_w(component
));
1191 return ERROR_FUNCTION_FAILED
;
1194 add_feature_component( ilfs
->feature
, comp
);
1195 comp
->Enabled
= TRUE
;
1197 return ERROR_SUCCESS
;
1200 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1202 MSIFEATURE
*feature
;
1207 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1209 if ( !lstrcmpW( feature
->Feature
, name
) )
1216 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1218 MSIPACKAGE
* package
= param
;
1219 MSIFEATURE
* feature
;
1220 static const WCHAR Query1
[] =
1221 {'S','E','L','E','C','T',' ',
1222 '`','C','o','m','p','o','n','e','n','t','_','`',
1223 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1224 'C','o','m','p','o','n','e','n','t','s','`',' ',
1225 'W','H','E','R','E',' ',
1226 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1231 /* fill in the data */
1233 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1235 return ERROR_NOT_ENOUGH_MEMORY
;
1237 list_init( &feature
->Children
);
1238 list_init( &feature
->Components
);
1240 feature
->Feature
= msi_dup_record_field( row
, 1 );
1242 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1244 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1245 feature
->Title
= msi_dup_record_field( row
, 3 );
1246 feature
->Description
= msi_dup_record_field( row
, 4 );
1248 if (!MSI_RecordIsNull(row
,5))
1249 feature
->Display
= MSI_RecordGetInteger(row
,5);
1251 feature
->Level
= MSI_RecordGetInteger(row
,6);
1252 feature
->Directory
= msi_dup_record_field( row
, 7 );
1253 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1255 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1256 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1258 list_add_tail( &package
->features
, &feature
->entry
);
1260 /* load feature components */
1262 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1263 if (rc
!= ERROR_SUCCESS
)
1264 return ERROR_SUCCESS
;
1266 ilfs
.package
= package
;
1267 ilfs
.feature
= feature
;
1269 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1270 msiobj_release(&view
->hdr
);
1272 return ERROR_SUCCESS
;
1275 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1277 MSIPACKAGE
* package
= param
;
1278 MSIFEATURE
*parent
, *child
;
1280 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1282 return ERROR_FUNCTION_FAILED
;
1284 if (!child
->Feature_Parent
)
1285 return ERROR_SUCCESS
;
1287 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1289 return ERROR_FUNCTION_FAILED
;
1291 add_feature_child( parent
, child
);
1292 return ERROR_SUCCESS
;
1295 static UINT
load_all_features( MSIPACKAGE
*package
)
1297 static const WCHAR query
[] = {
1298 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1299 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1300 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1304 if (!list_empty(&package
->features
))
1305 return ERROR_SUCCESS
;
1307 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1308 if (r
!= ERROR_SUCCESS
)
1311 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1312 if (r
!= ERROR_SUCCESS
)
1315 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1316 msiobj_release( &view
->hdr
);
1321 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1332 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1334 static const WCHAR query
[] = {
1335 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1336 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1337 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1338 MSIQUERY
*view
= NULL
;
1339 MSIRECORD
*row
= NULL
;
1342 TRACE("%s\n", debugstr_w(file
->File
));
1344 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1345 if (r
!= ERROR_SUCCESS
)
1348 r
= MSI_ViewExecute(view
, NULL
);
1349 if (r
!= ERROR_SUCCESS
)
1352 r
= MSI_ViewFetch(view
, &row
);
1353 if (r
!= ERROR_SUCCESS
)
1356 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1357 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1358 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1359 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1360 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1363 if (view
) msiobj_release(&view
->hdr
);
1364 if (row
) msiobj_release(&row
->hdr
);
1368 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1370 MSIPACKAGE
* package
= param
;
1374 /* fill in the data */
1376 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1378 return ERROR_NOT_ENOUGH_MEMORY
;
1380 file
->File
= msi_dup_record_field( row
, 1 );
1382 component
= MSI_RecordGetString( row
, 2 );
1383 file
->Component
= get_loaded_component( package
, component
);
1385 if (!file
->Component
)
1387 WARN("Component not found: %s\n", debugstr_w(component
));
1388 msi_free(file
->File
);
1390 return ERROR_SUCCESS
;
1393 file
->FileName
= msi_dup_record_field( row
, 3 );
1394 reduce_to_longfilename( file
->FileName
);
1396 file
->ShortName
= msi_dup_record_field( row
, 3 );
1397 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1399 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1400 file
->Version
= msi_dup_record_field( row
, 5 );
1401 file
->Language
= msi_dup_record_field( row
, 6 );
1402 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1403 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1405 file
->state
= msifs_invalid
;
1407 /* if the compressed bits are not set in the file attributes,
1408 * then read the information from the package word count property
1410 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1412 file
->IsCompressed
= FALSE
;
1414 else if (file
->Attributes
&
1415 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1417 file
->IsCompressed
= TRUE
;
1419 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1421 file
->IsCompressed
= FALSE
;
1425 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1428 load_file_hash(package
, file
);
1430 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1432 list_add_tail( &package
->files
, &file
->entry
);
1434 return ERROR_SUCCESS
;
1437 static UINT
load_all_files(MSIPACKAGE
*package
)
1441 static const WCHAR Query
[] =
1442 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1443 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1444 '`','S','e','q','u','e','n','c','e','`', 0};
1446 if (!list_empty(&package
->files
))
1447 return ERROR_SUCCESS
;
1449 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1450 if (rc
!= ERROR_SUCCESS
)
1451 return ERROR_SUCCESS
;
1453 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1454 msiobj_release(&view
->hdr
);
1456 return ERROR_SUCCESS
;
1459 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1461 MSIPACKAGE
*package
= param
;
1462 static WCHAR szEmpty
[] = { 0 };
1463 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1466 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1468 return ERROR_NOT_ENOUGH_MEMORY
;
1470 folder
->Directory
= msi_dup_record_field( row
, 1 );
1472 TRACE("%s\n", debugstr_w(folder
->Directory
));
1474 p
= msi_dup_record_field(row
, 3);
1476 /* split src and target dir */
1478 src_short
= folder_split_path( p
, ':' );
1480 /* split the long and short paths */
1481 tgt_long
= folder_split_path( tgt_short
, '|' );
1482 src_long
= folder_split_path( src_short
, '|' );
1484 /* check for no-op dirs */
1485 if (!lstrcmpW(szDot
, tgt_short
))
1486 tgt_short
= szEmpty
;
1487 if (!lstrcmpW(szDot
, src_short
))
1488 src_short
= szEmpty
;
1491 tgt_long
= tgt_short
;
1494 src_short
= tgt_short
;
1495 src_long
= tgt_long
;
1499 src_long
= src_short
;
1501 /* FIXME: use the target short path too */
1502 folder
->TargetDefault
= strdupW(tgt_long
);
1503 folder
->SourceShortPath
= strdupW(src_short
);
1504 folder
->SourceLongPath
= strdupW(src_long
);
1507 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1508 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1509 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1511 folder
->Parent
= msi_dup_record_field( row
, 2 );
1513 folder
->Property
= msi_dup_property( package
->db
, folder
->Directory
);
1515 list_add_tail( &package
->folders
, &folder
->entry
);
1517 TRACE("returning %p\n", folder
);
1519 return ERROR_SUCCESS
;
1522 static UINT
load_all_folders( MSIPACKAGE
*package
)
1524 static const WCHAR query
[] = {
1525 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1526 '`','D','i','r','e','c','t','o','r','y','`',0 };
1530 if (!list_empty(&package
->folders
))
1531 return ERROR_SUCCESS
;
1533 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1534 if (r
!= ERROR_SUCCESS
)
1537 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1538 msiobj_release(&view
->hdr
);
1543 * I am not doing any of the costing functionality yet.
1544 * Mostly looking at doing the Component and Feature loading
1546 * The native MSI does A LOT of modification to tables here. Mostly adding
1547 * a lot of temporary columns to the Feature and Component tables.
1549 * note: Native msi also tracks the short filename. But I am only going to
1550 * track the long ones. Also looking at this directory table
1551 * it appears that the directory table does not get the parents
1552 * resolved base on property only based on their entries in the
1555 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1557 static const WCHAR szCosting
[] =
1558 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1560 msi_set_property( package
->db
, szCosting
, szZero
);
1561 msi_set_property( package
->db
, cszRootDrive
, c_colon
);
1563 load_all_folders( package
);
1564 load_all_components( package
);
1565 load_all_features( package
);
1566 load_all_files( package
);
1568 return ERROR_SUCCESS
;
1571 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1574 UINT rc
= ERROR_SUCCESS
;
1576 TRACE("Executing Script %i\n",script
);
1578 if (!package
->script
)
1580 ERR("no script!\n");
1581 return ERROR_FUNCTION_FAILED
;
1584 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1587 action
= package
->script
->Actions
[script
][i
];
1588 ui_actionstart(package
, action
);
1589 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1590 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1591 if (rc
!= ERROR_SUCCESS
)
1594 msi_free_action_script(package
, script
);
1598 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1600 return ERROR_SUCCESS
;
1603 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1609 state
= MsiQueryProductStateW(package
->ProductCode
);
1611 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1613 if (!comp
->ComponentId
)
1616 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1617 comp
->Installed
= INSTALLSTATE_ABSENT
;
1620 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1621 package
->Context
, comp
->ComponentId
,
1623 if (r
!= ERROR_SUCCESS
)
1624 comp
->Installed
= INSTALLSTATE_ABSENT
;
1629 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1631 MSIFEATURE
*feature
;
1634 state
= MsiQueryProductStateW(package
->ProductCode
);
1636 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1638 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1639 feature
->Installed
= INSTALLSTATE_ABSENT
;
1642 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1648 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1649 LPCWSTR property
, INSTALLSTATE state
)
1652 MSIFEATURE
*feature
;
1654 override
= msi_dup_property( package
->db
, property
);
1658 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1660 if (lstrcmpW(property
, szRemove
) &&
1661 (feature
->Level
<= 0 || feature
->Level
> level
))
1664 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1666 if (strcmpiW(override
, szAll
)==0)
1667 msi_feature_set_state(package
, feature
, state
);
1670 LPWSTR ptr
= override
;
1671 LPWSTR ptr2
= strchrW(override
,',');
1675 int len
= ptr2
- ptr
;
1677 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1678 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1680 msi_feature_set_state(package
, feature
, state
);
1686 ptr2
= strchrW(ptr
,',');
1698 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
1700 static const WCHAR szAddLocal
[] =
1701 {'A','D','D','L','O','C','A','L',0};
1702 static const WCHAR szAddSource
[] =
1703 {'A','D','D','S','O','U','R','C','E',0};
1704 static const WCHAR szAdvertise
[] =
1705 {'A','D','V','E','R','T','I','S','E',0};
1708 /* all these activation/deactivation things happen in order and things
1709 * later on the list override things earlier on the list.
1711 * 0 INSTALLLEVEL processing
1724 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1725 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1726 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1727 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1728 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1731 msi_set_property( package
->db
, szPreselected
, szOne
);
1736 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1739 static const WCHAR szlevel
[] =
1740 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1741 MSICOMPONENT
* component
;
1742 MSIFEATURE
*feature
;
1744 TRACE("Checking Install Level\n");
1746 level
= msi_get_property_int(package
->db
, szlevel
, 1);
1748 if (!msi_get_property_int( package
->db
, szPreselected
, 0 ))
1750 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1752 BOOL feature_state
= ((feature
->Level
> 0) &&
1753 (feature
->Level
<= level
));
1755 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1757 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1758 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1759 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1760 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1762 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1766 /* disable child features of unselected parent features */
1767 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1771 if (feature
->Level
> 0 && feature
->Level
<= level
)
1774 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1775 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1780 * now we want to enable or disable components base on feature
1783 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1787 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1788 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1790 if (!feature
->Level
)
1793 /* features with components that have compressed files are made local */
1794 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1796 if (cl
->component
->Enabled
&&
1797 cl
->component
->ForceLocalState
&&
1798 feature
->Action
== INSTALLSTATE_SOURCE
)
1800 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1805 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1807 component
= cl
->component
;
1809 if (!component
->Enabled
)
1812 switch (feature
->Action
)
1814 case INSTALLSTATE_ABSENT
:
1815 component
->anyAbsent
= 1;
1817 case INSTALLSTATE_ADVERTISED
:
1818 component
->hasAdvertiseFeature
= 1;
1820 case INSTALLSTATE_SOURCE
:
1821 component
->hasSourceFeature
= 1;
1823 case INSTALLSTATE_LOCAL
:
1824 component
->hasLocalFeature
= 1;
1826 case INSTALLSTATE_DEFAULT
:
1827 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1828 component
->hasAdvertiseFeature
= 1;
1829 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1830 component
->hasSourceFeature
= 1;
1832 component
->hasLocalFeature
= 1;
1840 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1842 /* if the component isn't enabled, leave it alone */
1843 if (!component
->Enabled
)
1846 /* check if it's local or source */
1847 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1848 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1850 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1851 !component
->ForceLocalState
)
1852 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1854 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1858 /* if any feature is local, the component must be local too */
1859 if (component
->hasLocalFeature
)
1861 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1865 if (component
->hasSourceFeature
)
1867 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1871 if (component
->hasAdvertiseFeature
)
1873 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1877 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1878 if (component
->anyAbsent
)
1879 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1882 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1884 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1886 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1887 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1890 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1891 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1895 return ERROR_SUCCESS
;
1898 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1900 MSIPACKAGE
*package
= param
;
1905 name
= MSI_RecordGetString(row
,1);
1907 f
= get_loaded_folder(package
, name
);
1908 if (!f
) return ERROR_SUCCESS
;
1910 /* reset the ResolvedTarget */
1911 msi_free(f
->ResolvedTarget
);
1912 f
->ResolvedTarget
= NULL
;
1914 /* This helper function now does ALL the work */
1915 TRACE("Dir %s ...\n",debugstr_w(name
));
1916 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1917 TRACE("resolves to %s\n",debugstr_w(path
));
1920 return ERROR_SUCCESS
;
1923 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1925 MSIPACKAGE
*package
= param
;
1927 MSIFEATURE
*feature
;
1929 name
= MSI_RecordGetString( row
, 1 );
1931 feature
= get_loaded_feature( package
, name
);
1933 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1937 Condition
= MSI_RecordGetString(row
,3);
1939 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1941 int level
= MSI_RecordGetInteger(row
,2);
1942 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1943 feature
->Level
= level
;
1946 return ERROR_SUCCESS
;
1949 static LPWSTR
get_disk_file_version( LPCWSTR filename
)
1951 static const WCHAR name_fmt
[] =
1952 {'%','u','.','%','u','.','%','u','.','%','u',0};
1953 static const WCHAR name
[] = {'\\',0};
1954 VS_FIXEDFILEINFO
*lpVer
;
1955 WCHAR filever
[0x100];
1961 TRACE("%s\n", debugstr_w(filename
));
1963 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1967 version
= msi_alloc( versize
);
1968 GetFileVersionInfoW( filename
, 0, versize
, version
);
1970 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1972 msi_free( version
);
1976 sprintfW( filever
, name_fmt
,
1977 HIWORD(lpVer
->dwFileVersionMS
),
1978 LOWORD(lpVer
->dwFileVersionMS
),
1979 HIWORD(lpVer
->dwFileVersionLS
),
1980 LOWORD(lpVer
->dwFileVersionLS
));
1982 msi_free( version
);
1984 return strdupW( filever
);
1987 static DWORD
get_disk_file_size( LPCWSTR filename
)
1992 TRACE("%s\n", debugstr_w(filename
));
1994 file
= CreateFileW( filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
1995 if (file
== INVALID_HANDLE_VALUE
)
1996 return INVALID_FILE_SIZE
;
1998 size
= GetFileSize( file
, NULL
);
1999 CloseHandle( file
);
2003 static BOOL
hash_matches( MSIFILE
*file
)
2006 MSIFILEHASHINFO hash
;
2008 hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
2009 r
= MsiGetFileHashW( file
->TargetPath
, 0, &hash
);
2010 if (r
!= ERROR_SUCCESS
)
2013 return !memcmp( &hash
, &file
->hash
, sizeof(MSIFILEHASHINFO
) );
2016 static UINT
set_file_install_states( MSIPACKAGE
*package
)
2018 LPWSTR file_version
;
2021 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2023 MSICOMPONENT
* comp
= file
->Component
;
2030 if (file
->IsCompressed
)
2031 comp
->ForceLocalState
= TRUE
;
2033 /* calculate target */
2034 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
2036 msi_free(file
->TargetPath
);
2038 TRACE("file %s is named %s\n",
2039 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
2041 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2045 TRACE("file %s resolves to %s\n",
2046 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
2048 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2050 file
->state
= msifs_missing
;
2051 comp
->Cost
+= file
->FileSize
;
2054 if (file
->Version
&& (file_version
= get_disk_file_version( file
->TargetPath
)))
2056 TRACE("new %s old %s\n", debugstr_w(file
->Version
), debugstr_w(file_version
));
2058 if (strcmpiW(file_version
, file
->Version
) < 0)
2060 file
->state
= msifs_overwrite
;
2061 comp
->Cost
+= file
->FileSize
;
2065 TRACE("Destination file version equal or greater, not overwriting\n");
2066 file
->state
= msifs_present
;
2068 msi_free( file_version
);
2071 if ((file_size
= get_disk_file_size( file
->TargetPath
)) != file
->FileSize
)
2073 file
->state
= msifs_overwrite
;
2074 comp
->Cost
+= file
->FileSize
- file_size
;
2077 if (file
->hash
.dwFileHashInfoSize
&& hash_matches( file
))
2079 TRACE("File hashes match, not overwriting\n");
2080 file
->state
= msifs_present
;
2083 file
->state
= msifs_overwrite
;
2084 comp
->Cost
+= file
->FileSize
- file_size
;
2087 return ERROR_SUCCESS
;
2091 * A lot is done in this function aside from just the costing.
2092 * The costing needs to be implemented at some point but for now I am going
2093 * to focus on the directory building
2096 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2098 static const WCHAR ExecSeqQuery
[] =
2099 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2100 '`','D','i','r','e','c','t','o','r','y','`',0};
2101 static const WCHAR ConditionQuery
[] =
2102 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2103 '`','C','o','n','d','i','t','i','o','n','`',0};
2104 static const WCHAR szCosting
[] =
2105 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2106 static const WCHAR szlevel
[] =
2107 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2108 static const WCHAR szOutOfDiskSpace
[] =
2109 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2111 UINT rc
= ERROR_SUCCESS
;
2115 TRACE("Building Directory properties\n");
2117 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2118 if (rc
== ERROR_SUCCESS
)
2120 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2122 msiobj_release(&view
->hdr
);
2125 /* read components states from the registry */
2126 ACTION_GetComponentInstallStates(package
);
2127 ACTION_GetFeatureInstallStates(package
);
2129 TRACE("Calculating file install states\n");
2130 set_file_install_states( package
);
2132 if (!process_overrides( package
, msi_get_property_int( package
->db
, szlevel
, 1 ) ))
2134 TRACE("Evaluating feature conditions\n");
2136 rc
= MSI_DatabaseOpenViewW( package
->db
, ConditionQuery
, &view
);
2137 if (rc
== ERROR_SUCCESS
)
2139 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
2140 msiobj_release( &view
->hdr
);
2143 TRACE("Evaluating component conditions\n");
2145 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2147 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
2149 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2150 comp
->Enabled
= FALSE
;
2153 comp
->Enabled
= TRUE
;
2156 msi_set_property( package
->db
, szCosting
, szOne
);
2157 /* set default run level if not set */
2158 level
= msi_dup_property( package
->db
, szlevel
);
2160 msi_set_property( package
->db
, szlevel
, szOne
);
2163 /* FIXME: check volume disk space */
2164 msi_set_property( package
->db
, szOutOfDiskSpace
, szZero
);
2166 return MSI_SetFeatureStates(package
);
2169 /* OK this value is "interpreted" and then formatted based on the
2170 first few characters */
2171 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2176 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2182 LPWSTR deformated
= NULL
;
2185 deformat_string(package
, &value
[2], &deformated
);
2187 /* binary value type */
2191 *size
= (strlenW(ptr
)/2)+1;
2193 *size
= strlenW(ptr
)/2;
2195 data
= msi_alloc(*size
);
2201 /* if uneven pad with a zero in front */
2207 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2209 TRACE("Uneven byte count\n");
2217 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2220 msi_free(deformated
);
2222 TRACE("Data %i bytes(%i)\n",*size
,count
);
2229 deformat_string(package
, &value
[1], &deformated
);
2232 *size
= sizeof(DWORD
);
2233 data
= msi_alloc(*size
);
2239 if ( (*p
< '0') || (*p
> '9') )
2245 if (deformated
[0] == '-')
2248 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2250 msi_free(deformated
);
2255 static const WCHAR szMulti
[] = {'[','~',']',0};
2264 *type
=REG_EXPAND_SZ
;
2272 if (strstrW(value
,szMulti
))
2273 *type
= REG_MULTI_SZ
;
2275 /* remove initial delimiter */
2276 if (!strncmpW(value
, szMulti
, 3))
2279 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2281 /* add double NULL terminator */
2282 if (*type
== REG_MULTI_SZ
)
2284 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2285 data
= msi_realloc_zero(data
, *size
);
2291 static const WCHAR
*get_root_key( MSIPACKAGE
*package
, INT root
, HKEY
*root_key
)
2298 if (msi_get_property_int( package
->db
, szAllUsers
, 0 ))
2300 *root_key
= HKEY_LOCAL_MACHINE
;
2305 *root_key
= HKEY_CURRENT_USER
;
2310 *root_key
= HKEY_CLASSES_ROOT
;
2314 *root_key
= HKEY_CURRENT_USER
;
2318 *root_key
= HKEY_LOCAL_MACHINE
;
2322 *root_key
= HKEY_USERS
;
2326 ERR("Unknown root %i\n", root
);
2333 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2335 MSIPACKAGE
*package
= param
;
2336 LPSTR value_data
= NULL
;
2337 HKEY root_key
, hkey
;
2340 LPCWSTR szRoot
, component
, name
, key
, value
;
2345 BOOL check_first
= FALSE
;
2348 ui_progress(package
,2,0,0,0);
2355 component
= MSI_RecordGetString(row
, 6);
2356 comp
= get_loaded_component(package
,component
);
2358 return ERROR_SUCCESS
;
2360 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2362 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2363 comp
->Action
= comp
->Installed
;
2364 return ERROR_SUCCESS
;
2366 comp
->Action
= INSTALLSTATE_LOCAL
;
2368 name
= MSI_RecordGetString(row
, 4);
2369 if( MSI_RecordIsNull(row
,5) && name
)
2371 /* null values can have special meanings */
2372 if (name
[0]=='-' && name
[1] == 0)
2373 return ERROR_SUCCESS
;
2374 else if ((name
[0]=='+' && name
[1] == 0) ||
2375 (name
[0] == '*' && name
[1] == 0))
2380 root
= MSI_RecordGetInteger(row
,2);
2381 key
= MSI_RecordGetString(row
, 3);
2383 szRoot
= get_root_key( package
, root
, &root_key
);
2385 return ERROR_SUCCESS
;
2387 deformat_string(package
, key
, &deformated
);
2388 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2389 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2390 strcpyW(uikey
,szRoot
);
2391 strcatW(uikey
,deformated
);
2393 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2395 ERR("Could not create key %s\n",debugstr_w(deformated
));
2396 msi_free(deformated
);
2398 return ERROR_SUCCESS
;
2400 msi_free(deformated
);
2402 value
= MSI_RecordGetString(row
,5);
2404 value_data
= parse_value(package
, value
, &type
, &size
);
2407 value_data
= (LPSTR
)strdupW(szEmpty
);
2408 size
= sizeof(szEmpty
);
2412 deformat_string(package
, name
, &deformated
);
2416 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2418 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2423 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2424 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2426 TRACE("value %s of %s checked already exists\n",
2427 debugstr_w(deformated
), debugstr_w(uikey
));
2431 TRACE("Checked and setting value %s of %s\n",
2432 debugstr_w(deformated
), debugstr_w(uikey
));
2433 if (deformated
|| size
)
2434 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2439 uirow
= MSI_CreateRecord(3);
2440 MSI_RecordSetStringW(uirow
,2,deformated
);
2441 MSI_RecordSetStringW(uirow
,1,uikey
);
2442 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
)
2443 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2444 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2445 msiobj_release( &uirow
->hdr
);
2447 msi_free(value_data
);
2448 msi_free(deformated
);
2451 return ERROR_SUCCESS
;
2454 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2458 static const WCHAR ExecSeqQuery
[] =
2459 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2460 '`','R','e','g','i','s','t','r','y','`',0 };
2462 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2463 if (rc
!= ERROR_SUCCESS
)
2464 return ERROR_SUCCESS
;
2466 /* increment progress bar each time action data is sent */
2467 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2469 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2471 msiobj_release(&view
->hdr
);
2475 static void delete_reg_key_or_value( HKEY hkey_root
, LPCWSTR key
, LPCWSTR value
, BOOL delete_key
)
2479 DWORD num_subkeys
, num_values
;
2483 if ((res
= RegDeleteTreeW( hkey_root
, key
)))
2485 WARN("Failed to delete key %s (%d)\n", debugstr_w(key
), res
);
2490 if (!(res
= RegOpenKeyW( hkey_root
, key
, &hkey
)))
2492 if ((res
= RegDeleteValueW( hkey
, value
)))
2494 WARN("Failed to delete value %s (%d)\n", debugstr_w(value
), res
);
2496 res
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
, NULL
, &num_values
,
2497 NULL
, NULL
, NULL
, NULL
);
2498 RegCloseKey( hkey
);
2500 if (!res
&& !num_subkeys
&& !num_values
)
2502 TRACE("Removing empty key %s\n", debugstr_w(key
));
2503 RegDeleteKeyW( hkey_root
, key
);
2507 WARN("Failed to open key %s (%d)\n", debugstr_w(key
), res
);
2511 static UINT
ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
2513 MSIPACKAGE
*package
= param
;
2514 LPCWSTR component
, name
, key_str
, root_key_str
;
2515 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2518 BOOL delete_key
= FALSE
;
2523 ui_progress( package
, 2, 0, 0, 0 );
2525 component
= MSI_RecordGetString( row
, 6 );
2526 comp
= get_loaded_component( package
, component
);
2528 return ERROR_SUCCESS
;
2530 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2532 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
2533 comp
->Action
= comp
->Installed
;
2534 return ERROR_SUCCESS
;
2536 comp
->Action
= INSTALLSTATE_ABSENT
;
2538 name
= MSI_RecordGetString( row
, 4 );
2539 if (MSI_RecordIsNull( row
, 5 ) && name
)
2541 if (name
[0] == '+' && !name
[1])
2542 return ERROR_SUCCESS
;
2543 else if ((name
[0] == '-' && !name
[1]) || (name
[0] == '*' && !name
[1]))
2550 root
= MSI_RecordGetInteger( row
, 2 );
2551 key_str
= MSI_RecordGetString( row
, 3 );
2553 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2555 return ERROR_SUCCESS
;
2557 deformat_string( package
, key_str
, &deformated_key
);
2558 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2559 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2560 strcpyW( ui_key_str
, root_key_str
);
2561 strcatW( ui_key_str
, deformated_key
);
2563 deformat_string( package
, name
, &deformated_name
);
2565 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2566 msi_free( deformated_key
);
2568 uirow
= MSI_CreateRecord( 2 );
2569 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2570 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2572 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2573 msiobj_release( &uirow
->hdr
);
2575 msi_free( ui_key_str
);
2576 msi_free( deformated_name
);
2577 return ERROR_SUCCESS
;
2580 static UINT
ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
2582 MSIPACKAGE
*package
= param
;
2583 LPCWSTR component
, name
, key_str
, root_key_str
;
2584 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2587 BOOL delete_key
= FALSE
;
2592 ui_progress( package
, 2, 0, 0, 0 );
2594 component
= MSI_RecordGetString( row
, 5 );
2595 comp
= get_loaded_component( package
, component
);
2597 return ERROR_SUCCESS
;
2599 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2601 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2602 comp
->Action
= comp
->Installed
;
2603 return ERROR_SUCCESS
;
2605 comp
->Action
= INSTALLSTATE_LOCAL
;
2607 if ((name
= MSI_RecordGetString( row
, 4 )))
2609 if (name
[0] == '-' && !name
[1])
2616 root
= MSI_RecordGetInteger( row
, 2 );
2617 key_str
= MSI_RecordGetString( row
, 3 );
2619 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2621 return ERROR_SUCCESS
;
2623 deformat_string( package
, key_str
, &deformated_key
);
2624 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2625 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2626 strcpyW( ui_key_str
, root_key_str
);
2627 strcatW( ui_key_str
, deformated_key
);
2629 deformat_string( package
, name
, &deformated_name
);
2631 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2632 msi_free( deformated_key
);
2634 uirow
= MSI_CreateRecord( 2 );
2635 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2636 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2638 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2639 msiobj_release( &uirow
->hdr
);
2641 msi_free( ui_key_str
);
2642 msi_free( deformated_name
);
2643 return ERROR_SUCCESS
;
2646 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
2650 static const WCHAR registry_query
[] =
2651 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2652 '`','R','e','g','i','s','t','r','y','`',0 };
2653 static const WCHAR remove_registry_query
[] =
2654 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2655 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2657 /* increment progress bar each time action data is sent */
2658 ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
2660 rc
= MSI_DatabaseOpenViewW( package
->db
, registry_query
, &view
);
2661 if (rc
== ERROR_SUCCESS
)
2663 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnUninstall
, package
);
2664 msiobj_release( &view
->hdr
);
2665 if (rc
!= ERROR_SUCCESS
)
2669 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_registry_query
, &view
);
2670 if (rc
== ERROR_SUCCESS
)
2672 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnInstall
, package
);
2673 msiobj_release( &view
->hdr
);
2674 if (rc
!= ERROR_SUCCESS
)
2678 return ERROR_SUCCESS
;
2681 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2683 package
->script
->CurrentlyScripting
= TRUE
;
2685 return ERROR_SUCCESS
;
2689 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2694 static const WCHAR q1
[]=
2695 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2696 '`','R','e','g','i','s','t','r','y','`',0};
2699 MSIFEATURE
*feature
;
2702 TRACE("InstallValidate\n");
2704 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2705 if (rc
== ERROR_SUCCESS
)
2707 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2708 msiobj_release( &view
->hdr
);
2709 total
+= progress
* REG_PROGRESS_VALUE
;
2712 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2713 total
+= COMPONENT_PROGRESS_VALUE
;
2715 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2716 total
+= file
->FileSize
;
2718 ui_progress(package
,0,total
,0,0);
2720 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2722 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2723 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2724 feature
->ActionRequest
);
2727 return ERROR_SUCCESS
;
2730 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2732 MSIPACKAGE
* package
= param
;
2733 LPCWSTR cond
= NULL
;
2734 LPCWSTR message
= NULL
;
2737 static const WCHAR title
[]=
2738 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2740 cond
= MSI_RecordGetString(row
,1);
2742 r
= MSI_EvaluateConditionW(package
,cond
);
2743 if (r
== MSICONDITION_FALSE
)
2745 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2748 message
= MSI_RecordGetString(row
,2);
2749 deformat_string(package
,message
,&deformated
);
2750 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2751 msi_free(deformated
);
2754 return ERROR_INSTALL_FAILURE
;
2757 return ERROR_SUCCESS
;
2760 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2763 MSIQUERY
* view
= NULL
;
2764 static const WCHAR ExecSeqQuery
[] =
2765 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2766 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2768 TRACE("Checking launch conditions\n");
2770 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2771 if (rc
!= ERROR_SUCCESS
)
2772 return ERROR_SUCCESS
;
2774 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2775 msiobj_release(&view
->hdr
);
2780 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2784 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2786 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2788 MSIRECORD
* row
= 0;
2790 LPWSTR deformated
,buffer
,deformated_name
;
2792 static const WCHAR ExecSeqQuery
[] =
2793 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2794 '`','R','e','g','i','s','t','r','y','`',' ',
2795 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2796 ' ','=',' ' ,'\'','%','s','\'',0 };
2797 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2798 static const WCHAR fmt2
[]=
2799 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2801 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2805 root
= MSI_RecordGetInteger(row
,2);
2806 key
= MSI_RecordGetString(row
, 3);
2807 name
= MSI_RecordGetString(row
, 4);
2808 deformat_string(package
, key
, &deformated
);
2809 deformat_string(package
, name
, &deformated_name
);
2811 len
= strlenW(deformated
) + 6;
2812 if (deformated_name
)
2813 len
+=strlenW(deformated_name
);
2815 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2817 if (deformated_name
)
2818 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2820 sprintfW(buffer
,fmt
,root
,deformated
);
2822 msi_free(deformated
);
2823 msi_free(deformated_name
);
2824 msiobj_release(&row
->hdr
);
2828 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2830 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2835 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2838 return strdupW( file
->TargetPath
);
2843 static HKEY
openSharedDLLsKey(void)
2846 static const WCHAR path
[] =
2847 {'S','o','f','t','w','a','r','e','\\',
2848 'M','i','c','r','o','s','o','f','t','\\',
2849 'W','i','n','d','o','w','s','\\',
2850 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2851 'S','h','a','r','e','d','D','L','L','s',0};
2853 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2857 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2862 DWORD sz
= sizeof(count
);
2865 hkey
= openSharedDLLsKey();
2866 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2867 if (rc
!= ERROR_SUCCESS
)
2873 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2877 hkey
= openSharedDLLsKey();
2879 msi_reg_set_val_dword( hkey
, path
, count
);
2881 RegDeleteValueW(hkey
,path
);
2887 * Return TRUE if the count should be written out and FALSE if not
2889 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2891 MSIFEATURE
*feature
;
2895 /* only refcount DLLs */
2896 if (comp
->KeyPath
== NULL
||
2897 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2898 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2902 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2903 write
= (count
> 0);
2905 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2909 /* increment counts */
2910 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2914 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2917 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2919 if ( cl
->component
== comp
)
2924 /* decrement counts */
2925 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2929 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2932 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2934 if ( cl
->component
== comp
)
2939 /* ref count all the files in the component */
2944 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2946 if (file
->Component
== comp
)
2947 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2951 /* add a count for permanent */
2952 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2955 comp
->RefCount
= count
;
2958 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2961 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2963 WCHAR squished_pc
[GUID_SIZE
];
2964 WCHAR squished_cc
[GUID_SIZE
];
2971 squash_guid(package
->ProductCode
,squished_pc
);
2972 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2974 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2978 ui_progress(package
,2,0,0,0);
2979 if (!comp
->ComponentId
)
2982 squash_guid(comp
->ComponentId
,squished_cc
);
2984 msi_free(comp
->FullKeypath
);
2985 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2987 ACTION_RefCountComponent( package
, comp
);
2989 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2990 debugstr_w(comp
->Component
),
2991 debugstr_w(squished_cc
),
2992 debugstr_w(comp
->FullKeypath
),
2995 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
||
2996 comp
->ActionRequest
== INSTALLSTATE_SOURCE
)
2998 if (!comp
->FullKeypath
)
3001 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3002 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
3005 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
3008 if (rc
!= ERROR_SUCCESS
)
3011 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
3013 static const WCHAR szPermKey
[] =
3014 { '0','0','0','0','0','0','0','0','0','0','0','0',
3015 '0','0','0','0','0','0','0','0','0','0','0','0',
3016 '0','0','0','0','0','0','0','0',0 };
3018 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
3021 if (comp
->Action
== INSTALLSTATE_LOCAL
)
3022 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
3028 WCHAR source
[MAX_PATH
];
3029 WCHAR base
[MAX_PATH
];
3032 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
3033 static const WCHAR query
[] = {
3034 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3035 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3036 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3037 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3038 '`','D','i','s','k','I','d','`',0};
3040 file
= get_loaded_file(package
, comp
->KeyPath
);
3044 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
3045 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
3046 ptr2
= strrchrW(source
, '\\') + 1;
3047 msiobj_release(&row
->hdr
);
3049 lstrcpyW(base
, package
->PackagePath
);
3050 ptr
= strrchrW(base
, '\\');
3053 sourcepath
= resolve_file_source(package
, file
);
3054 ptr
= sourcepath
+ lstrlenW(base
);
3055 lstrcpyW(ptr2
, ptr
);
3056 msi_free(sourcepath
);
3058 msi_reg_set_val_str(hkey
, squished_pc
, source
);
3062 else if (comp
->ActionRequest
== INSTALLSTATE_ABSENT
)
3064 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3065 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
3067 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
3069 comp
->Action
= comp
->ActionRequest
;
3072 uirow
= MSI_CreateRecord(3);
3073 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
3074 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
3075 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
3076 ui_actiondata(package
,szProcessComponents
,uirow
);
3077 msiobj_release( &uirow
->hdr
);
3080 return ERROR_SUCCESS
;
3091 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
3092 LPWSTR lpszName
, LONG_PTR lParam
)
3095 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
3096 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
3100 if (!IS_INTRESOURCE(lpszName
))
3102 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
3106 sz
= strlenW(tl_struct
->source
)+4;
3107 sz
*= sizeof(WCHAR
);
3109 if ((INT_PTR
)lpszName
== 1)
3110 tl_struct
->path
= strdupW(tl_struct
->source
);
3113 tl_struct
->path
= msi_alloc(sz
);
3114 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
3117 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
3118 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
3121 msi_free(tl_struct
->path
);
3122 tl_struct
->path
= NULL
;
3127 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
3128 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
3130 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3134 msi_free(tl_struct
->path
);
3135 tl_struct
->path
= NULL
;
3137 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3138 ITypeLib_Release(tl_struct
->ptLib
);
3143 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3145 MSIPACKAGE
* package
= param
;
3149 typelib_struct tl_struct
;
3154 component
= MSI_RecordGetString(row
,3);
3155 comp
= get_loaded_component(package
,component
);
3157 return ERROR_SUCCESS
;
3159 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3161 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3162 comp
->Action
= comp
->Installed
;
3163 return ERROR_SUCCESS
;
3165 comp
->Action
= INSTALLSTATE_LOCAL
;
3167 file
= get_loaded_file( package
, comp
->KeyPath
);
3169 return ERROR_SUCCESS
;
3171 ui_actiondata( package
, szRegisterTypeLibraries
, row
);
3173 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3177 guid
= MSI_RecordGetString(row
,1);
3178 CLSIDFromString((LPCWSTR
)guid
, &tl_struct
.clsid
);
3179 tl_struct
.source
= strdupW( file
->TargetPath
);
3180 tl_struct
.path
= NULL
;
3182 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3183 (LONG_PTR
)&tl_struct
);
3191 helpid
= MSI_RecordGetString(row
,6);
3194 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3195 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3199 ERR("Failed to register type library %s\n",
3200 debugstr_w(tl_struct
.path
));
3202 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3204 ITypeLib_Release(tl_struct
.ptLib
);
3205 msi_free(tl_struct
.path
);
3208 ERR("Failed to load type library %s\n",
3209 debugstr_w(tl_struct
.source
));
3211 FreeLibrary(module
);
3212 msi_free(tl_struct
.source
);
3216 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3219 ERR("Failed to load type library: %08x\n", hr
);
3220 return ERROR_INSTALL_FAILURE
;
3223 ITypeLib_Release(tlib
);
3226 return ERROR_SUCCESS
;
3229 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3232 * OK this is a bit confusing.. I am given a _Component key and I believe
3233 * that the file that is being registered as a type library is the "key file
3234 * of that component" which I interpret to mean "The file in the KeyPath of
3239 static const WCHAR Query
[] =
3240 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3241 '`','T','y','p','e','L','i','b','`',0};
3243 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3244 if (rc
!= ERROR_SUCCESS
)
3245 return ERROR_SUCCESS
;
3247 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3248 msiobj_release(&view
->hdr
);
3252 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
3254 MSIPACKAGE
*package
= param
;
3255 LPCWSTR component
, guid
;
3263 component
= MSI_RecordGetString( row
, 3 );
3264 comp
= get_loaded_component( package
, component
);
3266 return ERROR_SUCCESS
;
3268 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3270 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3271 comp
->Action
= comp
->Installed
;
3272 return ERROR_SUCCESS
;
3274 comp
->Action
= INSTALLSTATE_ABSENT
;
3276 ui_actiondata( package
, szUnregisterTypeLibraries
, row
);
3278 guid
= MSI_RecordGetString( row
, 1 );
3279 CLSIDFromString( (LPCWSTR
)guid
, &libid
);
3280 version
= MSI_RecordGetInteger( row
, 4 );
3281 language
= MSI_RecordGetInteger( row
, 2 );
3284 syskind
= SYS_WIN64
;
3286 syskind
= SYS_WIN32
;
3289 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
3292 WARN("Failed to unregister typelib: %08x\n", hr
);
3295 return ERROR_SUCCESS
;
3298 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
3302 static const WCHAR query
[] =
3303 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3304 '`','T','y','p','e','L','i','b','`',0};
3306 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3307 if (rc
!= ERROR_SUCCESS
)
3308 return ERROR_SUCCESS
;
3310 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
3311 msiobj_release( &view
->hdr
);
3315 static WCHAR
*get_link_file( MSIPACKAGE
*package
, MSIRECORD
*row
)
3317 static const WCHAR szlnk
[] = {'.','l','n','k',0};
3318 LPCWSTR directory
, extension
;
3319 LPWSTR link_folder
, link_file
, filename
;
3321 directory
= MSI_RecordGetString( row
, 2 );
3322 link_folder
= resolve_folder( package
, directory
, FALSE
, FALSE
, TRUE
, NULL
);
3324 /* may be needed because of a bug somewhere else */
3325 create_full_pathW( link_folder
);
3327 filename
= msi_dup_record_field( row
, 3 );
3328 reduce_to_longfilename( filename
);
3330 extension
= strchrW( filename
, '.' );
3331 if (!extension
|| strcmpiW( extension
, szlnk
))
3333 int len
= strlenW( filename
);
3334 filename
= msi_realloc( filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
) );
3335 memcpy( filename
+ len
, szlnk
, sizeof(szlnk
) );
3337 link_file
= build_directory_name( 2, link_folder
, filename
);
3338 msi_free( link_folder
);
3339 msi_free( filename
);
3344 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3346 MSIPACKAGE
*package
= param
;
3347 LPWSTR link_file
, deformated
, path
;
3348 LPCWSTR component
, target
;
3350 IShellLinkW
*sl
= NULL
;
3351 IPersistFile
*pf
= NULL
;
3354 component
= MSI_RecordGetString(row
, 4);
3355 comp
= get_loaded_component(package
, component
);
3357 return ERROR_SUCCESS
;
3359 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3361 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3362 comp
->Action
= comp
->Installed
;
3363 return ERROR_SUCCESS
;
3365 comp
->Action
= INSTALLSTATE_LOCAL
;
3367 ui_actiondata(package
,szCreateShortcuts
,row
);
3369 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3370 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3374 ERR("CLSID_ShellLink not available\n");
3378 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3381 ERR("QueryInterface(IID_IPersistFile) failed\n");
3385 target
= MSI_RecordGetString(row
, 5);
3386 if (strchrW(target
, '['))
3388 deformat_string(package
, target
, &deformated
);
3389 IShellLinkW_SetPath(sl
,deformated
);
3390 msi_free(deformated
);
3394 FIXME("poorly handled shortcut format, advertised shortcut\n");
3395 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3398 if (!MSI_RecordIsNull(row
,6))
3400 LPCWSTR arguments
= MSI_RecordGetString(row
, 6);
3401 deformat_string(package
, arguments
, &deformated
);
3402 IShellLinkW_SetArguments(sl
,deformated
);
3403 msi_free(deformated
);
3406 if (!MSI_RecordIsNull(row
,7))
3408 LPCWSTR description
= MSI_RecordGetString(row
, 7);
3409 IShellLinkW_SetDescription(sl
, description
);
3412 if (!MSI_RecordIsNull(row
,8))
3413 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3415 if (!MSI_RecordIsNull(row
,9))
3418 LPCWSTR icon
= MSI_RecordGetString(row
, 9);
3420 path
= build_icon_path(package
, icon
);
3421 index
= MSI_RecordGetInteger(row
,10);
3423 /* no value means 0 */
3424 if (index
== MSI_NULL_INTEGER
)
3427 IShellLinkW_SetIconLocation(sl
, path
, index
);
3431 if (!MSI_RecordIsNull(row
,11))
3432 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3434 if (!MSI_RecordIsNull(row
,12))
3436 LPCWSTR wkdir
= MSI_RecordGetString(row
, 12);
3437 path
= resolve_folder(package
, wkdir
, FALSE
, FALSE
, TRUE
, NULL
);
3439 IShellLinkW_SetWorkingDirectory(sl
, path
);
3443 link_file
= get_link_file(package
, row
);
3445 TRACE("Writing shortcut to %s\n", debugstr_w(link_file
));
3446 IPersistFile_Save(pf
, link_file
, FALSE
);
3448 msi_free(link_file
);
3452 IPersistFile_Release( pf
);
3454 IShellLinkW_Release( sl
);
3456 return ERROR_SUCCESS
;
3459 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3464 static const WCHAR Query
[] =
3465 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3466 '`','S','h','o','r','t','c','u','t','`',0};
3468 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3469 if (rc
!= ERROR_SUCCESS
)
3470 return ERROR_SUCCESS
;
3472 res
= CoInitialize( NULL
);
3474 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3475 msiobj_release(&view
->hdr
);
3483 static UINT
ITERATE_RemoveShortcuts( MSIRECORD
*row
, LPVOID param
)
3485 MSIPACKAGE
*package
= param
;
3490 component
= MSI_RecordGetString( row
, 4 );
3491 comp
= get_loaded_component( package
, component
);
3493 return ERROR_SUCCESS
;
3495 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3497 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3498 comp
->Action
= comp
->Installed
;
3499 return ERROR_SUCCESS
;
3501 comp
->Action
= INSTALLSTATE_ABSENT
;
3503 ui_actiondata( package
, szRemoveShortcuts
, row
);
3505 link_file
= get_link_file( package
, row
);
3507 TRACE("Removing shortcut file %s\n", debugstr_w( link_file
));
3508 if (!DeleteFileW( link_file
))
3510 WARN("Failed to remove shortcut file %u\n", GetLastError());
3512 msi_free( link_file
);
3514 return ERROR_SUCCESS
;
3517 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
3521 static const WCHAR query
[] =
3522 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3523 '`','S','h','o','r','t','c','u','t','`',0};
3525 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3526 if (rc
!= ERROR_SUCCESS
)
3527 return ERROR_SUCCESS
;
3529 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveShortcuts
, package
);
3530 msiobj_release( &view
->hdr
);
3535 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3537 MSIPACKAGE
* package
= param
;
3545 FileName
= MSI_RecordGetString(row
,1);
3548 ERR("Unable to get FileName\n");
3549 return ERROR_SUCCESS
;
3552 FilePath
= build_icon_path(package
,FileName
);
3554 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3556 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3557 FILE_ATTRIBUTE_NORMAL
, NULL
);
3559 if (the_file
== INVALID_HANDLE_VALUE
)
3561 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3563 return ERROR_SUCCESS
;
3570 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3571 if (rc
!= ERROR_SUCCESS
)
3573 ERR("Failed to get stream\n");
3574 CloseHandle(the_file
);
3575 DeleteFileW(FilePath
);
3578 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3579 } while (sz
== 1024);
3582 CloseHandle(the_file
);
3584 return ERROR_SUCCESS
;
3587 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3592 static const WCHAR query
[]= {
3593 'S','E','L','E','C','T',' ','*',' ',
3594 'F','R','O','M',' ','`','I','c','o','n','`',0};
3596 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3597 if (r
== ERROR_SUCCESS
)
3599 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3600 msiobj_release(&view
->hdr
);
3603 return ERROR_SUCCESS
;
3606 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3612 MSISOURCELISTINFO
*info
;
3614 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3615 if (r
!= ERROR_SUCCESS
)
3618 RegCloseKey(source
);
3620 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3621 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3622 package
->Context
, MSICODE_PRODUCT
,
3623 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3624 if (r
!= ERROR_SUCCESS
)
3627 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3628 package
->Context
, MSICODE_PRODUCT
,
3629 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3630 if (r
!= ERROR_SUCCESS
)
3633 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3634 package
->Context
, MSICODE_PRODUCT
,
3635 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3636 if (r
!= ERROR_SUCCESS
)
3639 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3641 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3642 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3643 info
->options
, info
->value
);
3645 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3646 info
->context
, info
->options
,
3647 info
->property
, info
->value
);
3650 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3652 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3653 disk
->context
, disk
->options
,
3654 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3657 return ERROR_SUCCESS
;
3660 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3662 MSIHANDLE hdb
, suminfo
;
3663 WCHAR guids
[MAX_PATH
];
3664 WCHAR packcode
[SQUISH_GUID_SIZE
];
3671 static const WCHAR szProductLanguage
[] =
3672 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3673 static const WCHAR szARPProductIcon
[] =
3674 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3675 static const WCHAR szProductVersion
[] =
3676 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3677 static const WCHAR szAssignment
[] =
3678 {'A','s','s','i','g','n','m','e','n','t',0};
3679 static const WCHAR szAdvertiseFlags
[] =
3680 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3681 static const WCHAR szClients
[] =
3682 {'C','l','i','e','n','t','s',0};
3683 static const WCHAR szColon
[] = {':',0};
3685 buffer
= msi_dup_property(package
->db
, INSTALLPROPERTY_PRODUCTNAMEW
);
3686 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3689 langid
= msi_get_property_int(package
->db
, szProductLanguage
, 0);
3690 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3693 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3695 buffer
= msi_dup_property(package
->db
, szARPProductIcon
);
3698 LPWSTR path
= build_icon_path(package
,buffer
);
3699 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3704 buffer
= msi_dup_property(package
->db
, szProductVersion
);
3707 DWORD verdword
= msi_version_str_to_dword(buffer
);
3708 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3712 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3713 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3714 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3715 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3717 hdb
= alloc_msihandle(&package
->db
->hdr
);
3719 return ERROR_NOT_ENOUGH_MEMORY
;
3721 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3722 MsiCloseHandle(hdb
);
3723 if (r
!= ERROR_SUCCESS
)
3727 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3728 NULL
, guids
, &size
);
3729 if (r
!= ERROR_SUCCESS
)
3732 ptr
= strchrW(guids
, ';');
3734 squash_guid(guids
, packcode
);
3735 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3738 MsiCloseHandle(suminfo
);
3739 return ERROR_SUCCESS
;
3742 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3747 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3749 static const WCHAR szUpgradeCode
[] =
3750 {'U','p','g','r','a','d','e','C','o','d','e',0};
3752 upgrade
= msi_dup_property(package
->db
, szUpgradeCode
);
3754 return ERROR_SUCCESS
;
3756 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3758 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3759 if (r
!= ERROR_SUCCESS
)
3764 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3765 if (r
!= ERROR_SUCCESS
)
3769 squash_guid(package
->ProductCode
, squashed_pc
);
3770 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3779 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3781 MSIFEATURE
*feature
;
3783 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3785 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3792 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3794 MSIFEATURE
*feature
;
3796 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3798 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3805 static UINT
msi_publish_patches( MSIPACKAGE
*package
, HKEY prodkey
)
3807 static const WCHAR szAllPatches
[] = {'A','l','l','P','a','t','c','h','e','s',0};
3808 WCHAR patch_squashed
[GUID_SIZE
];
3809 HKEY patches_key
= NULL
, product_patches_key
;
3811 MSIPATCHINFO
*patch
;
3813 WCHAR
*p
, *all_patches
= NULL
;
3816 res
= RegCreateKeyExW( prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &patches_key
, NULL
);
3817 if (res
!= ERROR_SUCCESS
)
3818 return ERROR_FUNCTION_FAILED
;
3820 r
= MSIREG_OpenUserDataProductPatchesKey( package
->ProductCode
, package
->Context
, &product_patches_key
, TRUE
);
3821 if (r
!= ERROR_SUCCESS
)
3824 LIST_FOR_EACH_ENTRY( patch
, &package
->patches
, MSIPATCHINFO
, entry
)
3826 squash_guid( patch
->patchcode
, patch_squashed
);
3827 len
+= strlenW( patch_squashed
) + 1;
3830 p
= all_patches
= msi_alloc( (len
+ 1) * sizeof(WCHAR
) );
3834 LIST_FOR_EACH_ENTRY( patch
, &package
->patches
, MSIPATCHINFO
, entry
)
3838 squash_guid( patch
->patchcode
, p
);
3839 p
+= strlenW( p
) + 1;
3841 res
= RegSetValueExW( patches_key
, patch_squashed
, 0, REG_SZ
,
3842 (const BYTE
*)patch
->transforms
,
3843 (strlenW(patch
->transforms
) + 1) * sizeof(WCHAR
) );
3844 if (res
!= ERROR_SUCCESS
)
3847 r
= MSIREG_OpenUserDataPatchKey( patch
->patchcode
, package
->Context
, &patch_key
, TRUE
);
3848 if (r
!= ERROR_SUCCESS
)
3851 res
= RegSetValueExW( patch_key
, szLocalPackage
, 0, REG_SZ
,
3852 (const BYTE
*)patch
->localfile
,
3853 (strlenW(patch
->localfile
) + 1) * sizeof(WCHAR
) );
3854 RegCloseKey( patch_key
);
3855 if (res
!= ERROR_SUCCESS
)
3858 res
= RegCreateKeyExW( product_patches_key
, patch_squashed
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &patch_key
, NULL
);
3859 RegCloseKey( patch_key
);
3860 if (res
!= ERROR_SUCCESS
)
3864 all_patches
[len
] = 0;
3865 res
= RegSetValueExW( patches_key
, szPatches
, 0, REG_MULTI_SZ
,
3866 (const BYTE
*)all_patches
, (len
+ 1) * sizeof(WCHAR
) );
3867 if (res
!= ERROR_SUCCESS
)
3870 res
= RegSetValueExW( product_patches_key
, szAllPatches
, 0, REG_MULTI_SZ
,
3871 (const BYTE
*)all_patches
, (len
+ 1) * sizeof(WCHAR
) );
3872 if (res
!= ERROR_SUCCESS
)
3873 r
= ERROR_FUNCTION_FAILED
;
3876 RegCloseKey( product_patches_key
);
3877 RegCloseKey( patches_key
);
3878 msi_free( all_patches
);
3883 * 99% of the work done here is only done for
3884 * advertised installs. However this is where the
3885 * Icon table is processed and written out
3886 * so that is what I am going to do here.
3888 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3891 HKEY hukey
= NULL
, hudkey
= NULL
;
3894 /* FIXME: also need to publish if the product is in advertise mode */
3895 if (!msi_check_publish(package
))
3896 return ERROR_SUCCESS
;
3898 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3900 if (rc
!= ERROR_SUCCESS
)
3903 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3904 NULL
, &hudkey
, TRUE
);
3905 if (rc
!= ERROR_SUCCESS
)
3908 rc
= msi_publish_upgrade_code(package
);
3909 if (rc
!= ERROR_SUCCESS
)
3912 if (!list_empty(&package
->patches
))
3914 rc
= msi_publish_patches(package
, hukey
);
3915 if (rc
!= ERROR_SUCCESS
)
3919 rc
= msi_publish_product_properties(package
, hukey
);
3920 if (rc
!= ERROR_SUCCESS
)
3923 rc
= msi_publish_sourcelist(package
, hukey
);
3924 if (rc
!= ERROR_SUCCESS
)
3927 rc
= msi_publish_icons(package
);
3930 uirow
= MSI_CreateRecord( 1 );
3931 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
3932 ui_actiondata( package
, szPublishProduct
, uirow
);
3933 msiobj_release( &uirow
->hdr
);
3936 RegCloseKey(hudkey
);
3941 static WCHAR
*get_ini_file_name( MSIPACKAGE
*package
, MSIRECORD
*row
)
3943 WCHAR
*filename
, *ptr
, *folder
, *ret
;
3944 const WCHAR
*dirprop
;
3946 filename
= msi_dup_record_field( row
, 2 );
3947 if (filename
&& (ptr
= strchrW( filename
, '|' )))
3952 dirprop
= MSI_RecordGetString( row
, 3 );
3955 folder
= resolve_folder( package
, dirprop
, FALSE
, FALSE
, TRUE
, NULL
);
3957 folder
= msi_dup_property( package
->db
, dirprop
);
3960 folder
= msi_dup_property( package
->db
, szWindowsFolder
);
3964 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop
));
3965 msi_free( filename
);
3969 ret
= build_directory_name( 2, folder
, ptr
);
3971 msi_free( filename
);
3976 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3978 MSIPACKAGE
*package
= param
;
3979 LPCWSTR component
, section
, key
, value
, identifier
;
3980 LPWSTR deformated_section
, deformated_key
, deformated_value
, fullname
;
3985 component
= MSI_RecordGetString(row
, 8);
3986 comp
= get_loaded_component(package
,component
);
3988 return ERROR_SUCCESS
;
3990 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3992 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3993 comp
->Action
= comp
->Installed
;
3994 return ERROR_SUCCESS
;
3996 comp
->Action
= INSTALLSTATE_LOCAL
;
3998 identifier
= MSI_RecordGetString(row
,1);
3999 section
= MSI_RecordGetString(row
,4);
4000 key
= MSI_RecordGetString(row
,5);
4001 value
= MSI_RecordGetString(row
,6);
4002 action
= MSI_RecordGetInteger(row
,7);
4004 deformat_string(package
,section
,&deformated_section
);
4005 deformat_string(package
,key
,&deformated_key
);
4006 deformat_string(package
,value
,&deformated_value
);
4008 fullname
= get_ini_file_name(package
, row
);
4012 TRACE("Adding value %s to section %s in %s\n",
4013 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4014 debugstr_w(fullname
));
4015 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4016 deformated_value
, fullname
);
4018 else if (action
== 1)
4021 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
4022 returned
, 10, fullname
);
4023 if (returned
[0] == 0)
4025 TRACE("Adding value %s to section %s in %s\n",
4026 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4027 debugstr_w(fullname
));
4029 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4030 deformated_value
, fullname
);
4033 else if (action
== 3)
4034 FIXME("Append to existing section not yet implemented\n");
4036 uirow
= MSI_CreateRecord(4);
4037 MSI_RecordSetStringW(uirow
,1,identifier
);
4038 MSI_RecordSetStringW(uirow
,2,deformated_section
);
4039 MSI_RecordSetStringW(uirow
,3,deformated_key
);
4040 MSI_RecordSetStringW(uirow
,4,deformated_value
);
4041 ui_actiondata(package
,szWriteIniValues
,uirow
);
4042 msiobj_release( &uirow
->hdr
);
4045 msi_free(deformated_key
);
4046 msi_free(deformated_value
);
4047 msi_free(deformated_section
);
4048 return ERROR_SUCCESS
;
4051 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
4055 static const WCHAR ExecSeqQuery
[] =
4056 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4057 '`','I','n','i','F','i','l','e','`',0};
4059 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4060 if (rc
!= ERROR_SUCCESS
)
4062 TRACE("no IniFile table\n");
4063 return ERROR_SUCCESS
;
4066 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
4067 msiobj_release(&view
->hdr
);
4071 static UINT
ITERATE_RemoveIniValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
4073 MSIPACKAGE
*package
= param
;
4074 LPCWSTR component
, section
, key
, value
, identifier
;
4075 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
4080 component
= MSI_RecordGetString( row
, 8 );
4081 comp
= get_loaded_component( package
, component
);
4083 return ERROR_SUCCESS
;
4085 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4087 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
4088 comp
->Action
= comp
->Installed
;
4089 return ERROR_SUCCESS
;
4091 comp
->Action
= INSTALLSTATE_ABSENT
;
4093 identifier
= MSI_RecordGetString( row
, 1 );
4094 section
= MSI_RecordGetString( row
, 4 );
4095 key
= MSI_RecordGetString( row
, 5 );
4096 value
= MSI_RecordGetString( row
, 6 );
4097 action
= MSI_RecordGetInteger( row
, 7 );
4099 deformat_string( package
, section
, &deformated_section
);
4100 deformat_string( package
, key
, &deformated_key
);
4101 deformat_string( package
, value
, &deformated_value
);
4103 if (action
== msidbIniFileActionAddLine
|| action
== msidbIniFileActionCreateLine
)
4105 filename
= get_ini_file_name( package
, row
);
4107 TRACE("Removing key %s from section %s in %s\n",
4108 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
4110 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
4112 WARN("Unable to remove key %u\n", GetLastError());
4114 msi_free( filename
);
4117 FIXME("Unsupported action %d\n", action
);
4120 uirow
= MSI_CreateRecord( 4 );
4121 MSI_RecordSetStringW( uirow
, 1, identifier
);
4122 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4123 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4124 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4125 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4126 msiobj_release( &uirow
->hdr
);
4128 msi_free( deformated_key
);
4129 msi_free( deformated_value
);
4130 msi_free( deformated_section
);
4131 return ERROR_SUCCESS
;
4134 static UINT
ITERATE_RemoveIniValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
4136 MSIPACKAGE
*package
= param
;
4137 LPCWSTR component
, section
, key
, value
, identifier
;
4138 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
4143 component
= MSI_RecordGetString( row
, 8 );
4144 comp
= get_loaded_component( package
, component
);
4146 return ERROR_SUCCESS
;
4148 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4150 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
4151 comp
->Action
= comp
->Installed
;
4152 return ERROR_SUCCESS
;
4154 comp
->Action
= INSTALLSTATE_LOCAL
;
4156 identifier
= MSI_RecordGetString( row
, 1 );
4157 section
= MSI_RecordGetString( row
, 4 );
4158 key
= MSI_RecordGetString( row
, 5 );
4159 value
= MSI_RecordGetString( row
, 6 );
4160 action
= MSI_RecordGetInteger( row
, 7 );
4162 deformat_string( package
, section
, &deformated_section
);
4163 deformat_string( package
, key
, &deformated_key
);
4164 deformat_string( package
, value
, &deformated_value
);
4166 if (action
== msidbIniFileActionRemoveLine
)
4168 filename
= get_ini_file_name( package
, row
);
4170 TRACE("Removing key %s from section %s in %s\n",
4171 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
4173 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
4175 WARN("Unable to remove key %u\n", GetLastError());
4177 msi_free( filename
);
4180 FIXME("Unsupported action %d\n", action
);
4182 uirow
= MSI_CreateRecord( 4 );
4183 MSI_RecordSetStringW( uirow
, 1, identifier
);
4184 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4185 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4186 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4187 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4188 msiobj_release( &uirow
->hdr
);
4190 msi_free( deformated_key
);
4191 msi_free( deformated_value
);
4192 msi_free( deformated_section
);
4193 return ERROR_SUCCESS
;
4196 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4200 static const WCHAR query
[] =
4201 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4202 '`','I','n','i','F','i','l','e','`',0};
4203 static const WCHAR remove_query
[] =
4204 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4205 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4207 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4208 if (rc
== ERROR_SUCCESS
)
4210 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnUninstall
, package
);
4211 msiobj_release( &view
->hdr
);
4212 if (rc
!= ERROR_SUCCESS
)
4216 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_query
, &view
);
4217 if (rc
== ERROR_SUCCESS
)
4219 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnInstall
, package
);
4220 msiobj_release( &view
->hdr
);
4221 if (rc
!= ERROR_SUCCESS
)
4225 return ERROR_SUCCESS
;
4228 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
4230 MSIPACKAGE
*package
= param
;
4235 static const WCHAR ExeStr
[] =
4236 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4237 static const WCHAR close
[] = {'\"',0};
4239 PROCESS_INFORMATION info
;
4244 memset(&si
,0,sizeof(STARTUPINFOW
));
4246 filename
= MSI_RecordGetString(row
,1);
4247 file
= get_loaded_file( package
, filename
);
4251 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4252 return ERROR_SUCCESS
;
4255 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
4257 FullName
= msi_alloc(len
*sizeof(WCHAR
));
4258 strcpyW(FullName
,ExeStr
);
4259 strcatW( FullName
, file
->TargetPath
);
4260 strcatW(FullName
,close
);
4262 TRACE("Registering %s\n",debugstr_w(FullName
));
4263 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
4268 CloseHandle(info
.hThread
);
4269 msi_dialog_check_messages(info
.hProcess
);
4270 CloseHandle(info
.hProcess
);
4273 uirow
= MSI_CreateRecord( 2 );
4274 MSI_RecordSetStringW( uirow
, 1, filename
);
4275 uipath
= strdupW( file
->TargetPath
);
4276 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4277 MSI_RecordSetStringW( uirow
, 2, uipath
);
4278 ui_actiondata( package
, szSelfRegModules
, uirow
);
4279 msiobj_release( &uirow
->hdr
);
4281 msi_free( FullName
);
4283 return ERROR_SUCCESS
;
4286 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4290 static const WCHAR ExecSeqQuery
[] =
4291 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4292 '`','S','e','l','f','R','e','g','`',0};
4294 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4295 if (rc
!= ERROR_SUCCESS
)
4297 TRACE("no SelfReg table\n");
4298 return ERROR_SUCCESS
;
4301 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
4302 msiobj_release(&view
->hdr
);
4304 return ERROR_SUCCESS
;
4307 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
4309 static const WCHAR regsvr32
[] =
4310 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4311 static const WCHAR close
[] = {'\"',0};
4312 MSIPACKAGE
*package
= param
;
4318 PROCESS_INFORMATION pi
;
4323 memset( &si
, 0, sizeof(STARTUPINFOW
) );
4325 filename
= MSI_RecordGetString( row
, 1 );
4326 file
= get_loaded_file( package
, filename
);
4330 ERR("Unable to find file id %s\n", debugstr_w(filename
));
4331 return ERROR_SUCCESS
;
4334 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
4336 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
4337 strcpyW( cmdline
, regsvr32
);
4338 strcatW( cmdline
, file
->TargetPath
);
4339 strcatW( cmdline
, close
);
4341 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
4343 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
4346 CloseHandle( pi
.hThread
);
4347 msi_dialog_check_messages( pi
.hProcess
);
4348 CloseHandle( pi
.hProcess
);
4351 uirow
= MSI_CreateRecord( 2 );
4352 MSI_RecordSetStringW( uirow
, 1, filename
);
4353 uipath
= strdupW( file
->TargetPath
);
4354 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4355 MSI_RecordSetStringW( uirow
, 2, uipath
);
4356 ui_actiondata( package
, szSelfUnregModules
, uirow
);
4357 msiobj_release( &uirow
->hdr
);
4359 msi_free( cmdline
);
4361 return ERROR_SUCCESS
;
4364 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4368 static const WCHAR query
[] =
4369 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4370 '`','S','e','l','f','R','e','g','`',0};
4372 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4373 if (rc
!= ERROR_SUCCESS
)
4375 TRACE("no SelfReg table\n");
4376 return ERROR_SUCCESS
;
4379 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
4380 msiobj_release( &view
->hdr
);
4382 return ERROR_SUCCESS
;
4385 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4387 MSIFEATURE
*feature
;
4389 HKEY hkey
= NULL
, userdata
= NULL
;
4391 if (!msi_check_publish(package
))
4392 return ERROR_SUCCESS
;
4394 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4396 if (rc
!= ERROR_SUCCESS
)
4399 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4401 if (rc
!= ERROR_SUCCESS
)
4404 /* here the guids are base 85 encoded */
4405 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
4411 BOOL absent
= FALSE
;
4414 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4415 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4416 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
4419 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4423 if (feature
->Feature_Parent
)
4424 size
+= strlenW( feature
->Feature_Parent
)+2;
4426 data
= msi_alloc(size
* sizeof(WCHAR
));
4429 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4431 MSICOMPONENT
* component
= cl
->component
;
4435 if (component
->ComponentId
)
4437 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4438 CLSIDFromString(component
->ComponentId
, &clsid
);
4439 encode_base85_guid(&clsid
,buf
);
4440 TRACE("to %s\n",debugstr_w(buf
));
4445 if (feature
->Feature_Parent
)
4447 static const WCHAR sep
[] = {'\2',0};
4449 strcatW(data
,feature
->Feature_Parent
);
4452 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4456 if (feature
->Feature_Parent
)
4457 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4460 size
+= sizeof(WCHAR
);
4461 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4462 (const BYTE
*)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
4466 size
+= 2*sizeof(WCHAR
);
4467 data
= msi_alloc(size
);
4470 if (feature
->Feature_Parent
)
4471 strcpyW( &data
[1], feature
->Feature_Parent
);
4472 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4478 uirow
= MSI_CreateRecord( 1 );
4479 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4480 ui_actiondata( package
, szPublishFeatures
, uirow
);
4481 msiobj_release( &uirow
->hdr
);
4482 /* FIXME: call ui_progress? */
4487 RegCloseKey(userdata
);
4491 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4497 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4499 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4501 if (r
== ERROR_SUCCESS
)
4503 RegDeleteValueW(hkey
, feature
->Feature
);
4507 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4509 if (r
== ERROR_SUCCESS
)
4511 RegDeleteValueW(hkey
, feature
->Feature
);
4515 uirow
= MSI_CreateRecord( 1 );
4516 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4517 ui_actiondata( package
, szUnpublishFeatures
, uirow
);
4518 msiobj_release( &uirow
->hdr
);
4520 return ERROR_SUCCESS
;
4523 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4525 MSIFEATURE
*feature
;
4527 if (!msi_check_unpublish(package
))
4528 return ERROR_SUCCESS
;
4530 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4532 msi_unpublish_feature(package
, feature
);
4535 return ERROR_SUCCESS
;
4538 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4540 LPWSTR prop
, val
, key
;
4546 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4547 static const WCHAR szWindowsInstaller
[] =
4548 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4549 static const WCHAR modpath_fmt
[] =
4550 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4551 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4552 static const WCHAR szModifyPath
[] =
4553 {'M','o','d','i','f','y','P','a','t','h',0};
4554 static const WCHAR szUninstallString
[] =
4555 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4556 static const WCHAR szEstimatedSize
[] =
4557 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4558 static const WCHAR szProductLanguage
[] =
4559 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4560 static const WCHAR szProductVersion
[] =
4561 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4562 static const WCHAR szProductName
[] =
4563 {'P','r','o','d','u','c','t','N','a','m','e',0};
4564 static const WCHAR szDisplayName
[] =
4565 {'D','i','s','p','l','a','y','N','a','m','e',0};
4566 static const WCHAR szDisplayVersion
[] =
4567 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4568 static const WCHAR szManufacturer
[] =
4569 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4571 static const LPCSTR propval
[] = {
4572 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4573 "ARPCONTACT", "Contact",
4574 "ARPCOMMENTS", "Comments",
4575 "ProductName", "DisplayName",
4576 "ProductVersion", "DisplayVersion",
4577 "ARPHELPLINK", "HelpLink",
4578 "ARPHELPTELEPHONE", "HelpTelephone",
4579 "ARPINSTALLLOCATION", "InstallLocation",
4580 "SourceDir", "InstallSource",
4581 "Manufacturer", "Publisher",
4582 "ARPREADME", "Readme",
4584 "ARPURLINFOABOUT", "URLInfoAbout",
4585 "ARPURLUPDATEINFO", "URLUpdateInfo",
4588 const LPCSTR
*p
= propval
;
4592 prop
= strdupAtoW(*p
++);
4593 key
= strdupAtoW(*p
++);
4594 val
= msi_dup_property(package
->db
, prop
);
4595 msi_reg_set_val_str(hkey
, key
, val
);
4601 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4603 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4604 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4605 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4608 /* FIXME: Write real Estimated Size when we have it */
4609 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4611 buffer
= msi_dup_property(package
->db
, szProductName
);
4612 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4615 buffer
= msi_dup_property(package
->db
, cszSourceDir
);
4616 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4619 buffer
= msi_dup_property(package
->db
, szManufacturer
);
4620 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4623 GetLocalTime(&systime
);
4624 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4625 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4627 langid
= msi_get_property_int(package
->db
, szProductLanguage
, 0);
4628 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4630 buffer
= msi_dup_property(package
->db
, szProductVersion
);
4631 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4634 DWORD verdword
= msi_version_str_to_dword(buffer
);
4636 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4637 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4638 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4642 return ERROR_SUCCESS
;
4645 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4647 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4649 LPWSTR upgrade_code
;
4654 static const WCHAR szUpgradeCode
[] = {
4655 'U','p','g','r','a','d','e','C','o','d','e',0};
4657 /* FIXME: also need to publish if the product is in advertise mode */
4658 if (!msi_check_publish(package
))
4659 return ERROR_SUCCESS
;
4661 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4662 if (rc
!= ERROR_SUCCESS
)
4665 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4666 NULL
, &props
, TRUE
);
4667 if (rc
!= ERROR_SUCCESS
)
4670 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4671 msi_free( package
->db
->localfile
);
4672 package
->db
->localfile
= NULL
;
4674 rc
= msi_publish_install_properties(package
, hkey
);
4675 if (rc
!= ERROR_SUCCESS
)
4678 rc
= msi_publish_install_properties(package
, props
);
4679 if (rc
!= ERROR_SUCCESS
)
4682 upgrade_code
= msi_dup_property(package
->db
, szUpgradeCode
);
4685 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4686 squash_guid(package
->ProductCode
, squashed_pc
);
4687 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4688 RegCloseKey(upgrade
);
4689 msi_free(upgrade_code
);
4693 uirow
= MSI_CreateRecord( 1 );
4694 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4695 ui_actiondata( package
, szRegisterProduct
, uirow
);
4696 msiobj_release( &uirow
->hdr
);
4699 return ERROR_SUCCESS
;
4702 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4704 return execute_script(package
,INSTALL_SCRIPT
);
4707 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4710 LPWSTR remove
= NULL
;
4711 LPWSTR
*features
= NULL
;
4712 BOOL full_uninstall
= TRUE
;
4713 MSIFEATURE
*feature
;
4714 MSIPATCHINFO
*patch
;
4716 static const WCHAR szUpgradeCode
[] =
4717 {'U','p','g','r','a','d','e','C','o','d','e',0};
4719 remove
= msi_dup_property(package
->db
, szRemove
);
4721 return ERROR_SUCCESS
;
4723 features
= msi_split_string(remove
, ',');
4727 ERR("REMOVE feature list is empty!\n");
4728 return ERROR_FUNCTION_FAILED
;
4731 if (!lstrcmpW(features
[0], szAll
))
4732 full_uninstall
= TRUE
;
4735 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4737 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4738 full_uninstall
= FALSE
;
4742 if (!full_uninstall
)
4745 MSIREG_DeleteProductKey(package
->ProductCode
);
4746 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4747 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4749 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4751 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4752 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4756 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4757 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4760 upgrade
= msi_dup_property(package
->db
, szUpgradeCode
);
4763 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4767 LIST_FOR_EACH_ENTRY(patch
, &package
->patches
, MSIPATCHINFO
, entry
)
4769 MSIREG_DeleteUserDataPatchKey(patch
->patchcode
, package
->Context
);
4775 return ERROR_SUCCESS
;
4778 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4782 rc
= msi_unpublish_product(package
);
4783 if (rc
!= ERROR_SUCCESS
)
4786 /* turn off scheduling */
4787 package
->script
->CurrentlyScripting
= FALSE
;
4789 /* first do the same as an InstallExecute */
4790 rc
= ACTION_InstallExecute(package
);
4791 if (rc
!= ERROR_SUCCESS
)
4794 /* then handle Commit Actions */
4795 rc
= execute_script(package
,COMMIT_SCRIPT
);
4800 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4802 static const WCHAR RunOnce
[] = {
4803 'S','o','f','t','w','a','r','e','\\',
4804 'M','i','c','r','o','s','o','f','t','\\',
4805 'W','i','n','d','o','w','s','\\',
4806 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4807 'R','u','n','O','n','c','e',0};
4808 static const WCHAR InstallRunOnce
[] = {
4809 'S','o','f','t','w','a','r','e','\\',
4810 'M','i','c','r','o','s','o','f','t','\\',
4811 'W','i','n','d','o','w','s','\\',
4812 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4813 'I','n','s','t','a','l','l','e','r','\\',
4814 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4816 static const WCHAR msiexec_fmt
[] = {
4818 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4819 '\"','%','s','\"',0};
4820 static const WCHAR install_fmt
[] = {
4821 '/','I',' ','\"','%','s','\"',' ',
4822 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4823 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4824 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4826 WCHAR squished_pc
[100];
4828 squash_guid(package
->ProductCode
,squished_pc
);
4830 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4831 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4832 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4835 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4838 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4840 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4841 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4843 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4846 return ERROR_INSTALL_SUSPEND
;
4849 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4855 * We are currently doing what should be done here in the top level Install
4856 * however for Administrative and uninstalls this step will be needed
4858 if (!package
->PackagePath
)
4859 return ERROR_SUCCESS
;
4861 msi_set_sourcedir_props(package
, TRUE
);
4863 attrib
= GetFileAttributesW(package
->db
->path
);
4864 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4870 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4871 package
->Context
, MSICODE_PRODUCT
,
4872 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4873 if (rc
== ERROR_MORE_DATA
)
4875 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4876 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4877 package
->Context
, MSICODE_PRODUCT
,
4878 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4881 prompt
= strdupW(package
->db
->path
);
4883 msg
= generate_error_string(package
,1302,1,prompt
);
4884 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4886 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4889 rc
= ERROR_INSTALL_USEREXIT
;
4892 attrib
= GetFileAttributesW(package
->db
->path
);
4898 return ERROR_SUCCESS
;
4903 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4906 LPWSTR buffer
, productid
= NULL
;
4907 UINT i
, rc
= ERROR_SUCCESS
;
4910 static const WCHAR szPropKeys
[][80] =
4912 {'P','r','o','d','u','c','t','I','D',0},
4913 {'U','S','E','R','N','A','M','E',0},
4914 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4918 static const WCHAR szRegKeys
[][80] =
4920 {'P','r','o','d','u','c','t','I','D',0},
4921 {'R','e','g','O','w','n','e','r',0},
4922 {'R','e','g','C','o','m','p','a','n','y',0},
4926 if (msi_check_unpublish(package
))
4928 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4932 productid
= msi_dup_property( package
->db
, INSTALLPROPERTY_PRODUCTIDW
);
4936 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4938 if (rc
!= ERROR_SUCCESS
)
4941 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4943 buffer
= msi_dup_property( package
->db
, szPropKeys
[i
] );
4944 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4949 uirow
= MSI_CreateRecord( 1 );
4950 MSI_RecordSetStringW( uirow
, 1, productid
);
4951 ui_actiondata( package
, szRegisterUser
, uirow
);
4952 msiobj_release( &uirow
->hdr
);
4954 msi_free(productid
);
4960 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4964 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4965 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4970 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4972 MSIPACKAGE
*package
= param
;
4973 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
4974 LPWSTR advertise
= NULL
, output
= NULL
;
4982 feature
= MSI_RecordGetString(rec
, 5);
4983 feat
= get_loaded_feature(package
, feature
);
4985 return ERROR_SUCCESS
;
4987 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4988 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4989 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
4991 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
4992 feat
->Action
= feat
->Installed
;
4993 return ERROR_SUCCESS
;
4996 component
= MSI_RecordGetString(rec
, 3);
4997 comp
= get_loaded_component(package
, component
);
4999 return ERROR_SUCCESS
;
5001 compgroupid
= MSI_RecordGetString(rec
,1);
5002 qualifier
= MSI_RecordGetString(rec
,2);
5004 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
5005 if (rc
!= ERROR_SUCCESS
)
5008 text
= MSI_RecordGetString(rec
,4);
5009 advertise
= create_component_advertise_string(package
, comp
, feature
);
5011 sz
= strlenW(advertise
);
5014 sz
+= lstrlenW(text
);
5017 sz
*= sizeof(WCHAR
);
5019 output
= msi_alloc_zero(sz
);
5020 strcpyW(output
,advertise
);
5021 msi_free(advertise
);
5024 strcatW(output
,text
);
5026 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
5033 uirow
= MSI_CreateRecord( 2 );
5034 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
5035 MSI_RecordSetStringW( uirow
, 2, qualifier
);
5036 ui_actiondata( package
, szPublishComponents
, uirow
);
5037 msiobj_release( &uirow
->hdr
);
5038 /* FIXME: call ui_progress? */
5044 * At present I am ignorning the advertised components part of this and only
5045 * focusing on the qualified component sets
5047 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
5051 static const WCHAR ExecSeqQuery
[] =
5052 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5053 '`','P','u','b','l','i','s','h',
5054 'C','o','m','p','o','n','e','n','t','`',0};
5056 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5057 if (rc
!= ERROR_SUCCESS
)
5058 return ERROR_SUCCESS
;
5060 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
5061 msiobj_release(&view
->hdr
);
5066 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
5068 static const WCHAR szInstallerComponents
[] = {
5069 'S','o','f','t','w','a','r','e','\\',
5070 'M','i','c','r','o','s','o','f','t','\\',
5071 'I','n','s','t','a','l','l','e','r','\\',
5072 'C','o','m','p','o','n','e','n','t','s','\\',0};
5074 MSIPACKAGE
*package
= param
;
5075 LPCWSTR compgroupid
, component
, feature
, qualifier
;
5079 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
5082 feature
= MSI_RecordGetString( rec
, 5 );
5083 feat
= get_loaded_feature( package
, feature
);
5085 return ERROR_SUCCESS
;
5087 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5089 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
5090 feat
->Action
= feat
->Installed
;
5091 return ERROR_SUCCESS
;
5094 component
= MSI_RecordGetString( rec
, 3 );
5095 comp
= get_loaded_component( package
, component
);
5097 return ERROR_SUCCESS
;
5099 compgroupid
= MSI_RecordGetString( rec
, 1 );
5100 qualifier
= MSI_RecordGetString( rec
, 2 );
5102 squash_guid( compgroupid
, squashed
);
5103 strcpyW( keypath
, szInstallerComponents
);
5104 strcatW( keypath
, squashed
);
5106 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
5107 if (res
!= ERROR_SUCCESS
)
5109 WARN("Unable to delete component key %d\n", res
);
5112 uirow
= MSI_CreateRecord( 2 );
5113 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
5114 MSI_RecordSetStringW( uirow
, 2, qualifier
);
5115 ui_actiondata( package
, szUnpublishComponents
, uirow
);
5116 msiobj_release( &uirow
->hdr
);
5118 return ERROR_SUCCESS
;
5121 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
5125 static const WCHAR query
[] =
5126 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5127 '`','P','u','b','l','i','s','h',
5128 'C','o','m','p','o','n','e','n','t','`',0};
5130 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5131 if (rc
!= ERROR_SUCCESS
)
5132 return ERROR_SUCCESS
;
5134 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
5135 msiobj_release( &view
->hdr
);
5140 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
5142 MSIPACKAGE
*package
= param
;
5145 SC_HANDLE hscm
, service
= NULL
;
5146 LPCWSTR comp
, depends
, pass
;
5147 LPWSTR name
= NULL
, disp
= NULL
;
5148 LPCWSTR load_order
, serv_name
, key
;
5149 DWORD serv_type
, start_type
;
5152 static const WCHAR query
[] =
5153 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5154 '`','C','o','m','p','o','n','e','n','t','`',' ',
5155 'W','H','E','R','E',' ',
5156 '`','C','o','m','p','o','n','e','n','t','`',' ',
5157 '=','\'','%','s','\'',0};
5159 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
5162 ERR("Failed to open the SC Manager!\n");
5166 start_type
= MSI_RecordGetInteger(rec
, 5);
5167 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
5170 depends
= MSI_RecordGetString(rec
, 8);
5171 if (depends
&& *depends
)
5172 FIXME("Dependency list unhandled!\n");
5174 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5175 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
5176 serv_type
= MSI_RecordGetInteger(rec
, 4);
5177 err_control
= MSI_RecordGetInteger(rec
, 6);
5178 load_order
= MSI_RecordGetString(rec
, 7);
5179 serv_name
= MSI_RecordGetString(rec
, 9);
5180 pass
= MSI_RecordGetString(rec
, 10);
5181 comp
= MSI_RecordGetString(rec
, 12);
5183 /* fetch the service path */
5184 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
5187 ERR("Control query failed!\n");
5191 key
= MSI_RecordGetString(row
, 6);
5193 file
= get_loaded_file(package
, key
);
5194 msiobj_release(&row
->hdr
);
5197 ERR("Failed to load the service file\n");
5201 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
5202 start_type
, err_control
, file
->TargetPath
,
5203 load_order
, NULL
, NULL
, serv_name
, pass
);
5206 if (GetLastError() != ERROR_SERVICE_EXISTS
)
5207 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
5211 CloseServiceHandle(service
);
5212 CloseServiceHandle(hscm
);
5216 return ERROR_SUCCESS
;
5219 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
5223 static const WCHAR ExecSeqQuery
[] =
5224 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5225 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5227 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5228 if (rc
!= ERROR_SUCCESS
)
5229 return ERROR_SUCCESS
;
5231 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
5232 msiobj_release(&view
->hdr
);
5237 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5238 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
5240 LPCWSTR
*vector
, *temp_vector
;
5244 static const WCHAR separator
[] = {'[','~',']',0};
5247 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
5252 vector
= msi_alloc(sizeof(LPWSTR
));
5260 vector
[*numargs
- 1] = p
;
5262 if ((q
= strstrW(p
, separator
)))
5266 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
5272 vector
= temp_vector
;
5281 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
5283 MSIPACKAGE
*package
= param
;
5286 SC_HANDLE scm
= NULL
, service
= NULL
;
5287 LPCWSTR component
, *vector
= NULL
;
5288 LPWSTR name
, args
, display_name
= NULL
;
5289 DWORD event
, numargs
, len
;
5290 UINT r
= ERROR_FUNCTION_FAILED
;
5292 component
= MSI_RecordGetString(rec
, 6);
5293 comp
= get_loaded_component(package
, component
);
5295 return ERROR_SUCCESS
;
5297 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5299 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
5300 comp
->Action
= comp
->Installed
;
5301 return ERROR_SUCCESS
;
5303 comp
->Action
= INSTALLSTATE_LOCAL
;
5305 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5306 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
5307 event
= MSI_RecordGetInteger(rec
, 3);
5309 if (!(event
& msidbServiceControlEventStart
))
5315 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
5318 ERR("Failed to open the service control manager\n");
5323 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5324 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5326 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5327 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5330 service
= OpenServiceW(scm
, name
, SERVICE_START
);
5333 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
5337 vector
= msi_service_args_to_vector(args
, &numargs
);
5339 if (!StartServiceW(service
, numargs
, vector
) &&
5340 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
5342 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
5349 uirow
= MSI_CreateRecord( 2 );
5350 MSI_RecordSetStringW( uirow
, 1, display_name
);
5351 MSI_RecordSetStringW( uirow
, 2, name
);
5352 ui_actiondata( package
, szStartServices
, uirow
);
5353 msiobj_release( &uirow
->hdr
);
5355 CloseServiceHandle(service
);
5356 CloseServiceHandle(scm
);
5361 msi_free(display_name
);
5365 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
5370 static const WCHAR query
[] = {
5371 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5372 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5374 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5375 if (rc
!= ERROR_SUCCESS
)
5376 return ERROR_SUCCESS
;
5378 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
5379 msiobj_release(&view
->hdr
);
5384 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
5386 DWORD i
, needed
, count
;
5387 ENUM_SERVICE_STATUSW
*dependencies
;
5391 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
5392 0, &needed
, &count
))
5395 if (GetLastError() != ERROR_MORE_DATA
)
5398 dependencies
= msi_alloc(needed
);
5402 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
5403 needed
, &needed
, &count
))
5406 for (i
= 0; i
< count
; i
++)
5408 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
5409 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
5413 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
5420 msi_free(dependencies
);
5424 static UINT
stop_service( LPCWSTR name
)
5426 SC_HANDLE scm
= NULL
, service
= NULL
;
5427 SERVICE_STATUS status
;
5428 SERVICE_STATUS_PROCESS ssp
;
5431 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5434 WARN("Failed to open the SCM: %d\n", GetLastError());
5438 service
= OpenServiceW(scm
, name
,
5440 SERVICE_QUERY_STATUS
|
5441 SERVICE_ENUMERATE_DEPENDENTS
);
5444 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
5448 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
5449 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
5451 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
5455 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
5458 stop_service_dependents(scm
, service
);
5460 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5461 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5464 CloseServiceHandle(service
);
5465 CloseServiceHandle(scm
);
5467 return ERROR_SUCCESS
;
5470 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
5472 MSIPACKAGE
*package
= param
;
5476 LPWSTR name
= NULL
, display_name
= NULL
;
5480 event
= MSI_RecordGetInteger( rec
, 3 );
5481 if (!(event
& msidbServiceControlEventStop
))
5482 return ERROR_SUCCESS
;
5484 component
= MSI_RecordGetString( rec
, 6 );
5485 comp
= get_loaded_component( package
, component
);
5487 return ERROR_SUCCESS
;
5489 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5491 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5492 comp
->Action
= comp
->Installed
;
5493 return ERROR_SUCCESS
;
5495 comp
->Action
= INSTALLSTATE_ABSENT
;
5497 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
5500 ERR("Failed to open the service control manager\n");
5505 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5506 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5508 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5509 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5511 CloseServiceHandle( scm
);
5513 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
5514 stop_service( name
);
5517 uirow
= MSI_CreateRecord( 2 );
5518 MSI_RecordSetStringW( uirow
, 1, display_name
);
5519 MSI_RecordSetStringW( uirow
, 2, name
);
5520 ui_actiondata( package
, szStopServices
, uirow
);
5521 msiobj_release( &uirow
->hdr
);
5524 msi_free( display_name
);
5525 return ERROR_SUCCESS
;
5528 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5533 static const WCHAR query
[] = {
5534 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5535 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5537 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5538 if (rc
!= ERROR_SUCCESS
)
5539 return ERROR_SUCCESS
;
5541 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5542 msiobj_release(&view
->hdr
);
5547 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
5549 MSIPACKAGE
*package
= param
;
5553 LPWSTR name
= NULL
, display_name
= NULL
;
5555 SC_HANDLE scm
= NULL
, service
= NULL
;
5557 event
= MSI_RecordGetInteger( rec
, 3 );
5558 if (!(event
& msidbServiceControlEventDelete
))
5559 return ERROR_SUCCESS
;
5561 component
= MSI_RecordGetString(rec
, 6);
5562 comp
= get_loaded_component(package
, component
);
5564 return ERROR_SUCCESS
;
5566 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5568 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5569 comp
->Action
= comp
->Installed
;
5570 return ERROR_SUCCESS
;
5572 comp
->Action
= INSTALLSTATE_ABSENT
;
5574 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
5575 stop_service( name
);
5577 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5580 WARN("Failed to open the SCM: %d\n", GetLastError());
5585 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5586 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5588 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5589 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5592 service
= OpenServiceW( scm
, name
, DELETE
);
5595 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
5599 if (!DeleteService( service
))
5600 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
5603 uirow
= MSI_CreateRecord( 2 );
5604 MSI_RecordSetStringW( uirow
, 1, display_name
);
5605 MSI_RecordSetStringW( uirow
, 2, name
);
5606 ui_actiondata( package
, szDeleteServices
, uirow
);
5607 msiobj_release( &uirow
->hdr
);
5609 CloseServiceHandle( service
);
5610 CloseServiceHandle( scm
);
5612 msi_free( display_name
);
5614 return ERROR_SUCCESS
;
5617 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5622 static const WCHAR query
[] = {
5623 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5624 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5626 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5627 if (rc
!= ERROR_SUCCESS
)
5628 return ERROR_SUCCESS
;
5630 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
5631 msiobj_release( &view
->hdr
);
5636 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5640 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5642 if (!lstrcmpW(file
->File
, filename
))
5649 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5651 MSIPACKAGE
*package
= param
;
5652 LPWSTR driver
, driver_path
, ptr
;
5653 WCHAR outpath
[MAX_PATH
];
5654 MSIFILE
*driver_file
, *setup_file
;
5658 UINT r
= ERROR_SUCCESS
;
5660 static const WCHAR driver_fmt
[] = {
5661 'D','r','i','v','e','r','=','%','s',0};
5662 static const WCHAR setup_fmt
[] = {
5663 'S','e','t','u','p','=','%','s',0};
5664 static const WCHAR usage_fmt
[] = {
5665 'F','i','l','e','U','s','a','g','e','=','1',0};
5667 desc
= MSI_RecordGetString(rec
, 3);
5669 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5670 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5674 ERR("ODBC Driver entry not found!\n");
5675 return ERROR_FUNCTION_FAILED
;
5678 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
5680 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5681 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
5683 driver
= msi_alloc(len
* sizeof(WCHAR
));
5685 return ERROR_OUTOFMEMORY
;
5688 lstrcpyW(ptr
, desc
);
5689 ptr
+= lstrlenW(ptr
) + 1;
5691 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5696 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5700 lstrcpyW(ptr
, usage_fmt
);
5701 ptr
+= lstrlenW(ptr
) + 1;
5704 driver_path
= strdupW(driver_file
->TargetPath
);
5705 ptr
= strrchrW(driver_path
, '\\');
5706 if (ptr
) *ptr
= '\0';
5708 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5709 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5711 ERR("Failed to install SQL driver!\n");
5712 r
= ERROR_FUNCTION_FAILED
;
5715 uirow
= MSI_CreateRecord( 5 );
5716 MSI_RecordSetStringW( uirow
, 1, desc
);
5717 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5718 MSI_RecordSetStringW( uirow
, 3, driver_path
);
5719 ui_actiondata( package
, szInstallODBC
, uirow
);
5720 msiobj_release( &uirow
->hdr
);
5723 msi_free(driver_path
);
5728 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5730 MSIPACKAGE
*package
= param
;
5731 LPWSTR translator
, translator_path
, ptr
;
5732 WCHAR outpath
[MAX_PATH
];
5733 MSIFILE
*translator_file
, *setup_file
;
5737 UINT r
= ERROR_SUCCESS
;
5739 static const WCHAR translator_fmt
[] = {
5740 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5741 static const WCHAR setup_fmt
[] = {
5742 'S','e','t','u','p','=','%','s',0};
5744 desc
= MSI_RecordGetString(rec
, 3);
5746 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5747 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5749 if (!translator_file
)
5751 ERR("ODBC Translator entry not found!\n");
5752 return ERROR_FUNCTION_FAILED
;
5755 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
5757 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5759 translator
= msi_alloc(len
* sizeof(WCHAR
));
5761 return ERROR_OUTOFMEMORY
;
5764 lstrcpyW(ptr
, desc
);
5765 ptr
+= lstrlenW(ptr
) + 1;
5767 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5772 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5777 translator_path
= strdupW(translator_file
->TargetPath
);
5778 ptr
= strrchrW(translator_path
, '\\');
5779 if (ptr
) *ptr
= '\0';
5781 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5782 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5784 ERR("Failed to install SQL translator!\n");
5785 r
= ERROR_FUNCTION_FAILED
;
5788 uirow
= MSI_CreateRecord( 5 );
5789 MSI_RecordSetStringW( uirow
, 1, desc
);
5790 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5791 MSI_RecordSetStringW( uirow
, 3, translator_path
);
5792 ui_actiondata( package
, szInstallODBC
, uirow
);
5793 msiobj_release( &uirow
->hdr
);
5795 msi_free(translator
);
5796 msi_free(translator_path
);
5801 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5803 MSIPACKAGE
*package
= param
;
5805 LPCWSTR desc
, driver
;
5806 WORD request
= ODBC_ADD_SYS_DSN
;
5809 UINT r
= ERROR_SUCCESS
;
5812 static const WCHAR attrs_fmt
[] = {
5813 'D','S','N','=','%','s',0 };
5815 desc
= MSI_RecordGetString(rec
, 3);
5816 driver
= MSI_RecordGetString(rec
, 4);
5817 registration
= MSI_RecordGetInteger(rec
, 5);
5819 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5820 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5822 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
5823 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5825 return ERROR_OUTOFMEMORY
;
5827 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5830 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5832 ERR("Failed to install SQL data source!\n");
5833 r
= ERROR_FUNCTION_FAILED
;
5836 uirow
= MSI_CreateRecord( 5 );
5837 MSI_RecordSetStringW( uirow
, 1, desc
);
5838 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5839 MSI_RecordSetInteger( uirow
, 3, request
);
5840 ui_actiondata( package
, szInstallODBC
, uirow
);
5841 msiobj_release( &uirow
->hdr
);
5848 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5853 static const WCHAR driver_query
[] = {
5854 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5855 'O','D','B','C','D','r','i','v','e','r',0 };
5857 static const WCHAR translator_query
[] = {
5858 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5859 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5861 static const WCHAR source_query
[] = {
5862 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5863 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5865 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5866 if (rc
!= ERROR_SUCCESS
)
5867 return ERROR_SUCCESS
;
5869 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5870 msiobj_release(&view
->hdr
);
5872 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5873 if (rc
!= ERROR_SUCCESS
)
5874 return ERROR_SUCCESS
;
5876 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5877 msiobj_release(&view
->hdr
);
5879 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5880 if (rc
!= ERROR_SUCCESS
)
5881 return ERROR_SUCCESS
;
5883 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5884 msiobj_release(&view
->hdr
);
5889 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5891 MSIPACKAGE
*package
= param
;
5896 desc
= MSI_RecordGetString( rec
, 3 );
5897 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5899 WARN("Failed to remove ODBC driver\n");
5903 FIXME("Usage count reached 0\n");
5906 uirow
= MSI_CreateRecord( 2 );
5907 MSI_RecordSetStringW( uirow
, 1, desc
);
5908 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5909 ui_actiondata( package
, szRemoveODBC
, uirow
);
5910 msiobj_release( &uirow
->hdr
);
5912 return ERROR_SUCCESS
;
5915 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5917 MSIPACKAGE
*package
= param
;
5922 desc
= MSI_RecordGetString( rec
, 3 );
5923 if (!SQLRemoveTranslatorW( desc
, &usage
))
5925 WARN("Failed to remove ODBC translator\n");
5929 FIXME("Usage count reached 0\n");
5932 uirow
= MSI_CreateRecord( 2 );
5933 MSI_RecordSetStringW( uirow
, 1, desc
);
5934 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5935 ui_actiondata( package
, szRemoveODBC
, uirow
);
5936 msiobj_release( &uirow
->hdr
);
5938 return ERROR_SUCCESS
;
5941 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5943 MSIPACKAGE
*package
= param
;
5946 LPCWSTR desc
, driver
;
5947 WORD request
= ODBC_REMOVE_SYS_DSN
;
5951 static const WCHAR attrs_fmt
[] = {
5952 'D','S','N','=','%','s',0 };
5954 desc
= MSI_RecordGetString( rec
, 3 );
5955 driver
= MSI_RecordGetString( rec
, 4 );
5956 registration
= MSI_RecordGetInteger( rec
, 5 );
5958 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5959 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5961 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
5962 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5964 return ERROR_OUTOFMEMORY
;
5966 FIXME("Use ODBCSourceAttribute table\n");
5968 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5971 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5973 WARN("Failed to remove ODBC data source\n");
5977 uirow
= MSI_CreateRecord( 3 );
5978 MSI_RecordSetStringW( uirow
, 1, desc
);
5979 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5980 MSI_RecordSetInteger( uirow
, 3, request
);
5981 ui_actiondata( package
, szRemoveODBC
, uirow
);
5982 msiobj_release( &uirow
->hdr
);
5984 return ERROR_SUCCESS
;
5987 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5992 static const WCHAR driver_query
[] = {
5993 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5994 'O','D','B','C','D','r','i','v','e','r',0 };
5996 static const WCHAR translator_query
[] = {
5997 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5998 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6000 static const WCHAR source_query
[] = {
6001 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6002 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6004 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
6005 if (rc
!= ERROR_SUCCESS
)
6006 return ERROR_SUCCESS
;
6008 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
6009 msiobj_release( &view
->hdr
);
6011 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
6012 if (rc
!= ERROR_SUCCESS
)
6013 return ERROR_SUCCESS
;
6015 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
6016 msiobj_release( &view
->hdr
);
6018 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
6019 if (rc
!= ERROR_SUCCESS
)
6020 return ERROR_SUCCESS
;
6022 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
6023 msiobj_release( &view
->hdr
);
6028 #define ENV_ACT_SETALWAYS 0x1
6029 #define ENV_ACT_SETABSENT 0x2
6030 #define ENV_ACT_REMOVE 0x4
6031 #define ENV_ACT_REMOVEMATCH 0x8
6033 #define ENV_MOD_MACHINE 0x20000000
6034 #define ENV_MOD_APPEND 0x40000000
6035 #define ENV_MOD_PREFIX 0x80000000
6036 #define ENV_MOD_MASK 0xC0000000
6038 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6040 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
6042 LPCWSTR cptr
= *name
;
6044 static const WCHAR prefix
[] = {'[','~',']',0};
6045 static const int prefix_len
= 3;
6051 *flags
|= ENV_ACT_SETALWAYS
;
6052 else if (*cptr
== '+')
6053 *flags
|= ENV_ACT_SETABSENT
;
6054 else if (*cptr
== '-')
6055 *flags
|= ENV_ACT_REMOVE
;
6056 else if (*cptr
== '!')
6057 *flags
|= ENV_ACT_REMOVEMATCH
;
6058 else if (*cptr
== '*')
6059 *flags
|= ENV_MOD_MACHINE
;
6069 ERR("Missing environment variable\n");
6070 return ERROR_FUNCTION_FAILED
;
6075 LPCWSTR ptr
= *value
;
6076 if (!strncmpW(ptr
, prefix
, prefix_len
))
6078 if (ptr
[prefix_len
] == szSemiColon
[0])
6080 *flags
|= ENV_MOD_APPEND
;
6081 *value
+= lstrlenW(prefix
);
6088 else if (lstrlenW(*value
) >= prefix_len
)
6090 ptr
+= lstrlenW(ptr
) - prefix_len
;
6091 if (!lstrcmpW(ptr
, prefix
))
6093 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
6095 *flags
|= ENV_MOD_PREFIX
;
6096 /* the "[~]" will be removed by deformat_string */;
6106 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
6107 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
6108 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
6109 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
6111 ERR("Invalid flags: %08x\n", *flags
);
6112 return ERROR_FUNCTION_FAILED
;
6116 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
6118 return ERROR_SUCCESS
;
6121 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
6123 static const WCHAR user_env
[] =
6124 {'E','n','v','i','r','o','n','m','e','n','t',0};
6125 static const WCHAR machine_env
[] =
6126 {'S','y','s','t','e','m','\\',
6127 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6128 'C','o','n','t','r','o','l','\\',
6129 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6130 'E','n','v','i','r','o','n','m','e','n','t',0};
6135 if (flags
& ENV_MOD_MACHINE
)
6138 root
= HKEY_LOCAL_MACHINE
;
6143 root
= HKEY_CURRENT_USER
;
6146 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
6147 if (res
!= ERROR_SUCCESS
)
6149 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
6150 return ERROR_FUNCTION_FAILED
;
6153 return ERROR_SUCCESS
;
6156 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6158 MSIPACKAGE
*package
= param
;
6159 LPCWSTR name
, value
, component
;
6160 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
6161 DWORD flags
, type
, size
;
6168 component
= MSI_RecordGetString(rec
, 4);
6169 comp
= get_loaded_component(package
, component
);
6171 return ERROR_SUCCESS
;
6173 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6175 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6176 comp
->Action
= comp
->Installed
;
6177 return ERROR_SUCCESS
;
6179 comp
->Action
= INSTALLSTATE_LOCAL
;
6181 name
= MSI_RecordGetString(rec
, 2);
6182 value
= MSI_RecordGetString(rec
, 3);
6184 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6186 res
= env_parse_flags(&name
, &value
, &flags
);
6187 if (res
!= ERROR_SUCCESS
|| !value
)
6190 if (value
&& !deformat_string(package
, value
, &deformatted
))
6192 res
= ERROR_OUTOFMEMORY
;
6196 value
= deformatted
;
6198 res
= open_env_key( flags
, &env
);
6199 if (res
!= ERROR_SUCCESS
)
6202 if (flags
& ENV_MOD_MACHINE
)
6203 action
|= 0x20000000;
6207 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
6208 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
6209 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
6212 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
6216 /* Nothing to do. */
6219 res
= ERROR_SUCCESS
;
6223 /* If we are appending but the string was empty, strip ; */
6224 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
6226 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
6227 newval
= strdupW(value
);
6230 res
= ERROR_OUTOFMEMORY
;
6238 /* Contrary to MSDN, +-variable to [~];path works */
6239 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
6241 res
= ERROR_SUCCESS
;
6245 data
= msi_alloc(size
);
6249 return ERROR_OUTOFMEMORY
;
6252 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
6253 if (res
!= ERROR_SUCCESS
)
6256 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
6259 res
= RegDeleteValueW(env
, name
);
6260 if (res
!= ERROR_SUCCESS
)
6261 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
6265 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
6266 if (flags
& ENV_MOD_MASK
)
6270 if (flags
& ENV_MOD_APPEND
) multiplier
++;
6271 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
6272 mod_size
= lstrlenW(value
) * multiplier
;
6273 size
+= mod_size
* sizeof(WCHAR
);
6276 newval
= msi_alloc(size
);
6280 res
= ERROR_OUTOFMEMORY
;
6284 if (flags
& ENV_MOD_PREFIX
)
6286 lstrcpyW(newval
, value
);
6287 ptr
= newval
+ lstrlenW(value
);
6288 action
|= 0x80000000;
6291 lstrcpyW(ptr
, data
);
6293 if (flags
& ENV_MOD_APPEND
)
6295 lstrcatW(newval
, value
);
6296 action
|= 0x40000000;
6299 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
6300 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
6303 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
6307 uirow
= MSI_CreateRecord( 3 );
6308 MSI_RecordSetStringW( uirow
, 1, name
);
6309 MSI_RecordSetStringW( uirow
, 2, newval
);
6310 MSI_RecordSetInteger( uirow
, 3, action
);
6311 ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
6312 msiobj_release( &uirow
->hdr
);
6314 if (env
) RegCloseKey(env
);
6315 msi_free(deformatted
);
6321 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
6325 static const WCHAR ExecSeqQuery
[] =
6326 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6327 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6328 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6329 if (rc
!= ERROR_SUCCESS
)
6330 return ERROR_SUCCESS
;
6332 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
6333 msiobj_release(&view
->hdr
);
6338 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6340 MSIPACKAGE
*package
= param
;
6341 LPCWSTR name
, value
, component
;
6342 LPWSTR deformatted
= NULL
;
6351 component
= MSI_RecordGetString( rec
, 4 );
6352 comp
= get_loaded_component( package
, component
);
6354 return ERROR_SUCCESS
;
6356 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6358 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6359 comp
->Action
= comp
->Installed
;
6360 return ERROR_SUCCESS
;
6362 comp
->Action
= INSTALLSTATE_ABSENT
;
6364 name
= MSI_RecordGetString( rec
, 2 );
6365 value
= MSI_RecordGetString( rec
, 3 );
6367 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6369 r
= env_parse_flags( &name
, &value
, &flags
);
6370 if (r
!= ERROR_SUCCESS
)
6373 if (!(flags
& ENV_ACT_REMOVE
))
6375 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
6376 return ERROR_SUCCESS
;
6379 if (value
&& !deformat_string( package
, value
, &deformatted
))
6380 return ERROR_OUTOFMEMORY
;
6382 value
= deformatted
;
6384 r
= open_env_key( flags
, &env
);
6385 if (r
!= ERROR_SUCCESS
)
6391 if (flags
& ENV_MOD_MACHINE
)
6392 action
|= 0x20000000;
6394 TRACE("Removing %s\n", debugstr_w(name
));
6396 res
= RegDeleteValueW( env
, name
);
6397 if (res
!= ERROR_SUCCESS
)
6399 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
6404 uirow
= MSI_CreateRecord( 3 );
6405 MSI_RecordSetStringW( uirow
, 1, name
);
6406 MSI_RecordSetStringW( uirow
, 2, value
);
6407 MSI_RecordSetInteger( uirow
, 3, action
);
6408 ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
6409 msiobj_release( &uirow
->hdr
);
6411 if (env
) RegCloseKey( env
);
6412 msi_free( deformatted
);
6416 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6420 static const WCHAR query
[] =
6421 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6422 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6424 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6425 if (rc
!= ERROR_SUCCESS
)
6426 return ERROR_SUCCESS
;
6428 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
6429 msiobj_release( &view
->hdr
);
6434 typedef struct tagMSIASSEMBLY
6437 MSICOMPONENT
*component
;
6438 MSIFEATURE
*feature
;
6442 LPWSTR display_name
;
6447 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
6449 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
6450 LPVOID pvReserved
, HMODULE
*phModDll
);
6452 static BOOL
init_functionpointers(void)
6458 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
6460 hmscoree
= LoadLibraryA("mscoree.dll");
6463 WARN("mscoree.dll not available\n");
6467 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
6468 if (!pLoadLibraryShim
)
6470 WARN("LoadLibraryShim not available\n");
6471 FreeLibrary(hmscoree
);
6475 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
6478 WARN("fusion.dll not available\n");
6479 FreeLibrary(hmscoree
);
6483 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
6485 FreeLibrary(hmscoree
);
6489 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
6492 IAssemblyCache
*cache
;
6495 UINT r
= ERROR_FUNCTION_FAILED
;
6497 TRACE("installing assembly: %s\n", debugstr_w(path
));
6499 uirow
= MSI_CreateRecord( 2 );
6500 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
6501 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
6502 msiobj_release( &uirow
->hdr
);
6504 if (assembly
->feature
)
6505 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
6507 if (assembly
->manifest
)
6508 FIXME("Manifest unhandled\n");
6510 if (assembly
->application
)
6512 FIXME("Assembly should be privately installed\n");
6513 return ERROR_SUCCESS
;
6516 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
6518 FIXME("Win32 assemblies not handled\n");
6519 return ERROR_SUCCESS
;
6522 hr
= pCreateAssemblyCache(&cache
, 0);
6526 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
6528 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
6533 IAssemblyCache_Release(cache
);
6537 typedef struct tagASSEMBLY_LIST
6539 MSIPACKAGE
*package
;
6540 IAssemblyCache
*cache
;
6541 struct list
*assemblies
;
6544 typedef struct tagASSEMBLY_NAME
6552 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
6554 ASSEMBLY_NAME
*asmname
= param
;
6555 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
6556 LPWSTR val
= msi_dup_record_field(rec
, 3);
6558 static const WCHAR Name
[] = {'N','a','m','e',0};
6559 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
6560 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
6561 static const WCHAR PublicKeyToken
[] = {
6562 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6564 if (!strcmpiW(name
, Name
))
6565 asmname
->name
= val
;
6566 else if (!strcmpiW(name
, Version
))
6567 asmname
->version
= val
;
6568 else if (!strcmpiW(name
, Culture
))
6569 asmname
->culture
= val
;
6570 else if (!strcmpiW(name
, PublicKeyToken
))
6571 asmname
->pubkeytoken
= val
;
6575 return ERROR_SUCCESS
;
6578 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
6582 *size
= lstrlenW(append
) + 1;
6583 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
6584 lstrcpyW(*str
, append
);
6588 (*size
) += lstrlenW(append
);
6589 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6590 lstrcatW(*str
, append
);
6593 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, MSICOMPONENT
*comp
)
6595 static const WCHAR separator
[] = {',',' ',0};
6596 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
6597 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
6598 static const WCHAR PublicKeyToken
[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6599 static const WCHAR query
[] = {
6600 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6601 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6602 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6603 '=','\'','%','s','\'',0};
6606 LPWSTR display_name
;
6610 display_name
= NULL
;
6611 memset( &name
, 0, sizeof(ASSEMBLY_NAME
) );
6613 r
= MSI_OpenQuery( db
, &view
, query
, comp
->Component
);
6614 if (r
!= ERROR_SUCCESS
)
6617 MSI_IterateRecords( view
, NULL
, parse_assembly_name
, &name
);
6618 msiobj_release( &view
->hdr
);
6622 ERR("No assembly name specified!\n");
6626 append_str( &display_name
, &size
, name
.name
);
6630 append_str( &display_name
, &size
, separator
);
6631 append_str( &display_name
, &size
, Version
);
6632 append_str( &display_name
, &size
, name
.version
);
6636 append_str( &display_name
, &size
, separator
);
6637 append_str( &display_name
, &size
, Culture
);
6638 append_str( &display_name
, &size
, name
.culture
);
6640 if (name
.pubkeytoken
)
6642 append_str( &display_name
, &size
, separator
);
6643 append_str( &display_name
, &size
, PublicKeyToken
);
6644 append_str( &display_name
, &size
, name
.pubkeytoken
);
6647 msi_free( name
.name
);
6648 msi_free( name
.version
);
6649 msi_free( name
.culture
);
6650 msi_free( name
.pubkeytoken
);
6652 return display_name
;
6655 static BOOL
check_assembly_installed( MSIDATABASE
*db
, IAssemblyCache
*cache
, MSICOMPONENT
*comp
)
6657 ASSEMBLY_INFO asminfo
;
6662 disp
= get_assembly_display_name( db
, comp
);
6666 memset( &asminfo
, 0, sizeof(ASSEMBLY_INFO
) );
6667 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6669 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, disp
, &asminfo
);
6671 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6677 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6679 ASSEMBLY_LIST
*list
= param
;
6680 MSIASSEMBLY
*assembly
;
6683 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6685 return ERROR_OUTOFMEMORY
;
6687 component
= MSI_RecordGetString(rec
, 1);
6688 assembly
->component
= get_loaded_component(list
->package
, component
);
6689 if (!assembly
->component
)
6690 return ERROR_SUCCESS
;
6692 if (assembly
->component
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6693 assembly
->component
->ActionRequest
!= INSTALLSTATE_SOURCE
)
6695 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6696 assembly
->component
->Action
= assembly
->component
->Installed
;
6697 return ERROR_SUCCESS
;
6699 assembly
->component
->Action
= assembly
->component
->ActionRequest
;
6701 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6702 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6704 if (!assembly
->file
)
6706 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6707 return ERROR_FUNCTION_FAILED
;
6710 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6711 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6712 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6714 if (assembly
->application
)
6717 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6719 /* FIXME: we should probably check the manifest file here */
6721 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6722 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6724 assembly
->installed
= TRUE
;
6728 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6730 assembly
->component
);
6732 list_add_head(list
->assemblies
, &assembly
->entry
);
6733 return ERROR_SUCCESS
;
6736 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6738 IAssemblyCache
*cache
= NULL
;
6744 static const WCHAR query
[] =
6745 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6746 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6748 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6749 if (r
!= ERROR_SUCCESS
)
6750 return ERROR_SUCCESS
;
6752 hr
= pCreateAssemblyCache(&cache
, 0);
6754 return ERROR_FUNCTION_FAILED
;
6756 list
.package
= package
;
6758 list
.assemblies
= assemblies
;
6760 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6761 msiobj_release(&view
->hdr
);
6763 IAssemblyCache_Release(cache
);
6768 static void free_assemblies(struct list
*assemblies
)
6770 struct list
*item
, *cursor
;
6772 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6774 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6776 list_remove(&assembly
->entry
);
6777 msi_free(assembly
->application
);
6778 msi_free(assembly
->manifest
);
6779 msi_free(assembly
->display_name
);
6784 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6786 MSIASSEMBLY
*assembly
;
6788 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6790 if (!lstrcmpW(assembly
->file
->File
, file
))
6800 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6801 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6803 MSIASSEMBLY
*assembly
;
6804 WCHAR temppath
[MAX_PATH
];
6805 struct list
*assemblies
= user
;
6808 if (!find_assembly(assemblies
, file
, &assembly
))
6811 GetTempPathW(MAX_PATH
, temppath
);
6812 PathAddBackslashW(temppath
);
6813 lstrcatW(temppath
, assembly
->file
->FileName
);
6815 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6817 if (assembly
->installed
)
6820 *path
= strdupW(temppath
);
6821 *attrs
= assembly
->file
->Attributes
;
6823 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6825 assembly
->installed
= TRUE
;
6827 r
= install_assembly(package
, assembly
, temppath
);
6828 if (r
!= ERROR_SUCCESS
)
6829 ERR("Failed to install assembly\n");
6835 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6838 struct list assemblies
= LIST_INIT(assemblies
);
6839 MSIASSEMBLY
*assembly
;
6842 if (!init_functionpointers() || !pCreateAssemblyCache
)
6843 return ERROR_FUNCTION_FAILED
;
6845 r
= load_assemblies(package
, &assemblies
);
6846 if (r
!= ERROR_SUCCESS
)
6849 if (list_empty(&assemblies
))
6852 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6855 r
= ERROR_OUTOFMEMORY
;
6859 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6861 if (assembly
->installed
&& !mi
->is_continuous
)
6864 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6865 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6869 r
= ready_media(package
, assembly
->file
, mi
);
6870 if (r
!= ERROR_SUCCESS
)
6872 ERR("Failed to ready media\n");
6877 data
.package
= package
;
6878 data
.cb
= installassembly_cb
;
6879 data
.user
= &assemblies
;
6881 if (assembly
->file
->IsCompressed
&&
6882 !msi_cabextract(package
, mi
, &data
))
6884 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6885 r
= ERROR_FUNCTION_FAILED
;
6890 if (!assembly
->file
->IsCompressed
)
6892 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6894 r
= install_assembly(package
, assembly
, source
);
6895 if (r
!= ERROR_SUCCESS
)
6896 ERR("Failed to install assembly\n");
6901 /* FIXME: write Installer assembly reg values */
6905 free_assemblies(&assemblies
);
6909 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6911 LPWSTR key
, template, id
;
6912 UINT r
= ERROR_SUCCESS
;
6914 id
= msi_dup_property( package
->db
, szProductID
);
6918 return ERROR_SUCCESS
;
6920 template = msi_dup_property( package
->db
, szPIDTemplate
);
6921 key
= msi_dup_property( package
->db
, szPIDKEY
);
6923 if (key
&& template)
6925 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6926 r
= msi_set_property( package
->db
, szProductID
, key
);
6928 msi_free( template );
6933 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6936 package
->need_reboot
= 1;
6937 return ERROR_SUCCESS
;
6940 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6942 static const WCHAR szAvailableFreeReg
[] =
6943 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6945 int space
= msi_get_property_int( package
->db
, szAvailableFreeReg
, 0 );
6947 TRACE("%p %d kilobytes\n", package
, space
);
6949 uirow
= MSI_CreateRecord( 1 );
6950 MSI_RecordSetInteger( uirow
, 1, space
);
6951 ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
6952 msiobj_release( &uirow
->hdr
);
6954 return ERROR_SUCCESS
;
6957 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6959 FIXME("%p\n", package
);
6960 return ERROR_SUCCESS
;
6963 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6965 FIXME("%p\n", package
);
6966 return ERROR_SUCCESS
;
6969 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6974 static const WCHAR driver_query
[] = {
6975 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6976 'O','D','B','C','D','r','i','v','e','r',0 };
6978 static const WCHAR translator_query
[] = {
6979 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6980 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6982 r
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
6983 if (r
== ERROR_SUCCESS
)
6986 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
6987 msiobj_release( &view
->hdr
);
6988 if (count
) FIXME("ignored %u rows in ODBCDriver table\n", count
);
6991 r
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
6992 if (r
== ERROR_SUCCESS
)
6995 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
6996 msiobj_release( &view
->hdr
);
6997 if (count
) FIXME("ignored %u rows in ODBCTranslator table\n", count
);
7000 return ERROR_SUCCESS
;
7003 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
7004 LPCSTR action
, LPCWSTR table
)
7006 static const WCHAR query
[] = {
7007 'S','E','L','E','C','T',' ','*',' ',
7008 'F','R','O','M',' ','`','%','s','`',0 };
7009 MSIQUERY
*view
= NULL
;
7013 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
7014 if (r
== ERROR_SUCCESS
)
7016 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
7017 msiobj_release(&view
->hdr
);
7021 FIXME("%s -> %u ignored %s table values\n",
7022 action
, count
, debugstr_w(table
));
7024 return ERROR_SUCCESS
;
7027 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
7029 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
7030 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
7033 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
7035 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
7036 return msi_unimplemented_action_stub( package
, "BindImage", table
);
7039 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
7041 static const WCHAR table
[] = {
7042 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7043 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
7046 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
7048 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
7049 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
7052 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
7054 static const WCHAR table
[] = {
7055 'M','s','i','A','s','s','e','m','b','l','y',0 };
7056 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
7059 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
7061 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
7062 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
7065 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
7067 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
7068 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
7071 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
7073 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
7074 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
7077 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
7079 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7080 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
7083 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
7085 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
7086 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
7089 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
7093 const WCHAR
*action
;
7094 UINT (*handler
)(MSIPACKAGE
*);
7098 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
7099 { szAppSearch
, ACTION_AppSearch
},
7100 { szBindImage
, ACTION_BindImage
},
7101 { szCCPSearch
, ACTION_CCPSearch
},
7102 { szCostFinalize
, ACTION_CostFinalize
},
7103 { szCostInitialize
, ACTION_CostInitialize
},
7104 { szCreateFolders
, ACTION_CreateFolders
},
7105 { szCreateShortcuts
, ACTION_CreateShortcuts
},
7106 { szDeleteServices
, ACTION_DeleteServices
},
7107 { szDisableRollback
, ACTION_DisableRollback
},
7108 { szDuplicateFiles
, ACTION_DuplicateFiles
},
7109 { szExecuteAction
, ACTION_ExecuteAction
},
7110 { szFileCost
, ACTION_FileCost
},
7111 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
7112 { szForceReboot
, ACTION_ForceReboot
},
7113 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
7114 { szInstallExecute
, ACTION_InstallExecute
},
7115 { szInstallExecuteAgain
, ACTION_InstallExecute
},
7116 { szInstallFiles
, ACTION_InstallFiles
},
7117 { szInstallFinalize
, ACTION_InstallFinalize
},
7118 { szInstallInitialize
, ACTION_InstallInitialize
},
7119 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
7120 { szInstallValidate
, ACTION_InstallValidate
},
7121 { szIsolateComponents
, ACTION_IsolateComponents
},
7122 { szLaunchConditions
, ACTION_LaunchConditions
},
7123 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
7124 { szMoveFiles
, ACTION_MoveFiles
},
7125 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
7126 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
7127 { szInstallODBC
, ACTION_InstallODBC
},
7128 { szInstallServices
, ACTION_InstallServices
},
7129 { szPatchFiles
, ACTION_PatchFiles
},
7130 { szProcessComponents
, ACTION_ProcessComponents
},
7131 { szPublishComponents
, ACTION_PublishComponents
},
7132 { szPublishFeatures
, ACTION_PublishFeatures
},
7133 { szPublishProduct
, ACTION_PublishProduct
},
7134 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
7135 { szRegisterComPlus
, ACTION_RegisterComPlus
},
7136 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
7137 { szRegisterFonts
, ACTION_RegisterFonts
},
7138 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
7139 { szRegisterProduct
, ACTION_RegisterProduct
},
7140 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
7141 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
7142 { szRegisterUser
, ACTION_RegisterUser
},
7143 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
7144 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
7145 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
7146 { szRemoveFiles
, ACTION_RemoveFiles
},
7147 { szRemoveFolders
, ACTION_RemoveFolders
},
7148 { szRemoveIniValues
, ACTION_RemoveIniValues
},
7149 { szRemoveODBC
, ACTION_RemoveODBC
},
7150 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
7151 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
7152 { szResolveSource
, ACTION_ResolveSource
},
7153 { szRMCCPSearch
, ACTION_RMCCPSearch
},
7154 { szScheduleReboot
, ACTION_ScheduleReboot
},
7155 { szSelfRegModules
, ACTION_SelfRegModules
},
7156 { szSelfUnregModules
, ACTION_SelfUnregModules
},
7157 { szSetODBCFolders
, ACTION_SetODBCFolders
},
7158 { szStartServices
, ACTION_StartServices
},
7159 { szStopServices
, ACTION_StopServices
},
7160 { szUnpublishComponents
, ACTION_UnpublishComponents
},
7161 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
7162 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
7163 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
7164 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
7165 { szUnregisterFonts
, ACTION_UnregisterFonts
},
7166 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
7167 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
7168 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
7169 { szValidateProductID
, ACTION_ValidateProductID
},
7170 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
7171 { szWriteIniValues
, ACTION_WriteIniValues
},
7172 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
7176 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
7177 UINT
* rc
, BOOL force
)
7183 if (!run
&& !package
->script
->CurrentlyScripting
)
7188 if (strcmpW(action
,szInstallFinalize
) == 0 ||
7189 strcmpW(action
,szInstallExecute
) == 0 ||
7190 strcmpW(action
,szInstallExecuteAgain
) == 0)
7195 while (StandardActions
[i
].action
!= NULL
)
7197 if (strcmpW(StandardActions
[i
].action
, action
)==0)
7201 ui_actioninfo(package
, action
, TRUE
, 0);
7202 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
7203 ui_actioninfo(package
, action
, FALSE
, *rc
);
7207 ui_actionstart(package
, action
);
7208 if (StandardActions
[i
].handler
)
7210 *rc
= StandardActions
[i
].handler(package
);
7214 FIXME("unhandled standard action %s\n",debugstr_w(action
));
7215 *rc
= ERROR_SUCCESS
;
7226 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
7228 UINT rc
= ERROR_SUCCESS
;
7231 TRACE("Performing action (%s)\n", debugstr_w(action
));
7233 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
7236 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
7240 WARN("unhandled msi action %s\n", debugstr_w(action
));
7241 rc
= ERROR_FUNCTION_NOT_CALLED
;
7247 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
7249 UINT rc
= ERROR_SUCCESS
;
7250 BOOL handled
= FALSE
;
7252 TRACE("Performing action (%s)\n", debugstr_w(action
));
7254 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
7257 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
7259 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
7264 WARN("unhandled msi action %s\n", debugstr_w(action
));
7265 rc
= ERROR_FUNCTION_NOT_CALLED
;
7271 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
7273 UINT rc
= ERROR_SUCCESS
;
7276 static const WCHAR ExecSeqQuery
[] =
7277 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7278 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7279 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7280 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7281 static const WCHAR UISeqQuery
[] =
7282 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7283 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7284 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7285 ' ', '=',' ','%','i',0};
7287 if (needs_ui_sequence(package
))
7288 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
7290 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
7294 LPCWSTR action
, cond
;
7296 TRACE("Running the actions\n");
7298 /* check conditions */
7299 cond
= MSI_RecordGetString(row
, 2);
7301 /* this is a hack to skip errors in the condition code */
7302 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
7304 msiobj_release(&row
->hdr
);
7305 return ERROR_SUCCESS
;
7308 action
= MSI_RecordGetString(row
, 1);
7311 ERR("failed to fetch action\n");
7312 msiobj_release(&row
->hdr
);
7313 return ERROR_FUNCTION_FAILED
;
7316 if (needs_ui_sequence(package
))
7317 rc
= ACTION_PerformUIAction(package
, action
, -1);
7319 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
7321 msiobj_release(&row
->hdr
);
7327 /****************************************************
7328 * TOP level entry points
7329 *****************************************************/
7331 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
7332 LPCWSTR szCommandLine
)
7337 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
7338 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
7340 msi_set_property( package
->db
, szAction
, szInstall
);
7342 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
7349 dir
= strdupW(szPackagePath
);
7350 p
= strrchrW(dir
, '\\');
7354 file
= szPackagePath
+ (p
- dir
);
7359 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
7360 GetCurrentDirectoryW(MAX_PATH
, dir
);
7361 lstrcatW(dir
, szBackSlash
);
7362 file
= szPackagePath
;
7365 msi_free( package
->PackagePath
);
7366 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
7367 if (!package
->PackagePath
)
7370 return ERROR_OUTOFMEMORY
;
7373 lstrcpyW(package
->PackagePath
, dir
);
7374 lstrcatW(package
->PackagePath
, file
);
7377 msi_set_sourcedir_props(package
, FALSE
);
7380 msi_parse_command_line( package
, szCommandLine
, FALSE
);
7382 msi_apply_transforms( package
);
7383 msi_apply_patches( package
);
7385 if (!szCommandLine
&& msi_get_property_int( package
->db
, szInstalled
, 0 ))
7387 TRACE("setting reinstall property\n");
7388 msi_set_property( package
->db
, szReinstall
, szAll
);
7391 /* properties may have been added by a transform */
7392 msi_clone_properties( package
);
7393 msi_set_context( package
);
7395 if (needs_ui_sequence( package
))
7397 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
7398 rc
= ACTION_ProcessUISequence(package
);
7399 ui_exists
= ui_sequence_exists(package
);
7400 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
7402 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
7403 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
7407 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
7409 package
->script
->CurrentlyScripting
= FALSE
;
7411 /* process the ending type action */
7412 if (rc
== ERROR_SUCCESS
)
7413 ACTION_PerformActionSequence(package
, -1);
7414 else if (rc
== ERROR_INSTALL_USEREXIT
)
7415 ACTION_PerformActionSequence(package
, -2);
7416 else if (rc
== ERROR_INSTALL_SUSPEND
)
7417 ACTION_PerformActionSequence(package
, -4);
7419 ACTION_PerformActionSequence(package
, -3);
7421 /* finish up running custom actions */
7422 ACTION_FinishCustomActions(package
);
7424 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
7425 return ERROR_SUCCESS_REBOOT_REQUIRED
;