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 szUnregisterExtensionInfo
[] =
162 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
163 static const WCHAR szUnregisterMIMEInfo
[] =
164 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
165 static const WCHAR szUnregisterTypeLibraries
[] =
166 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
167 static const WCHAR szValidateProductID
[] =
168 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
169 static const WCHAR szWriteEnvironmentStrings
[] =
170 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
172 /********************************************************
174 ********************************************************/
176 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
178 static const WCHAR Query_t
[] =
179 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
180 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
181 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
182 ' ','\'','%','s','\'',0};
185 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
188 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
189 msiobj_release(&row
->hdr
);
192 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
196 static const WCHAR template_s
[]=
197 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
199 static const WCHAR template_e
[]=
200 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
201 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
203 static const WCHAR format
[] =
204 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
208 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
210 sprintfW(message
,template_s
,timet
,action
);
212 sprintfW(message
,template_e
,timet
,action
,rc
);
214 row
= MSI_CreateRecord(1);
215 MSI_RecordSetStringW(row
,1,message
);
217 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
218 msiobj_release(&row
->hdr
);
221 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
227 LPWSTR prop
= NULL
, val
= NULL
;
230 return ERROR_SUCCESS
;
242 TRACE("Looking at %s\n",debugstr_w(ptr
));
244 ptr2
= strchrW(ptr
,'=');
247 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
254 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
255 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
265 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
278 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
279 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
282 if (lstrlenW(prop
) > 0)
284 TRACE("Found commandline property (%s) = (%s)\n",
285 debugstr_w(prop
), debugstr_w(val
));
286 MSI_SetPropertyW(package
,prop
,val
);
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
, 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
, 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
, 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
, szPatch
);
484 MSI_SetPropertyW(package
, prop
, patch
);
489 if (rec
) msiobj_release(&rec
->hdr
);
490 msiobj_release(&view
->hdr
);
495 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
498 LPWSTR str
, *substorage
;
499 UINT i
, r
= ERROR_SUCCESS
;
501 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
503 return ERROR_FUNCTION_FAILED
;
505 if (msi_check_patch_applicable( package
, si
) != ERROR_SUCCESS
)
507 TRACE("Patch not applicable\n");
508 return ERROR_SUCCESS
;
511 package
->patch
= msi_alloc(sizeof(MSIPATCHINFO
));
513 return ERROR_OUTOFMEMORY
;
515 package
->patch
->patchcode
= msi_suminfo_dup_string(si
, PID_REVNUMBER
);
516 if (!package
->patch
->patchcode
)
517 return ERROR_OUTOFMEMORY
;
519 /* enumerate the substorage */
520 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
521 package
->patch
->transforms
= str
;
523 substorage
= msi_split_string( str
, ';' );
524 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
525 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
527 msi_free( substorage
);
528 msiobj_release( &si
->hdr
);
530 msi_set_media_source_prop(package
);
535 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
537 MSIDATABASE
*patch_db
= NULL
;
540 TRACE("%p %s\n", package
, debugstr_w( file
) );
543 * We probably want to make sure we only open a patch collection here.
544 * Patch collections (.msp) and databases (.msi) have different GUIDs
545 * but currently MSI_OpenDatabaseW will accept both.
547 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
548 if ( r
!= ERROR_SUCCESS
)
550 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
554 msi_parse_patch_summary( package
, patch_db
);
557 * There might be a CAB file in the patch package,
558 * so append it to the list of storage to search for streams.
560 append_storage_to_db( package
->db
, patch_db
->storage
);
562 msiobj_release( &patch_db
->hdr
);
564 return ERROR_SUCCESS
;
567 /* get the PATCH property, and apply all the patches it specifies */
568 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
570 LPWSTR patch_list
, *patches
;
571 UINT i
, r
= ERROR_SUCCESS
;
573 patch_list
= msi_dup_property( package
, szPatch
);
575 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
577 patches
= msi_split_string( patch_list
, ';' );
578 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
579 r
= msi_apply_patch_package( package
, patches
[i
] );
582 msi_free( patch_list
);
587 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
589 static const WCHAR szTransforms
[] = {
590 'T','R','A','N','S','F','O','R','M','S',0 };
591 LPWSTR xform_list
, *xforms
;
592 UINT i
, r
= ERROR_SUCCESS
;
594 xform_list
= msi_dup_property( package
, szTransforms
);
595 xforms
= msi_split_string( xform_list
, ';' );
597 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
599 if (xforms
[i
][0] == ':')
600 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
602 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
606 msi_free( xform_list
);
611 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
616 static const WCHAR ExecSeqQuery
[] =
617 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
618 '`','I','n','s','t','a','l','l',
619 'U','I','S','e','q','u','e','n','c','e','`',
620 ' ','W','H','E','R','E',' ',
621 '`','S','e','q','u','e','n','c','e','`',' ',
622 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
623 '`','S','e','q','u','e','n','c','e','`',0};
625 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
626 if (rc
== ERROR_SUCCESS
)
628 msiobj_release(&view
->hdr
);
635 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
638 LPWSTR source
, check
;
641 static const WCHAR szOriginalDatabase
[] =
642 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
644 db
= msi_dup_property( package
, szOriginalDatabase
);
646 return ERROR_OUTOFMEMORY
;
648 p
= strrchrW( db
, '\\' );
651 p
= strrchrW( db
, '/' );
655 return ERROR_SUCCESS
;
660 source
= msi_alloc( len
* sizeof(WCHAR
) );
661 lstrcpynW( source
, db
, len
);
663 check
= msi_dup_property( package
, cszSourceDir
);
664 if (!check
|| replace
)
665 MSI_SetPropertyW( package
, cszSourceDir
, source
);
669 check
= msi_dup_property( package
, cszSOURCEDIR
);
670 if (!check
|| replace
)
671 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
677 return ERROR_SUCCESS
;
680 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
682 INT level
= msi_get_property_int(package
, szUILevel
, 0);
683 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
686 static UINT
msi_set_context(MSIPACKAGE
*package
)
693 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
695 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
696 if (r
== ERROR_SUCCESS
)
699 if (num
== 1 || num
== 2)
700 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
703 return ERROR_SUCCESS
;
706 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
709 LPCWSTR cond
, action
;
710 MSIPACKAGE
*package
= param
;
712 action
= MSI_RecordGetString(row
,1);
715 ERR("Error is retrieving action name\n");
716 return ERROR_FUNCTION_FAILED
;
719 /* check conditions */
720 cond
= MSI_RecordGetString(row
,2);
722 /* this is a hack to skip errors in the condition code */
723 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
725 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
726 return ERROR_SUCCESS
;
729 if (needs_ui_sequence(package
))
730 rc
= ACTION_PerformUIAction(package
, action
, -1);
732 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
734 msi_dialog_check_messages( NULL
);
736 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
737 rc
= package
->CurrentInstallState
;
739 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
742 if (rc
!= ERROR_SUCCESS
)
743 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
748 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
752 static const WCHAR query
[] =
753 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
755 ' ','W','H','E','R','E',' ',
756 '`','S','e','q','u','e','n','c','e','`',' ',
757 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
758 '`','S','e','q','u','e','n','c','e','`',0};
760 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
762 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
763 if (r
== ERROR_SUCCESS
)
765 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
766 msiobj_release(&view
->hdr
);
772 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
776 static const WCHAR ExecSeqQuery
[] =
777 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
778 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
779 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
780 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
781 'O','R','D','E','R',' ', 'B','Y',' ',
782 '`','S','e','q','u','e','n','c','e','`',0 };
783 static const WCHAR IVQuery
[] =
784 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
785 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
786 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
787 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
788 ' ','\'', 'I','n','s','t','a','l','l',
789 'V','a','l','i','d','a','t','e','\'', 0};
792 if (package
->script
->ExecuteSequenceRun
)
794 TRACE("Execute Sequence already Run\n");
795 return ERROR_SUCCESS
;
798 package
->script
->ExecuteSequenceRun
= TRUE
;
800 /* get the sequence number */
803 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
805 return ERROR_FUNCTION_FAILED
;
806 seq
= MSI_RecordGetInteger(row
,1);
807 msiobj_release(&row
->hdr
);
810 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
811 if (rc
== ERROR_SUCCESS
)
813 TRACE("Running the actions\n");
815 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
816 msiobj_release(&view
->hdr
);
822 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
826 static const WCHAR ExecSeqQuery
[] =
827 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
828 '`','I','n','s','t','a','l','l',
829 'U','I','S','e','q','u','e','n','c','e','`',
830 ' ','W','H','E','R','E',' ',
831 '`','S','e','q','u','e','n','c','e','`',' ',
832 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
833 '`','S','e','q','u','e','n','c','e','`',0};
835 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
836 if (rc
== ERROR_SUCCESS
)
838 TRACE("Running the actions\n");
840 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
841 msiobj_release(&view
->hdr
);
847 /********************************************************
848 * ACTION helper functions and functions that perform the actions
849 *******************************************************/
850 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
851 UINT
* rc
, UINT script
, BOOL force
)
856 arc
= ACTION_CustomAction(package
, action
, script
, force
);
858 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
867 * Actual Action Handlers
870 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
872 MSIPACKAGE
*package
= param
;
873 LPCWSTR dir
, component
;
879 component
= MSI_RecordGetString(row
, 2);
880 comp
= get_loaded_component(package
, component
);
882 return ERROR_SUCCESS
;
884 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
886 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
887 comp
->Action
= comp
->Installed
;
888 return ERROR_SUCCESS
;
890 comp
->Action
= INSTALLSTATE_LOCAL
;
892 dir
= MSI_RecordGetString(row
,1);
895 ERR("Unable to get folder id\n");
896 return ERROR_SUCCESS
;
899 uirow
= MSI_CreateRecord(1);
900 MSI_RecordSetStringW(uirow
, 1, dir
);
901 ui_actiondata(package
, szCreateFolders
, uirow
);
902 msiobj_release(&uirow
->hdr
);
904 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
907 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
908 return ERROR_SUCCESS
;
911 TRACE("Folder is %s\n",debugstr_w(full_path
));
913 if (folder
->State
== 0)
914 create_full_pathW(full_path
);
919 return ERROR_SUCCESS
;
922 /* FIXME: probably should merge this with the above function */
923 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
925 UINT rc
= ERROR_SUCCESS
;
929 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
931 return ERROR_FUNCTION_FAILED
;
933 /* create the path */
934 if (folder
->State
== 0)
936 create_full_pathW(install_path
);
939 msi_free(install_path
);
944 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
948 /* create all the folders required by the components are going to install */
949 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
951 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
953 msi_create_directory( package
, comp
->Directory
);
956 return ERROR_SUCCESS
;
959 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
961 static const WCHAR ExecSeqQuery
[] =
962 {'S','E','L','E','C','T',' ',
963 '`','D','i','r','e','c','t','o','r','y','_','`',
964 ' ','F','R','O','M',' ',
965 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
969 /* create all the empty folders specified in the CreateFolder table */
970 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
971 if (rc
!= ERROR_SUCCESS
)
972 return ERROR_SUCCESS
;
974 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
975 msiobj_release(&view
->hdr
);
980 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
982 MSIPACKAGE
*package
= param
;
983 LPCWSTR dir
, component
;
989 component
= MSI_RecordGetString(row
, 2);
990 comp
= get_loaded_component(package
, component
);
992 return ERROR_SUCCESS
;
994 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
996 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
997 comp
->Action
= comp
->Installed
;
998 return ERROR_SUCCESS
;
1000 comp
->Action
= INSTALLSTATE_ABSENT
;
1002 dir
= MSI_RecordGetString( row
, 1 );
1005 ERR("Unable to get folder id\n");
1006 return ERROR_SUCCESS
;
1009 full_path
= resolve_folder( package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1012 ERR("Unable to resolve folder id %s\n", debugstr_w(dir
));
1013 return ERROR_SUCCESS
;
1016 TRACE("folder is %s\n", debugstr_w(full_path
));
1018 uirow
= MSI_CreateRecord( 1 );
1019 MSI_RecordSetStringW( uirow
, 1, full_path
);
1020 ui_actiondata( package
, szRemoveFolders
, uirow
);
1021 msiobj_release( &uirow
->hdr
);
1023 RemoveDirectoryW( full_path
);
1026 msi_free( full_path
);
1027 return ERROR_SUCCESS
;
1030 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1032 static const WCHAR query
[] =
1033 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1034 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1039 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1040 if (rc
!= ERROR_SUCCESS
)
1041 return ERROR_SUCCESS
;
1043 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1044 msiobj_release( &view
->hdr
);
1049 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1051 MSIPACKAGE
*package
= param
;
1054 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1056 return ERROR_FUNCTION_FAILED
;
1058 list_add_tail( &package
->components
, &comp
->entry
);
1060 /* fill in the data */
1061 comp
->Component
= msi_dup_record_field( row
, 1 );
1063 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1065 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1066 comp
->Directory
= msi_dup_record_field( row
, 3 );
1067 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1068 comp
->Condition
= msi_dup_record_field( row
, 5 );
1069 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1071 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1072 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1074 return ERROR_SUCCESS
;
1077 static UINT
load_all_components( MSIPACKAGE
*package
)
1079 static const WCHAR query
[] = {
1080 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1081 '`','C','o','m','p','o','n','e','n','t','`',0 };
1085 if (!list_empty(&package
->components
))
1086 return ERROR_SUCCESS
;
1088 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1089 if (r
!= ERROR_SUCCESS
)
1092 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1093 msiobj_release(&view
->hdr
);
1098 MSIPACKAGE
*package
;
1099 MSIFEATURE
*feature
;
1102 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1106 cl
= msi_alloc( sizeof (*cl
) );
1108 return ERROR_NOT_ENOUGH_MEMORY
;
1109 cl
->component
= comp
;
1110 list_add_tail( &feature
->Components
, &cl
->entry
);
1112 return ERROR_SUCCESS
;
1115 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1119 fl
= msi_alloc( sizeof(*fl
) );
1121 return ERROR_NOT_ENOUGH_MEMORY
;
1122 fl
->feature
= child
;
1123 list_add_tail( &parent
->Children
, &fl
->entry
);
1125 return ERROR_SUCCESS
;
1128 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1130 _ilfs
* ilfs
= param
;
1134 component
= MSI_RecordGetString(row
,1);
1136 /* check to see if the component is already loaded */
1137 comp
= get_loaded_component( ilfs
->package
, component
);
1140 ERR("unknown component %s\n", debugstr_w(component
));
1141 return ERROR_FUNCTION_FAILED
;
1144 add_feature_component( ilfs
->feature
, comp
);
1145 comp
->Enabled
= TRUE
;
1147 return ERROR_SUCCESS
;
1150 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1152 MSIFEATURE
*feature
;
1157 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1159 if ( !lstrcmpW( feature
->Feature
, name
) )
1166 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1168 MSIPACKAGE
* package
= param
;
1169 MSIFEATURE
* feature
;
1170 static const WCHAR Query1
[] =
1171 {'S','E','L','E','C','T',' ',
1172 '`','C','o','m','p','o','n','e','n','t','_','`',
1173 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1174 'C','o','m','p','o','n','e','n','t','s','`',' ',
1175 'W','H','E','R','E',' ',
1176 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1181 /* fill in the data */
1183 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1185 return ERROR_NOT_ENOUGH_MEMORY
;
1187 list_init( &feature
->Children
);
1188 list_init( &feature
->Components
);
1190 feature
->Feature
= msi_dup_record_field( row
, 1 );
1192 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1194 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1195 feature
->Title
= msi_dup_record_field( row
, 3 );
1196 feature
->Description
= msi_dup_record_field( row
, 4 );
1198 if (!MSI_RecordIsNull(row
,5))
1199 feature
->Display
= MSI_RecordGetInteger(row
,5);
1201 feature
->Level
= MSI_RecordGetInteger(row
,6);
1202 feature
->Directory
= msi_dup_record_field( row
, 7 );
1203 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1205 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1206 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1208 list_add_tail( &package
->features
, &feature
->entry
);
1210 /* load feature components */
1212 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1213 if (rc
!= ERROR_SUCCESS
)
1214 return ERROR_SUCCESS
;
1216 ilfs
.package
= package
;
1217 ilfs
.feature
= feature
;
1219 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1220 msiobj_release(&view
->hdr
);
1222 return ERROR_SUCCESS
;
1225 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1227 MSIPACKAGE
* package
= param
;
1228 MSIFEATURE
*parent
, *child
;
1230 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1232 return ERROR_FUNCTION_FAILED
;
1234 if (!child
->Feature_Parent
)
1235 return ERROR_SUCCESS
;
1237 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1239 return ERROR_FUNCTION_FAILED
;
1241 add_feature_child( parent
, child
);
1242 return ERROR_SUCCESS
;
1245 static UINT
load_all_features( MSIPACKAGE
*package
)
1247 static const WCHAR query
[] = {
1248 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1249 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1250 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1254 if (!list_empty(&package
->features
))
1255 return ERROR_SUCCESS
;
1257 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1258 if (r
!= ERROR_SUCCESS
)
1261 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1262 if (r
!= ERROR_SUCCESS
)
1265 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1266 msiobj_release( &view
->hdr
);
1271 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1282 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1284 static const WCHAR query
[] = {
1285 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1286 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1287 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1288 MSIQUERY
*view
= NULL
;
1289 MSIRECORD
*row
= NULL
;
1292 TRACE("%s\n", debugstr_w(file
->File
));
1294 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1295 if (r
!= ERROR_SUCCESS
)
1298 r
= MSI_ViewExecute(view
, NULL
);
1299 if (r
!= ERROR_SUCCESS
)
1302 r
= MSI_ViewFetch(view
, &row
);
1303 if (r
!= ERROR_SUCCESS
)
1306 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1307 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1308 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1309 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1310 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1313 if (view
) msiobj_release(&view
->hdr
);
1314 if (row
) msiobj_release(&row
->hdr
);
1318 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1320 MSIPACKAGE
* package
= param
;
1324 /* fill in the data */
1326 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1328 return ERROR_NOT_ENOUGH_MEMORY
;
1330 file
->File
= msi_dup_record_field( row
, 1 );
1332 component
= MSI_RecordGetString( row
, 2 );
1333 file
->Component
= get_loaded_component( package
, component
);
1335 if (!file
->Component
)
1337 WARN("Component not found: %s\n", debugstr_w(component
));
1338 msi_free(file
->File
);
1340 return ERROR_SUCCESS
;
1343 file
->FileName
= msi_dup_record_field( row
, 3 );
1344 reduce_to_longfilename( file
->FileName
);
1346 file
->ShortName
= msi_dup_record_field( row
, 3 );
1347 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1349 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1350 file
->Version
= msi_dup_record_field( row
, 5 );
1351 file
->Language
= msi_dup_record_field( row
, 6 );
1352 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1353 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1355 file
->state
= msifs_invalid
;
1357 /* if the compressed bits are not set in the file attributes,
1358 * then read the information from the package word count property
1360 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1362 file
->IsCompressed
= FALSE
;
1364 else if (file
->Attributes
&
1365 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1367 file
->IsCompressed
= TRUE
;
1369 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1371 file
->IsCompressed
= FALSE
;
1375 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1378 load_file_hash(package
, file
);
1380 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1382 list_add_tail( &package
->files
, &file
->entry
);
1384 return ERROR_SUCCESS
;
1387 static UINT
load_all_files(MSIPACKAGE
*package
)
1391 static const WCHAR Query
[] =
1392 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1393 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1394 '`','S','e','q','u','e','n','c','e','`', 0};
1396 if (!list_empty(&package
->files
))
1397 return ERROR_SUCCESS
;
1399 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1400 if (rc
!= ERROR_SUCCESS
)
1401 return ERROR_SUCCESS
;
1403 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1404 msiobj_release(&view
->hdr
);
1406 return ERROR_SUCCESS
;
1409 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1411 MSIPACKAGE
*package
= param
;
1412 static WCHAR szEmpty
[] = { 0 };
1413 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1416 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1418 return ERROR_NOT_ENOUGH_MEMORY
;
1420 folder
->Directory
= msi_dup_record_field( row
, 1 );
1422 TRACE("%s\n", debugstr_w(folder
->Directory
));
1424 p
= msi_dup_record_field(row
, 3);
1426 /* split src and target dir */
1428 src_short
= folder_split_path( p
, ':' );
1430 /* split the long and short paths */
1431 tgt_long
= folder_split_path( tgt_short
, '|' );
1432 src_long
= folder_split_path( src_short
, '|' );
1434 /* check for no-op dirs */
1435 if (!lstrcmpW(szDot
, tgt_short
))
1436 tgt_short
= szEmpty
;
1437 if (!lstrcmpW(szDot
, src_short
))
1438 src_short
= szEmpty
;
1441 tgt_long
= tgt_short
;
1444 src_short
= tgt_short
;
1445 src_long
= tgt_long
;
1449 src_long
= src_short
;
1451 /* FIXME: use the target short path too */
1452 folder
->TargetDefault
= strdupW(tgt_long
);
1453 folder
->SourceShortPath
= strdupW(src_short
);
1454 folder
->SourceLongPath
= strdupW(src_long
);
1457 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1458 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1459 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1461 folder
->Parent
= msi_dup_record_field( row
, 2 );
1463 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1465 list_add_tail( &package
->folders
, &folder
->entry
);
1467 TRACE("returning %p\n", folder
);
1469 return ERROR_SUCCESS
;
1472 static UINT
load_all_folders( MSIPACKAGE
*package
)
1474 static const WCHAR query
[] = {
1475 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1476 '`','D','i','r','e','c','t','o','r','y','`',0 };
1480 if (!list_empty(&package
->folders
))
1481 return ERROR_SUCCESS
;
1483 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1484 if (r
!= ERROR_SUCCESS
)
1487 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1488 msiobj_release(&view
->hdr
);
1493 * I am not doing any of the costing functionality yet.
1494 * Mostly looking at doing the Component and Feature loading
1496 * The native MSI does A LOT of modification to tables here. Mostly adding
1497 * a lot of temporary columns to the Feature and Component tables.
1499 * note: Native msi also tracks the short filename. But I am only going to
1500 * track the long ones. Also looking at this directory table
1501 * it appears that the directory table does not get the parents
1502 * resolved base on property only based on their entries in the
1505 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1507 static const WCHAR szCosting
[] =
1508 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1510 MSI_SetPropertyW(package
, szCosting
, szZero
);
1511 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1513 load_all_folders( package
);
1514 load_all_components( package
);
1515 load_all_features( package
);
1516 load_all_files( package
);
1518 return ERROR_SUCCESS
;
1521 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1524 UINT rc
= ERROR_SUCCESS
;
1526 TRACE("Executing Script %i\n",script
);
1528 if (!package
->script
)
1530 ERR("no script!\n");
1531 return ERROR_FUNCTION_FAILED
;
1534 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1537 action
= package
->script
->Actions
[script
][i
];
1538 ui_actionstart(package
, action
);
1539 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1540 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1541 if (rc
!= ERROR_SUCCESS
)
1544 msi_free_action_script(package
, script
);
1548 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1550 return ERROR_SUCCESS
;
1553 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1559 state
= MsiQueryProductStateW(package
->ProductCode
);
1561 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1563 if (!comp
->ComponentId
)
1566 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1567 comp
->Installed
= INSTALLSTATE_ABSENT
;
1570 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1571 package
->Context
, comp
->ComponentId
,
1573 if (r
!= ERROR_SUCCESS
)
1574 comp
->Installed
= INSTALLSTATE_ABSENT
;
1579 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1581 MSIFEATURE
*feature
;
1584 state
= MsiQueryProductStateW(package
->ProductCode
);
1586 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1588 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1589 feature
->Installed
= INSTALLSTATE_ABSENT
;
1592 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1598 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1599 LPCWSTR property
, INSTALLSTATE state
)
1602 MSIFEATURE
*feature
;
1604 override
= msi_dup_property( package
, property
);
1608 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1610 if (lstrcmpW(property
, szRemove
) &&
1611 (feature
->Level
<= 0 || feature
->Level
> level
))
1614 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1616 if (strcmpiW(override
, szAll
)==0)
1617 msi_feature_set_state(package
, feature
, state
);
1620 LPWSTR ptr
= override
;
1621 LPWSTR ptr2
= strchrW(override
,',');
1625 int len
= ptr2
- ptr
;
1627 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1628 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1630 msi_feature_set_state(package
, feature
, state
);
1636 ptr2
= strchrW(ptr
,',');
1648 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
1650 static const WCHAR szAddLocal
[] =
1651 {'A','D','D','L','O','C','A','L',0};
1652 static const WCHAR szAddSource
[] =
1653 {'A','D','D','S','O','U','R','C','E',0};
1654 static const WCHAR szAdvertise
[] =
1655 {'A','D','V','E','R','T','I','S','E',0};
1658 /* all these activation/deactivation things happen in order and things
1659 * later on the list override things earlier on the list.
1661 * 0 INSTALLLEVEL processing
1674 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1675 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1676 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1677 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1678 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1681 MSI_SetPropertyW( package
, szPreselected
, szOne
);
1686 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1689 static const WCHAR szlevel
[] =
1690 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1691 MSICOMPONENT
* component
;
1692 MSIFEATURE
*feature
;
1694 TRACE("Checking Install Level\n");
1696 level
= msi_get_property_int(package
, szlevel
, 1);
1698 if (!msi_get_property_int( package
, szPreselected
, 0 ))
1700 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1702 BOOL feature_state
= ((feature
->Level
> 0) &&
1703 (feature
->Level
<= level
));
1705 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1707 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1708 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1709 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1710 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1712 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1716 /* disable child features of unselected parent features */
1717 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1721 if (feature
->Level
> 0 && feature
->Level
<= level
)
1724 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1725 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1730 * now we want to enable or disable components base on feature
1733 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1737 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1738 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1740 if (!feature
->Level
)
1743 /* features with components that have compressed files are made local */
1744 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1746 if (cl
->component
->Enabled
&&
1747 cl
->component
->ForceLocalState
&&
1748 feature
->Action
== INSTALLSTATE_SOURCE
)
1750 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1755 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1757 component
= cl
->component
;
1759 if (!component
->Enabled
)
1762 switch (feature
->Action
)
1764 case INSTALLSTATE_ABSENT
:
1765 component
->anyAbsent
= 1;
1767 case INSTALLSTATE_ADVERTISED
:
1768 component
->hasAdvertiseFeature
= 1;
1770 case INSTALLSTATE_SOURCE
:
1771 component
->hasSourceFeature
= 1;
1773 case INSTALLSTATE_LOCAL
:
1774 component
->hasLocalFeature
= 1;
1776 case INSTALLSTATE_DEFAULT
:
1777 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1778 component
->hasAdvertiseFeature
= 1;
1779 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1780 component
->hasSourceFeature
= 1;
1782 component
->hasLocalFeature
= 1;
1790 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1792 /* if the component isn't enabled, leave it alone */
1793 if (!component
->Enabled
)
1796 /* check if it's local or source */
1797 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1798 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1800 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1801 !component
->ForceLocalState
)
1802 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1804 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1808 /* if any feature is local, the component must be local too */
1809 if (component
->hasLocalFeature
)
1811 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1815 if (component
->hasSourceFeature
)
1817 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1821 if (component
->hasAdvertiseFeature
)
1823 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1827 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1828 if (component
->anyAbsent
)
1829 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1832 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1834 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1836 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1837 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1840 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1841 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1845 return ERROR_SUCCESS
;
1848 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1850 MSIPACKAGE
*package
= param
;
1855 name
= MSI_RecordGetString(row
,1);
1857 f
= get_loaded_folder(package
, name
);
1858 if (!f
) return ERROR_SUCCESS
;
1860 /* reset the ResolvedTarget */
1861 msi_free(f
->ResolvedTarget
);
1862 f
->ResolvedTarget
= NULL
;
1864 /* This helper function now does ALL the work */
1865 TRACE("Dir %s ...\n",debugstr_w(name
));
1866 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1867 TRACE("resolves to %s\n",debugstr_w(path
));
1870 return ERROR_SUCCESS
;
1873 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1875 MSIPACKAGE
*package
= param
;
1877 MSIFEATURE
*feature
;
1879 name
= MSI_RecordGetString( row
, 1 );
1881 feature
= get_loaded_feature( package
, name
);
1883 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1887 Condition
= MSI_RecordGetString(row
,3);
1889 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1891 int level
= MSI_RecordGetInteger(row
,2);
1892 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1893 feature
->Level
= level
;
1896 return ERROR_SUCCESS
;
1899 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1901 static const WCHAR name_fmt
[] =
1902 {'%','u','.','%','u','.','%','u','.','%','u',0};
1903 static const WCHAR name
[] = {'\\',0};
1904 VS_FIXEDFILEINFO
*lpVer
;
1905 WCHAR filever
[0x100];
1911 TRACE("%s\n", debugstr_w(filename
));
1913 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1917 version
= msi_alloc( versize
);
1918 GetFileVersionInfoW( filename
, 0, versize
, version
);
1920 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1922 msi_free( version
);
1926 sprintfW( filever
, name_fmt
,
1927 HIWORD(lpVer
->dwFileVersionMS
),
1928 LOWORD(lpVer
->dwFileVersionMS
),
1929 HIWORD(lpVer
->dwFileVersionLS
),
1930 LOWORD(lpVer
->dwFileVersionLS
));
1932 msi_free( version
);
1934 return strdupW( filever
);
1937 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1939 LPWSTR file_version
;
1942 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1944 MSICOMPONENT
* comp
= file
->Component
;
1950 if (file
->IsCompressed
)
1951 comp
->ForceLocalState
= TRUE
;
1953 /* calculate target */
1954 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
1956 msi_free(file
->TargetPath
);
1958 TRACE("file %s is named %s\n",
1959 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
1961 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1965 TRACE("file %s resolves to %s\n",
1966 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
1968 /* don't check files of components that aren't installed */
1969 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
1970 comp
->Installed
== INSTALLSTATE_ABSENT
)
1972 file
->state
= msifs_missing
; /* assume files are missing */
1976 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1978 file
->state
= msifs_missing
;
1979 comp
->Cost
+= file
->FileSize
;
1983 if (file
->Version
&&
1984 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
1986 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1987 debugstr_w(file_version
));
1988 /* FIXME: seems like a bad way to compare version numbers */
1989 if (lstrcmpiW(file_version
, file
->Version
)<0)
1991 file
->state
= msifs_overwrite
;
1992 comp
->Cost
+= file
->FileSize
;
1995 file
->state
= msifs_present
;
1996 msi_free( file_version
);
1999 file
->state
= msifs_present
;
2002 return ERROR_SUCCESS
;
2006 * A lot is done in this function aside from just the costing.
2007 * The costing needs to be implemented at some point but for now I am going
2008 * to focus on the directory building
2011 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2013 static const WCHAR ExecSeqQuery
[] =
2014 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2015 '`','D','i','r','e','c','t','o','r','y','`',0};
2016 static const WCHAR ConditionQuery
[] =
2017 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2018 '`','C','o','n','d','i','t','i','o','n','`',0};
2019 static const WCHAR szCosting
[] =
2020 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2021 static const WCHAR szlevel
[] =
2022 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2023 static const WCHAR szOutOfDiskSpace
[] =
2024 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2026 UINT rc
= ERROR_SUCCESS
;
2030 TRACE("Building Directory properties\n");
2032 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2033 if (rc
== ERROR_SUCCESS
)
2035 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2037 msiobj_release(&view
->hdr
);
2040 /* read components states from the registry */
2041 ACTION_GetComponentInstallStates(package
);
2042 ACTION_GetFeatureInstallStates(package
);
2044 TRACE("File calculations\n");
2045 msi_check_file_install_states( package
);
2047 if (!process_overrides( package
, msi_get_property_int( package
, szlevel
, 1 ) ))
2049 TRACE("Evaluating Condition Table\n");
2051 rc
= MSI_DatabaseOpenViewW( package
->db
, ConditionQuery
, &view
);
2052 if (rc
== ERROR_SUCCESS
)
2054 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
2055 msiobj_release( &view
->hdr
);
2058 TRACE("Enabling or Disabling Components\n");
2059 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2061 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
2063 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2064 comp
->Enabled
= FALSE
;
2067 comp
->Enabled
= TRUE
;
2071 MSI_SetPropertyW(package
,szCosting
,szOne
);
2072 /* set default run level if not set */
2073 level
= msi_dup_property( package
, szlevel
);
2075 MSI_SetPropertyW(package
,szlevel
, szOne
);
2078 /* FIXME: check volume disk space */
2079 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2081 return MSI_SetFeatureStates(package
);
2084 /* OK this value is "interpreted" and then formatted based on the
2085 first few characters */
2086 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2091 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2097 LPWSTR deformated
= NULL
;
2100 deformat_string(package
, &value
[2], &deformated
);
2102 /* binary value type */
2106 *size
= (strlenW(ptr
)/2)+1;
2108 *size
= strlenW(ptr
)/2;
2110 data
= msi_alloc(*size
);
2116 /* if uneven pad with a zero in front */
2122 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2124 TRACE("Uneven byte count\n");
2132 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2135 msi_free(deformated
);
2137 TRACE("Data %i bytes(%i)\n",*size
,count
);
2144 deformat_string(package
, &value
[1], &deformated
);
2147 *size
= sizeof(DWORD
);
2148 data
= msi_alloc(*size
);
2154 if ( (*p
< '0') || (*p
> '9') )
2160 if (deformated
[0] == '-')
2163 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2165 msi_free(deformated
);
2170 static const WCHAR szMulti
[] = {'[','~',']',0};
2179 *type
=REG_EXPAND_SZ
;
2187 if (strstrW(value
,szMulti
))
2188 *type
= REG_MULTI_SZ
;
2190 /* remove initial delimiter */
2191 if (!strncmpW(value
, szMulti
, 3))
2194 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2196 /* add double NULL terminator */
2197 if (*type
== REG_MULTI_SZ
)
2199 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2200 data
= msi_realloc_zero(data
, *size
);
2206 static const WCHAR
*get_root_key( MSIPACKAGE
*package
, INT root
, HKEY
*root_key
)
2213 if (msi_get_property_int( package
, szAllUsers
, 0 ))
2215 *root_key
= HKEY_LOCAL_MACHINE
;
2220 *root_key
= HKEY_CURRENT_USER
;
2225 *root_key
= HKEY_CLASSES_ROOT
;
2229 *root_key
= HKEY_CURRENT_USER
;
2233 *root_key
= HKEY_LOCAL_MACHINE
;
2237 *root_key
= HKEY_USERS
;
2241 ERR("Unknown root %i\n", root
);
2248 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2250 MSIPACKAGE
*package
= param
;
2251 LPSTR value_data
= NULL
;
2252 HKEY root_key
, hkey
;
2255 LPCWSTR szRoot
, component
, name
, key
, value
;
2260 BOOL check_first
= FALSE
;
2263 ui_progress(package
,2,0,0,0);
2270 component
= MSI_RecordGetString(row
, 6);
2271 comp
= get_loaded_component(package
,component
);
2273 return ERROR_SUCCESS
;
2275 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2277 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2278 comp
->Action
= comp
->Installed
;
2279 return ERROR_SUCCESS
;
2281 comp
->Action
= INSTALLSTATE_LOCAL
;
2283 name
= MSI_RecordGetString(row
, 4);
2284 if( MSI_RecordIsNull(row
,5) && name
)
2286 /* null values can have special meanings */
2287 if (name
[0]=='-' && name
[1] == 0)
2288 return ERROR_SUCCESS
;
2289 else if ((name
[0]=='+' && name
[1] == 0) ||
2290 (name
[0] == '*' && name
[1] == 0))
2295 root
= MSI_RecordGetInteger(row
,2);
2296 key
= MSI_RecordGetString(row
, 3);
2298 szRoot
= get_root_key( package
, root
, &root_key
);
2300 return ERROR_SUCCESS
;
2302 deformat_string(package
, key
, &deformated
);
2303 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2304 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2305 strcpyW(uikey
,szRoot
);
2306 strcatW(uikey
,deformated
);
2308 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2310 ERR("Could not create key %s\n",debugstr_w(deformated
));
2311 msi_free(deformated
);
2313 return ERROR_SUCCESS
;
2315 msi_free(deformated
);
2317 value
= MSI_RecordGetString(row
,5);
2319 value_data
= parse_value(package
, value
, &type
, &size
);
2322 value_data
= (LPSTR
)strdupW(szEmpty
);
2323 size
= sizeof(szEmpty
);
2327 deformat_string(package
, name
, &deformated
);
2331 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2333 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2338 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2339 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2341 TRACE("value %s of %s checked already exists\n",
2342 debugstr_w(deformated
), debugstr_w(uikey
));
2346 TRACE("Checked and setting value %s of %s\n",
2347 debugstr_w(deformated
), debugstr_w(uikey
));
2348 if (deformated
|| size
)
2349 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2354 uirow
= MSI_CreateRecord(3);
2355 MSI_RecordSetStringW(uirow
,2,deformated
);
2356 MSI_RecordSetStringW(uirow
,1,uikey
);
2357 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
)
2358 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2359 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2360 msiobj_release( &uirow
->hdr
);
2362 msi_free(value_data
);
2363 msi_free(deformated
);
2366 return ERROR_SUCCESS
;
2369 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2373 static const WCHAR ExecSeqQuery
[] =
2374 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2375 '`','R','e','g','i','s','t','r','y','`',0 };
2377 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2378 if (rc
!= ERROR_SUCCESS
)
2379 return ERROR_SUCCESS
;
2381 /* increment progress bar each time action data is sent */
2382 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2384 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2386 msiobj_release(&view
->hdr
);
2390 static void delete_reg_key_or_value( HKEY hkey_root
, LPCWSTR key
, LPCWSTR value
, BOOL delete_key
)
2394 DWORD num_subkeys
, num_values
;
2398 if ((res
= RegDeleteTreeW( hkey_root
, key
)))
2400 WARN("Failed to delete key %s (%d)\n", debugstr_w(key
), res
);
2405 if (!(res
= RegOpenKeyW( hkey_root
, key
, &hkey
)))
2407 if ((res
= RegDeleteValueW( hkey
, value
)))
2409 WARN("Failed to delete value %s (%d)\n", debugstr_w(value
), res
);
2411 res
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
, NULL
, &num_values
,
2412 NULL
, NULL
, NULL
, NULL
);
2413 RegCloseKey( hkey
);
2415 if (!res
&& !num_subkeys
&& !num_values
)
2417 TRACE("Removing empty key %s\n", debugstr_w(key
));
2418 RegDeleteKeyW( hkey_root
, key
);
2422 WARN("Failed to open key %s (%d)\n", debugstr_w(key
), res
);
2426 static UINT
ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
2428 MSIPACKAGE
*package
= param
;
2429 LPCWSTR component
, name
, key_str
, root_key_str
;
2430 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2433 BOOL delete_key
= FALSE
;
2438 ui_progress( package
, 2, 0, 0, 0 );
2440 component
= MSI_RecordGetString( row
, 6 );
2441 comp
= get_loaded_component( package
, component
);
2443 return ERROR_SUCCESS
;
2445 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2447 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
2448 comp
->Action
= comp
->Installed
;
2449 return ERROR_SUCCESS
;
2451 comp
->Action
= INSTALLSTATE_ABSENT
;
2453 name
= MSI_RecordGetString( row
, 4 );
2454 if (MSI_RecordIsNull( row
, 5 ) && name
)
2456 if (name
[0] == '+' && !name
[1])
2457 return ERROR_SUCCESS
;
2458 else if ((name
[0] == '-' && !name
[1]) || (name
[0] == '*' && !name
[1]))
2465 root
= MSI_RecordGetInteger( row
, 2 );
2466 key_str
= MSI_RecordGetString( row
, 3 );
2468 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2470 return ERROR_SUCCESS
;
2472 deformat_string( package
, key_str
, &deformated_key
);
2473 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2474 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2475 strcpyW( ui_key_str
, root_key_str
);
2476 strcatW( ui_key_str
, deformated_key
);
2478 deformat_string( package
, name
, &deformated_name
);
2480 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2481 msi_free( deformated_key
);
2483 uirow
= MSI_CreateRecord( 2 );
2484 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2485 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2487 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2488 msiobj_release( &uirow
->hdr
);
2490 msi_free( ui_key_str
);
2491 msi_free( deformated_name
);
2492 return ERROR_SUCCESS
;
2495 static UINT
ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
2497 MSIPACKAGE
*package
= param
;
2498 LPCWSTR component
, name
, key_str
, root_key_str
;
2499 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2502 BOOL delete_key
= FALSE
;
2507 ui_progress( package
, 2, 0, 0, 0 );
2509 component
= MSI_RecordGetString( row
, 5 );
2510 comp
= get_loaded_component( package
, component
);
2512 return ERROR_SUCCESS
;
2514 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2516 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2517 comp
->Action
= comp
->Installed
;
2518 return ERROR_SUCCESS
;
2520 comp
->Action
= INSTALLSTATE_LOCAL
;
2522 if ((name
= MSI_RecordGetString( row
, 4 )))
2524 if (name
[0] == '-' && !name
[1])
2531 root
= MSI_RecordGetInteger( row
, 2 );
2532 key_str
= MSI_RecordGetString( row
, 3 );
2534 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2536 return ERROR_SUCCESS
;
2538 deformat_string( package
, key_str
, &deformated_key
);
2539 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2540 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2541 strcpyW( ui_key_str
, root_key_str
);
2542 strcatW( ui_key_str
, deformated_key
);
2544 deformat_string( package
, name
, &deformated_name
);
2546 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2547 msi_free( deformated_key
);
2549 uirow
= MSI_CreateRecord( 2 );
2550 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2551 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2553 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2554 msiobj_release( &uirow
->hdr
);
2556 msi_free( ui_key_str
);
2557 msi_free( deformated_name
);
2558 return ERROR_SUCCESS
;
2561 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
2565 static const WCHAR registry_query
[] =
2566 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2567 '`','R','e','g','i','s','t','r','y','`',0 };
2568 static const WCHAR remove_registry_query
[] =
2569 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2570 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2572 /* increment progress bar each time action data is sent */
2573 ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
2575 rc
= MSI_DatabaseOpenViewW( package
->db
, registry_query
, &view
);
2576 if (rc
== ERROR_SUCCESS
)
2578 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnUninstall
, package
);
2579 msiobj_release( &view
->hdr
);
2580 if (rc
!= ERROR_SUCCESS
)
2584 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_registry_query
, &view
);
2585 if (rc
== ERROR_SUCCESS
)
2587 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnInstall
, package
);
2588 msiobj_release( &view
->hdr
);
2589 if (rc
!= ERROR_SUCCESS
)
2593 return ERROR_SUCCESS
;
2596 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2598 package
->script
->CurrentlyScripting
= TRUE
;
2600 return ERROR_SUCCESS
;
2604 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2609 static const WCHAR q1
[]=
2610 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2611 '`','R','e','g','i','s','t','r','y','`',0};
2614 MSIFEATURE
*feature
;
2617 TRACE("InstallValidate\n");
2619 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2620 if (rc
== ERROR_SUCCESS
)
2622 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2623 msiobj_release( &view
->hdr
);
2624 total
+= progress
* REG_PROGRESS_VALUE
;
2627 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2628 total
+= COMPONENT_PROGRESS_VALUE
;
2630 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2631 total
+= file
->FileSize
;
2633 ui_progress(package
,0,total
,0,0);
2635 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2637 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2638 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2639 feature
->ActionRequest
);
2642 return ERROR_SUCCESS
;
2645 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2647 MSIPACKAGE
* package
= param
;
2648 LPCWSTR cond
= NULL
;
2649 LPCWSTR message
= NULL
;
2652 static const WCHAR title
[]=
2653 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2655 cond
= MSI_RecordGetString(row
,1);
2657 r
= MSI_EvaluateConditionW(package
,cond
);
2658 if (r
== MSICONDITION_FALSE
)
2660 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2663 message
= MSI_RecordGetString(row
,2);
2664 deformat_string(package
,message
,&deformated
);
2665 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2666 msi_free(deformated
);
2669 return ERROR_INSTALL_FAILURE
;
2672 return ERROR_SUCCESS
;
2675 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2678 MSIQUERY
* view
= NULL
;
2679 static const WCHAR ExecSeqQuery
[] =
2680 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2681 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2683 TRACE("Checking launch conditions\n");
2685 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2686 if (rc
!= ERROR_SUCCESS
)
2687 return ERROR_SUCCESS
;
2689 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2690 msiobj_release(&view
->hdr
);
2695 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2699 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2701 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2703 MSIRECORD
* row
= 0;
2705 LPWSTR deformated
,buffer
,deformated_name
;
2707 static const WCHAR ExecSeqQuery
[] =
2708 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2709 '`','R','e','g','i','s','t','r','y','`',' ',
2710 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2711 ' ','=',' ' ,'\'','%','s','\'',0 };
2712 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2713 static const WCHAR fmt2
[]=
2714 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2716 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2720 root
= MSI_RecordGetInteger(row
,2);
2721 key
= MSI_RecordGetString(row
, 3);
2722 name
= MSI_RecordGetString(row
, 4);
2723 deformat_string(package
, key
, &deformated
);
2724 deformat_string(package
, name
, &deformated_name
);
2726 len
= strlenW(deformated
) + 6;
2727 if (deformated_name
)
2728 len
+=strlenW(deformated_name
);
2730 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2732 if (deformated_name
)
2733 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2735 sprintfW(buffer
,fmt
,root
,deformated
);
2737 msi_free(deformated
);
2738 msi_free(deformated_name
);
2739 msiobj_release(&row
->hdr
);
2743 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2745 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2750 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2753 return strdupW( file
->TargetPath
);
2758 static HKEY
openSharedDLLsKey(void)
2761 static const WCHAR path
[] =
2762 {'S','o','f','t','w','a','r','e','\\',
2763 'M','i','c','r','o','s','o','f','t','\\',
2764 'W','i','n','d','o','w','s','\\',
2765 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2766 'S','h','a','r','e','d','D','L','L','s',0};
2768 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2772 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2777 DWORD sz
= sizeof(count
);
2780 hkey
= openSharedDLLsKey();
2781 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2782 if (rc
!= ERROR_SUCCESS
)
2788 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2792 hkey
= openSharedDLLsKey();
2794 msi_reg_set_val_dword( hkey
, path
, count
);
2796 RegDeleteValueW(hkey
,path
);
2802 * Return TRUE if the count should be written out and FALSE if not
2804 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2806 MSIFEATURE
*feature
;
2810 /* only refcount DLLs */
2811 if (comp
->KeyPath
== NULL
||
2812 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2813 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2817 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2818 write
= (count
> 0);
2820 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2824 /* increment counts */
2825 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2829 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2832 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2834 if ( cl
->component
== comp
)
2839 /* decrement counts */
2840 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2844 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2847 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2849 if ( cl
->component
== comp
)
2854 /* ref count all the files in the component */
2859 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2861 if (file
->Component
== comp
)
2862 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2866 /* add a count for permanent */
2867 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2870 comp
->RefCount
= count
;
2873 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2876 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2878 WCHAR squished_pc
[GUID_SIZE
];
2879 WCHAR squished_cc
[GUID_SIZE
];
2886 squash_guid(package
->ProductCode
,squished_pc
);
2887 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2889 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2893 ui_progress(package
,2,0,0,0);
2894 if (!comp
->ComponentId
)
2897 squash_guid(comp
->ComponentId
,squished_cc
);
2899 msi_free(comp
->FullKeypath
);
2900 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2902 ACTION_RefCountComponent( package
, comp
);
2904 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2905 debugstr_w(comp
->Component
),
2906 debugstr_w(squished_cc
),
2907 debugstr_w(comp
->FullKeypath
),
2910 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
||
2911 comp
->ActionRequest
== INSTALLSTATE_SOURCE
)
2913 if (!comp
->FullKeypath
)
2916 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2917 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2920 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2923 if (rc
!= ERROR_SUCCESS
)
2926 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2928 static const WCHAR szPermKey
[] =
2929 { '0','0','0','0','0','0','0','0','0','0','0','0',
2930 '0','0','0','0','0','0','0','0','0','0','0','0',
2931 '0','0','0','0','0','0','0','0',0 };
2933 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2936 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2937 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2943 WCHAR source
[MAX_PATH
];
2944 WCHAR base
[MAX_PATH
];
2947 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2948 static const WCHAR query
[] = {
2949 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2950 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2951 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2952 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2953 '`','D','i','s','k','I','d','`',0};
2955 file
= get_loaded_file(package
, comp
->KeyPath
);
2959 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2960 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2961 ptr2
= strrchrW(source
, '\\') + 1;
2962 msiobj_release(&row
->hdr
);
2964 lstrcpyW(base
, package
->PackagePath
);
2965 ptr
= strrchrW(base
, '\\');
2968 sourcepath
= resolve_file_source(package
, file
);
2969 ptr
= sourcepath
+ lstrlenW(base
);
2970 lstrcpyW(ptr2
, ptr
);
2971 msi_free(sourcepath
);
2973 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2977 else if (comp
->ActionRequest
== INSTALLSTATE_ABSENT
)
2979 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2980 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
2982 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
2984 comp
->Action
= comp
->ActionRequest
;
2987 uirow
= MSI_CreateRecord(3);
2988 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2989 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2990 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2991 ui_actiondata(package
,szProcessComponents
,uirow
);
2992 msiobj_release( &uirow
->hdr
);
2995 return ERROR_SUCCESS
;
3006 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
3007 LPWSTR lpszName
, LONG_PTR lParam
)
3010 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
3011 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
3015 if (!IS_INTRESOURCE(lpszName
))
3017 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
3021 sz
= strlenW(tl_struct
->source
)+4;
3022 sz
*= sizeof(WCHAR
);
3024 if ((INT_PTR
)lpszName
== 1)
3025 tl_struct
->path
= strdupW(tl_struct
->source
);
3028 tl_struct
->path
= msi_alloc(sz
);
3029 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
3032 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
3033 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
3036 msi_free(tl_struct
->path
);
3037 tl_struct
->path
= NULL
;
3042 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
3043 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
3045 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3049 msi_free(tl_struct
->path
);
3050 tl_struct
->path
= NULL
;
3052 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3053 ITypeLib_Release(tl_struct
->ptLib
);
3058 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3060 MSIPACKAGE
* package
= param
;
3064 typelib_struct tl_struct
;
3069 component
= MSI_RecordGetString(row
,3);
3070 comp
= get_loaded_component(package
,component
);
3072 return ERROR_SUCCESS
;
3074 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3076 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3077 comp
->Action
= comp
->Installed
;
3078 return ERROR_SUCCESS
;
3080 comp
->Action
= INSTALLSTATE_LOCAL
;
3082 file
= get_loaded_file( package
, comp
->KeyPath
);
3084 return ERROR_SUCCESS
;
3086 ui_actiondata( package
, szRegisterTypeLibraries
, row
);
3088 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3092 guid
= MSI_RecordGetString(row
,1);
3093 CLSIDFromString((LPCWSTR
)guid
, &tl_struct
.clsid
);
3094 tl_struct
.source
= strdupW( file
->TargetPath
);
3095 tl_struct
.path
= NULL
;
3097 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3098 (LONG_PTR
)&tl_struct
);
3106 helpid
= MSI_RecordGetString(row
,6);
3109 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3110 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3114 ERR("Failed to register type library %s\n",
3115 debugstr_w(tl_struct
.path
));
3117 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3119 ITypeLib_Release(tl_struct
.ptLib
);
3120 msi_free(tl_struct
.path
);
3123 ERR("Failed to load type library %s\n",
3124 debugstr_w(tl_struct
.source
));
3126 FreeLibrary(module
);
3127 msi_free(tl_struct
.source
);
3131 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3134 ERR("Failed to load type library: %08x\n", hr
);
3135 return ERROR_INSTALL_FAILURE
;
3138 ITypeLib_Release(tlib
);
3141 return ERROR_SUCCESS
;
3144 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3147 * OK this is a bit confusing.. I am given a _Component key and I believe
3148 * that the file that is being registered as a type library is the "key file
3149 * of that component" which I interpret to mean "The file in the KeyPath of
3154 static const WCHAR Query
[] =
3155 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3156 '`','T','y','p','e','L','i','b','`',0};
3158 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3159 if (rc
!= ERROR_SUCCESS
)
3160 return ERROR_SUCCESS
;
3162 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3163 msiobj_release(&view
->hdr
);
3167 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
3169 MSIPACKAGE
*package
= param
;
3170 LPCWSTR component
, guid
;
3178 component
= MSI_RecordGetString( row
, 3 );
3179 comp
= get_loaded_component( package
, component
);
3181 return ERROR_SUCCESS
;
3183 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3185 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3186 comp
->Action
= comp
->Installed
;
3187 return ERROR_SUCCESS
;
3189 comp
->Action
= INSTALLSTATE_ABSENT
;
3191 ui_actiondata( package
, szUnregisterTypeLibraries
, row
);
3193 guid
= MSI_RecordGetString( row
, 1 );
3194 CLSIDFromString( (LPCWSTR
)guid
, &libid
);
3195 version
= MSI_RecordGetInteger( row
, 4 );
3196 language
= MSI_RecordGetInteger( row
, 2 );
3199 syskind
= SYS_WIN64
;
3201 syskind
= SYS_WIN32
;
3204 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
3207 WARN("Failed to unregister typelib: %08x\n", hr
);
3210 return ERROR_SUCCESS
;
3213 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
3217 static const WCHAR query
[] =
3218 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3219 '`','T','y','p','e','L','i','b','`',0};
3221 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3222 if (rc
!= ERROR_SUCCESS
)
3223 return ERROR_SUCCESS
;
3225 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
3226 msiobj_release( &view
->hdr
);
3230 static WCHAR
*get_link_file( MSIPACKAGE
*package
, MSIRECORD
*row
)
3232 static const WCHAR szlnk
[] = {'.','l','n','k',0};
3233 LPCWSTR directory
, extension
;
3234 LPWSTR link_folder
, link_file
, filename
;
3236 directory
= MSI_RecordGetString( row
, 2 );
3237 link_folder
= resolve_folder( package
, directory
, FALSE
, FALSE
, TRUE
, NULL
);
3239 /* may be needed because of a bug somewhere else */
3240 create_full_pathW( link_folder
);
3242 filename
= msi_dup_record_field( row
, 3 );
3243 reduce_to_longfilename( filename
);
3245 extension
= strchrW( filename
, '.' );
3246 if (!extension
|| strcmpiW( extension
, szlnk
))
3248 int len
= strlenW( filename
);
3249 filename
= msi_realloc( filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
) );
3250 memcpy( filename
+ len
, szlnk
, sizeof(szlnk
) );
3252 link_file
= build_directory_name( 2, link_folder
, filename
);
3253 msi_free( link_folder
);
3254 msi_free( filename
);
3259 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3261 MSIPACKAGE
*package
= param
;
3262 LPWSTR link_file
, deformated
, path
;
3263 LPCWSTR component
, target
;
3265 IShellLinkW
*sl
= NULL
;
3266 IPersistFile
*pf
= NULL
;
3269 component
= MSI_RecordGetString(row
, 4);
3270 comp
= get_loaded_component(package
, component
);
3272 return ERROR_SUCCESS
;
3274 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3276 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3277 comp
->Action
= comp
->Installed
;
3278 return ERROR_SUCCESS
;
3280 comp
->Action
= INSTALLSTATE_LOCAL
;
3282 ui_actiondata(package
,szCreateShortcuts
,row
);
3284 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3285 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3289 ERR("CLSID_ShellLink not available\n");
3293 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3296 ERR("QueryInterface(IID_IPersistFile) failed\n");
3300 target
= MSI_RecordGetString(row
, 5);
3301 if (strchrW(target
, '['))
3303 deformat_string(package
, target
, &deformated
);
3304 IShellLinkW_SetPath(sl
,deformated
);
3305 msi_free(deformated
);
3309 FIXME("poorly handled shortcut format, advertised shortcut\n");
3310 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3313 if (!MSI_RecordIsNull(row
,6))
3315 LPCWSTR arguments
= MSI_RecordGetString(row
, 6);
3316 deformat_string(package
, arguments
, &deformated
);
3317 IShellLinkW_SetArguments(sl
,deformated
);
3318 msi_free(deformated
);
3321 if (!MSI_RecordIsNull(row
,7))
3323 LPCWSTR description
= MSI_RecordGetString(row
, 7);
3324 IShellLinkW_SetDescription(sl
, description
);
3327 if (!MSI_RecordIsNull(row
,8))
3328 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3330 if (!MSI_RecordIsNull(row
,9))
3333 LPCWSTR icon
= MSI_RecordGetString(row
, 9);
3335 path
= build_icon_path(package
, icon
);
3336 index
= MSI_RecordGetInteger(row
,10);
3338 /* no value means 0 */
3339 if (index
== MSI_NULL_INTEGER
)
3342 IShellLinkW_SetIconLocation(sl
, path
, index
);
3346 if (!MSI_RecordIsNull(row
,11))
3347 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3349 if (!MSI_RecordIsNull(row
,12))
3351 LPCWSTR wkdir
= MSI_RecordGetString(row
, 12);
3352 path
= resolve_folder(package
, wkdir
, FALSE
, FALSE
, TRUE
, NULL
);
3354 IShellLinkW_SetWorkingDirectory(sl
, path
);
3358 link_file
= get_link_file(package
, row
);
3360 TRACE("Writing shortcut to %s\n", debugstr_w(link_file
));
3361 IPersistFile_Save(pf
, link_file
, FALSE
);
3363 msi_free(link_file
);
3367 IPersistFile_Release( pf
);
3369 IShellLinkW_Release( sl
);
3371 return ERROR_SUCCESS
;
3374 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3379 static const WCHAR Query
[] =
3380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3381 '`','S','h','o','r','t','c','u','t','`',0};
3383 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3384 if (rc
!= ERROR_SUCCESS
)
3385 return ERROR_SUCCESS
;
3387 res
= CoInitialize( NULL
);
3389 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3390 msiobj_release(&view
->hdr
);
3398 static UINT
ITERATE_RemoveShortcuts( MSIRECORD
*row
, LPVOID param
)
3400 MSIPACKAGE
*package
= param
;
3405 component
= MSI_RecordGetString( row
, 4 );
3406 comp
= get_loaded_component( package
, component
);
3408 return ERROR_SUCCESS
;
3410 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3412 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3413 comp
->Action
= comp
->Installed
;
3414 return ERROR_SUCCESS
;
3416 comp
->Action
= INSTALLSTATE_ABSENT
;
3418 ui_actiondata( package
, szRemoveShortcuts
, row
);
3420 link_file
= get_link_file( package
, row
);
3422 TRACE("Removing shortcut file %s\n", debugstr_w( link_file
));
3423 if (!DeleteFileW( link_file
))
3425 WARN("Failed to remove shortcut file %u\n", GetLastError());
3427 msi_free( link_file
);
3429 return ERROR_SUCCESS
;
3432 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
3436 static const WCHAR query
[] =
3437 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3438 '`','S','h','o','r','t','c','u','t','`',0};
3440 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3441 if (rc
!= ERROR_SUCCESS
)
3442 return ERROR_SUCCESS
;
3444 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveShortcuts
, package
);
3445 msiobj_release( &view
->hdr
);
3450 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3452 MSIPACKAGE
* package
= param
;
3460 FileName
= MSI_RecordGetString(row
,1);
3463 ERR("Unable to get FileName\n");
3464 return ERROR_SUCCESS
;
3467 FilePath
= build_icon_path(package
,FileName
);
3469 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3471 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3472 FILE_ATTRIBUTE_NORMAL
, NULL
);
3474 if (the_file
== INVALID_HANDLE_VALUE
)
3476 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3478 return ERROR_SUCCESS
;
3485 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3486 if (rc
!= ERROR_SUCCESS
)
3488 ERR("Failed to get stream\n");
3489 CloseHandle(the_file
);
3490 DeleteFileW(FilePath
);
3493 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3494 } while (sz
== 1024);
3497 CloseHandle(the_file
);
3499 return ERROR_SUCCESS
;
3502 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3507 static const WCHAR query
[]= {
3508 'S','E','L','E','C','T',' ','*',' ',
3509 'F','R','O','M',' ','`','I','c','o','n','`',0};
3511 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3512 if (r
== ERROR_SUCCESS
)
3514 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3515 msiobj_release(&view
->hdr
);
3518 return ERROR_SUCCESS
;
3521 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3527 MSISOURCELISTINFO
*info
;
3529 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3530 if (r
!= ERROR_SUCCESS
)
3533 RegCloseKey(source
);
3535 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3536 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3537 package
->Context
, MSICODE_PRODUCT
,
3538 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3539 if (r
!= ERROR_SUCCESS
)
3542 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3543 package
->Context
, MSICODE_PRODUCT
,
3544 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3545 if (r
!= ERROR_SUCCESS
)
3548 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3549 package
->Context
, MSICODE_PRODUCT
,
3550 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3551 if (r
!= ERROR_SUCCESS
)
3554 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3556 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3557 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3558 info
->options
, info
->value
);
3560 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3561 info
->context
, info
->options
,
3562 info
->property
, info
->value
);
3565 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3567 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3568 disk
->context
, disk
->options
,
3569 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3572 return ERROR_SUCCESS
;
3575 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3577 MSIHANDLE hdb
, suminfo
;
3578 WCHAR guids
[MAX_PATH
];
3579 WCHAR packcode
[SQUISH_GUID_SIZE
];
3586 static const WCHAR szProductLanguage
[] =
3587 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3588 static const WCHAR szARPProductIcon
[] =
3589 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3590 static const WCHAR szProductVersion
[] =
3591 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3592 static const WCHAR szAssignment
[] =
3593 {'A','s','s','i','g','n','m','e','n','t',0};
3594 static const WCHAR szAdvertiseFlags
[] =
3595 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3596 static const WCHAR szClients
[] =
3597 {'C','l','i','e','n','t','s',0};
3598 static const WCHAR szColon
[] = {':',0};
3600 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3601 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3604 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3605 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3608 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3610 buffer
= msi_dup_property(package
, szARPProductIcon
);
3613 LPWSTR path
= build_icon_path(package
,buffer
);
3614 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3619 buffer
= msi_dup_property(package
, szProductVersion
);
3622 DWORD verdword
= msi_version_str_to_dword(buffer
);
3623 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3627 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3628 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3629 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3630 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3632 hdb
= alloc_msihandle(&package
->db
->hdr
);
3634 return ERROR_NOT_ENOUGH_MEMORY
;
3636 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3637 MsiCloseHandle(hdb
);
3638 if (r
!= ERROR_SUCCESS
)
3642 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3643 NULL
, guids
, &size
);
3644 if (r
!= ERROR_SUCCESS
)
3647 ptr
= strchrW(guids
, ';');
3649 squash_guid(guids
, packcode
);
3650 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3653 MsiCloseHandle(suminfo
);
3654 return ERROR_SUCCESS
;
3657 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3662 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3664 static const WCHAR szUpgradeCode
[] =
3665 {'U','p','g','r','a','d','e','C','o','d','e',0};
3667 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3669 return ERROR_SUCCESS
;
3671 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3673 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3674 if (r
!= ERROR_SUCCESS
)
3679 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3680 if (r
!= ERROR_SUCCESS
)
3684 squash_guid(package
->ProductCode
, squashed_pc
);
3685 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3694 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3696 MSIFEATURE
*feature
;
3698 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3700 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3707 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3709 MSIFEATURE
*feature
;
3711 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3713 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3720 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3722 WCHAR patch_squashed
[GUID_SIZE
];
3725 UINT r
= ERROR_FUNCTION_FAILED
;
3727 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3729 if (res
!= ERROR_SUCCESS
)
3730 return ERROR_FUNCTION_FAILED
;
3732 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3734 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3735 (const BYTE
*)patch_squashed
,
3736 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3737 if (res
!= ERROR_SUCCESS
)
3740 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3741 (const BYTE
*)package
->patch
->transforms
,
3742 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3743 if (res
== ERROR_SUCCESS
)
3747 RegCloseKey(patches
);
3752 * 99% of the work done here is only done for
3753 * advertised installs. However this is where the
3754 * Icon table is processed and written out
3755 * so that is what I am going to do here.
3757 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3760 HKEY hukey
= NULL
, hudkey
= NULL
;
3763 /* FIXME: also need to publish if the product is in advertise mode */
3764 if (!msi_check_publish(package
))
3765 return ERROR_SUCCESS
;
3767 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3769 if (rc
!= ERROR_SUCCESS
)
3772 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3773 NULL
, &hudkey
, TRUE
);
3774 if (rc
!= ERROR_SUCCESS
)
3777 rc
= msi_publish_upgrade_code(package
);
3778 if (rc
!= ERROR_SUCCESS
)
3783 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3784 if (rc
!= ERROR_SUCCESS
)
3788 rc
= msi_publish_product_properties(package
, hukey
);
3789 if (rc
!= ERROR_SUCCESS
)
3792 rc
= msi_publish_sourcelist(package
, hukey
);
3793 if (rc
!= ERROR_SUCCESS
)
3796 rc
= msi_publish_icons(package
);
3799 uirow
= MSI_CreateRecord( 1 );
3800 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
3801 ui_actiondata( package
, szPublishProduct
, uirow
);
3802 msiobj_release( &uirow
->hdr
);
3805 RegCloseKey(hudkey
);
3810 static WCHAR
*get_ini_file_name( MSIPACKAGE
*package
, MSIRECORD
*row
)
3812 WCHAR
*filename
, *ptr
, *folder
, *ret
;
3813 const WCHAR
*dirprop
;
3815 filename
= msi_dup_record_field( row
, 2 );
3816 if (filename
&& (ptr
= strchrW( filename
, '|' )))
3821 dirprop
= MSI_RecordGetString( row
, 3 );
3824 folder
= resolve_folder( package
, dirprop
, FALSE
, FALSE
, TRUE
, NULL
);
3826 folder
= msi_dup_property( package
, dirprop
);
3829 folder
= msi_dup_property( package
, szWindowsFolder
);
3833 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop
));
3834 msi_free( filename
);
3838 ret
= build_directory_name( 2, folder
, ptr
);
3840 msi_free( filename
);
3845 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3847 MSIPACKAGE
*package
= param
;
3848 LPCWSTR component
, section
, key
, value
, identifier
;
3849 LPWSTR deformated_section
, deformated_key
, deformated_value
, fullname
;
3854 component
= MSI_RecordGetString(row
, 8);
3855 comp
= get_loaded_component(package
,component
);
3857 return ERROR_SUCCESS
;
3859 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3861 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3862 comp
->Action
= comp
->Installed
;
3863 return ERROR_SUCCESS
;
3865 comp
->Action
= INSTALLSTATE_LOCAL
;
3867 identifier
= MSI_RecordGetString(row
,1);
3868 section
= MSI_RecordGetString(row
,4);
3869 key
= MSI_RecordGetString(row
,5);
3870 value
= MSI_RecordGetString(row
,6);
3871 action
= MSI_RecordGetInteger(row
,7);
3873 deformat_string(package
,section
,&deformated_section
);
3874 deformat_string(package
,key
,&deformated_key
);
3875 deformat_string(package
,value
,&deformated_value
);
3877 fullname
= get_ini_file_name(package
, row
);
3881 TRACE("Adding value %s to section %s in %s\n",
3882 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3883 debugstr_w(fullname
));
3884 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3885 deformated_value
, fullname
);
3887 else if (action
== 1)
3890 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3891 returned
, 10, fullname
);
3892 if (returned
[0] == 0)
3894 TRACE("Adding value %s to section %s in %s\n",
3895 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3896 debugstr_w(fullname
));
3898 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3899 deformated_value
, fullname
);
3902 else if (action
== 3)
3903 FIXME("Append to existing section not yet implemented\n");
3905 uirow
= MSI_CreateRecord(4);
3906 MSI_RecordSetStringW(uirow
,1,identifier
);
3907 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3908 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3909 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3910 ui_actiondata(package
,szWriteIniValues
,uirow
);
3911 msiobj_release( &uirow
->hdr
);
3914 msi_free(deformated_key
);
3915 msi_free(deformated_value
);
3916 msi_free(deformated_section
);
3917 return ERROR_SUCCESS
;
3920 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3924 static const WCHAR ExecSeqQuery
[] =
3925 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3926 '`','I','n','i','F','i','l','e','`',0};
3928 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3929 if (rc
!= ERROR_SUCCESS
)
3931 TRACE("no IniFile table\n");
3932 return ERROR_SUCCESS
;
3935 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3936 msiobj_release(&view
->hdr
);
3940 static UINT
ITERATE_RemoveIniValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
3942 MSIPACKAGE
*package
= param
;
3943 LPCWSTR component
, section
, key
, value
, identifier
;
3944 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
3949 component
= MSI_RecordGetString( row
, 8 );
3950 comp
= get_loaded_component( package
, component
);
3952 return ERROR_SUCCESS
;
3954 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3956 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3957 comp
->Action
= comp
->Installed
;
3958 return ERROR_SUCCESS
;
3960 comp
->Action
= INSTALLSTATE_ABSENT
;
3962 identifier
= MSI_RecordGetString( row
, 1 );
3963 section
= MSI_RecordGetString( row
, 4 );
3964 key
= MSI_RecordGetString( row
, 5 );
3965 value
= MSI_RecordGetString( row
, 6 );
3966 action
= MSI_RecordGetInteger( row
, 7 );
3968 deformat_string( package
, section
, &deformated_section
);
3969 deformat_string( package
, key
, &deformated_key
);
3970 deformat_string( package
, value
, &deformated_value
);
3972 if (action
== msidbIniFileActionAddLine
|| action
== msidbIniFileActionCreateLine
)
3974 filename
= get_ini_file_name( package
, row
);
3976 TRACE("Removing key %s from section %s in %s\n",
3977 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
3979 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
3981 WARN("Unable to remove key %u\n", GetLastError());
3983 msi_free( filename
);
3986 FIXME("Unsupported action %d\n", action
);
3989 uirow
= MSI_CreateRecord( 4 );
3990 MSI_RecordSetStringW( uirow
, 1, identifier
);
3991 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
3992 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
3993 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
3994 ui_actiondata( package
, szRemoveIniValues
, uirow
);
3995 msiobj_release( &uirow
->hdr
);
3997 msi_free( deformated_key
);
3998 msi_free( deformated_value
);
3999 msi_free( deformated_section
);
4000 return ERROR_SUCCESS
;
4003 static UINT
ITERATE_RemoveIniValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
4005 MSIPACKAGE
*package
= param
;
4006 LPCWSTR component
, section
, key
, value
, identifier
;
4007 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
4012 component
= MSI_RecordGetString( row
, 8 );
4013 comp
= get_loaded_component( package
, component
);
4015 return ERROR_SUCCESS
;
4017 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4019 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
4020 comp
->Action
= comp
->Installed
;
4021 return ERROR_SUCCESS
;
4023 comp
->Action
= INSTALLSTATE_LOCAL
;
4025 identifier
= MSI_RecordGetString( row
, 1 );
4026 section
= MSI_RecordGetString( row
, 4 );
4027 key
= MSI_RecordGetString( row
, 5 );
4028 value
= MSI_RecordGetString( row
, 6 );
4029 action
= MSI_RecordGetInteger( row
, 7 );
4031 deformat_string( package
, section
, &deformated_section
);
4032 deformat_string( package
, key
, &deformated_key
);
4033 deformat_string( package
, value
, &deformated_value
);
4035 if (action
== msidbIniFileActionRemoveLine
)
4037 filename
= get_ini_file_name( package
, row
);
4039 TRACE("Removing key %s from section %s in %s\n",
4040 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
4042 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
4044 WARN("Unable to remove key %u\n", GetLastError());
4046 msi_free( filename
);
4049 FIXME("Unsupported action %d\n", action
);
4051 uirow
= MSI_CreateRecord( 4 );
4052 MSI_RecordSetStringW( uirow
, 1, identifier
);
4053 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4054 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4055 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4056 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4057 msiobj_release( &uirow
->hdr
);
4059 msi_free( deformated_key
);
4060 msi_free( deformated_value
);
4061 msi_free( deformated_section
);
4062 return ERROR_SUCCESS
;
4065 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4069 static const WCHAR query
[] =
4070 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4071 '`','I','n','i','F','i','l','e','`',0};
4072 static const WCHAR remove_query
[] =
4073 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4074 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4076 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4077 if (rc
== ERROR_SUCCESS
)
4079 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnUninstall
, package
);
4080 msiobj_release( &view
->hdr
);
4081 if (rc
!= ERROR_SUCCESS
)
4085 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_query
, &view
);
4086 if (rc
== ERROR_SUCCESS
)
4088 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnInstall
, package
);
4089 msiobj_release( &view
->hdr
);
4090 if (rc
!= ERROR_SUCCESS
)
4094 return ERROR_SUCCESS
;
4097 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
4099 MSIPACKAGE
*package
= param
;
4104 static const WCHAR ExeStr
[] =
4105 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4106 static const WCHAR close
[] = {'\"',0};
4108 PROCESS_INFORMATION info
;
4113 memset(&si
,0,sizeof(STARTUPINFOW
));
4115 filename
= MSI_RecordGetString(row
,1);
4116 file
= get_loaded_file( package
, filename
);
4120 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4121 return ERROR_SUCCESS
;
4124 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
4126 FullName
= msi_alloc(len
*sizeof(WCHAR
));
4127 strcpyW(FullName
,ExeStr
);
4128 strcatW( FullName
, file
->TargetPath
);
4129 strcatW(FullName
,close
);
4131 TRACE("Registering %s\n",debugstr_w(FullName
));
4132 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
4137 CloseHandle(info
.hThread
);
4138 msi_dialog_check_messages(info
.hProcess
);
4139 CloseHandle(info
.hProcess
);
4142 uirow
= MSI_CreateRecord( 2 );
4143 MSI_RecordSetStringW( uirow
, 1, filename
);
4144 uipath
= strdupW( file
->TargetPath
);
4145 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4146 MSI_RecordSetStringW( uirow
, 2, uipath
);
4147 ui_actiondata( package
, szSelfRegModules
, uirow
);
4148 msiobj_release( &uirow
->hdr
);
4150 msi_free( FullName
);
4152 return ERROR_SUCCESS
;
4155 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4159 static const WCHAR ExecSeqQuery
[] =
4160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4161 '`','S','e','l','f','R','e','g','`',0};
4163 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4164 if (rc
!= ERROR_SUCCESS
)
4166 TRACE("no SelfReg table\n");
4167 return ERROR_SUCCESS
;
4170 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
4171 msiobj_release(&view
->hdr
);
4173 return ERROR_SUCCESS
;
4176 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
4178 static const WCHAR regsvr32
[] =
4179 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4180 static const WCHAR close
[] = {'\"',0};
4181 MSIPACKAGE
*package
= param
;
4187 PROCESS_INFORMATION pi
;
4192 memset( &si
, 0, sizeof(STARTUPINFOW
) );
4194 filename
= MSI_RecordGetString( row
, 1 );
4195 file
= get_loaded_file( package
, filename
);
4199 ERR("Unable to find file id %s\n", debugstr_w(filename
));
4200 return ERROR_SUCCESS
;
4203 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
4205 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
4206 strcpyW( cmdline
, regsvr32
);
4207 strcatW( cmdline
, file
->TargetPath
);
4208 strcatW( cmdline
, close
);
4210 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
4212 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
4215 CloseHandle( pi
.hThread
);
4216 msi_dialog_check_messages( pi
.hProcess
);
4217 CloseHandle( pi
.hProcess
);
4220 uirow
= MSI_CreateRecord( 2 );
4221 MSI_RecordSetStringW( uirow
, 1, filename
);
4222 uipath
= strdupW( file
->TargetPath
);
4223 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4224 MSI_RecordSetStringW( uirow
, 2, uipath
);
4225 ui_actiondata( package
, szSelfUnregModules
, uirow
);
4226 msiobj_release( &uirow
->hdr
);
4228 msi_free( cmdline
);
4230 return ERROR_SUCCESS
;
4233 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4237 static const WCHAR query
[] =
4238 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4239 '`','S','e','l','f','R','e','g','`',0};
4241 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4242 if (rc
!= ERROR_SUCCESS
)
4244 TRACE("no SelfReg table\n");
4245 return ERROR_SUCCESS
;
4248 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
4249 msiobj_release( &view
->hdr
);
4251 return ERROR_SUCCESS
;
4254 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4256 MSIFEATURE
*feature
;
4258 HKEY hkey
= NULL
, userdata
= NULL
;
4260 if (!msi_check_publish(package
))
4261 return ERROR_SUCCESS
;
4263 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4265 if (rc
!= ERROR_SUCCESS
)
4268 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4270 if (rc
!= ERROR_SUCCESS
)
4273 /* here the guids are base 85 encoded */
4274 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
4280 BOOL absent
= FALSE
;
4283 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4284 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4285 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
4288 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4292 if (feature
->Feature_Parent
)
4293 size
+= strlenW( feature
->Feature_Parent
)+2;
4295 data
= msi_alloc(size
* sizeof(WCHAR
));
4298 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4300 MSICOMPONENT
* component
= cl
->component
;
4304 if (component
->ComponentId
)
4306 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4307 CLSIDFromString(component
->ComponentId
, &clsid
);
4308 encode_base85_guid(&clsid
,buf
);
4309 TRACE("to %s\n",debugstr_w(buf
));
4314 if (feature
->Feature_Parent
)
4316 static const WCHAR sep
[] = {'\2',0};
4318 strcatW(data
,feature
->Feature_Parent
);
4321 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4325 if (feature
->Feature_Parent
)
4326 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4329 size
+= sizeof(WCHAR
);
4330 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4331 (const BYTE
*)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
4335 size
+= 2*sizeof(WCHAR
);
4336 data
= msi_alloc(size
);
4339 if (feature
->Feature_Parent
)
4340 strcpyW( &data
[1], feature
->Feature_Parent
);
4341 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4347 uirow
= MSI_CreateRecord( 1 );
4348 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4349 ui_actiondata( package
, szPublishFeatures
, uirow
);
4350 msiobj_release( &uirow
->hdr
);
4351 /* FIXME: call ui_progress? */
4356 RegCloseKey(userdata
);
4360 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4366 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4368 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4370 if (r
== ERROR_SUCCESS
)
4372 RegDeleteValueW(hkey
, feature
->Feature
);
4376 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4378 if (r
== ERROR_SUCCESS
)
4380 RegDeleteValueW(hkey
, feature
->Feature
);
4384 uirow
= MSI_CreateRecord( 1 );
4385 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4386 ui_actiondata( package
, szUnpublishFeatures
, uirow
);
4387 msiobj_release( &uirow
->hdr
);
4389 return ERROR_SUCCESS
;
4392 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4394 MSIFEATURE
*feature
;
4396 if (!msi_check_unpublish(package
))
4397 return ERROR_SUCCESS
;
4399 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4401 msi_unpublish_feature(package
, feature
);
4404 return ERROR_SUCCESS
;
4407 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4409 LPWSTR prop
, val
, key
;
4415 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4416 static const WCHAR szWindowsInstaller
[] =
4417 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4418 static const WCHAR modpath_fmt
[] =
4419 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4420 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4421 static const WCHAR szModifyPath
[] =
4422 {'M','o','d','i','f','y','P','a','t','h',0};
4423 static const WCHAR szUninstallString
[] =
4424 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4425 static const WCHAR szEstimatedSize
[] =
4426 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4427 static const WCHAR szProductLanguage
[] =
4428 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4429 static const WCHAR szProductVersion
[] =
4430 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4431 static const WCHAR szProductName
[] =
4432 {'P','r','o','d','u','c','t','N','a','m','e',0};
4433 static const WCHAR szDisplayName
[] =
4434 {'D','i','s','p','l','a','y','N','a','m','e',0};
4435 static const WCHAR szDisplayVersion
[] =
4436 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4437 static const WCHAR szManufacturer
[] =
4438 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4440 static const LPCSTR propval
[] = {
4441 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4442 "ARPCONTACT", "Contact",
4443 "ARPCOMMENTS", "Comments",
4444 "ProductName", "DisplayName",
4445 "ProductVersion", "DisplayVersion",
4446 "ARPHELPLINK", "HelpLink",
4447 "ARPHELPTELEPHONE", "HelpTelephone",
4448 "ARPINSTALLLOCATION", "InstallLocation",
4449 "SourceDir", "InstallSource",
4450 "Manufacturer", "Publisher",
4451 "ARPREADME", "Readme",
4453 "ARPURLINFOABOUT", "URLInfoAbout",
4454 "ARPURLUPDATEINFO", "URLUpdateInfo",
4457 const LPCSTR
*p
= propval
;
4461 prop
= strdupAtoW(*p
++);
4462 key
= strdupAtoW(*p
++);
4463 val
= msi_dup_property(package
, prop
);
4464 msi_reg_set_val_str(hkey
, key
, val
);
4470 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4472 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4473 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4474 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4477 /* FIXME: Write real Estimated Size when we have it */
4478 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4480 buffer
= msi_dup_property(package
, szProductName
);
4481 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4484 buffer
= msi_dup_property(package
, cszSourceDir
);
4485 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4488 buffer
= msi_dup_property(package
, szManufacturer
);
4489 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4492 GetLocalTime(&systime
);
4493 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4494 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4496 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4497 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4499 buffer
= msi_dup_property(package
, szProductVersion
);
4500 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4503 DWORD verdword
= msi_version_str_to_dword(buffer
);
4505 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4506 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4507 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4511 return ERROR_SUCCESS
;
4514 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4516 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4518 LPWSTR upgrade_code
;
4523 static const WCHAR szUpgradeCode
[] = {
4524 'U','p','g','r','a','d','e','C','o','d','e',0};
4526 /* FIXME: also need to publish if the product is in advertise mode */
4527 if (!msi_check_publish(package
))
4528 return ERROR_SUCCESS
;
4530 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4531 if (rc
!= ERROR_SUCCESS
)
4534 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4535 NULL
, &props
, TRUE
);
4536 if (rc
!= ERROR_SUCCESS
)
4539 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4540 msi_free( package
->db
->localfile
);
4541 package
->db
->localfile
= NULL
;
4543 rc
= msi_publish_install_properties(package
, hkey
);
4544 if (rc
!= ERROR_SUCCESS
)
4547 rc
= msi_publish_install_properties(package
, props
);
4548 if (rc
!= ERROR_SUCCESS
)
4551 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4554 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4555 squash_guid(package
->ProductCode
, squashed_pc
);
4556 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4557 RegCloseKey(upgrade
);
4558 msi_free(upgrade_code
);
4562 uirow
= MSI_CreateRecord( 1 );
4563 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4564 ui_actiondata( package
, szRegisterProduct
, uirow
);
4565 msiobj_release( &uirow
->hdr
);
4568 return ERROR_SUCCESS
;
4571 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4573 return execute_script(package
,INSTALL_SCRIPT
);
4576 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4579 LPWSTR remove
= NULL
;
4580 LPWSTR
*features
= NULL
;
4581 BOOL full_uninstall
= TRUE
;
4582 MSIFEATURE
*feature
;
4584 static const WCHAR szUpgradeCode
[] =
4585 {'U','p','g','r','a','d','e','C','o','d','e',0};
4587 remove
= msi_dup_property(package
, szRemove
);
4589 return ERROR_SUCCESS
;
4591 features
= msi_split_string(remove
, ',');
4595 ERR("REMOVE feature list is empty!\n");
4596 return ERROR_FUNCTION_FAILED
;
4599 if (!lstrcmpW(features
[0], szAll
))
4600 full_uninstall
= TRUE
;
4603 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4605 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4606 full_uninstall
= FALSE
;
4610 if (!full_uninstall
)
4613 MSIREG_DeleteProductKey(package
->ProductCode
);
4614 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4615 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4617 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4619 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4620 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4624 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4625 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4628 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4631 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4638 return ERROR_SUCCESS
;
4641 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4645 rc
= msi_unpublish_product(package
);
4646 if (rc
!= ERROR_SUCCESS
)
4649 /* turn off scheduling */
4650 package
->script
->CurrentlyScripting
= FALSE
;
4652 /* first do the same as an InstallExecute */
4653 rc
= ACTION_InstallExecute(package
);
4654 if (rc
!= ERROR_SUCCESS
)
4657 /* then handle Commit Actions */
4658 rc
= execute_script(package
,COMMIT_SCRIPT
);
4663 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4665 static const WCHAR RunOnce
[] = {
4666 'S','o','f','t','w','a','r','e','\\',
4667 'M','i','c','r','o','s','o','f','t','\\',
4668 'W','i','n','d','o','w','s','\\',
4669 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4670 'R','u','n','O','n','c','e',0};
4671 static const WCHAR InstallRunOnce
[] = {
4672 'S','o','f','t','w','a','r','e','\\',
4673 'M','i','c','r','o','s','o','f','t','\\',
4674 'W','i','n','d','o','w','s','\\',
4675 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4676 'I','n','s','t','a','l','l','e','r','\\',
4677 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4679 static const WCHAR msiexec_fmt
[] = {
4681 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4682 '\"','%','s','\"',0};
4683 static const WCHAR install_fmt
[] = {
4684 '/','I',' ','\"','%','s','\"',' ',
4685 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4686 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4687 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4689 WCHAR squished_pc
[100];
4691 squash_guid(package
->ProductCode
,squished_pc
);
4693 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4694 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4695 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4698 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4701 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4703 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4704 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4706 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4709 return ERROR_INSTALL_SUSPEND
;
4712 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4718 * We are currently doing what should be done here in the top level Install
4719 * however for Administrative and uninstalls this step will be needed
4721 if (!package
->PackagePath
)
4722 return ERROR_SUCCESS
;
4724 msi_set_sourcedir_props(package
, TRUE
);
4726 attrib
= GetFileAttributesW(package
->db
->path
);
4727 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4733 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4734 package
->Context
, MSICODE_PRODUCT
,
4735 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4736 if (rc
== ERROR_MORE_DATA
)
4738 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4739 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4740 package
->Context
, MSICODE_PRODUCT
,
4741 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4744 prompt
= strdupW(package
->db
->path
);
4746 msg
= generate_error_string(package
,1302,1,prompt
);
4747 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4749 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4752 rc
= ERROR_INSTALL_USEREXIT
;
4755 attrib
= GetFileAttributesW(package
->db
->path
);
4761 return ERROR_SUCCESS
;
4766 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4769 LPWSTR buffer
, productid
= NULL
;
4770 UINT i
, rc
= ERROR_SUCCESS
;
4773 static const WCHAR szPropKeys
[][80] =
4775 {'P','r','o','d','u','c','t','I','D',0},
4776 {'U','S','E','R','N','A','M','E',0},
4777 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4781 static const WCHAR szRegKeys
[][80] =
4783 {'P','r','o','d','u','c','t','I','D',0},
4784 {'R','e','g','O','w','n','e','r',0},
4785 {'R','e','g','C','o','m','p','a','n','y',0},
4789 if (msi_check_unpublish(package
))
4791 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4795 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4799 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4801 if (rc
!= ERROR_SUCCESS
)
4804 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4806 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4807 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4812 uirow
= MSI_CreateRecord( 1 );
4813 MSI_RecordSetStringW( uirow
, 1, productid
);
4814 ui_actiondata( package
, szRegisterUser
, uirow
);
4815 msiobj_release( &uirow
->hdr
);
4817 msi_free(productid
);
4823 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4827 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4828 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4833 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4835 MSIPACKAGE
*package
= param
;
4836 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
4837 LPWSTR advertise
= NULL
, output
= NULL
;
4845 feature
= MSI_RecordGetString(rec
, 5);
4846 feat
= get_loaded_feature(package
, feature
);
4848 return ERROR_SUCCESS
;
4850 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4851 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4852 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
4854 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
4855 feat
->Action
= feat
->Installed
;
4856 return ERROR_SUCCESS
;
4859 component
= MSI_RecordGetString(rec
, 3);
4860 comp
= get_loaded_component(package
, component
);
4862 return ERROR_SUCCESS
;
4864 compgroupid
= MSI_RecordGetString(rec
,1);
4865 qualifier
= MSI_RecordGetString(rec
,2);
4867 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4868 if (rc
!= ERROR_SUCCESS
)
4871 text
= MSI_RecordGetString(rec
,4);
4872 advertise
= create_component_advertise_string(package
, comp
, feature
);
4874 sz
= strlenW(advertise
);
4877 sz
+= lstrlenW(text
);
4880 sz
*= sizeof(WCHAR
);
4882 output
= msi_alloc_zero(sz
);
4883 strcpyW(output
,advertise
);
4884 msi_free(advertise
);
4887 strcatW(output
,text
);
4889 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4896 uirow
= MSI_CreateRecord( 2 );
4897 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4898 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4899 ui_actiondata( package
, szPublishComponents
, uirow
);
4900 msiobj_release( &uirow
->hdr
);
4901 /* FIXME: call ui_progress? */
4907 * At present I am ignorning the advertised components part of this and only
4908 * focusing on the qualified component sets
4910 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4914 static const WCHAR ExecSeqQuery
[] =
4915 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4916 '`','P','u','b','l','i','s','h',
4917 'C','o','m','p','o','n','e','n','t','`',0};
4919 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4920 if (rc
!= ERROR_SUCCESS
)
4921 return ERROR_SUCCESS
;
4923 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4924 msiobj_release(&view
->hdr
);
4929 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
4931 static const WCHAR szInstallerComponents
[] = {
4932 'S','o','f','t','w','a','r','e','\\',
4933 'M','i','c','r','o','s','o','f','t','\\',
4934 'I','n','s','t','a','l','l','e','r','\\',
4935 'C','o','m','p','o','n','e','n','t','s','\\',0};
4937 MSIPACKAGE
*package
= param
;
4938 LPCWSTR compgroupid
, component
, feature
, qualifier
;
4942 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
4945 feature
= MSI_RecordGetString( rec
, 5 );
4946 feat
= get_loaded_feature( package
, feature
);
4948 return ERROR_SUCCESS
;
4950 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4952 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
4953 feat
->Action
= feat
->Installed
;
4954 return ERROR_SUCCESS
;
4957 component
= MSI_RecordGetString( rec
, 3 );
4958 comp
= get_loaded_component( package
, component
);
4960 return ERROR_SUCCESS
;
4962 compgroupid
= MSI_RecordGetString( rec
, 1 );
4963 qualifier
= MSI_RecordGetString( rec
, 2 );
4965 squash_guid( compgroupid
, squashed
);
4966 strcpyW( keypath
, szInstallerComponents
);
4967 strcatW( keypath
, squashed
);
4969 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
4970 if (res
!= ERROR_SUCCESS
)
4972 WARN("Unable to delete component key %d\n", res
);
4975 uirow
= MSI_CreateRecord( 2 );
4976 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4977 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4978 ui_actiondata( package
, szUnpublishComponents
, uirow
);
4979 msiobj_release( &uirow
->hdr
);
4981 return ERROR_SUCCESS
;
4984 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
4988 static const WCHAR query
[] =
4989 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4990 '`','P','u','b','l','i','s','h',
4991 'C','o','m','p','o','n','e','n','t','`',0};
4993 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4994 if (rc
!= ERROR_SUCCESS
)
4995 return ERROR_SUCCESS
;
4997 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
4998 msiobj_release( &view
->hdr
);
5003 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
5005 MSIPACKAGE
*package
= param
;
5008 SC_HANDLE hscm
, service
= NULL
;
5009 LPCWSTR comp
, depends
, pass
;
5010 LPWSTR name
= NULL
, disp
= NULL
;
5011 LPCWSTR load_order
, serv_name
, key
;
5012 DWORD serv_type
, start_type
;
5015 static const WCHAR query
[] =
5016 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5017 '`','C','o','m','p','o','n','e','n','t','`',' ',
5018 'W','H','E','R','E',' ',
5019 '`','C','o','m','p','o','n','e','n','t','`',' ',
5020 '=','\'','%','s','\'',0};
5022 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
5025 ERR("Failed to open the SC Manager!\n");
5029 start_type
= MSI_RecordGetInteger(rec
, 5);
5030 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
5033 depends
= MSI_RecordGetString(rec
, 8);
5034 if (depends
&& *depends
)
5035 FIXME("Dependency list unhandled!\n");
5037 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5038 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
5039 serv_type
= MSI_RecordGetInteger(rec
, 4);
5040 err_control
= MSI_RecordGetInteger(rec
, 6);
5041 load_order
= MSI_RecordGetString(rec
, 7);
5042 serv_name
= MSI_RecordGetString(rec
, 9);
5043 pass
= MSI_RecordGetString(rec
, 10);
5044 comp
= MSI_RecordGetString(rec
, 12);
5046 /* fetch the service path */
5047 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
5050 ERR("Control query failed!\n");
5054 key
= MSI_RecordGetString(row
, 6);
5056 file
= get_loaded_file(package
, key
);
5057 msiobj_release(&row
->hdr
);
5060 ERR("Failed to load the service file\n");
5064 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
5065 start_type
, err_control
, file
->TargetPath
,
5066 load_order
, NULL
, NULL
, serv_name
, pass
);
5069 if (GetLastError() != ERROR_SERVICE_EXISTS
)
5070 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
5074 CloseServiceHandle(service
);
5075 CloseServiceHandle(hscm
);
5079 return ERROR_SUCCESS
;
5082 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
5086 static const WCHAR ExecSeqQuery
[] =
5087 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5088 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5090 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5091 if (rc
!= ERROR_SUCCESS
)
5092 return ERROR_SUCCESS
;
5094 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
5095 msiobj_release(&view
->hdr
);
5100 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5101 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
5103 LPCWSTR
*vector
, *temp_vector
;
5107 static const WCHAR separator
[] = {'[','~',']',0};
5110 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
5115 vector
= msi_alloc(sizeof(LPWSTR
));
5123 vector
[*numargs
- 1] = p
;
5125 if ((q
= strstrW(p
, separator
)))
5129 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
5135 vector
= temp_vector
;
5144 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
5146 MSIPACKAGE
*package
= param
;
5149 SC_HANDLE scm
= NULL
, service
= NULL
;
5150 LPCWSTR component
, *vector
= NULL
;
5151 LPWSTR name
, args
, display_name
= NULL
;
5152 DWORD event
, numargs
, len
;
5153 UINT r
= ERROR_FUNCTION_FAILED
;
5155 component
= MSI_RecordGetString(rec
, 6);
5156 comp
= get_loaded_component(package
, component
);
5158 return ERROR_SUCCESS
;
5160 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5162 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
5163 comp
->Action
= comp
->Installed
;
5164 return ERROR_SUCCESS
;
5166 comp
->Action
= INSTALLSTATE_LOCAL
;
5168 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5169 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
5170 event
= MSI_RecordGetInteger(rec
, 3);
5172 if (!(event
& msidbServiceControlEventStart
))
5178 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
5181 ERR("Failed to open the service control manager\n");
5186 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5187 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5189 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5190 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5193 service
= OpenServiceW(scm
, name
, SERVICE_START
);
5196 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
5200 vector
= msi_service_args_to_vector(args
, &numargs
);
5202 if (!StartServiceW(service
, numargs
, vector
) &&
5203 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
5205 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
5212 uirow
= MSI_CreateRecord( 2 );
5213 MSI_RecordSetStringW( uirow
, 1, display_name
);
5214 MSI_RecordSetStringW( uirow
, 2, name
);
5215 ui_actiondata( package
, szStartServices
, uirow
);
5216 msiobj_release( &uirow
->hdr
);
5218 CloseServiceHandle(service
);
5219 CloseServiceHandle(scm
);
5224 msi_free(display_name
);
5228 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
5233 static const WCHAR query
[] = {
5234 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5235 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5237 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5238 if (rc
!= ERROR_SUCCESS
)
5239 return ERROR_SUCCESS
;
5241 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
5242 msiobj_release(&view
->hdr
);
5247 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
5249 DWORD i
, needed
, count
;
5250 ENUM_SERVICE_STATUSW
*dependencies
;
5254 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
5255 0, &needed
, &count
))
5258 if (GetLastError() != ERROR_MORE_DATA
)
5261 dependencies
= msi_alloc(needed
);
5265 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
5266 needed
, &needed
, &count
))
5269 for (i
= 0; i
< count
; i
++)
5271 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
5272 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
5276 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
5283 msi_free(dependencies
);
5287 static UINT
stop_service( LPCWSTR name
)
5289 SC_HANDLE scm
= NULL
, service
= NULL
;
5290 SERVICE_STATUS status
;
5291 SERVICE_STATUS_PROCESS ssp
;
5294 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5297 WARN("Failed to open the SCM: %d\n", GetLastError());
5301 service
= OpenServiceW(scm
, name
,
5303 SERVICE_QUERY_STATUS
|
5304 SERVICE_ENUMERATE_DEPENDENTS
);
5307 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
5311 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
5312 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
5314 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
5318 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
5321 stop_service_dependents(scm
, service
);
5323 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5324 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5327 CloseServiceHandle(service
);
5328 CloseServiceHandle(scm
);
5330 return ERROR_SUCCESS
;
5333 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
5335 MSIPACKAGE
*package
= param
;
5339 LPWSTR name
= NULL
, display_name
= NULL
;
5343 event
= MSI_RecordGetInteger( rec
, 3 );
5344 if (!(event
& msidbServiceControlEventStop
))
5345 return ERROR_SUCCESS
;
5347 component
= MSI_RecordGetString( rec
, 6 );
5348 comp
= get_loaded_component( package
, component
);
5350 return ERROR_SUCCESS
;
5352 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5354 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5355 comp
->Action
= comp
->Installed
;
5356 return ERROR_SUCCESS
;
5358 comp
->Action
= INSTALLSTATE_ABSENT
;
5360 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
5363 ERR("Failed to open the service control manager\n");
5368 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5369 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5371 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5372 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5374 CloseServiceHandle( scm
);
5376 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
5377 stop_service( name
);
5380 uirow
= MSI_CreateRecord( 2 );
5381 MSI_RecordSetStringW( uirow
, 1, display_name
);
5382 MSI_RecordSetStringW( uirow
, 2, name
);
5383 ui_actiondata( package
, szStopServices
, uirow
);
5384 msiobj_release( &uirow
->hdr
);
5387 msi_free( display_name
);
5388 return ERROR_SUCCESS
;
5391 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5396 static const WCHAR query
[] = {
5397 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5398 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5400 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5401 if (rc
!= ERROR_SUCCESS
)
5402 return ERROR_SUCCESS
;
5404 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5405 msiobj_release(&view
->hdr
);
5410 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
5412 MSIPACKAGE
*package
= param
;
5416 LPWSTR name
= NULL
, display_name
= NULL
;
5418 SC_HANDLE scm
= NULL
, service
= NULL
;
5420 event
= MSI_RecordGetInteger( rec
, 3 );
5421 if (!(event
& msidbServiceControlEventDelete
))
5422 return ERROR_SUCCESS
;
5424 component
= MSI_RecordGetString(rec
, 6);
5425 comp
= get_loaded_component(package
, component
);
5427 return ERROR_SUCCESS
;
5429 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5431 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5432 comp
->Action
= comp
->Installed
;
5433 return ERROR_SUCCESS
;
5435 comp
->Action
= INSTALLSTATE_ABSENT
;
5437 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
5438 stop_service( name
);
5440 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5443 WARN("Failed to open the SCM: %d\n", GetLastError());
5448 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5449 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5451 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5452 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5455 service
= OpenServiceW( scm
, name
, DELETE
);
5458 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
5462 if (!DeleteService( service
))
5463 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
5466 uirow
= MSI_CreateRecord( 2 );
5467 MSI_RecordSetStringW( uirow
, 1, display_name
);
5468 MSI_RecordSetStringW( uirow
, 2, name
);
5469 ui_actiondata( package
, szDeleteServices
, uirow
);
5470 msiobj_release( &uirow
->hdr
);
5472 CloseServiceHandle( service
);
5473 CloseServiceHandle( scm
);
5475 msi_free( display_name
);
5477 return ERROR_SUCCESS
;
5480 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5485 static const WCHAR query
[] = {
5486 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5487 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5489 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5490 if (rc
!= ERROR_SUCCESS
)
5491 return ERROR_SUCCESS
;
5493 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
5494 msiobj_release( &view
->hdr
);
5499 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5503 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5505 if (!lstrcmpW(file
->File
, filename
))
5512 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5514 MSIPACKAGE
*package
= param
;
5515 LPWSTR driver
, driver_path
, ptr
;
5516 WCHAR outpath
[MAX_PATH
];
5517 MSIFILE
*driver_file
, *setup_file
;
5521 UINT r
= ERROR_SUCCESS
;
5523 static const WCHAR driver_fmt
[] = {
5524 'D','r','i','v','e','r','=','%','s',0};
5525 static const WCHAR setup_fmt
[] = {
5526 'S','e','t','u','p','=','%','s',0};
5527 static const WCHAR usage_fmt
[] = {
5528 'F','i','l','e','U','s','a','g','e','=','1',0};
5530 desc
= MSI_RecordGetString(rec
, 3);
5532 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5533 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5537 ERR("ODBC Driver entry not found!\n");
5538 return ERROR_FUNCTION_FAILED
;
5541 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
5543 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5544 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
5546 driver
= msi_alloc(len
* sizeof(WCHAR
));
5548 return ERROR_OUTOFMEMORY
;
5551 lstrcpyW(ptr
, desc
);
5552 ptr
+= lstrlenW(ptr
) + 1;
5554 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5559 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5563 lstrcpyW(ptr
, usage_fmt
);
5564 ptr
+= lstrlenW(ptr
) + 1;
5567 driver_path
= strdupW(driver_file
->TargetPath
);
5568 ptr
= strrchrW(driver_path
, '\\');
5569 if (ptr
) *ptr
= '\0';
5571 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5572 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5574 ERR("Failed to install SQL driver!\n");
5575 r
= ERROR_FUNCTION_FAILED
;
5578 uirow
= MSI_CreateRecord( 5 );
5579 MSI_RecordSetStringW( uirow
, 1, desc
);
5580 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5581 MSI_RecordSetStringW( uirow
, 3, driver_path
);
5582 ui_actiondata( package
, szInstallODBC
, uirow
);
5583 msiobj_release( &uirow
->hdr
);
5586 msi_free(driver_path
);
5591 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5593 MSIPACKAGE
*package
= param
;
5594 LPWSTR translator
, translator_path
, ptr
;
5595 WCHAR outpath
[MAX_PATH
];
5596 MSIFILE
*translator_file
, *setup_file
;
5600 UINT r
= ERROR_SUCCESS
;
5602 static const WCHAR translator_fmt
[] = {
5603 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5604 static const WCHAR setup_fmt
[] = {
5605 'S','e','t','u','p','=','%','s',0};
5607 desc
= MSI_RecordGetString(rec
, 3);
5609 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5610 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5612 if (!translator_file
)
5614 ERR("ODBC Translator entry not found!\n");
5615 return ERROR_FUNCTION_FAILED
;
5618 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
5620 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5622 translator
= msi_alloc(len
* sizeof(WCHAR
));
5624 return ERROR_OUTOFMEMORY
;
5627 lstrcpyW(ptr
, desc
);
5628 ptr
+= lstrlenW(ptr
) + 1;
5630 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5635 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5640 translator_path
= strdupW(translator_file
->TargetPath
);
5641 ptr
= strrchrW(translator_path
, '\\');
5642 if (ptr
) *ptr
= '\0';
5644 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5645 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5647 ERR("Failed to install SQL translator!\n");
5648 r
= ERROR_FUNCTION_FAILED
;
5651 uirow
= MSI_CreateRecord( 5 );
5652 MSI_RecordSetStringW( uirow
, 1, desc
);
5653 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5654 MSI_RecordSetStringW( uirow
, 3, translator_path
);
5655 ui_actiondata( package
, szInstallODBC
, uirow
);
5656 msiobj_release( &uirow
->hdr
);
5658 msi_free(translator
);
5659 msi_free(translator_path
);
5664 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5666 MSIPACKAGE
*package
= param
;
5668 LPCWSTR desc
, driver
;
5669 WORD request
= ODBC_ADD_SYS_DSN
;
5672 UINT r
= ERROR_SUCCESS
;
5675 static const WCHAR attrs_fmt
[] = {
5676 'D','S','N','=','%','s',0 };
5678 desc
= MSI_RecordGetString(rec
, 3);
5679 driver
= MSI_RecordGetString(rec
, 4);
5680 registration
= MSI_RecordGetInteger(rec
, 5);
5682 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5683 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5685 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
5686 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5688 return ERROR_OUTOFMEMORY
;
5690 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5693 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5695 ERR("Failed to install SQL data source!\n");
5696 r
= ERROR_FUNCTION_FAILED
;
5699 uirow
= MSI_CreateRecord( 5 );
5700 MSI_RecordSetStringW( uirow
, 1, desc
);
5701 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5702 MSI_RecordSetInteger( uirow
, 3, request
);
5703 ui_actiondata( package
, szInstallODBC
, uirow
);
5704 msiobj_release( &uirow
->hdr
);
5711 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5716 static const WCHAR driver_query
[] = {
5717 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5718 'O','D','B','C','D','r','i','v','e','r',0 };
5720 static const WCHAR translator_query
[] = {
5721 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5722 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5724 static const WCHAR source_query
[] = {
5725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5728 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5729 if (rc
!= ERROR_SUCCESS
)
5730 return ERROR_SUCCESS
;
5732 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5733 msiobj_release(&view
->hdr
);
5735 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5736 if (rc
!= ERROR_SUCCESS
)
5737 return ERROR_SUCCESS
;
5739 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5740 msiobj_release(&view
->hdr
);
5742 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5743 if (rc
!= ERROR_SUCCESS
)
5744 return ERROR_SUCCESS
;
5746 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5747 msiobj_release(&view
->hdr
);
5752 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5754 MSIPACKAGE
*package
= param
;
5759 desc
= MSI_RecordGetString( rec
, 3 );
5760 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5762 WARN("Failed to remove ODBC driver\n");
5766 FIXME("Usage count reached 0\n");
5769 uirow
= MSI_CreateRecord( 2 );
5770 MSI_RecordSetStringW( uirow
, 1, desc
);
5771 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5772 ui_actiondata( package
, szRemoveODBC
, uirow
);
5773 msiobj_release( &uirow
->hdr
);
5775 return ERROR_SUCCESS
;
5778 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5780 MSIPACKAGE
*package
= param
;
5785 desc
= MSI_RecordGetString( rec
, 3 );
5786 if (!SQLRemoveTranslatorW( desc
, &usage
))
5788 WARN("Failed to remove ODBC translator\n");
5792 FIXME("Usage count reached 0\n");
5795 uirow
= MSI_CreateRecord( 2 );
5796 MSI_RecordSetStringW( uirow
, 1, desc
);
5797 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5798 ui_actiondata( package
, szRemoveODBC
, uirow
);
5799 msiobj_release( &uirow
->hdr
);
5801 return ERROR_SUCCESS
;
5804 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5806 MSIPACKAGE
*package
= param
;
5809 LPCWSTR desc
, driver
;
5810 WORD request
= ODBC_REMOVE_SYS_DSN
;
5814 static const WCHAR attrs_fmt
[] = {
5815 'D','S','N','=','%','s',0 };
5817 desc
= MSI_RecordGetString( rec
, 3 );
5818 driver
= MSI_RecordGetString( rec
, 4 );
5819 registration
= MSI_RecordGetInteger( rec
, 5 );
5821 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5822 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5824 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
5825 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5827 return ERROR_OUTOFMEMORY
;
5829 FIXME("Use ODBCSourceAttribute table\n");
5831 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5834 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5836 WARN("Failed to remove ODBC data source\n");
5840 uirow
= MSI_CreateRecord( 3 );
5841 MSI_RecordSetStringW( uirow
, 1, desc
);
5842 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5843 MSI_RecordSetInteger( uirow
, 3, request
);
5844 ui_actiondata( package
, szRemoveODBC
, uirow
);
5845 msiobj_release( &uirow
->hdr
);
5847 return ERROR_SUCCESS
;
5850 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5855 static const WCHAR driver_query
[] = {
5856 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5857 'O','D','B','C','D','r','i','v','e','r',0 };
5859 static const WCHAR translator_query
[] = {
5860 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5861 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5863 static const WCHAR source_query
[] = {
5864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5865 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5867 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
5868 if (rc
!= ERROR_SUCCESS
)
5869 return ERROR_SUCCESS
;
5871 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
5872 msiobj_release( &view
->hdr
);
5874 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
5875 if (rc
!= ERROR_SUCCESS
)
5876 return ERROR_SUCCESS
;
5878 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
5879 msiobj_release( &view
->hdr
);
5881 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
5882 if (rc
!= ERROR_SUCCESS
)
5883 return ERROR_SUCCESS
;
5885 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
5886 msiobj_release( &view
->hdr
);
5891 #define ENV_ACT_SETALWAYS 0x1
5892 #define ENV_ACT_SETABSENT 0x2
5893 #define ENV_ACT_REMOVE 0x4
5894 #define ENV_ACT_REMOVEMATCH 0x8
5896 #define ENV_MOD_MACHINE 0x20000000
5897 #define ENV_MOD_APPEND 0x40000000
5898 #define ENV_MOD_PREFIX 0x80000000
5899 #define ENV_MOD_MASK 0xC0000000
5901 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5903 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5905 LPCWSTR cptr
= *name
;
5907 static const WCHAR prefix
[] = {'[','~',']',0};
5908 static const int prefix_len
= 3;
5914 *flags
|= ENV_ACT_SETALWAYS
;
5915 else if (*cptr
== '+')
5916 *flags
|= ENV_ACT_SETABSENT
;
5917 else if (*cptr
== '-')
5918 *flags
|= ENV_ACT_REMOVE
;
5919 else if (*cptr
== '!')
5920 *flags
|= ENV_ACT_REMOVEMATCH
;
5921 else if (*cptr
== '*')
5922 *flags
|= ENV_MOD_MACHINE
;
5932 ERR("Missing environment variable\n");
5933 return ERROR_FUNCTION_FAILED
;
5938 LPCWSTR ptr
= *value
;
5939 if (!strncmpW(ptr
, prefix
, prefix_len
))
5941 if (ptr
[prefix_len
] == szSemiColon
[0])
5943 *flags
|= ENV_MOD_APPEND
;
5944 *value
+= lstrlenW(prefix
);
5951 else if (lstrlenW(*value
) >= prefix_len
)
5953 ptr
+= lstrlenW(ptr
) - prefix_len
;
5954 if (!lstrcmpW(ptr
, prefix
))
5956 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
5958 *flags
|= ENV_MOD_PREFIX
;
5959 /* the "[~]" will be removed by deformat_string */;
5969 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5970 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5971 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5972 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5974 ERR("Invalid flags: %08x\n", *flags
);
5975 return ERROR_FUNCTION_FAILED
;
5979 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
5981 return ERROR_SUCCESS
;
5984 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
5986 static const WCHAR user_env
[] =
5987 {'E','n','v','i','r','o','n','m','e','n','t',0};
5988 static const WCHAR machine_env
[] =
5989 {'S','y','s','t','e','m','\\',
5990 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5991 'C','o','n','t','r','o','l','\\',
5992 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5993 'E','n','v','i','r','o','n','m','e','n','t',0};
5998 if (flags
& ENV_MOD_MACHINE
)
6001 root
= HKEY_LOCAL_MACHINE
;
6006 root
= HKEY_CURRENT_USER
;
6009 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
6010 if (res
!= ERROR_SUCCESS
)
6012 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
6013 return ERROR_FUNCTION_FAILED
;
6016 return ERROR_SUCCESS
;
6019 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6021 MSIPACKAGE
*package
= param
;
6022 LPCWSTR name
, value
, component
;
6023 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
6024 DWORD flags
, type
, size
;
6031 component
= MSI_RecordGetString(rec
, 4);
6032 comp
= get_loaded_component(package
, component
);
6034 return ERROR_SUCCESS
;
6036 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6038 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6039 comp
->Action
= comp
->Installed
;
6040 return ERROR_SUCCESS
;
6042 comp
->Action
= INSTALLSTATE_LOCAL
;
6044 name
= MSI_RecordGetString(rec
, 2);
6045 value
= MSI_RecordGetString(rec
, 3);
6047 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6049 res
= env_parse_flags(&name
, &value
, &flags
);
6050 if (res
!= ERROR_SUCCESS
|| !value
)
6053 if (value
&& !deformat_string(package
, value
, &deformatted
))
6055 res
= ERROR_OUTOFMEMORY
;
6059 value
= deformatted
;
6061 res
= open_env_key( flags
, &env
);
6062 if (res
!= ERROR_SUCCESS
)
6065 if (flags
& ENV_MOD_MACHINE
)
6066 action
|= 0x20000000;
6070 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
6071 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
6072 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
6075 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
6079 /* Nothing to do. */
6082 res
= ERROR_SUCCESS
;
6086 /* If we are appending but the string was empty, strip ; */
6087 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
6089 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
6090 newval
= strdupW(value
);
6093 res
= ERROR_OUTOFMEMORY
;
6101 /* Contrary to MSDN, +-variable to [~];path works */
6102 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
6104 res
= ERROR_SUCCESS
;
6108 data
= msi_alloc(size
);
6112 return ERROR_OUTOFMEMORY
;
6115 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
6116 if (res
!= ERROR_SUCCESS
)
6119 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
6122 res
= RegDeleteValueW(env
, name
);
6123 if (res
!= ERROR_SUCCESS
)
6124 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
6128 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
6129 if (flags
& ENV_MOD_MASK
)
6133 if (flags
& ENV_MOD_APPEND
) multiplier
++;
6134 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
6135 mod_size
= lstrlenW(value
) * multiplier
;
6136 size
+= mod_size
* sizeof(WCHAR
);
6139 newval
= msi_alloc(size
);
6143 res
= ERROR_OUTOFMEMORY
;
6147 if (flags
& ENV_MOD_PREFIX
)
6149 lstrcpyW(newval
, value
);
6150 ptr
= newval
+ lstrlenW(value
);
6151 action
|= 0x80000000;
6154 lstrcpyW(ptr
, data
);
6156 if (flags
& ENV_MOD_APPEND
)
6158 lstrcatW(newval
, value
);
6159 action
|= 0x40000000;
6162 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
6163 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
6166 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
6170 uirow
= MSI_CreateRecord( 3 );
6171 MSI_RecordSetStringW( uirow
, 1, name
);
6172 MSI_RecordSetStringW( uirow
, 2, newval
);
6173 MSI_RecordSetInteger( uirow
, 3, action
);
6174 ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
6175 msiobj_release( &uirow
->hdr
);
6177 if (env
) RegCloseKey(env
);
6178 msi_free(deformatted
);
6184 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
6188 static const WCHAR ExecSeqQuery
[] =
6189 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6190 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6191 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6192 if (rc
!= ERROR_SUCCESS
)
6193 return ERROR_SUCCESS
;
6195 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
6196 msiobj_release(&view
->hdr
);
6201 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6203 MSIPACKAGE
*package
= param
;
6204 LPCWSTR name
, value
, component
;
6205 LPWSTR deformatted
= NULL
;
6214 component
= MSI_RecordGetString( rec
, 4 );
6215 comp
= get_loaded_component( package
, component
);
6217 return ERROR_SUCCESS
;
6219 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6221 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6222 comp
->Action
= comp
->Installed
;
6223 return ERROR_SUCCESS
;
6225 comp
->Action
= INSTALLSTATE_ABSENT
;
6227 name
= MSI_RecordGetString( rec
, 2 );
6228 value
= MSI_RecordGetString( rec
, 3 );
6230 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6232 r
= env_parse_flags( &name
, &value
, &flags
);
6233 if (r
!= ERROR_SUCCESS
)
6236 if (!(flags
& ENV_ACT_REMOVE
))
6238 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
6239 return ERROR_SUCCESS
;
6242 if (value
&& !deformat_string( package
, value
, &deformatted
))
6243 return ERROR_OUTOFMEMORY
;
6245 value
= deformatted
;
6247 r
= open_env_key( flags
, &env
);
6248 if (r
!= ERROR_SUCCESS
)
6254 if (flags
& ENV_MOD_MACHINE
)
6255 action
|= 0x20000000;
6257 TRACE("Removing %s\n", debugstr_w(name
));
6259 res
= RegDeleteValueW( env
, name
);
6260 if (res
!= ERROR_SUCCESS
)
6262 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
6267 uirow
= MSI_CreateRecord( 3 );
6268 MSI_RecordSetStringW( uirow
, 1, name
);
6269 MSI_RecordSetStringW( uirow
, 2, value
);
6270 MSI_RecordSetInteger( uirow
, 3, action
);
6271 ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
6272 msiobj_release( &uirow
->hdr
);
6274 if (env
) RegCloseKey( env
);
6275 msi_free( deformatted
);
6279 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6283 static const WCHAR query
[] =
6284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6285 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6287 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6288 if (rc
!= ERROR_SUCCESS
)
6289 return ERROR_SUCCESS
;
6291 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
6292 msiobj_release( &view
->hdr
);
6297 typedef struct tagMSIASSEMBLY
6300 MSICOMPONENT
*component
;
6301 MSIFEATURE
*feature
;
6305 LPWSTR display_name
;
6310 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
6312 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
6313 LPVOID pvReserved
, HMODULE
*phModDll
);
6315 static BOOL
init_functionpointers(void)
6321 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
6323 hmscoree
= LoadLibraryA("mscoree.dll");
6326 WARN("mscoree.dll not available\n");
6330 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
6331 if (!pLoadLibraryShim
)
6333 WARN("LoadLibraryShim not available\n");
6334 FreeLibrary(hmscoree
);
6338 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
6341 WARN("fusion.dll not available\n");
6342 FreeLibrary(hmscoree
);
6346 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
6348 FreeLibrary(hmscoree
);
6352 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
6355 IAssemblyCache
*cache
;
6358 UINT r
= ERROR_FUNCTION_FAILED
;
6360 TRACE("installing assembly: %s\n", debugstr_w(path
));
6362 uirow
= MSI_CreateRecord( 2 );
6363 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
6364 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
6365 msiobj_release( &uirow
->hdr
);
6367 if (assembly
->feature
)
6368 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
6370 if (assembly
->manifest
)
6371 FIXME("Manifest unhandled\n");
6373 if (assembly
->application
)
6375 FIXME("Assembly should be privately installed\n");
6376 return ERROR_SUCCESS
;
6379 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
6381 FIXME("Win32 assemblies not handled\n");
6382 return ERROR_SUCCESS
;
6385 hr
= pCreateAssemblyCache(&cache
, 0);
6389 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
6391 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
6396 IAssemblyCache_Release(cache
);
6400 typedef struct tagASSEMBLY_LIST
6402 MSIPACKAGE
*package
;
6403 IAssemblyCache
*cache
;
6404 struct list
*assemblies
;
6407 typedef struct tagASSEMBLY_NAME
6415 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
6417 ASSEMBLY_NAME
*asmname
= param
;
6418 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
6419 LPWSTR val
= msi_dup_record_field(rec
, 3);
6421 static const WCHAR Name
[] = {'N','a','m','e',0};
6422 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
6423 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
6424 static const WCHAR PublicKeyToken
[] = {
6425 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6427 if (!strcmpiW(name
, Name
))
6428 asmname
->name
= val
;
6429 else if (!strcmpiW(name
, Version
))
6430 asmname
->version
= val
;
6431 else if (!strcmpiW(name
, Culture
))
6432 asmname
->culture
= val
;
6433 else if (!strcmpiW(name
, PublicKeyToken
))
6434 asmname
->pubkeytoken
= val
;
6438 return ERROR_SUCCESS
;
6441 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
6445 *size
= lstrlenW(append
) + 1;
6446 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
6447 lstrcpyW(*str
, append
);
6451 (*size
) += lstrlenW(append
);
6452 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6453 lstrcatW(*str
, append
);
6456 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, MSICOMPONENT
*comp
)
6458 static const WCHAR separator
[] = {',',' ',0};
6459 static const WCHAR Version
[] = {'V','e','r','s','i','o','n','=',0};
6460 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e','=',0};
6461 static const WCHAR PublicKeyToken
[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6462 static const WCHAR query
[] = {
6463 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6464 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6465 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6466 '=','\'','%','s','\'',0};
6469 LPWSTR display_name
;
6473 display_name
= NULL
;
6474 memset( &name
, 0, sizeof(ASSEMBLY_NAME
) );
6476 r
= MSI_OpenQuery( db
, &view
, query
, comp
->Component
);
6477 if (r
!= ERROR_SUCCESS
)
6480 MSI_IterateRecords( view
, NULL
, parse_assembly_name
, &name
);
6481 msiobj_release( &view
->hdr
);
6485 ERR("No assembly name specified!\n");
6489 append_str( &display_name
, &size
, name
.name
);
6493 append_str( &display_name
, &size
, separator
);
6494 append_str( &display_name
, &size
, Version
);
6495 append_str( &display_name
, &size
, name
.version
);
6499 append_str( &display_name
, &size
, separator
);
6500 append_str( &display_name
, &size
, Culture
);
6501 append_str( &display_name
, &size
, name
.culture
);
6503 if (name
.pubkeytoken
)
6505 append_str( &display_name
, &size
, separator
);
6506 append_str( &display_name
, &size
, PublicKeyToken
);
6507 append_str( &display_name
, &size
, name
.pubkeytoken
);
6510 msi_free( name
.name
);
6511 msi_free( name
.version
);
6512 msi_free( name
.culture
);
6513 msi_free( name
.pubkeytoken
);
6515 return display_name
;
6518 static BOOL
check_assembly_installed( MSIDATABASE
*db
, IAssemblyCache
*cache
, MSICOMPONENT
*comp
)
6520 ASSEMBLY_INFO asminfo
;
6525 disp
= get_assembly_display_name( db
, comp
);
6529 memset( &asminfo
, 0, sizeof(ASSEMBLY_INFO
) );
6530 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6532 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, disp
, &asminfo
);
6534 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6540 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6542 ASSEMBLY_LIST
*list
= param
;
6543 MSIASSEMBLY
*assembly
;
6546 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6548 return ERROR_OUTOFMEMORY
;
6550 component
= MSI_RecordGetString(rec
, 1);
6551 assembly
->component
= get_loaded_component(list
->package
, component
);
6552 if (!assembly
->component
)
6553 return ERROR_SUCCESS
;
6555 if (assembly
->component
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6556 assembly
->component
->ActionRequest
!= INSTALLSTATE_SOURCE
)
6558 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6559 assembly
->component
->Action
= assembly
->component
->Installed
;
6560 return ERROR_SUCCESS
;
6562 assembly
->component
->Action
= assembly
->component
->ActionRequest
;
6564 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6565 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6567 if (!assembly
->file
)
6569 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6570 return ERROR_FUNCTION_FAILED
;
6573 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6574 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6575 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6577 if (assembly
->application
)
6580 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6582 /* FIXME: we should probably check the manifest file here */
6584 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6585 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6587 assembly
->installed
= TRUE
;
6591 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6593 assembly
->component
);
6595 list_add_head(list
->assemblies
, &assembly
->entry
);
6596 return ERROR_SUCCESS
;
6599 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6601 IAssemblyCache
*cache
= NULL
;
6607 static const WCHAR query
[] =
6608 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6609 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6611 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6612 if (r
!= ERROR_SUCCESS
)
6613 return ERROR_SUCCESS
;
6615 hr
= pCreateAssemblyCache(&cache
, 0);
6617 return ERROR_FUNCTION_FAILED
;
6619 list
.package
= package
;
6621 list
.assemblies
= assemblies
;
6623 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6624 msiobj_release(&view
->hdr
);
6626 IAssemblyCache_Release(cache
);
6631 static void free_assemblies(struct list
*assemblies
)
6633 struct list
*item
, *cursor
;
6635 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6637 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6639 list_remove(&assembly
->entry
);
6640 msi_free(assembly
->application
);
6641 msi_free(assembly
->manifest
);
6642 msi_free(assembly
->display_name
);
6647 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6649 MSIASSEMBLY
*assembly
;
6651 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6653 if (!lstrcmpW(assembly
->file
->File
, file
))
6663 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6664 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6666 MSIASSEMBLY
*assembly
;
6667 WCHAR temppath
[MAX_PATH
];
6668 struct list
*assemblies
= user
;
6671 if (!find_assembly(assemblies
, file
, &assembly
))
6674 GetTempPathW(MAX_PATH
, temppath
);
6675 PathAddBackslashW(temppath
);
6676 lstrcatW(temppath
, assembly
->file
->FileName
);
6678 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6680 if (assembly
->installed
)
6683 *path
= strdupW(temppath
);
6684 *attrs
= assembly
->file
->Attributes
;
6686 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6688 assembly
->installed
= TRUE
;
6690 r
= install_assembly(package
, assembly
, temppath
);
6691 if (r
!= ERROR_SUCCESS
)
6692 ERR("Failed to install assembly\n");
6698 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6701 struct list assemblies
= LIST_INIT(assemblies
);
6702 MSIASSEMBLY
*assembly
;
6705 if (!init_functionpointers() || !pCreateAssemblyCache
)
6706 return ERROR_FUNCTION_FAILED
;
6708 r
= load_assemblies(package
, &assemblies
);
6709 if (r
!= ERROR_SUCCESS
)
6712 if (list_empty(&assemblies
))
6715 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6718 r
= ERROR_OUTOFMEMORY
;
6722 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6724 if (assembly
->installed
&& !mi
->is_continuous
)
6727 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6728 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6732 r
= ready_media(package
, assembly
->file
, mi
);
6733 if (r
!= ERROR_SUCCESS
)
6735 ERR("Failed to ready media\n");
6740 data
.package
= package
;
6741 data
.cb
= installassembly_cb
;
6742 data
.user
= &assemblies
;
6744 if (assembly
->file
->IsCompressed
&&
6745 !msi_cabextract(package
, mi
, &data
))
6747 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6748 r
= ERROR_FUNCTION_FAILED
;
6753 if (!assembly
->file
->IsCompressed
)
6755 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6757 r
= install_assembly(package
, assembly
, source
);
6758 if (r
!= ERROR_SUCCESS
)
6759 ERR("Failed to install assembly\n");
6764 /* FIXME: write Installer assembly reg values */
6768 free_assemblies(&assemblies
);
6772 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6774 LPWSTR key
, template, id
;
6775 UINT r
= ERROR_SUCCESS
;
6777 id
= msi_dup_property( package
, szProductID
);
6781 return ERROR_SUCCESS
;
6783 template = msi_dup_property( package
, szPIDTemplate
);
6784 key
= msi_dup_property( package
, szPIDKEY
);
6786 if (key
&& template)
6788 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6789 r
= MSI_SetPropertyW( package
, szProductID
, key
);
6791 msi_free( template );
6796 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6799 package
->need_reboot
= 1;
6800 return ERROR_SUCCESS
;
6803 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6805 static const WCHAR szAvailableFreeReg
[] =
6806 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6808 int space
= msi_get_property_int( package
, szAvailableFreeReg
, 0 );
6810 TRACE("%p %d kilobytes\n", package
, space
);
6812 uirow
= MSI_CreateRecord( 1 );
6813 MSI_RecordSetInteger( uirow
, 1, space
);
6814 ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
6815 msiobj_release( &uirow
->hdr
);
6817 return ERROR_SUCCESS
;
6820 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6822 FIXME("%p\n", package
);
6823 return ERROR_SUCCESS
;
6826 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6828 FIXME("%p\n", package
);
6829 return ERROR_SUCCESS
;
6832 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6837 static const WCHAR driver_query
[] = {
6838 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6839 'O','D','B','C','D','r','i','v','e','r',0 };
6841 static const WCHAR translator_query
[] = {
6842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6843 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6845 r
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
6846 if (r
== ERROR_SUCCESS
)
6849 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
6850 msiobj_release( &view
->hdr
);
6851 if (count
) FIXME("ignored %u rows in ODBCDriver table\n", count
);
6854 r
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
6855 if (r
== ERROR_SUCCESS
)
6858 r
= MSI_IterateRecords( view
, &count
, NULL
, package
);
6859 msiobj_release( &view
->hdr
);
6860 if (count
) FIXME("ignored %u rows in ODBCTranslator table\n", count
);
6863 return ERROR_SUCCESS
;
6866 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6867 LPCSTR action
, LPCWSTR table
)
6869 static const WCHAR query
[] = {
6870 'S','E','L','E','C','T',' ','*',' ',
6871 'F','R','O','M',' ','`','%','s','`',0 };
6872 MSIQUERY
*view
= NULL
;
6876 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6877 if (r
== ERROR_SUCCESS
)
6879 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6880 msiobj_release(&view
->hdr
);
6884 FIXME("%s -> %u ignored %s table values\n",
6885 action
, count
, debugstr_w(table
));
6887 return ERROR_SUCCESS
;
6890 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6892 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6893 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6896 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6898 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6899 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6902 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6904 static const WCHAR table
[] = {
6905 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6906 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6909 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6911 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6912 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6915 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6917 static const WCHAR table
[] = {
6918 'M','s','i','A','s','s','e','m','b','l','y',0 };
6919 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6922 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6924 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6925 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6928 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6930 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6931 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6934 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6936 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6937 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6940 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6942 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6943 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6946 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6948 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6949 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6952 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6954 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6955 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6958 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6960 static const WCHAR table
[] = { 'M','I','M','E',0 };
6961 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6964 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6968 const WCHAR
*action
;
6969 UINT (*handler
)(MSIPACKAGE
*);
6973 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6974 { szAppSearch
, ACTION_AppSearch
},
6975 { szBindImage
, ACTION_BindImage
},
6976 { szCCPSearch
, ACTION_CCPSearch
},
6977 { szCostFinalize
, ACTION_CostFinalize
},
6978 { szCostInitialize
, ACTION_CostInitialize
},
6979 { szCreateFolders
, ACTION_CreateFolders
},
6980 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6981 { szDeleteServices
, ACTION_DeleteServices
},
6982 { szDisableRollback
, ACTION_DisableRollback
},
6983 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6984 { szExecuteAction
, ACTION_ExecuteAction
},
6985 { szFileCost
, ACTION_FileCost
},
6986 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6987 { szForceReboot
, ACTION_ForceReboot
},
6988 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
6989 { szInstallExecute
, ACTION_InstallExecute
},
6990 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6991 { szInstallFiles
, ACTION_InstallFiles
},
6992 { szInstallFinalize
, ACTION_InstallFinalize
},
6993 { szInstallInitialize
, ACTION_InstallInitialize
},
6994 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6995 { szInstallValidate
, ACTION_InstallValidate
},
6996 { szIsolateComponents
, ACTION_IsolateComponents
},
6997 { szLaunchConditions
, ACTION_LaunchConditions
},
6998 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6999 { szMoveFiles
, ACTION_MoveFiles
},
7000 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
7001 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
7002 { szInstallODBC
, ACTION_InstallODBC
},
7003 { szInstallServices
, ACTION_InstallServices
},
7004 { szPatchFiles
, ACTION_PatchFiles
},
7005 { szProcessComponents
, ACTION_ProcessComponents
},
7006 { szPublishComponents
, ACTION_PublishComponents
},
7007 { szPublishFeatures
, ACTION_PublishFeatures
},
7008 { szPublishProduct
, ACTION_PublishProduct
},
7009 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
7010 { szRegisterComPlus
, ACTION_RegisterComPlus
},
7011 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
7012 { szRegisterFonts
, ACTION_RegisterFonts
},
7013 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
7014 { szRegisterProduct
, ACTION_RegisterProduct
},
7015 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
7016 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
7017 { szRegisterUser
, ACTION_RegisterUser
},
7018 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
7019 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
7020 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
7021 { szRemoveFiles
, ACTION_RemoveFiles
},
7022 { szRemoveFolders
, ACTION_RemoveFolders
},
7023 { szRemoveIniValues
, ACTION_RemoveIniValues
},
7024 { szRemoveODBC
, ACTION_RemoveODBC
},
7025 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
7026 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
7027 { szResolveSource
, ACTION_ResolveSource
},
7028 { szRMCCPSearch
, ACTION_RMCCPSearch
},
7029 { szScheduleReboot
, ACTION_ScheduleReboot
},
7030 { szSelfRegModules
, ACTION_SelfRegModules
},
7031 { szSelfUnregModules
, ACTION_SelfUnregModules
},
7032 { szSetODBCFolders
, ACTION_SetODBCFolders
},
7033 { szStartServices
, ACTION_StartServices
},
7034 { szStopServices
, ACTION_StopServices
},
7035 { szUnpublishComponents
, ACTION_UnpublishComponents
},
7036 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
7037 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
7038 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
7039 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
7040 { szUnregisterFonts
, ACTION_UnregisterFonts
},
7041 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
7042 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
7043 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
7044 { szValidateProductID
, ACTION_ValidateProductID
},
7045 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
7046 { szWriteIniValues
, ACTION_WriteIniValues
},
7047 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
7051 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
7052 UINT
* rc
, BOOL force
)
7058 if (!run
&& !package
->script
->CurrentlyScripting
)
7063 if (strcmpW(action
,szInstallFinalize
) == 0 ||
7064 strcmpW(action
,szInstallExecute
) == 0 ||
7065 strcmpW(action
,szInstallExecuteAgain
) == 0)
7070 while (StandardActions
[i
].action
!= NULL
)
7072 if (strcmpW(StandardActions
[i
].action
, action
)==0)
7076 ui_actioninfo(package
, action
, TRUE
, 0);
7077 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
7078 ui_actioninfo(package
, action
, FALSE
, *rc
);
7082 ui_actionstart(package
, action
);
7083 if (StandardActions
[i
].handler
)
7085 *rc
= StandardActions
[i
].handler(package
);
7089 FIXME("unhandled standard action %s\n",debugstr_w(action
));
7090 *rc
= ERROR_SUCCESS
;
7101 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
7103 UINT rc
= ERROR_SUCCESS
;
7106 TRACE("Performing action (%s)\n", debugstr_w(action
));
7108 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
7111 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
7115 WARN("unhandled msi action %s\n", debugstr_w(action
));
7116 rc
= ERROR_FUNCTION_NOT_CALLED
;
7122 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
7124 UINT rc
= ERROR_SUCCESS
;
7125 BOOL handled
= FALSE
;
7127 TRACE("Performing action (%s)\n", debugstr_w(action
));
7129 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
7132 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
7134 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
7139 WARN("unhandled msi action %s\n", debugstr_w(action
));
7140 rc
= ERROR_FUNCTION_NOT_CALLED
;
7146 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
7148 UINT rc
= ERROR_SUCCESS
;
7151 static const WCHAR ExecSeqQuery
[] =
7152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7153 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7154 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7155 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7156 static const WCHAR UISeqQuery
[] =
7157 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7158 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7159 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7160 ' ', '=',' ','%','i',0};
7162 if (needs_ui_sequence(package
))
7163 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
7165 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
7169 LPCWSTR action
, cond
;
7171 TRACE("Running the actions\n");
7173 /* check conditions */
7174 cond
= MSI_RecordGetString(row
, 2);
7176 /* this is a hack to skip errors in the condition code */
7177 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
7179 msiobj_release(&row
->hdr
);
7180 return ERROR_SUCCESS
;
7183 action
= MSI_RecordGetString(row
, 1);
7186 ERR("failed to fetch action\n");
7187 msiobj_release(&row
->hdr
);
7188 return ERROR_FUNCTION_FAILED
;
7191 if (needs_ui_sequence(package
))
7192 rc
= ACTION_PerformUIAction(package
, action
, -1);
7194 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
7196 msiobj_release(&row
->hdr
);
7202 /****************************************************
7203 * TOP level entry points
7204 *****************************************************/
7206 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
7207 LPCWSTR szCommandLine
)
7212 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
7213 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
7215 MSI_SetPropertyW(package
, szAction
, szInstall
);
7217 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
7224 dir
= strdupW(szPackagePath
);
7225 p
= strrchrW(dir
, '\\');
7229 file
= szPackagePath
+ (p
- dir
);
7234 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
7235 GetCurrentDirectoryW(MAX_PATH
, dir
);
7236 lstrcatW(dir
, szBackSlash
);
7237 file
= szPackagePath
;
7240 msi_free( package
->PackagePath
);
7241 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
7242 if (!package
->PackagePath
)
7245 return ERROR_OUTOFMEMORY
;
7248 lstrcpyW(package
->PackagePath
, dir
);
7249 lstrcatW(package
->PackagePath
, file
);
7252 msi_set_sourcedir_props(package
, FALSE
);
7255 msi_parse_command_line( package
, szCommandLine
, FALSE
);
7257 msi_apply_transforms( package
);
7258 msi_apply_patches( package
);
7260 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
7262 TRACE("setting reinstall property\n");
7263 MSI_SetPropertyW( package
, szReinstall
, szAll
);
7266 /* properties may have been added by a transform */
7267 msi_clone_properties( package
);
7268 msi_set_context( package
);
7270 if (needs_ui_sequence( package
))
7272 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
7273 rc
= ACTION_ProcessUISequence(package
);
7274 ui_exists
= ui_sequence_exists(package
);
7275 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
7277 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
7278 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
7282 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
7284 package
->script
->CurrentlyScripting
= FALSE
;
7286 /* process the ending type action */
7287 if (rc
== ERROR_SUCCESS
)
7288 ACTION_PerformActionSequence(package
, -1);
7289 else if (rc
== ERROR_INSTALL_USEREXIT
)
7290 ACTION_PerformActionSequence(package
, -2);
7291 else if (rc
== ERROR_INSTALL_SUSPEND
)
7292 ACTION_PerformActionSequence(package
, -4);
7294 ACTION_PerformActionSequence(package
, -3);
7296 /* finish up running custom actions */
7297 ACTION_FinishCustomActions(package
);
7299 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
7300 return ERROR_SUCCESS_REBOOT_REQUIRED
;