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 szRegisterFonts
[] =
128 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
129 static const WCHAR szRegisterUser
[] =
130 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
131 static const WCHAR szRemoveEnvironmentStrings
[] =
132 {'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};
133 static const WCHAR szRemoveExistingProducts
[] =
134 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
135 static const WCHAR szRemoveFolders
[] =
136 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
137 static const WCHAR szRemoveIniValues
[] =
138 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
139 static const WCHAR szRemoveODBC
[] =
140 {'R','e','m','o','v','e','O','D','B','C',0};
141 static const WCHAR szRemoveRegistryValues
[] =
142 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
143 static const WCHAR szRemoveShortcuts
[] =
144 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
145 static const WCHAR szRMCCPSearch
[] =
146 {'R','M','C','C','P','S','e','a','r','c','h',0};
147 static const WCHAR szScheduleReboot
[] =
148 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
149 static const WCHAR szSelfUnregModules
[] =
150 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
151 static const WCHAR szSetODBCFolders
[] =
152 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
153 static const WCHAR szStartServices
[] =
154 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
155 static const WCHAR szStopServices
[] =
156 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
157 static const WCHAR szUnpublishComponents
[] =
158 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szUnpublishFeatures
[] =
160 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
161 static const WCHAR szUnregisterClassInfo
[] =
162 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
163 static const WCHAR szUnregisterComPlus
[] =
164 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
165 static const WCHAR szUnregisterExtensionInfo
[] =
166 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
167 static const WCHAR szUnregisterFonts
[] =
168 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 static const WCHAR szUnregisterMIMEInfo
[] =
170 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szUnregisterProgIdInfo
[] =
172 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
173 static const WCHAR szUnregisterTypeLibraries
[] =
174 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
175 static const WCHAR szValidateProductID
[] =
176 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
177 static const WCHAR szWriteEnvironmentStrings
[] =
178 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
180 /********************************************************
182 ********************************************************/
184 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
186 static const WCHAR Query_t
[] =
187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
188 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
189 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
190 ' ','\'','%','s','\'',0};
193 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
196 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
197 msiobj_release(&row
->hdr
);
200 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
204 static const WCHAR template_s
[]=
205 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
207 static const WCHAR template_e
[]=
208 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
209 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
211 static const WCHAR format
[] =
212 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
216 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
218 sprintfW(message
,template_s
,timet
,action
);
220 sprintfW(message
,template_e
,timet
,action
,rc
);
222 row
= MSI_CreateRecord(1);
223 MSI_RecordSetStringW(row
,1,message
);
225 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
226 msiobj_release(&row
->hdr
);
229 UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
,
235 LPWSTR prop
= NULL
, val
= NULL
;
238 return ERROR_SUCCESS
;
250 TRACE("Looking at %s\n",debugstr_w(ptr
));
252 ptr2
= strchrW(ptr
,'=');
255 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
262 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
263 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
273 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
286 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
287 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
290 if (lstrlenW(prop
) > 0)
292 TRACE("Found commandline property (%s) = (%s)\n",
293 debugstr_w(prop
), debugstr_w(val
));
294 MSI_SetPropertyW(package
,prop
,val
);
300 return ERROR_SUCCESS
;
304 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
307 LPWSTR p
, *ret
= NULL
;
313 /* count the number of substrings */
314 for ( pc
= str
, count
= 0; pc
; count
++ )
316 pc
= strchrW( pc
, sep
);
321 /* allocate space for an array of substring pointers and the substrings */
322 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
323 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
327 /* copy the string and set the pointers */
328 p
= (LPWSTR
) &ret
[count
+1];
330 for( count
= 0; (ret
[count
] = p
); count
++ )
332 p
= strchrW( p
, sep
);
340 static UINT
msi_check_transform_applicable( MSIPACKAGE
*package
, IStorage
*patch
)
342 static const WCHAR szSystemLanguageID
[] =
343 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
345 LPWSTR prod_code
, patch_product
, langid
= NULL
, template = NULL
;
346 UINT ret
= ERROR_FUNCTION_FAILED
;
348 prod_code
= msi_dup_property( package
, szProductCode
);
349 patch_product
= msi_get_suminfo_product( patch
);
351 TRACE("db = %s patch = %s\n", debugstr_w(prod_code
), debugstr_w(patch_product
));
353 if ( strstrW( patch_product
, prod_code
) )
358 si
= MSI_GetSummaryInformationW( patch
, 0 );
361 ERR("no summary information!\n");
365 template = msi_suminfo_dup_string( si
, PID_TEMPLATE
);
368 ERR("no template property!\n");
369 msiobj_release( &si
->hdr
);
376 msiobj_release( &si
->hdr
);
380 langid
= msi_dup_property( package
, szSystemLanguageID
);
383 msiobj_release( &si
->hdr
);
387 p
= strchrW( template, ';' );
388 if (p
&& (!strcmpW( p
+ 1, langid
) || !strcmpW( p
+ 1, szZero
)))
390 TRACE("applicable transform\n");
394 /* FIXME: check platform */
396 msiobj_release( &si
->hdr
);
400 msi_free( patch_product
);
401 msi_free( prod_code
);
402 msi_free( template );
408 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
409 MSIDATABASE
*patch_db
, LPCWSTR name
)
411 UINT ret
= ERROR_FUNCTION_FAILED
;
412 IStorage
*stg
= NULL
;
415 TRACE("%p %s\n", package
, debugstr_w(name
) );
419 ERR("expected a colon in %s\n", debugstr_w(name
));
420 return ERROR_FUNCTION_FAILED
;
423 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
426 ret
= msi_check_transform_applicable( package
, stg
);
427 if (ret
== ERROR_SUCCESS
)
428 msi_table_apply_transform( package
->db
, stg
);
430 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name
));
431 IStorage_Release( stg
);
434 ERR("failed to open substorage %s\n", debugstr_w(name
));
436 return ERROR_SUCCESS
;
439 UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
441 LPWSTR guid_list
, *guids
, product_code
;
442 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
444 product_code
= msi_dup_property( package
, szProductCode
);
447 /* FIXME: the property ProductCode should be written into the DB somewhere */
448 ERR("no product code to check\n");
449 return ERROR_SUCCESS
;
452 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
453 guids
= msi_split_string( guid_list
, ';' );
454 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
456 if (!lstrcmpW( guids
[i
], product_code
))
460 msi_free( guid_list
);
461 msi_free( product_code
);
466 static UINT
msi_set_media_source_prop(MSIPACKAGE
*package
)
469 MSIRECORD
*rec
= NULL
;
474 static const WCHAR query
[] = {'S','E','L','E','C','T',' ',
475 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
476 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
477 '`','S','o','u','r','c','e','`',' ','I','S',' ',
478 'N','O','T',' ','N','U','L','L',0};
480 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
481 if (r
!= ERROR_SUCCESS
)
484 r
= MSI_ViewExecute(view
, 0);
485 if (r
!= ERROR_SUCCESS
)
488 if (MSI_ViewFetch(view
, &rec
) == ERROR_SUCCESS
)
490 prop
= MSI_RecordGetString(rec
, 1);
491 patch
= msi_dup_property(package
, szPatch
);
492 MSI_SetPropertyW(package
, prop
, patch
);
497 if (rec
) msiobj_release(&rec
->hdr
);
498 msiobj_release(&view
->hdr
);
503 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
506 LPWSTR str
, *substorage
;
507 UINT i
, r
= ERROR_SUCCESS
;
509 si
= MSI_GetSummaryInformationW( patch_db
->storage
, 0 );
511 return ERROR_FUNCTION_FAILED
;
513 if (msi_check_patch_applicable( package
, si
) != ERROR_SUCCESS
)
515 TRACE("Patch not applicable\n");
516 return ERROR_SUCCESS
;
519 package
->patch
= msi_alloc(sizeof(MSIPATCHINFO
));
521 return ERROR_OUTOFMEMORY
;
523 package
->patch
->patchcode
= msi_suminfo_dup_string(si
, PID_REVNUMBER
);
524 if (!package
->patch
->patchcode
)
525 return ERROR_OUTOFMEMORY
;
527 /* enumerate the substorage */
528 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
529 package
->patch
->transforms
= str
;
531 substorage
= msi_split_string( str
, ';' );
532 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
533 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
535 msi_free( substorage
);
536 msiobj_release( &si
->hdr
);
538 msi_set_media_source_prop(package
);
543 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
545 MSIDATABASE
*patch_db
= NULL
;
548 TRACE("%p %s\n", package
, debugstr_w( file
) );
551 * We probably want to make sure we only open a patch collection here.
552 * Patch collections (.msp) and databases (.msi) have different GUIDs
553 * but currently MSI_OpenDatabaseW will accept both.
555 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
556 if ( r
!= ERROR_SUCCESS
)
558 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
562 msi_parse_patch_summary( package
, patch_db
);
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storage to search for streams.
568 append_storage_to_db( package
->db
, patch_db
->storage
);
570 msiobj_release( &patch_db
->hdr
);
572 return ERROR_SUCCESS
;
575 /* get the PATCH property, and apply all the patches it specifies */
576 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
578 LPWSTR patch_list
, *patches
;
579 UINT i
, r
= ERROR_SUCCESS
;
581 patch_list
= msi_dup_property( package
, szPatch
);
583 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
585 patches
= msi_split_string( patch_list
, ';' );
586 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
587 r
= msi_apply_patch_package( package
, patches
[i
] );
590 msi_free( patch_list
);
595 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
597 static const WCHAR szTransforms
[] = {
598 'T','R','A','N','S','F','O','R','M','S',0 };
599 LPWSTR xform_list
, *xforms
;
600 UINT i
, r
= ERROR_SUCCESS
;
602 xform_list
= msi_dup_property( package
, szTransforms
);
603 xforms
= msi_split_string( xform_list
, ';' );
605 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
607 if (xforms
[i
][0] == ':')
608 r
= msi_apply_substorage_transform( package
, package
->db
, xforms
[i
] );
610 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
614 msi_free( xform_list
);
619 static BOOL
ui_sequence_exists( MSIPACKAGE
*package
)
624 static const WCHAR ExecSeqQuery
[] =
625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
626 '`','I','n','s','t','a','l','l',
627 'U','I','S','e','q','u','e','n','c','e','`',
628 ' ','W','H','E','R','E',' ',
629 '`','S','e','q','u','e','n','c','e','`',' ',
630 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
631 '`','S','e','q','u','e','n','c','e','`',0};
633 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
634 if (rc
== ERROR_SUCCESS
)
636 msiobj_release(&view
->hdr
);
643 static UINT
msi_set_sourcedir_props(MSIPACKAGE
*package
, BOOL replace
)
646 LPWSTR source
, check
;
649 static const WCHAR szOriginalDatabase
[] =
650 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
652 db
= msi_dup_property( package
, szOriginalDatabase
);
654 return ERROR_OUTOFMEMORY
;
656 p
= strrchrW( db
, '\\' );
659 p
= strrchrW( db
, '/' );
663 return ERROR_SUCCESS
;
668 source
= msi_alloc( len
* sizeof(WCHAR
) );
669 lstrcpynW( source
, db
, len
);
671 check
= msi_dup_property( package
, cszSourceDir
);
672 if (!check
|| replace
)
673 MSI_SetPropertyW( package
, cszSourceDir
, source
);
677 check
= msi_dup_property( package
, cszSOURCEDIR
);
678 if (!check
|| replace
)
679 MSI_SetPropertyW( package
, cszSOURCEDIR
, source
);
685 return ERROR_SUCCESS
;
688 static BOOL
needs_ui_sequence(MSIPACKAGE
*package
)
690 INT level
= msi_get_property_int(package
, szUILevel
, 0);
691 return (level
& INSTALLUILEVEL_MASK
) >= INSTALLUILEVEL_REDUCED
;
694 static UINT
msi_set_context(MSIPACKAGE
*package
)
701 package
->Context
= MSIINSTALLCONTEXT_USERUNMANAGED
;
703 r
= MSI_GetPropertyW(package
, szAllUsers
, val
, &sz
);
704 if (r
== ERROR_SUCCESS
)
707 if (num
== 1 || num
== 2)
708 package
->Context
= MSIINSTALLCONTEXT_MACHINE
;
711 return ERROR_SUCCESS
;
714 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
717 LPCWSTR cond
, action
;
718 MSIPACKAGE
*package
= param
;
720 action
= MSI_RecordGetString(row
,1);
723 ERR("Error is retrieving action name\n");
724 return ERROR_FUNCTION_FAILED
;
727 /* check conditions */
728 cond
= MSI_RecordGetString(row
,2);
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
733 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action
));
734 return ERROR_SUCCESS
;
737 if (needs_ui_sequence(package
))
738 rc
= ACTION_PerformUIAction(package
, action
, -1);
740 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
742 msi_dialog_check_messages( NULL
);
744 if (package
->CurrentInstallState
!= ERROR_SUCCESS
)
745 rc
= package
->CurrentInstallState
;
747 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
750 if (rc
!= ERROR_SUCCESS
)
751 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
756 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
760 static const WCHAR query
[] =
761 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
763 ' ','W','H','E','R','E',' ',
764 '`','S','e','q','u','e','n','c','e','`',' ',
765 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
766 '`','S','e','q','u','e','n','c','e','`',0};
768 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
770 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
771 if (r
== ERROR_SUCCESS
)
773 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, package
);
774 msiobj_release(&view
->hdr
);
780 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
784 static const WCHAR ExecSeqQuery
[] =
785 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
786 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
787 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
788 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
789 'O','R','D','E','R',' ', 'B','Y',' ',
790 '`','S','e','q','u','e','n','c','e','`',0 };
791 static const WCHAR IVQuery
[] =
792 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
793 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
794 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
795 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
796 ' ','\'', 'I','n','s','t','a','l','l',
797 'V','a','l','i','d','a','t','e','\'', 0};
800 if (package
->script
->ExecuteSequenceRun
)
802 TRACE("Execute Sequence already Run\n");
803 return ERROR_SUCCESS
;
806 package
->script
->ExecuteSequenceRun
= TRUE
;
808 /* get the sequence number */
811 MSIRECORD
*row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
813 return ERROR_FUNCTION_FAILED
;
814 seq
= MSI_RecordGetInteger(row
,1);
815 msiobj_release(&row
->hdr
);
818 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
819 if (rc
== ERROR_SUCCESS
)
821 TRACE("Running the actions\n");
823 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
824 msiobj_release(&view
->hdr
);
830 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
834 static const WCHAR ExecSeqQuery
[] =
835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
836 '`','I','n','s','t','a','l','l',
837 'U','I','S','e','q','u','e','n','c','e','`',
838 ' ','W','H','E','R','E',' ',
839 '`','S','e','q','u','e','n','c','e','`',' ',
840 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
841 '`','S','e','q','u','e','n','c','e','`',0};
843 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
844 if (rc
== ERROR_SUCCESS
)
846 TRACE("Running the actions\n");
848 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, package
);
849 msiobj_release(&view
->hdr
);
855 /********************************************************
856 * ACTION helper functions and functions that perform the actions
857 *******************************************************/
858 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
859 UINT
* rc
, UINT script
, BOOL force
)
864 arc
= ACTION_CustomAction(package
, action
, script
, force
);
866 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
875 * Actual Action Handlers
878 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
880 MSIPACKAGE
*package
= param
;
881 LPCWSTR dir
, component
;
887 component
= MSI_RecordGetString(row
, 2);
888 comp
= get_loaded_component(package
, component
);
890 return ERROR_SUCCESS
;
892 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
894 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
895 comp
->Action
= comp
->Installed
;
896 return ERROR_SUCCESS
;
898 comp
->Action
= INSTALLSTATE_LOCAL
;
900 dir
= MSI_RecordGetString(row
,1);
903 ERR("Unable to get folder id\n");
904 return ERROR_SUCCESS
;
907 uirow
= MSI_CreateRecord(1);
908 MSI_RecordSetStringW(uirow
, 1, dir
);
909 ui_actiondata(package
, szCreateFolders
, uirow
);
910 msiobj_release(&uirow
->hdr
);
912 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,TRUE
,&folder
);
915 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
916 return ERROR_SUCCESS
;
919 TRACE("Folder is %s\n",debugstr_w(full_path
));
921 if (folder
->State
== 0)
922 create_full_pathW(full_path
);
927 return ERROR_SUCCESS
;
930 /* FIXME: probably should merge this with the above function */
931 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
933 UINT rc
= ERROR_SUCCESS
;
937 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
939 return ERROR_FUNCTION_FAILED
;
941 /* create the path */
942 if (folder
->State
== 0)
944 create_full_pathW(install_path
);
947 msi_free(install_path
);
952 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
956 /* create all the folders required by the components are going to install */
957 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
959 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
961 msi_create_directory( package
, comp
->Directory
);
964 return ERROR_SUCCESS
;
967 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
969 static const WCHAR ExecSeqQuery
[] =
970 {'S','E','L','E','C','T',' ',
971 '`','D','i','r','e','c','t','o','r','y','_','`',
972 ' ','F','R','O','M',' ',
973 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
977 /* create all the empty folders specified in the CreateFolder table */
978 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
979 if (rc
!= ERROR_SUCCESS
)
980 return ERROR_SUCCESS
;
982 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
983 msiobj_release(&view
->hdr
);
988 static UINT
ITERATE_RemoveFolders( MSIRECORD
*row
, LPVOID param
)
990 MSIPACKAGE
*package
= param
;
991 LPCWSTR dir
, component
;
997 component
= MSI_RecordGetString(row
, 2);
998 comp
= get_loaded_component(package
, component
);
1000 return ERROR_SUCCESS
;
1002 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
1004 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
1005 comp
->Action
= comp
->Installed
;
1006 return ERROR_SUCCESS
;
1008 comp
->Action
= INSTALLSTATE_ABSENT
;
1010 dir
= MSI_RecordGetString( row
, 1 );
1013 ERR("Unable to get folder id\n");
1014 return ERROR_SUCCESS
;
1017 full_path
= resolve_folder( package
, dir
, FALSE
, FALSE
, TRUE
, &folder
);
1020 ERR("Unable to resolve folder id %s\n", debugstr_w(dir
));
1021 return ERROR_SUCCESS
;
1024 TRACE("folder is %s\n", debugstr_w(full_path
));
1026 uirow
= MSI_CreateRecord( 1 );
1027 MSI_RecordSetStringW( uirow
, 1, full_path
);
1028 ui_actiondata( package
, szRemoveFolders
, uirow
);
1029 msiobj_release( &uirow
->hdr
);
1031 RemoveDirectoryW( full_path
);
1034 msi_free( full_path
);
1035 return ERROR_SUCCESS
;
1038 static UINT
ACTION_RemoveFolders( MSIPACKAGE
*package
)
1040 static const WCHAR query
[] =
1041 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1042 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1047 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1048 if (rc
!= ERROR_SUCCESS
)
1049 return ERROR_SUCCESS
;
1051 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveFolders
, package
);
1052 msiobj_release( &view
->hdr
);
1057 static UINT
load_component( MSIRECORD
*row
, LPVOID param
)
1059 MSIPACKAGE
*package
= param
;
1062 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1064 return ERROR_FUNCTION_FAILED
;
1066 list_add_tail( &package
->components
, &comp
->entry
);
1068 /* fill in the data */
1069 comp
->Component
= msi_dup_record_field( row
, 1 );
1071 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1073 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1074 comp
->Directory
= msi_dup_record_field( row
, 3 );
1075 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1076 comp
->Condition
= msi_dup_record_field( row
, 5 );
1077 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1079 comp
->Installed
= INSTALLSTATE_UNKNOWN
;
1080 msi_component_set_state(package
, comp
, INSTALLSTATE_UNKNOWN
);
1082 return ERROR_SUCCESS
;
1085 static UINT
load_all_components( MSIPACKAGE
*package
)
1087 static const WCHAR query
[] = {
1088 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1089 '`','C','o','m','p','o','n','e','n','t','`',0 };
1093 if (!list_empty(&package
->components
))
1094 return ERROR_SUCCESS
;
1096 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1097 if (r
!= ERROR_SUCCESS
)
1100 r
= MSI_IterateRecords(view
, NULL
, load_component
, package
);
1101 msiobj_release(&view
->hdr
);
1106 MSIPACKAGE
*package
;
1107 MSIFEATURE
*feature
;
1110 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1114 cl
= msi_alloc( sizeof (*cl
) );
1116 return ERROR_NOT_ENOUGH_MEMORY
;
1117 cl
->component
= comp
;
1118 list_add_tail( &feature
->Components
, &cl
->entry
);
1120 return ERROR_SUCCESS
;
1123 static UINT
add_feature_child( MSIFEATURE
*parent
, MSIFEATURE
*child
)
1127 fl
= msi_alloc( sizeof(*fl
) );
1129 return ERROR_NOT_ENOUGH_MEMORY
;
1130 fl
->feature
= child
;
1131 list_add_tail( &parent
->Children
, &fl
->entry
);
1133 return ERROR_SUCCESS
;
1136 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1138 _ilfs
* ilfs
= param
;
1142 component
= MSI_RecordGetString(row
,1);
1144 /* check to see if the component is already loaded */
1145 comp
= get_loaded_component( ilfs
->package
, component
);
1148 ERR("unknown component %s\n", debugstr_w(component
));
1149 return ERROR_FUNCTION_FAILED
;
1152 add_feature_component( ilfs
->feature
, comp
);
1153 comp
->Enabled
= TRUE
;
1155 return ERROR_SUCCESS
;
1158 static MSIFEATURE
*find_feature_by_name( MSIPACKAGE
*package
, LPCWSTR name
)
1160 MSIFEATURE
*feature
;
1165 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1167 if ( !lstrcmpW( feature
->Feature
, name
) )
1174 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1176 MSIPACKAGE
* package
= param
;
1177 MSIFEATURE
* feature
;
1178 static const WCHAR Query1
[] =
1179 {'S','E','L','E','C','T',' ',
1180 '`','C','o','m','p','o','n','e','n','t','_','`',
1181 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1182 'C','o','m','p','o','n','e','n','t','s','`',' ',
1183 'W','H','E','R','E',' ',
1184 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1189 /* fill in the data */
1191 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1193 return ERROR_NOT_ENOUGH_MEMORY
;
1195 list_init( &feature
->Children
);
1196 list_init( &feature
->Components
);
1198 feature
->Feature
= msi_dup_record_field( row
, 1 );
1200 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1202 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1203 feature
->Title
= msi_dup_record_field( row
, 3 );
1204 feature
->Description
= msi_dup_record_field( row
, 4 );
1206 if (!MSI_RecordIsNull(row
,5))
1207 feature
->Display
= MSI_RecordGetInteger(row
,5);
1209 feature
->Level
= MSI_RecordGetInteger(row
,6);
1210 feature
->Directory
= msi_dup_record_field( row
, 7 );
1211 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1213 feature
->Installed
= INSTALLSTATE_UNKNOWN
;
1214 msi_feature_set_state(package
, feature
, INSTALLSTATE_UNKNOWN
);
1216 list_add_tail( &package
->features
, &feature
->entry
);
1218 /* load feature components */
1220 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1221 if (rc
!= ERROR_SUCCESS
)
1222 return ERROR_SUCCESS
;
1224 ilfs
.package
= package
;
1225 ilfs
.feature
= feature
;
1227 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1228 msiobj_release(&view
->hdr
);
1230 return ERROR_SUCCESS
;
1233 static UINT
find_feature_children(MSIRECORD
* row
, LPVOID param
)
1235 MSIPACKAGE
* package
= param
;
1236 MSIFEATURE
*parent
, *child
;
1238 child
= find_feature_by_name( package
, MSI_RecordGetString( row
, 1 ) );
1240 return ERROR_FUNCTION_FAILED
;
1242 if (!child
->Feature_Parent
)
1243 return ERROR_SUCCESS
;
1245 parent
= find_feature_by_name( package
, child
->Feature_Parent
);
1247 return ERROR_FUNCTION_FAILED
;
1249 add_feature_child( parent
, child
);
1250 return ERROR_SUCCESS
;
1253 static UINT
load_all_features( MSIPACKAGE
*package
)
1255 static const WCHAR query
[] = {
1256 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1257 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1258 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1262 if (!list_empty(&package
->features
))
1263 return ERROR_SUCCESS
;
1265 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1266 if (r
!= ERROR_SUCCESS
)
1269 r
= MSI_IterateRecords( view
, NULL
, load_feature
, package
);
1270 if (r
!= ERROR_SUCCESS
)
1273 r
= MSI_IterateRecords( view
, NULL
, find_feature_children
, package
);
1274 msiobj_release( &view
->hdr
);
1279 static LPWSTR
folder_split_path(LPWSTR p
, WCHAR ch
)
1290 static UINT
load_file_hash(MSIPACKAGE
*package
, MSIFILE
*file
)
1292 static const WCHAR query
[] = {
1293 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1294 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1295 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1296 MSIQUERY
*view
= NULL
;
1297 MSIRECORD
*row
= NULL
;
1300 TRACE("%s\n", debugstr_w(file
->File
));
1302 r
= MSI_OpenQuery(package
->db
, &view
, query
, file
->File
);
1303 if (r
!= ERROR_SUCCESS
)
1306 r
= MSI_ViewExecute(view
, NULL
);
1307 if (r
!= ERROR_SUCCESS
)
1310 r
= MSI_ViewFetch(view
, &row
);
1311 if (r
!= ERROR_SUCCESS
)
1314 file
->hash
.dwFileHashInfoSize
= sizeof(MSIFILEHASHINFO
);
1315 file
->hash
.dwData
[0] = MSI_RecordGetInteger(row
, 3);
1316 file
->hash
.dwData
[1] = MSI_RecordGetInteger(row
, 4);
1317 file
->hash
.dwData
[2] = MSI_RecordGetInteger(row
, 5);
1318 file
->hash
.dwData
[3] = MSI_RecordGetInteger(row
, 6);
1321 if (view
) msiobj_release(&view
->hdr
);
1322 if (row
) msiobj_release(&row
->hdr
);
1326 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1328 MSIPACKAGE
* package
= param
;
1332 /* fill in the data */
1334 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1336 return ERROR_NOT_ENOUGH_MEMORY
;
1338 file
->File
= msi_dup_record_field( row
, 1 );
1340 component
= MSI_RecordGetString( row
, 2 );
1341 file
->Component
= get_loaded_component( package
, component
);
1343 if (!file
->Component
)
1345 WARN("Component not found: %s\n", debugstr_w(component
));
1346 msi_free(file
->File
);
1348 return ERROR_SUCCESS
;
1351 file
->FileName
= msi_dup_record_field( row
, 3 );
1352 reduce_to_longfilename( file
->FileName
);
1354 file
->ShortName
= msi_dup_record_field( row
, 3 );
1355 file
->LongName
= strdupW( folder_split_path(file
->ShortName
, '|'));
1357 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1358 file
->Version
= msi_dup_record_field( row
, 5 );
1359 file
->Language
= msi_dup_record_field( row
, 6 );
1360 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1361 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1363 file
->state
= msifs_invalid
;
1365 /* if the compressed bits are not set in the file attributes,
1366 * then read the information from the package word count property
1368 if (package
->WordCount
& msidbSumInfoSourceTypeAdminImage
)
1370 file
->IsCompressed
= FALSE
;
1372 else if (file
->Attributes
&
1373 (msidbFileAttributesCompressed
| msidbFileAttributesPatchAdded
))
1375 file
->IsCompressed
= TRUE
;
1377 else if (file
->Attributes
& msidbFileAttributesNoncompressed
)
1379 file
->IsCompressed
= FALSE
;
1383 file
->IsCompressed
= package
->WordCount
& msidbSumInfoSourceTypeCompressed
;
1386 load_file_hash(package
, file
);
1388 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1390 list_add_tail( &package
->files
, &file
->entry
);
1392 return ERROR_SUCCESS
;
1395 static UINT
load_all_files(MSIPACKAGE
*package
)
1399 static const WCHAR Query
[] =
1400 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1401 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1402 '`','S','e','q','u','e','n','c','e','`', 0};
1404 if (!list_empty(&package
->files
))
1405 return ERROR_SUCCESS
;
1407 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1408 if (rc
!= ERROR_SUCCESS
)
1409 return ERROR_SUCCESS
;
1411 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1412 msiobj_release(&view
->hdr
);
1414 return ERROR_SUCCESS
;
1417 static UINT
load_folder( MSIRECORD
*row
, LPVOID param
)
1419 MSIPACKAGE
*package
= param
;
1420 static WCHAR szEmpty
[] = { 0 };
1421 LPWSTR p
, tgt_short
, tgt_long
, src_short
, src_long
;
1424 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1426 return ERROR_NOT_ENOUGH_MEMORY
;
1428 folder
->Directory
= msi_dup_record_field( row
, 1 );
1430 TRACE("%s\n", debugstr_w(folder
->Directory
));
1432 p
= msi_dup_record_field(row
, 3);
1434 /* split src and target dir */
1436 src_short
= folder_split_path( p
, ':' );
1438 /* split the long and short paths */
1439 tgt_long
= folder_split_path( tgt_short
, '|' );
1440 src_long
= folder_split_path( src_short
, '|' );
1442 /* check for no-op dirs */
1443 if (!lstrcmpW(szDot
, tgt_short
))
1444 tgt_short
= szEmpty
;
1445 if (!lstrcmpW(szDot
, src_short
))
1446 src_short
= szEmpty
;
1449 tgt_long
= tgt_short
;
1452 src_short
= tgt_short
;
1453 src_long
= tgt_long
;
1457 src_long
= src_short
;
1459 /* FIXME: use the target short path too */
1460 folder
->TargetDefault
= strdupW(tgt_long
);
1461 folder
->SourceShortPath
= strdupW(src_short
);
1462 folder
->SourceLongPath
= strdupW(src_long
);
1465 TRACE("TargetDefault = %s\n",debugstr_w( folder
->TargetDefault
));
1466 TRACE("SourceLong = %s\n", debugstr_w( folder
->SourceLongPath
));
1467 TRACE("SourceShort = %s\n", debugstr_w( folder
->SourceShortPath
));
1469 folder
->Parent
= msi_dup_record_field( row
, 2 );
1471 folder
->Property
= msi_dup_property( package
, folder
->Directory
);
1473 list_add_tail( &package
->folders
, &folder
->entry
);
1475 TRACE("returning %p\n", folder
);
1477 return ERROR_SUCCESS
;
1480 static UINT
load_all_folders( MSIPACKAGE
*package
)
1482 static const WCHAR query
[] = {
1483 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1484 '`','D','i','r','e','c','t','o','r','y','`',0 };
1488 if (!list_empty(&package
->folders
))
1489 return ERROR_SUCCESS
;
1491 r
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
1492 if (r
!= ERROR_SUCCESS
)
1495 r
= MSI_IterateRecords(view
, NULL
, load_folder
, package
);
1496 msiobj_release(&view
->hdr
);
1501 * I am not doing any of the costing functionality yet.
1502 * Mostly looking at doing the Component and Feature loading
1504 * The native MSI does A LOT of modification to tables here. Mostly adding
1505 * a lot of temporary columns to the Feature and Component tables.
1507 * note: Native msi also tracks the short filename. But I am only going to
1508 * track the long ones. Also looking at this directory table
1509 * it appears that the directory table does not get the parents
1510 * resolved base on property only based on their entries in the
1513 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1515 static const WCHAR szCosting
[] =
1516 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1518 MSI_SetPropertyW(package
, szCosting
, szZero
);
1519 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1521 load_all_folders( package
);
1522 load_all_components( package
);
1523 load_all_features( package
);
1524 load_all_files( package
);
1526 return ERROR_SUCCESS
;
1529 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1532 UINT rc
= ERROR_SUCCESS
;
1534 TRACE("Executing Script %i\n",script
);
1536 if (!package
->script
)
1538 ERR("no script!\n");
1539 return ERROR_FUNCTION_FAILED
;
1542 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1545 action
= package
->script
->Actions
[script
][i
];
1546 ui_actionstart(package
, action
);
1547 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1548 rc
= ACTION_PerformAction(package
, action
, script
, TRUE
);
1549 if (rc
!= ERROR_SUCCESS
)
1552 msi_free_action_script(package
, script
);
1556 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1558 return ERROR_SUCCESS
;
1561 static void ACTION_GetComponentInstallStates(MSIPACKAGE
*package
)
1567 state
= MsiQueryProductStateW(package
->ProductCode
);
1569 LIST_FOR_EACH_ENTRY(comp
, &package
->components
, MSICOMPONENT
, entry
)
1571 if (!comp
->ComponentId
)
1574 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1575 comp
->Installed
= INSTALLSTATE_ABSENT
;
1578 r
= MsiQueryComponentStateW(package
->ProductCode
, NULL
,
1579 package
->Context
, comp
->ComponentId
,
1581 if (r
!= ERROR_SUCCESS
)
1582 comp
->Installed
= INSTALLSTATE_ABSENT
;
1587 static void ACTION_GetFeatureInstallStates(MSIPACKAGE
*package
)
1589 MSIFEATURE
*feature
;
1592 state
= MsiQueryProductStateW(package
->ProductCode
);
1594 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1596 if (state
!= INSTALLSTATE_LOCAL
&& state
!= INSTALLSTATE_DEFAULT
)
1597 feature
->Installed
= INSTALLSTATE_ABSENT
;
1600 feature
->Installed
= MsiQueryFeatureStateW(package
->ProductCode
,
1606 static BOOL
process_state_property(MSIPACKAGE
* package
, int level
,
1607 LPCWSTR property
, INSTALLSTATE state
)
1610 MSIFEATURE
*feature
;
1612 override
= msi_dup_property( package
, property
);
1616 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1618 if (lstrcmpW(property
, szRemove
) &&
1619 (feature
->Level
<= 0 || feature
->Level
> level
))
1622 if (!strcmpW(property
, szReinstall
)) state
= feature
->Installed
;
1624 if (strcmpiW(override
, szAll
)==0)
1625 msi_feature_set_state(package
, feature
, state
);
1628 LPWSTR ptr
= override
;
1629 LPWSTR ptr2
= strchrW(override
,',');
1633 int len
= ptr2
- ptr
;
1635 if ((ptr2
&& strlenW(feature
->Feature
) == len
&& !strncmpW(ptr
, feature
->Feature
, len
))
1636 || (!ptr2
&& !strcmpW(ptr
, feature
->Feature
)))
1638 msi_feature_set_state(package
, feature
, state
);
1644 ptr2
= strchrW(ptr
,',');
1656 static BOOL
process_overrides( MSIPACKAGE
*package
, int level
)
1658 static const WCHAR szAddLocal
[] =
1659 {'A','D','D','L','O','C','A','L',0};
1660 static const WCHAR szAddSource
[] =
1661 {'A','D','D','S','O','U','R','C','E',0};
1662 static const WCHAR szAdvertise
[] =
1663 {'A','D','V','E','R','T','I','S','E',0};
1666 /* all these activation/deactivation things happen in order and things
1667 * later on the list override things earlier on the list.
1669 * 0 INSTALLLEVEL processing
1682 ret
|= process_state_property( package
, level
, szAddLocal
, INSTALLSTATE_LOCAL
);
1683 ret
|= process_state_property( package
, level
, szRemove
, INSTALLSTATE_ABSENT
);
1684 ret
|= process_state_property( package
, level
, szAddSource
, INSTALLSTATE_SOURCE
);
1685 ret
|= process_state_property( package
, level
, szReinstall
, INSTALLSTATE_UNKNOWN
);
1686 ret
|= process_state_property( package
, level
, szAdvertise
, INSTALLSTATE_ADVERTISED
);
1689 MSI_SetPropertyW( package
, szPreselected
, szOne
);
1694 UINT
MSI_SetFeatureStates(MSIPACKAGE
*package
)
1697 static const WCHAR szlevel
[] =
1698 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1699 MSICOMPONENT
* component
;
1700 MSIFEATURE
*feature
;
1702 TRACE("Checking Install Level\n");
1704 level
= msi_get_property_int(package
, szlevel
, 1);
1706 if (!msi_get_property_int( package
, szPreselected
, 0 ))
1708 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1710 BOOL feature_state
= ((feature
->Level
> 0) &&
1711 (feature
->Level
<= level
));
1713 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1715 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1716 msi_feature_set_state(package
, feature
, INSTALLSTATE_SOURCE
);
1717 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1718 msi_feature_set_state(package
, feature
, INSTALLSTATE_ADVERTISED
);
1720 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1724 /* disable child features of unselected parent features */
1725 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1729 if (feature
->Level
> 0 && feature
->Level
<= level
)
1732 LIST_FOR_EACH_ENTRY( fl
, &feature
->Children
, FeatureList
, entry
)
1733 msi_feature_set_state(package
, fl
->feature
, INSTALLSTATE_UNKNOWN
);
1738 * now we want to enable or disable components base on feature
1741 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1745 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1746 debugstr_w(feature
->Feature
), feature
->Level
, feature
->Installed
, feature
->Action
);
1748 if (!feature
->Level
)
1751 /* features with components that have compressed files are made local */
1752 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1754 if (cl
->component
->Enabled
&&
1755 cl
->component
->ForceLocalState
&&
1756 feature
->Action
== INSTALLSTATE_SOURCE
)
1758 msi_feature_set_state(package
, feature
, INSTALLSTATE_LOCAL
);
1763 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1765 component
= cl
->component
;
1767 if (!component
->Enabled
)
1770 switch (feature
->Action
)
1772 case INSTALLSTATE_ABSENT
:
1773 component
->anyAbsent
= 1;
1775 case INSTALLSTATE_ADVERTISED
:
1776 component
->hasAdvertiseFeature
= 1;
1778 case INSTALLSTATE_SOURCE
:
1779 component
->hasSourceFeature
= 1;
1781 case INSTALLSTATE_LOCAL
:
1782 component
->hasLocalFeature
= 1;
1784 case INSTALLSTATE_DEFAULT
:
1785 if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1786 component
->hasAdvertiseFeature
= 1;
1787 else if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1788 component
->hasSourceFeature
= 1;
1790 component
->hasLocalFeature
= 1;
1798 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1800 /* if the component isn't enabled, leave it alone */
1801 if (!component
->Enabled
)
1804 /* check if it's local or source */
1805 if (!(component
->Attributes
& msidbComponentAttributesOptional
) &&
1806 (component
->hasLocalFeature
|| component
->hasSourceFeature
))
1808 if ((component
->Attributes
& msidbComponentAttributesSourceOnly
) &&
1809 !component
->ForceLocalState
)
1810 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1812 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1816 /* if any feature is local, the component must be local too */
1817 if (component
->hasLocalFeature
)
1819 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1823 if (component
->hasSourceFeature
)
1825 msi_component_set_state(package
, component
, INSTALLSTATE_SOURCE
);
1829 if (component
->hasAdvertiseFeature
)
1831 msi_component_set_state(package
, component
, INSTALLSTATE_ADVERTISED
);
1835 TRACE("nobody wants component %s\n", debugstr_w(component
->Component
));
1836 if (component
->anyAbsent
)
1837 msi_component_set_state(package
, component
, INSTALLSTATE_ABSENT
);
1840 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1842 if (component
->Action
== INSTALLSTATE_DEFAULT
)
1844 TRACE("%s was default, setting to local\n", debugstr_w(component
->Component
));
1845 msi_component_set_state(package
, component
, INSTALLSTATE_LOCAL
);
1848 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1849 debugstr_w(component
->Component
), component
->Installed
, component
->Action
);
1853 return ERROR_SUCCESS
;
1856 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1858 MSIPACKAGE
*package
= param
;
1863 name
= MSI_RecordGetString(row
,1);
1865 f
= get_loaded_folder(package
, name
);
1866 if (!f
) return ERROR_SUCCESS
;
1868 /* reset the ResolvedTarget */
1869 msi_free(f
->ResolvedTarget
);
1870 f
->ResolvedTarget
= NULL
;
1872 /* This helper function now does ALL the work */
1873 TRACE("Dir %s ...\n",debugstr_w(name
));
1874 path
= resolve_folder(package
,name
,FALSE
,TRUE
,TRUE
,NULL
);
1875 TRACE("resolves to %s\n",debugstr_w(path
));
1878 return ERROR_SUCCESS
;
1881 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1883 MSIPACKAGE
*package
= param
;
1885 MSIFEATURE
*feature
;
1887 name
= MSI_RecordGetString( row
, 1 );
1889 feature
= get_loaded_feature( package
, name
);
1891 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1895 Condition
= MSI_RecordGetString(row
,3);
1897 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1899 int level
= MSI_RecordGetInteger(row
,2);
1900 TRACE("Resetting feature %s to level %i\n", debugstr_w(name
), level
);
1901 feature
->Level
= level
;
1904 return ERROR_SUCCESS
;
1907 static LPWSTR
msi_get_disk_file_version( LPCWSTR filename
)
1909 static const WCHAR name_fmt
[] =
1910 {'%','u','.','%','u','.','%','u','.','%','u',0};
1911 static const WCHAR name
[] = {'\\',0};
1912 VS_FIXEDFILEINFO
*lpVer
;
1913 WCHAR filever
[0x100];
1919 TRACE("%s\n", debugstr_w(filename
));
1921 versize
= GetFileVersionInfoSizeW( filename
, &handle
);
1925 version
= msi_alloc( versize
);
1926 GetFileVersionInfoW( filename
, 0, versize
, version
);
1928 if (!VerQueryValueW( version
, name
, (LPVOID
*)&lpVer
, &sz
))
1930 msi_free( version
);
1934 sprintfW( filever
, name_fmt
,
1935 HIWORD(lpVer
->dwFileVersionMS
),
1936 LOWORD(lpVer
->dwFileVersionMS
),
1937 HIWORD(lpVer
->dwFileVersionLS
),
1938 LOWORD(lpVer
->dwFileVersionLS
));
1940 msi_free( version
);
1942 return strdupW( filever
);
1945 static UINT
msi_check_file_install_states( MSIPACKAGE
*package
)
1947 LPWSTR file_version
;
1950 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1952 MSICOMPONENT
* comp
= file
->Component
;
1958 if (file
->IsCompressed
)
1959 comp
->ForceLocalState
= TRUE
;
1961 /* calculate target */
1962 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, TRUE
, NULL
);
1964 msi_free(file
->TargetPath
);
1966 TRACE("file %s is named %s\n",
1967 debugstr_w(file
->File
), debugstr_w(file
->FileName
));
1969 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1973 TRACE("file %s resolves to %s\n",
1974 debugstr_w(file
->File
), debugstr_w(file
->TargetPath
));
1976 /* don't check files of components that aren't installed */
1977 if (comp
->Installed
== INSTALLSTATE_UNKNOWN
||
1978 comp
->Installed
== INSTALLSTATE_ABSENT
)
1980 file
->state
= msifs_missing
; /* assume files are missing */
1984 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1986 file
->state
= msifs_missing
;
1987 comp
->Cost
+= file
->FileSize
;
1991 if (file
->Version
&&
1992 (file_version
= msi_get_disk_file_version( file
->TargetPath
)))
1994 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1995 debugstr_w(file_version
));
1996 /* FIXME: seems like a bad way to compare version numbers */
1997 if (lstrcmpiW(file_version
, file
->Version
)<0)
1999 file
->state
= msifs_overwrite
;
2000 comp
->Cost
+= file
->FileSize
;
2003 file
->state
= msifs_present
;
2004 msi_free( file_version
);
2007 file
->state
= msifs_present
;
2010 return ERROR_SUCCESS
;
2014 * A lot is done in this function aside from just the costing.
2015 * The costing needs to be implemented at some point but for now I am going
2016 * to focus on the directory building
2019 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2021 static const WCHAR ExecSeqQuery
[] =
2022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023 '`','D','i','r','e','c','t','o','r','y','`',0};
2024 static const WCHAR ConditionQuery
[] =
2025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026 '`','C','o','n','d','i','t','i','o','n','`',0};
2027 static const WCHAR szCosting
[] =
2028 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029 static const WCHAR szlevel
[] =
2030 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2031 static const WCHAR szOutOfDiskSpace
[] =
2032 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2034 UINT rc
= ERROR_SUCCESS
;
2038 TRACE("Building Directory properties\n");
2040 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2041 if (rc
== ERROR_SUCCESS
)
2043 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
2045 msiobj_release(&view
->hdr
);
2048 /* read components states from the registry */
2049 ACTION_GetComponentInstallStates(package
);
2050 ACTION_GetFeatureInstallStates(package
);
2052 TRACE("File calculations\n");
2053 msi_check_file_install_states( package
);
2055 if (!process_overrides( package
, msi_get_property_int( package
, szlevel
, 1 ) ))
2057 TRACE("Evaluating Condition Table\n");
2059 rc
= MSI_DatabaseOpenViewW( package
->db
, ConditionQuery
, &view
);
2060 if (rc
== ERROR_SUCCESS
)
2062 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_CostFinalizeConditions
, package
);
2063 msiobj_release( &view
->hdr
);
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2069 if (MSI_EvaluateConditionW( package
, comp
->Condition
) == MSICONDITION_FALSE
)
2071 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
2072 comp
->Enabled
= FALSE
;
2075 comp
->Enabled
= TRUE
;
2079 MSI_SetPropertyW(package
,szCosting
,szOne
);
2080 /* set default run level if not set */
2081 level
= msi_dup_property( package
, szlevel
);
2083 MSI_SetPropertyW(package
,szlevel
, szOne
);
2086 /* FIXME: check volume disk space */
2087 MSI_SetPropertyW(package
, szOutOfDiskSpace
, szZero
);
2089 return MSI_SetFeatureStates(package
);
2092 /* OK this value is "interpreted" and then formatted based on the
2093 first few characters */
2094 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
2099 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2105 LPWSTR deformated
= NULL
;
2108 deformat_string(package
, &value
[2], &deformated
);
2110 /* binary value type */
2114 *size
= (strlenW(ptr
)/2)+1;
2116 *size
= strlenW(ptr
)/2;
2118 data
= msi_alloc(*size
);
2124 /* if uneven pad with a zero in front */
2130 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2132 TRACE("Uneven byte count\n");
2140 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2143 msi_free(deformated
);
2145 TRACE("Data %i bytes(%i)\n",*size
,count
);
2152 deformat_string(package
, &value
[1], &deformated
);
2155 *size
= sizeof(DWORD
);
2156 data
= msi_alloc(*size
);
2162 if ( (*p
< '0') || (*p
> '9') )
2168 if (deformated
[0] == '-')
2171 TRACE("DWORD %i\n",*(LPDWORD
)data
);
2173 msi_free(deformated
);
2178 static const WCHAR szMulti
[] = {'[','~',']',0};
2187 *type
=REG_EXPAND_SZ
;
2195 if (strstrW(value
,szMulti
))
2196 *type
= REG_MULTI_SZ
;
2198 /* remove initial delimiter */
2199 if (!strncmpW(value
, szMulti
, 3))
2202 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2204 /* add double NULL terminator */
2205 if (*type
== REG_MULTI_SZ
)
2207 *size
+= 2 * sizeof(WCHAR
); /* two NULL terminators */
2208 data
= msi_realloc_zero(data
, *size
);
2214 static const WCHAR
*get_root_key( MSIPACKAGE
*package
, INT root
, HKEY
*root_key
)
2221 if (msi_get_property_int( package
, szAllUsers
, 0 ))
2223 *root_key
= HKEY_LOCAL_MACHINE
;
2228 *root_key
= HKEY_CURRENT_USER
;
2233 *root_key
= HKEY_CLASSES_ROOT
;
2237 *root_key
= HKEY_CURRENT_USER
;
2241 *root_key
= HKEY_LOCAL_MACHINE
;
2245 *root_key
= HKEY_USERS
;
2249 ERR("Unknown root %i\n", root
);
2256 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2258 MSIPACKAGE
*package
= param
;
2259 LPSTR value_data
= NULL
;
2260 HKEY root_key
, hkey
;
2263 LPCWSTR szRoot
, component
, name
, key
, value
;
2268 BOOL check_first
= FALSE
;
2271 ui_progress(package
,2,0,0,0);
2278 component
= MSI_RecordGetString(row
, 6);
2279 comp
= get_loaded_component(package
,component
);
2281 return ERROR_SUCCESS
;
2283 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2285 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2286 comp
->Action
= comp
->Installed
;
2287 return ERROR_SUCCESS
;
2289 comp
->Action
= INSTALLSTATE_LOCAL
;
2291 name
= MSI_RecordGetString(row
, 4);
2292 if( MSI_RecordIsNull(row
,5) && name
)
2294 /* null values can have special meanings */
2295 if (name
[0]=='-' && name
[1] == 0)
2296 return ERROR_SUCCESS
;
2297 else if ((name
[0]=='+' && name
[1] == 0) ||
2298 (name
[0] == '*' && name
[1] == 0))
2303 root
= MSI_RecordGetInteger(row
,2);
2304 key
= MSI_RecordGetString(row
, 3);
2306 szRoot
= get_root_key( package
, root
, &root_key
);
2308 return ERROR_SUCCESS
;
2310 deformat_string(package
, key
, &deformated
);
2311 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2312 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2313 strcpyW(uikey
,szRoot
);
2314 strcatW(uikey
,deformated
);
2316 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2318 ERR("Could not create key %s\n",debugstr_w(deformated
));
2319 msi_free(deformated
);
2321 return ERROR_SUCCESS
;
2323 msi_free(deformated
);
2325 value
= MSI_RecordGetString(row
,5);
2327 value_data
= parse_value(package
, value
, &type
, &size
);
2330 value_data
= (LPSTR
)strdupW(szEmpty
);
2331 size
= sizeof(szEmpty
);
2335 deformat_string(package
, name
, &deformated
);
2339 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2341 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2346 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2347 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2349 TRACE("value %s of %s checked already exists\n",
2350 debugstr_w(deformated
), debugstr_w(uikey
));
2354 TRACE("Checked and setting value %s of %s\n",
2355 debugstr_w(deformated
), debugstr_w(uikey
));
2356 if (deformated
|| size
)
2357 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2362 uirow
= MSI_CreateRecord(3);
2363 MSI_RecordSetStringW(uirow
,2,deformated
);
2364 MSI_RecordSetStringW(uirow
,1,uikey
);
2367 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2369 MSI_RecordSetStringW(uirow
,3,value
);
2371 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2372 msiobj_release( &uirow
->hdr
);
2374 msi_free(value_data
);
2375 msi_free(deformated
);
2378 return ERROR_SUCCESS
;
2381 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2385 static const WCHAR ExecSeqQuery
[] =
2386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2387 '`','R','e','g','i','s','t','r','y','`',0 };
2389 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2390 if (rc
!= ERROR_SUCCESS
)
2391 return ERROR_SUCCESS
;
2393 /* increment progress bar each time action data is sent */
2394 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2396 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2398 msiobj_release(&view
->hdr
);
2402 static void delete_reg_key_or_value( HKEY hkey_root
, LPCWSTR key
, LPCWSTR value
, BOOL delete_key
)
2406 DWORD num_subkeys
, num_values
;
2410 if ((res
= RegDeleteTreeW( hkey_root
, key
)))
2412 WARN("Failed to delete key %s (%d)\n", debugstr_w(key
), res
);
2417 if (!(res
= RegOpenKeyW( hkey_root
, key
, &hkey
)))
2419 if ((res
= RegDeleteValueW( hkey
, value
)))
2421 WARN("Failed to delete value %s (%d)\n", debugstr_w(value
), res
);
2423 res
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
, NULL
, &num_values
,
2424 NULL
, NULL
, NULL
, NULL
);
2425 RegCloseKey( hkey
);
2427 if (!res
&& !num_subkeys
&& !num_values
)
2429 TRACE("Removing empty key %s\n", debugstr_w(key
));
2430 RegDeleteKeyW( hkey_root
, key
);
2434 WARN("Failed to open key %s (%d)\n", debugstr_w(key
), res
);
2438 static UINT
ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
2440 MSIPACKAGE
*package
= param
;
2441 LPCWSTR component
, name
, key_str
, root_key_str
;
2442 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2445 BOOL delete_key
= FALSE
;
2450 ui_progress( package
, 2, 0, 0, 0 );
2452 component
= MSI_RecordGetString( row
, 6 );
2453 comp
= get_loaded_component( package
, component
);
2455 return ERROR_SUCCESS
;
2457 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2459 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
2460 comp
->Action
= comp
->Installed
;
2461 return ERROR_SUCCESS
;
2463 comp
->Action
= INSTALLSTATE_ABSENT
;
2465 name
= MSI_RecordGetString( row
, 4 );
2466 if (MSI_RecordIsNull( row
, 5 ) && name
)
2468 if (name
[0] == '+' && !name
[1])
2469 return ERROR_SUCCESS
;
2470 else if ((name
[0] == '-' && !name
[1]) || (name
[0] == '*' && !name
[1]))
2477 root
= MSI_RecordGetInteger( row
, 2 );
2478 key_str
= MSI_RecordGetString( row
, 3 );
2480 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2482 return ERROR_SUCCESS
;
2484 deformat_string( package
, key_str
, &deformated_key
);
2485 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2486 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2487 strcpyW( ui_key_str
, root_key_str
);
2488 strcatW( ui_key_str
, deformated_key
);
2490 deformat_string( package
, name
, &deformated_name
);
2492 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2493 msi_free( deformated_key
);
2495 uirow
= MSI_CreateRecord( 2 );
2496 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2497 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2499 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2500 msiobj_release( &uirow
->hdr
);
2502 msi_free( ui_key_str
);
2503 msi_free( deformated_name
);
2504 return ERROR_SUCCESS
;
2507 static UINT
ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
2509 MSIPACKAGE
*package
= param
;
2510 LPCWSTR component
, name
, key_str
, root_key_str
;
2511 LPWSTR deformated_key
, deformated_name
, ui_key_str
;
2514 BOOL delete_key
= FALSE
;
2519 ui_progress( package
, 2, 0, 0, 0 );
2521 component
= MSI_RecordGetString( row
, 5 );
2522 comp
= get_loaded_component( package
, component
);
2524 return ERROR_SUCCESS
;
2526 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2528 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
2529 comp
->Action
= comp
->Installed
;
2530 return ERROR_SUCCESS
;
2532 comp
->Action
= INSTALLSTATE_LOCAL
;
2534 if ((name
= MSI_RecordGetString( row
, 4 )))
2536 if (name
[0] == '-' && !name
[1])
2543 root
= MSI_RecordGetInteger( row
, 2 );
2544 key_str
= MSI_RecordGetString( row
, 3 );
2546 root_key_str
= get_root_key( package
, root
, &hkey_root
);
2548 return ERROR_SUCCESS
;
2550 deformat_string( package
, key_str
, &deformated_key
);
2551 size
= strlenW( deformated_key
) + strlenW( root_key_str
) + 1;
2552 ui_key_str
= msi_alloc( size
* sizeof(WCHAR
) );
2553 strcpyW( ui_key_str
, root_key_str
);
2554 strcatW( ui_key_str
, deformated_key
);
2556 deformat_string( package
, name
, &deformated_name
);
2558 delete_reg_key_or_value( hkey_root
, deformated_key
, deformated_name
, delete_key
);
2559 msi_free( deformated_key
);
2561 uirow
= MSI_CreateRecord( 2 );
2562 MSI_RecordSetStringW( uirow
, 1, ui_key_str
);
2563 MSI_RecordSetStringW( uirow
, 2, deformated_name
);
2565 ui_actiondata( package
, szRemoveRegistryValues
, uirow
);
2566 msiobj_release( &uirow
->hdr
);
2568 msi_free( ui_key_str
);
2569 msi_free( deformated_name
);
2570 return ERROR_SUCCESS
;
2573 static UINT
ACTION_RemoveRegistryValues( MSIPACKAGE
*package
)
2577 static const WCHAR registry_query
[] =
2578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2579 '`','R','e','g','i','s','t','r','y','`',0 };
2580 static const WCHAR remove_registry_query
[] =
2581 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2582 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2584 /* increment progress bar each time action data is sent */
2585 ui_progress( package
, 1, REG_PROGRESS_VALUE
, 1, 0 );
2587 rc
= MSI_DatabaseOpenViewW( package
->db
, registry_query
, &view
);
2588 if (rc
== ERROR_SUCCESS
)
2590 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnUninstall
, package
);
2591 msiobj_release( &view
->hdr
);
2592 if (rc
!= ERROR_SUCCESS
)
2596 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_registry_query
, &view
);
2597 if (rc
== ERROR_SUCCESS
)
2599 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveRegistryValuesOnInstall
, package
);
2600 msiobj_release( &view
->hdr
);
2601 if (rc
!= ERROR_SUCCESS
)
2605 return ERROR_SUCCESS
;
2608 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2610 package
->script
->CurrentlyScripting
= TRUE
;
2612 return ERROR_SUCCESS
;
2616 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2621 static const WCHAR q1
[]=
2622 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2623 '`','R','e','g','i','s','t','r','y','`',0};
2626 MSIFEATURE
*feature
;
2629 TRACE("InstallValidate\n");
2631 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2632 if (rc
== ERROR_SUCCESS
)
2634 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2635 msiobj_release( &view
->hdr
);
2636 total
+= progress
* REG_PROGRESS_VALUE
;
2639 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2640 total
+= COMPONENT_PROGRESS_VALUE
;
2642 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2643 total
+= file
->FileSize
;
2645 ui_progress(package
,0,total
,0,0);
2647 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2649 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2650 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2651 feature
->ActionRequest
);
2654 return ERROR_SUCCESS
;
2657 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2659 MSIPACKAGE
* package
= param
;
2660 LPCWSTR cond
= NULL
;
2661 LPCWSTR message
= NULL
;
2664 static const WCHAR title
[]=
2665 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2667 cond
= MSI_RecordGetString(row
,1);
2669 r
= MSI_EvaluateConditionW(package
,cond
);
2670 if (r
== MSICONDITION_FALSE
)
2672 if ((gUILevel
& INSTALLUILEVEL_MASK
) != INSTALLUILEVEL_NONE
)
2675 message
= MSI_RecordGetString(row
,2);
2676 deformat_string(package
,message
,&deformated
);
2677 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2678 msi_free(deformated
);
2681 return ERROR_INSTALL_FAILURE
;
2684 return ERROR_SUCCESS
;
2687 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2690 MSIQUERY
* view
= NULL
;
2691 static const WCHAR ExecSeqQuery
[] =
2692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2693 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2695 TRACE("Checking launch conditions\n");
2697 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2698 if (rc
!= ERROR_SUCCESS
)
2699 return ERROR_SUCCESS
;
2701 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2702 msiobj_release(&view
->hdr
);
2707 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2711 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,TRUE
,NULL
);
2713 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2715 MSIRECORD
* row
= 0;
2717 LPWSTR deformated
,buffer
,deformated_name
;
2719 static const WCHAR ExecSeqQuery
[] =
2720 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2721 '`','R','e','g','i','s','t','r','y','`',' ',
2722 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2723 ' ','=',' ' ,'\'','%','s','\'',0 };
2724 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2725 static const WCHAR fmt2
[]=
2726 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2728 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2732 root
= MSI_RecordGetInteger(row
,2);
2733 key
= MSI_RecordGetString(row
, 3);
2734 name
= MSI_RecordGetString(row
, 4);
2735 deformat_string(package
, key
, &deformated
);
2736 deformat_string(package
, name
, &deformated_name
);
2738 len
= strlenW(deformated
) + 6;
2739 if (deformated_name
)
2740 len
+=strlenW(deformated_name
);
2742 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2744 if (deformated_name
)
2745 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2747 sprintfW(buffer
,fmt
,root
,deformated
);
2749 msi_free(deformated
);
2750 msi_free(deformated_name
);
2751 msiobj_release(&row
->hdr
);
2755 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2757 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2762 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2765 return strdupW( file
->TargetPath
);
2770 static HKEY
openSharedDLLsKey(void)
2773 static const WCHAR path
[] =
2774 {'S','o','f','t','w','a','r','e','\\',
2775 'M','i','c','r','o','s','o','f','t','\\',
2776 'W','i','n','d','o','w','s','\\',
2777 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2778 'S','h','a','r','e','d','D','L','L','s',0};
2780 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2784 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2789 DWORD sz
= sizeof(count
);
2792 hkey
= openSharedDLLsKey();
2793 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2794 if (rc
!= ERROR_SUCCESS
)
2800 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2804 hkey
= openSharedDLLsKey();
2806 msi_reg_set_val_dword( hkey
, path
, count
);
2808 RegDeleteValueW(hkey
,path
);
2814 * Return TRUE if the count should be written out and FALSE if not
2816 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2818 MSIFEATURE
*feature
;
2822 /* only refcount DLLs */
2823 if (comp
->KeyPath
== NULL
||
2824 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2825 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2829 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2830 write
= (count
> 0);
2832 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2836 /* increment counts */
2837 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2841 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
)
2844 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2846 if ( cl
->component
== comp
)
2851 /* decrement counts */
2852 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2856 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
2859 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2861 if ( cl
->component
== comp
)
2866 /* ref count all the files in the component */
2871 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2873 if (file
->Component
== comp
)
2874 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2878 /* add a count for permanent */
2879 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2882 comp
->RefCount
= count
;
2885 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2888 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2890 WCHAR squished_pc
[GUID_SIZE
];
2891 WCHAR squished_cc
[GUID_SIZE
];
2898 squash_guid(package
->ProductCode
,squished_pc
);
2899 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2901 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2905 ui_progress(package
,2,0,0,0);
2906 if (!comp
->ComponentId
)
2909 squash_guid(comp
->ComponentId
,squished_cc
);
2911 msi_free(comp
->FullKeypath
);
2912 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2914 ACTION_RefCountComponent( package
, comp
);
2916 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2917 debugstr_w(comp
->Component
),
2918 debugstr_w(squished_cc
),
2919 debugstr_w(comp
->FullKeypath
),
2922 if (comp
->ActionRequest
== INSTALLSTATE_LOCAL
||
2923 comp
->ActionRequest
== INSTALLSTATE_SOURCE
)
2925 if (!comp
->FullKeypath
)
2928 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2929 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, szLocalSid
,
2932 rc
= MSIREG_OpenUserDataComponentKey(comp
->ComponentId
, NULL
,
2935 if (rc
!= ERROR_SUCCESS
)
2938 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2940 static const WCHAR szPermKey
[] =
2941 { '0','0','0','0','0','0','0','0','0','0','0','0',
2942 '0','0','0','0','0','0','0','0','0','0','0','0',
2943 '0','0','0','0','0','0','0','0',0 };
2945 msi_reg_set_val_str(hkey
, szPermKey
, comp
->FullKeypath
);
2948 if (comp
->Action
== INSTALLSTATE_LOCAL
)
2949 msi_reg_set_val_str(hkey
, squished_pc
, comp
->FullKeypath
);
2955 WCHAR source
[MAX_PATH
];
2956 WCHAR base
[MAX_PATH
];
2959 static const WCHAR fmt
[] = {'%','0','2','d','\\',0};
2960 static const WCHAR query
[] = {
2961 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2962 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2963 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2964 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2965 '`','D','i','s','k','I','d','`',0};
2967 file
= get_loaded_file(package
, comp
->KeyPath
);
2971 row
= MSI_QueryGetRecord(package
->db
, query
, file
->Sequence
);
2972 sprintfW(source
, fmt
, MSI_RecordGetInteger(row
, 1));
2973 ptr2
= strrchrW(source
, '\\') + 1;
2974 msiobj_release(&row
->hdr
);
2976 lstrcpyW(base
, package
->PackagePath
);
2977 ptr
= strrchrW(base
, '\\');
2980 sourcepath
= resolve_file_source(package
, file
);
2981 ptr
= sourcepath
+ lstrlenW(base
);
2982 lstrcpyW(ptr2
, ptr
);
2983 msi_free(sourcepath
);
2985 msi_reg_set_val_str(hkey
, squished_pc
, source
);
2989 else if (comp
->ActionRequest
== INSTALLSTATE_ABSENT
)
2991 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
2992 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, szLocalSid
);
2994 MSIREG_DeleteUserDataComponentKey(comp
->ComponentId
, NULL
);
2998 uirow
= MSI_CreateRecord(3);
2999 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
3000 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
3001 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
3002 ui_actiondata(package
,szProcessComponents
,uirow
);
3003 msiobj_release( &uirow
->hdr
);
3006 return ERROR_SUCCESS
;
3017 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
3018 LPWSTR lpszName
, LONG_PTR lParam
)
3021 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
3022 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
3026 if (!IS_INTRESOURCE(lpszName
))
3028 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
3032 sz
= strlenW(tl_struct
->source
)+4;
3033 sz
*= sizeof(WCHAR
);
3035 if ((INT_PTR
)lpszName
== 1)
3036 tl_struct
->path
= strdupW(tl_struct
->source
);
3039 tl_struct
->path
= msi_alloc(sz
);
3040 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
3043 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
3044 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
3047 msi_free(tl_struct
->path
);
3048 tl_struct
->path
= NULL
;
3053 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
3054 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
3056 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3060 msi_free(tl_struct
->path
);
3061 tl_struct
->path
= NULL
;
3063 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
3064 ITypeLib_Release(tl_struct
->ptLib
);
3069 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
3071 MSIPACKAGE
* package
= param
;
3075 typelib_struct tl_struct
;
3080 component
= MSI_RecordGetString(row
,3);
3081 comp
= get_loaded_component(package
,component
);
3083 return ERROR_SUCCESS
;
3085 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3087 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
3088 comp
->Action
= comp
->Installed
;
3089 return ERROR_SUCCESS
;
3091 comp
->Action
= INSTALLSTATE_LOCAL
;
3093 file
= get_loaded_file( package
, comp
->KeyPath
);
3095 return ERROR_SUCCESS
;
3097 ui_actiondata( package
, szRegisterTypeLibraries
, row
);
3099 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3103 guid
= MSI_RecordGetString(row
,1);
3104 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
3105 tl_struct
.source
= strdupW( file
->TargetPath
);
3106 tl_struct
.path
= NULL
;
3108 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
3109 (LONG_PTR
)&tl_struct
);
3117 helpid
= MSI_RecordGetString(row
,6);
3120 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,TRUE
,NULL
);
3121 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
3125 ERR("Failed to register type library %s\n",
3126 debugstr_w(tl_struct
.path
));
3128 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
3130 ITypeLib_Release(tl_struct
.ptLib
);
3131 msi_free(tl_struct
.path
);
3134 ERR("Failed to load type library %s\n",
3135 debugstr_w(tl_struct
.source
));
3137 FreeLibrary(module
);
3138 msi_free(tl_struct
.source
);
3142 hr
= LoadTypeLibEx(file
->TargetPath
, REGKIND_REGISTER
, &tlib
);
3145 ERR("Failed to load type library: %08x\n", hr
);
3146 return ERROR_INSTALL_FAILURE
;
3149 ITypeLib_Release(tlib
);
3152 return ERROR_SUCCESS
;
3155 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3158 * OK this is a bit confusing.. I am given a _Component key and I believe
3159 * that the file that is being registered as a type library is the "key file
3160 * of that component" which I interpret to mean "The file in the KeyPath of
3165 static const WCHAR Query
[] =
3166 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3167 '`','T','y','p','e','L','i','b','`',0};
3169 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3170 if (rc
!= ERROR_SUCCESS
)
3171 return ERROR_SUCCESS
;
3173 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
3174 msiobj_release(&view
->hdr
);
3178 static UINT
ITERATE_UnregisterTypeLibraries( MSIRECORD
*row
, LPVOID param
)
3180 MSIPACKAGE
*package
= param
;
3181 LPCWSTR component
, guid
;
3189 component
= MSI_RecordGetString( row
, 3 );
3190 comp
= get_loaded_component( package
, component
);
3192 return ERROR_SUCCESS
;
3194 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3196 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3197 comp
->Action
= comp
->Installed
;
3198 return ERROR_SUCCESS
;
3200 comp
->Action
= INSTALLSTATE_ABSENT
;
3202 ui_actiondata( package
, szUnregisterTypeLibraries
, row
);
3204 guid
= MSI_RecordGetString( row
, 1 );
3205 CLSIDFromString( (LPWSTR
)guid
, &libid
);
3206 version
= MSI_RecordGetInteger( row
, 4 );
3207 language
= MSI_RecordGetInteger( row
, 2 );
3210 syskind
= SYS_WIN64
;
3212 syskind
= SYS_WIN32
;
3215 hr
= UnRegisterTypeLib( &libid
, (version
>> 8) & 0xffff, version
& 0xff, language
, syskind
);
3218 WARN("Failed to unregister typelib: %08x\n", hr
);
3221 return ERROR_SUCCESS
;
3224 static UINT
ACTION_UnregisterTypeLibraries( MSIPACKAGE
*package
)
3228 static const WCHAR query
[] =
3229 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3230 '`','T','y','p','e','L','i','b','`',0};
3232 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3233 if (rc
!= ERROR_SUCCESS
)
3234 return ERROR_SUCCESS
;
3236 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnregisterTypeLibraries
, package
);
3237 msiobj_release( &view
->hdr
);
3241 static WCHAR
*get_link_file( MSIPACKAGE
*package
, MSIRECORD
*row
)
3243 static const WCHAR szlnk
[] = {'.','l','n','k',0};
3244 LPCWSTR directory
, extension
;
3245 LPWSTR link_folder
, link_file
, filename
;
3247 directory
= MSI_RecordGetString( row
, 2 );
3248 link_folder
= resolve_folder( package
, directory
, FALSE
, FALSE
, TRUE
, NULL
);
3250 /* may be needed because of a bug somewhere else */
3251 create_full_pathW( link_folder
);
3253 filename
= msi_dup_record_field( row
, 3 );
3254 reduce_to_longfilename( filename
);
3256 extension
= strchrW( filename
, '.' );
3257 if (!extension
|| strcmpiW( extension
, szlnk
))
3259 int len
= strlenW( filename
);
3260 filename
= msi_realloc( filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
) );
3261 memcpy( filename
+ len
, szlnk
, sizeof(szlnk
) );
3263 link_file
= build_directory_name( 2, link_folder
, filename
);
3264 msi_free( link_folder
);
3265 msi_free( filename
);
3270 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
3272 MSIPACKAGE
*package
= param
;
3273 LPWSTR link_file
, deformated
, path
;
3274 LPCWSTR component
, target
;
3276 IShellLinkW
*sl
= NULL
;
3277 IPersistFile
*pf
= NULL
;
3280 component
= MSI_RecordGetString(row
, 4);
3281 comp
= get_loaded_component(package
, component
);
3283 return ERROR_SUCCESS
;
3285 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3287 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3288 comp
->Action
= comp
->Installed
;
3289 return ERROR_SUCCESS
;
3291 comp
->Action
= INSTALLSTATE_LOCAL
;
3293 ui_actiondata(package
,szCreateShortcuts
,row
);
3295 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3296 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3300 ERR("CLSID_ShellLink not available\n");
3304 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3307 ERR("QueryInterface(IID_IPersistFile) failed\n");
3311 target
= MSI_RecordGetString(row
, 5);
3312 if (strchrW(target
, '['))
3314 deformat_string(package
, target
, &deformated
);
3315 IShellLinkW_SetPath(sl
,deformated
);
3316 msi_free(deformated
);
3320 FIXME("poorly handled shortcut format, advertised shortcut\n");
3321 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
3324 if (!MSI_RecordIsNull(row
,6))
3326 LPCWSTR arguments
= MSI_RecordGetString(row
, 6);
3327 deformat_string(package
, arguments
, &deformated
);
3328 IShellLinkW_SetArguments(sl
,deformated
);
3329 msi_free(deformated
);
3332 if (!MSI_RecordIsNull(row
,7))
3334 LPCWSTR description
= MSI_RecordGetString(row
, 7);
3335 IShellLinkW_SetDescription(sl
, description
);
3338 if (!MSI_RecordIsNull(row
,8))
3339 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
3341 if (!MSI_RecordIsNull(row
,9))
3344 LPCWSTR icon
= MSI_RecordGetString(row
, 9);
3346 path
= build_icon_path(package
, icon
);
3347 index
= MSI_RecordGetInteger(row
,10);
3349 /* no value means 0 */
3350 if (index
== MSI_NULL_INTEGER
)
3353 IShellLinkW_SetIconLocation(sl
, path
, index
);
3357 if (!MSI_RecordIsNull(row
,11))
3358 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
3360 if (!MSI_RecordIsNull(row
,12))
3362 LPCWSTR wkdir
= MSI_RecordGetString(row
, 12);
3363 path
= resolve_folder(package
, wkdir
, FALSE
, FALSE
, TRUE
, NULL
);
3365 IShellLinkW_SetWorkingDirectory(sl
, path
);
3369 link_file
= get_link_file(package
, row
);
3371 TRACE("Writing shortcut to %s\n", debugstr_w(link_file
));
3372 IPersistFile_Save(pf
, link_file
, FALSE
);
3374 msi_free(link_file
);
3378 IPersistFile_Release( pf
);
3380 IShellLinkW_Release( sl
);
3382 return ERROR_SUCCESS
;
3385 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3390 static const WCHAR Query
[] =
3391 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3392 '`','S','h','o','r','t','c','u','t','`',0};
3394 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3395 if (rc
!= ERROR_SUCCESS
)
3396 return ERROR_SUCCESS
;
3398 res
= CoInitialize( NULL
);
3400 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
3401 msiobj_release(&view
->hdr
);
3409 static UINT
ITERATE_RemoveShortcuts( MSIRECORD
*row
, LPVOID param
)
3411 MSIPACKAGE
*package
= param
;
3416 component
= MSI_RecordGetString( row
, 4 );
3417 comp
= get_loaded_component( package
, component
);
3419 return ERROR_SUCCESS
;
3421 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3423 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3424 comp
->Action
= comp
->Installed
;
3425 return ERROR_SUCCESS
;
3427 comp
->Action
= INSTALLSTATE_ABSENT
;
3429 ui_actiondata( package
, szRemoveShortcuts
, row
);
3431 link_file
= get_link_file( package
, row
);
3433 TRACE("Removing shortcut file %s\n", debugstr_w( link_file
));
3434 if (!DeleteFileW( link_file
))
3436 WARN("Failed to remove shortcut file %u\n", GetLastError());
3438 msi_free( link_file
);
3440 return ERROR_SUCCESS
;
3443 static UINT
ACTION_RemoveShortcuts( MSIPACKAGE
*package
)
3447 static const WCHAR query
[] =
3448 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3449 '`','S','h','o','r','t','c','u','t','`',0};
3451 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
3452 if (rc
!= ERROR_SUCCESS
)
3453 return ERROR_SUCCESS
;
3455 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveShortcuts
, package
);
3456 msiobj_release( &view
->hdr
);
3461 static UINT
ITERATE_PublishIcon(MSIRECORD
*row
, LPVOID param
)
3463 MSIPACKAGE
* package
= param
;
3471 FileName
= MSI_RecordGetString(row
,1);
3474 ERR("Unable to get FileName\n");
3475 return ERROR_SUCCESS
;
3478 FilePath
= build_icon_path(package
,FileName
);
3480 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
3482 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
3483 FILE_ATTRIBUTE_NORMAL
, NULL
);
3485 if (the_file
== INVALID_HANDLE_VALUE
)
3487 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3489 return ERROR_SUCCESS
;
3496 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3497 if (rc
!= ERROR_SUCCESS
)
3499 ERR("Failed to get stream\n");
3500 CloseHandle(the_file
);
3501 DeleteFileW(FilePath
);
3504 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3505 } while (sz
== 1024);
3508 CloseHandle(the_file
);
3510 return ERROR_SUCCESS
;
3513 static UINT
msi_publish_icons(MSIPACKAGE
*package
)
3518 static const WCHAR query
[]= {
3519 'S','E','L','E','C','T',' ','*',' ',
3520 'F','R','O','M',' ','`','I','c','o','n','`',0};
3522 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
3523 if (r
== ERROR_SUCCESS
)
3525 MSI_IterateRecords(view
, NULL
, ITERATE_PublishIcon
, package
);
3526 msiobj_release(&view
->hdr
);
3529 return ERROR_SUCCESS
;
3532 static UINT
msi_publish_sourcelist(MSIPACKAGE
*package
, HKEY hkey
)
3538 MSISOURCELISTINFO
*info
;
3540 r
= RegCreateKeyW(hkey
, szSourceList
, &source
);
3541 if (r
!= ERROR_SUCCESS
)
3544 RegCloseKey(source
);
3546 buffer
= strrchrW(package
->PackagePath
, '\\') + 1;
3547 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3548 package
->Context
, MSICODE_PRODUCT
,
3549 INSTALLPROPERTY_PACKAGENAMEW
, buffer
);
3550 if (r
!= ERROR_SUCCESS
)
3553 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3554 package
->Context
, MSICODE_PRODUCT
,
3555 INSTALLPROPERTY_MEDIAPACKAGEPATHW
, szEmpty
);
3556 if (r
!= ERROR_SUCCESS
)
3559 r
= MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3560 package
->Context
, MSICODE_PRODUCT
,
3561 INSTALLPROPERTY_DISKPROMPTW
, szEmpty
);
3562 if (r
!= ERROR_SUCCESS
)
3565 LIST_FOR_EACH_ENTRY(info
, &package
->sourcelist_info
, MSISOURCELISTINFO
, entry
)
3567 if (!lstrcmpW(info
->property
, INSTALLPROPERTY_LASTUSEDSOURCEW
))
3568 msi_set_last_used_source(package
->ProductCode
, NULL
, info
->context
,
3569 info
->options
, info
->value
);
3571 MsiSourceListSetInfoW(package
->ProductCode
, NULL
,
3572 info
->context
, info
->options
,
3573 info
->property
, info
->value
);
3576 LIST_FOR_EACH_ENTRY(disk
, &package
->sourcelist_media
, MSIMEDIADISK
, entry
)
3578 MsiSourceListAddMediaDiskW(package
->ProductCode
, NULL
,
3579 disk
->context
, disk
->options
,
3580 disk
->disk_id
, disk
->volume_label
, disk
->disk_prompt
);
3583 return ERROR_SUCCESS
;
3586 static UINT
msi_publish_product_properties(MSIPACKAGE
*package
, HKEY hkey
)
3588 MSIHANDLE hdb
, suminfo
;
3589 WCHAR guids
[MAX_PATH
];
3590 WCHAR packcode
[SQUISH_GUID_SIZE
];
3597 static const WCHAR szProductLanguage
[] =
3598 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3599 static const WCHAR szARPProductIcon
[] =
3600 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3601 static const WCHAR szProductVersion
[] =
3602 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3603 static const WCHAR szAssignment
[] =
3604 {'A','s','s','i','g','n','m','e','n','t',0};
3605 static const WCHAR szAdvertiseFlags
[] =
3606 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3607 static const WCHAR szClients
[] =
3608 {'C','l','i','e','n','t','s',0};
3609 static const WCHAR szColon
[] = {':',0};
3611 buffer
= msi_dup_property(package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3612 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3615 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
3616 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3619 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_AUTHORIZED_LUA_APPW
, 0);
3621 buffer
= msi_dup_property(package
, szARPProductIcon
);
3624 LPWSTR path
= build_icon_path(package
,buffer
);
3625 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3630 buffer
= msi_dup_property(package
, szProductVersion
);
3633 DWORD verdword
= msi_version_str_to_dword(buffer
);
3634 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3638 msi_reg_set_val_dword(hkey
, szAssignment
, 0);
3639 msi_reg_set_val_dword(hkey
, szAdvertiseFlags
, 0x184);
3640 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_INSTANCETYPEW
, 0);
3641 msi_reg_set_val_str(hkey
, szClients
, szColon
);
3643 hdb
= alloc_msihandle(&package
->db
->hdr
);
3645 return ERROR_NOT_ENOUGH_MEMORY
;
3647 r
= MsiGetSummaryInformationW(hdb
, NULL
, 0, &suminfo
);
3648 MsiCloseHandle(hdb
);
3649 if (r
!= ERROR_SUCCESS
)
3653 r
= MsiSummaryInfoGetPropertyW(suminfo
, PID_REVNUMBER
, NULL
, NULL
,
3654 NULL
, guids
, &size
);
3655 if (r
!= ERROR_SUCCESS
)
3658 ptr
= strchrW(guids
, ';');
3660 squash_guid(guids
, packcode
);
3661 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PACKAGECODEW
, packcode
);
3664 MsiCloseHandle(suminfo
);
3665 return ERROR_SUCCESS
;
3668 static UINT
msi_publish_upgrade_code(MSIPACKAGE
*package
)
3673 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
3675 static const WCHAR szUpgradeCode
[] =
3676 {'U','p','g','r','a','d','e','C','o','d','e',0};
3678 upgrade
= msi_dup_property(package
, szUpgradeCode
);
3680 return ERROR_SUCCESS
;
3682 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
3684 r
= MSIREG_OpenClassesUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3685 if (r
!= ERROR_SUCCESS
)
3690 r
= MSIREG_OpenUserUpgradeCodesKey(upgrade
, &hkey
, TRUE
);
3691 if (r
!= ERROR_SUCCESS
)
3695 squash_guid(package
->ProductCode
, squashed_pc
);
3696 msi_reg_set_val_str(hkey
, squashed_pc
, NULL
);
3705 static BOOL
msi_check_publish(MSIPACKAGE
*package
)
3707 MSIFEATURE
*feature
;
3709 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3711 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
3718 static BOOL
msi_check_unpublish(MSIPACKAGE
*package
)
3720 MSIFEATURE
*feature
;
3722 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
3724 if (feature
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3731 static UINT
msi_publish_patch(MSIPACKAGE
*package
, HKEY prodkey
, HKEY hudkey
)
3733 WCHAR patch_squashed
[GUID_SIZE
];
3736 UINT r
= ERROR_FUNCTION_FAILED
;
3738 res
= RegCreateKeyExW(prodkey
, szPatches
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
3740 if (res
!= ERROR_SUCCESS
)
3741 return ERROR_FUNCTION_FAILED
;
3743 squash_guid(package
->patch
->patchcode
, patch_squashed
);
3745 res
= RegSetValueExW(patches
, szPatches
, 0, REG_MULTI_SZ
,
3746 (const BYTE
*)patch_squashed
,
3747 (lstrlenW(patch_squashed
) + 1) * sizeof(WCHAR
));
3748 if (res
!= ERROR_SUCCESS
)
3751 res
= RegSetValueExW(patches
, patch_squashed
, 0, REG_SZ
,
3752 (const BYTE
*)package
->patch
->transforms
,
3753 (lstrlenW(package
->patch
->transforms
) + 1) * sizeof(WCHAR
));
3754 if (res
== ERROR_SUCCESS
)
3758 RegCloseKey(patches
);
3763 * 99% of the work done here is only done for
3764 * advertised installs. However this is where the
3765 * Icon table is processed and written out
3766 * so that is what I am going to do here.
3768 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3771 HKEY hukey
= NULL
, hudkey
= NULL
;
3774 /* FIXME: also need to publish if the product is in advertise mode */
3775 if (!msi_check_publish(package
))
3776 return ERROR_SUCCESS
;
3778 rc
= MSIREG_OpenProductKey(package
->ProductCode
, NULL
, package
->Context
,
3780 if (rc
!= ERROR_SUCCESS
)
3783 rc
= MSIREG_OpenUserDataProductKey(package
->ProductCode
, package
->Context
,
3784 NULL
, &hudkey
, TRUE
);
3785 if (rc
!= ERROR_SUCCESS
)
3788 rc
= msi_publish_upgrade_code(package
);
3789 if (rc
!= ERROR_SUCCESS
)
3794 rc
= msi_publish_patch(package
, hukey
, hudkey
);
3795 if (rc
!= ERROR_SUCCESS
)
3799 rc
= msi_publish_product_properties(package
, hukey
);
3800 if (rc
!= ERROR_SUCCESS
)
3803 rc
= msi_publish_sourcelist(package
, hukey
);
3804 if (rc
!= ERROR_SUCCESS
)
3807 rc
= msi_publish_icons(package
);
3810 uirow
= MSI_CreateRecord( 1 );
3811 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
3812 ui_actiondata( package
, szPublishProduct
, uirow
);
3813 msiobj_release( &uirow
->hdr
);
3816 RegCloseKey(hudkey
);
3821 static WCHAR
*get_ini_file_name( MSIPACKAGE
*package
, MSIRECORD
*row
)
3823 WCHAR
*filename
, *ptr
, *folder
, *ret
;
3824 const WCHAR
*dirprop
;
3826 filename
= msi_dup_record_field( row
, 2 );
3827 if (filename
&& (ptr
= strchrW( filename
, '|' )))
3832 dirprop
= MSI_RecordGetString( row
, 3 );
3835 folder
= resolve_folder( package
, dirprop
, FALSE
, FALSE
, TRUE
, NULL
);
3837 folder
= msi_dup_property( package
, dirprop
);
3840 folder
= msi_dup_property( package
, szWindowsFolder
);
3844 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop
));
3845 msi_free( filename
);
3849 ret
= build_directory_name( 2, folder
, ptr
);
3851 msi_free( filename
);
3856 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3858 MSIPACKAGE
*package
= param
;
3859 LPCWSTR component
, section
, key
, value
, identifier
;
3860 LPWSTR deformated_section
, deformated_key
, deformated_value
, fullname
;
3865 component
= MSI_RecordGetString(row
, 8);
3866 comp
= get_loaded_component(package
,component
);
3868 return ERROR_SUCCESS
;
3870 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
3872 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
3873 comp
->Action
= comp
->Installed
;
3874 return ERROR_SUCCESS
;
3876 comp
->Action
= INSTALLSTATE_LOCAL
;
3878 identifier
= MSI_RecordGetString(row
,1);
3879 section
= MSI_RecordGetString(row
,4);
3880 key
= MSI_RecordGetString(row
,5);
3881 value
= MSI_RecordGetString(row
,6);
3882 action
= MSI_RecordGetInteger(row
,7);
3884 deformat_string(package
,section
,&deformated_section
);
3885 deformat_string(package
,key
,&deformated_key
);
3886 deformat_string(package
,value
,&deformated_value
);
3888 fullname
= get_ini_file_name(package
, row
);
3892 TRACE("Adding value %s to section %s in %s\n",
3893 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3894 debugstr_w(fullname
));
3895 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3896 deformated_value
, fullname
);
3898 else if (action
== 1)
3901 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3902 returned
, 10, fullname
);
3903 if (returned
[0] == 0)
3905 TRACE("Adding value %s to section %s in %s\n",
3906 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3907 debugstr_w(fullname
));
3909 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3910 deformated_value
, fullname
);
3913 else if (action
== 3)
3914 FIXME("Append to existing section not yet implemented\n");
3916 uirow
= MSI_CreateRecord(4);
3917 MSI_RecordSetStringW(uirow
,1,identifier
);
3918 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3919 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3920 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3921 ui_actiondata(package
,szWriteIniValues
,uirow
);
3922 msiobj_release( &uirow
->hdr
);
3925 msi_free(deformated_key
);
3926 msi_free(deformated_value
);
3927 msi_free(deformated_section
);
3928 return ERROR_SUCCESS
;
3931 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3935 static const WCHAR ExecSeqQuery
[] =
3936 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3937 '`','I','n','i','F','i','l','e','`',0};
3939 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3940 if (rc
!= ERROR_SUCCESS
)
3942 TRACE("no IniFile table\n");
3943 return ERROR_SUCCESS
;
3946 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3947 msiobj_release(&view
->hdr
);
3951 static UINT
ITERATE_RemoveIniValuesOnUninstall( MSIRECORD
*row
, LPVOID param
)
3953 MSIPACKAGE
*package
= param
;
3954 LPCWSTR component
, section
, key
, value
, identifier
;
3955 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
3960 component
= MSI_RecordGetString( row
, 8 );
3961 comp
= get_loaded_component( package
, component
);
3963 return ERROR_SUCCESS
;
3965 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
3967 TRACE("Component not scheduled for removal %s\n", debugstr_w(component
));
3968 comp
->Action
= comp
->Installed
;
3969 return ERROR_SUCCESS
;
3971 comp
->Action
= INSTALLSTATE_ABSENT
;
3973 identifier
= MSI_RecordGetString( row
, 1 );
3974 section
= MSI_RecordGetString( row
, 4 );
3975 key
= MSI_RecordGetString( row
, 5 );
3976 value
= MSI_RecordGetString( row
, 6 );
3977 action
= MSI_RecordGetInteger( row
, 7 );
3979 deformat_string( package
, section
, &deformated_section
);
3980 deformat_string( package
, key
, &deformated_key
);
3981 deformat_string( package
, value
, &deformated_value
);
3983 if (action
== msidbIniFileActionAddLine
|| action
== msidbIniFileActionCreateLine
)
3985 filename
= get_ini_file_name( package
, row
);
3987 TRACE("Removing key %s from section %s in %s\n",
3988 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
3990 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
3992 WARN("Unable to remove key %u\n", GetLastError());
3994 msi_free( filename
);
3997 FIXME("Unsupported action %d\n", action
);
4000 uirow
= MSI_CreateRecord( 4 );
4001 MSI_RecordSetStringW( uirow
, 1, identifier
);
4002 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4003 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4004 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4005 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4006 msiobj_release( &uirow
->hdr
);
4008 msi_free( deformated_key
);
4009 msi_free( deformated_value
);
4010 msi_free( deformated_section
);
4011 return ERROR_SUCCESS
;
4014 static UINT
ITERATE_RemoveIniValuesOnInstall( MSIRECORD
*row
, LPVOID param
)
4016 MSIPACKAGE
*package
= param
;
4017 LPCWSTR component
, section
, key
, value
, identifier
;
4018 LPWSTR deformated_section
, deformated_key
, deformated_value
, filename
;
4023 component
= MSI_RecordGetString( row
, 8 );
4024 comp
= get_loaded_component( package
, component
);
4026 return ERROR_SUCCESS
;
4028 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
4030 TRACE("Component not scheduled for installation %s\n", debugstr_w(component
));
4031 comp
->Action
= comp
->Installed
;
4032 return ERROR_SUCCESS
;
4034 comp
->Action
= INSTALLSTATE_LOCAL
;
4036 identifier
= MSI_RecordGetString( row
, 1 );
4037 section
= MSI_RecordGetString( row
, 4 );
4038 key
= MSI_RecordGetString( row
, 5 );
4039 value
= MSI_RecordGetString( row
, 6 );
4040 action
= MSI_RecordGetInteger( row
, 7 );
4042 deformat_string( package
, section
, &deformated_section
);
4043 deformat_string( package
, key
, &deformated_key
);
4044 deformat_string( package
, value
, &deformated_value
);
4046 if (action
== msidbIniFileActionRemoveLine
)
4048 filename
= get_ini_file_name( package
, row
);
4050 TRACE("Removing key %s from section %s in %s\n",
4051 debugstr_w(deformated_key
), debugstr_w(deformated_section
), debugstr_w(filename
));
4053 if (!WritePrivateProfileStringW( deformated_section
, deformated_key
, NULL
, filename
))
4055 WARN("Unable to remove key %u\n", GetLastError());
4057 msi_free( filename
);
4060 FIXME("Unsupported action %d\n", action
);
4062 uirow
= MSI_CreateRecord( 4 );
4063 MSI_RecordSetStringW( uirow
, 1, identifier
);
4064 MSI_RecordSetStringW( uirow
, 2, deformated_section
);
4065 MSI_RecordSetStringW( uirow
, 3, deformated_key
);
4066 MSI_RecordSetStringW( uirow
, 4, deformated_value
);
4067 ui_actiondata( package
, szRemoveIniValues
, uirow
);
4068 msiobj_release( &uirow
->hdr
);
4070 msi_free( deformated_key
);
4071 msi_free( deformated_value
);
4072 msi_free( deformated_section
);
4073 return ERROR_SUCCESS
;
4076 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4080 static const WCHAR query
[] =
4081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4082 '`','I','n','i','F','i','l','e','`',0};
4083 static const WCHAR remove_query
[] =
4084 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4085 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4087 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4088 if (rc
== ERROR_SUCCESS
)
4090 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnUninstall
, package
);
4091 msiobj_release( &view
->hdr
);
4092 if (rc
!= ERROR_SUCCESS
)
4096 rc
= MSI_DatabaseOpenViewW( package
->db
, remove_query
, &view
);
4097 if (rc
== ERROR_SUCCESS
)
4099 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveIniValuesOnInstall
, package
);
4100 msiobj_release( &view
->hdr
);
4101 if (rc
!= ERROR_SUCCESS
)
4105 return ERROR_SUCCESS
;
4108 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
4110 MSIPACKAGE
*package
= param
;
4115 static const WCHAR ExeStr
[] =
4116 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4117 static const WCHAR close
[] = {'\"',0};
4119 PROCESS_INFORMATION info
;
4124 memset(&si
,0,sizeof(STARTUPINFOW
));
4126 filename
= MSI_RecordGetString(row
,1);
4127 file
= get_loaded_file( package
, filename
);
4131 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4132 return ERROR_SUCCESS
;
4135 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
4137 FullName
= msi_alloc(len
*sizeof(WCHAR
));
4138 strcpyW(FullName
,ExeStr
);
4139 strcatW( FullName
, file
->TargetPath
);
4140 strcatW(FullName
,close
);
4142 TRACE("Registering %s\n",debugstr_w(FullName
));
4143 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
4148 CloseHandle(info
.hThread
);
4149 msi_dialog_check_messages(info
.hProcess
);
4150 CloseHandle(info
.hProcess
);
4153 uirow
= MSI_CreateRecord( 2 );
4154 MSI_RecordSetStringW( uirow
, 1, filename
);
4155 uipath
= strdupW( file
->TargetPath
);
4156 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4157 MSI_RecordSetStringW( uirow
, 2, uipath
);
4158 ui_actiondata( package
, szSelfRegModules
, uirow
);
4159 msiobj_release( &uirow
->hdr
);
4161 msi_free( FullName
);
4163 return ERROR_SUCCESS
;
4166 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4170 static const WCHAR ExecSeqQuery
[] =
4171 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4172 '`','S','e','l','f','R','e','g','`',0};
4174 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4175 if (rc
!= ERROR_SUCCESS
)
4177 TRACE("no SelfReg table\n");
4178 return ERROR_SUCCESS
;
4181 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
4182 msiobj_release(&view
->hdr
);
4184 return ERROR_SUCCESS
;
4187 static UINT
ITERATE_SelfUnregModules( MSIRECORD
*row
, LPVOID param
)
4189 static const WCHAR regsvr32
[] =
4190 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4191 static const WCHAR close
[] = {'\"',0};
4192 MSIPACKAGE
*package
= param
;
4198 PROCESS_INFORMATION pi
;
4203 memset( &si
, 0, sizeof(STARTUPINFOW
) );
4205 filename
= MSI_RecordGetString( row
, 1 );
4206 file
= get_loaded_file( package
, filename
);
4210 ERR("Unable to find file id %s\n", debugstr_w(filename
));
4211 return ERROR_SUCCESS
;
4214 len
= strlenW( regsvr32
) + strlenW( file
->TargetPath
) + 2;
4216 cmdline
= msi_alloc( len
* sizeof(WCHAR
) );
4217 strcpyW( cmdline
, regsvr32
);
4218 strcatW( cmdline
, file
->TargetPath
);
4219 strcatW( cmdline
, close
);
4221 TRACE("Unregistering %s\n", debugstr_w(cmdline
));
4223 ret
= CreateProcessW( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
, &si
, &pi
);
4226 CloseHandle( pi
.hThread
);
4227 msi_dialog_check_messages( pi
.hProcess
);
4228 CloseHandle( pi
.hProcess
);
4231 uirow
= MSI_CreateRecord( 2 );
4232 MSI_RecordSetStringW( uirow
, 1, filename
);
4233 uipath
= strdupW( file
->TargetPath
);
4234 if ((p
= strrchrW( uipath
,'\\' ))) *p
= 0;
4235 MSI_RecordSetStringW( uirow
, 2, uipath
);
4236 ui_actiondata( package
, szSelfUnregModules
, uirow
);
4237 msiobj_release( &uirow
->hdr
);
4239 msi_free( cmdline
);
4241 return ERROR_SUCCESS
;
4244 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4248 static const WCHAR query
[] =
4249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4250 '`','S','e','l','f','R','e','g','`',0};
4252 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4253 if (rc
!= ERROR_SUCCESS
)
4255 TRACE("no SelfReg table\n");
4256 return ERROR_SUCCESS
;
4259 MSI_IterateRecords( view
, NULL
, ITERATE_SelfUnregModules
, package
);
4260 msiobj_release( &view
->hdr
);
4262 return ERROR_SUCCESS
;
4265 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4267 MSIFEATURE
*feature
;
4269 HKEY hkey
= NULL
, userdata
= NULL
;
4271 if (!msi_check_publish(package
))
4272 return ERROR_SUCCESS
;
4274 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4276 if (rc
!= ERROR_SUCCESS
)
4279 rc
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4281 if (rc
!= ERROR_SUCCESS
)
4284 /* here the guids are base 85 encoded */
4285 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
4291 BOOL absent
= FALSE
;
4294 if (feature
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4295 feature
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4296 feature
->ActionRequest
!= INSTALLSTATE_ADVERTISED
) absent
= TRUE
;
4299 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4303 if (feature
->Feature_Parent
)
4304 size
+= strlenW( feature
->Feature_Parent
)+2;
4306 data
= msi_alloc(size
* sizeof(WCHAR
));
4309 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
4311 MSICOMPONENT
* component
= cl
->component
;
4315 if (component
->ComponentId
)
4317 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
4318 CLSIDFromString(component
->ComponentId
, &clsid
);
4319 encode_base85_guid(&clsid
,buf
);
4320 TRACE("to %s\n",debugstr_w(buf
));
4325 if (feature
->Feature_Parent
)
4327 static const WCHAR sep
[] = {'\2',0};
4329 strcatW(data
,feature
->Feature_Parent
);
4332 msi_reg_set_val_str( userdata
, feature
->Feature
, data
);
4336 if (feature
->Feature_Parent
)
4337 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
4340 size
+= sizeof(WCHAR
);
4341 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4342 (LPBYTE
)(feature
->Feature_Parent
? feature
->Feature_Parent
: szEmpty
),size
);
4346 size
+= 2*sizeof(WCHAR
);
4347 data
= msi_alloc(size
);
4350 if (feature
->Feature_Parent
)
4351 strcpyW( &data
[1], feature
->Feature_Parent
);
4352 RegSetValueExW(hkey
,feature
->Feature
,0,REG_SZ
,
4358 uirow
= MSI_CreateRecord( 1 );
4359 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
4360 ui_actiondata( package
, szPublishFeatures
, uirow
);
4361 msiobj_release( &uirow
->hdr
);
4362 /* FIXME: call ui_progress? */
4367 RegCloseKey(userdata
);
4371 static UINT
msi_unpublish_feature(MSIPACKAGE
*package
, MSIFEATURE
*feature
)
4376 TRACE("unpublishing feature %s\n", debugstr_w(feature
->Feature
));
4378 r
= MSIREG_OpenFeaturesKey(package
->ProductCode
, package
->Context
,
4380 if (r
== ERROR_SUCCESS
)
4382 RegDeleteValueW(hkey
, feature
->Feature
);
4386 r
= MSIREG_OpenUserDataFeaturesKey(package
->ProductCode
, package
->Context
,
4388 if (r
== ERROR_SUCCESS
)
4390 RegDeleteValueW(hkey
, feature
->Feature
);
4394 return ERROR_SUCCESS
;
4397 static UINT
ACTION_UnpublishFeatures(MSIPACKAGE
*package
)
4399 MSIFEATURE
*feature
;
4401 if (!msi_check_unpublish(package
))
4402 return ERROR_SUCCESS
;
4404 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4406 msi_unpublish_feature(package
, feature
);
4409 return ERROR_SUCCESS
;
4412 static UINT
msi_publish_install_properties(MSIPACKAGE
*package
, HKEY hkey
)
4414 LPWSTR prop
, val
, key
;
4420 static const WCHAR date_fmt
[] = {'%','i','%','0','2','i','%','0','2','i',0};
4421 static const WCHAR szWindowsInstaller
[] =
4422 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4423 static const WCHAR modpath_fmt
[] =
4424 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4425 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4426 static const WCHAR szModifyPath
[] =
4427 {'M','o','d','i','f','y','P','a','t','h',0};
4428 static const WCHAR szUninstallString
[] =
4429 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4430 static const WCHAR szEstimatedSize
[] =
4431 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4432 static const WCHAR szProductLanguage
[] =
4433 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4434 static const WCHAR szProductVersion
[] =
4435 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4436 static const WCHAR szProductName
[] =
4437 {'P','r','o','d','u','c','t','N','a','m','e',0};
4438 static const WCHAR szDisplayName
[] =
4439 {'D','i','s','p','l','a','y','N','a','m','e',0};
4440 static const WCHAR szDisplayVersion
[] =
4441 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4442 static const WCHAR szManufacturer
[] =
4443 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4445 static const LPCSTR propval
[] = {
4446 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4447 "ARPCONTACT", "Contact",
4448 "ARPCOMMENTS", "Comments",
4449 "ProductName", "DisplayName",
4450 "ProductVersion", "DisplayVersion",
4451 "ARPHELPLINK", "HelpLink",
4452 "ARPHELPTELEPHONE", "HelpTelephone",
4453 "ARPINSTALLLOCATION", "InstallLocation",
4454 "SourceDir", "InstallSource",
4455 "Manufacturer", "Publisher",
4456 "ARPREADME", "Readme",
4458 "ARPURLINFOABOUT", "URLInfoAbout",
4459 "ARPURLUPDATEINFO", "URLUpdateInfo",
4462 const LPCSTR
*p
= propval
;
4466 prop
= strdupAtoW(*p
++);
4467 key
= strdupAtoW(*p
++);
4468 val
= msi_dup_property(package
, prop
);
4469 msi_reg_set_val_str(hkey
, key
, val
);
4475 msi_reg_set_val_dword(hkey
, szWindowsInstaller
, 1);
4477 size
= deformat_string(package
, modpath_fmt
, &buffer
);
4478 RegSetValueExW(hkey
, szModifyPath
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4479 RegSetValueExW(hkey
, szUninstallString
, 0, REG_EXPAND_SZ
, (LPBYTE
)buffer
, size
);
4482 /* FIXME: Write real Estimated Size when we have it */
4483 msi_reg_set_val_dword(hkey
, szEstimatedSize
, 0);
4485 buffer
= msi_dup_property(package
, szProductName
);
4486 msi_reg_set_val_str(hkey
, szDisplayName
, buffer
);
4489 buffer
= msi_dup_property(package
, cszSourceDir
);
4490 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLSOURCEW
, buffer
);
4493 buffer
= msi_dup_property(package
, szManufacturer
);
4494 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_PUBLISHERW
, buffer
);
4497 GetLocalTime(&systime
);
4498 sprintfW(date
, date_fmt
, systime
.wYear
, systime
.wMonth
, systime
.wDay
);
4499 msi_reg_set_val_str(hkey
, INSTALLPROPERTY_INSTALLDATEW
, date
);
4501 langid
= msi_get_property_int(package
, szProductLanguage
, 0);
4502 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
4504 buffer
= msi_dup_property(package
, szProductVersion
);
4505 msi_reg_set_val_str(hkey
, szDisplayVersion
, buffer
);
4508 DWORD verdword
= msi_version_str_to_dword(buffer
);
4510 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
4511 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>> 24);
4512 msi_reg_set_val_dword(hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>> 16) & 0xFF);
4516 return ERROR_SUCCESS
;
4519 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4521 WCHAR squashed_pc
[SQUISH_GUID_SIZE
];
4523 LPWSTR upgrade_code
;
4528 static const WCHAR szUpgradeCode
[] = {
4529 'U','p','g','r','a','d','e','C','o','d','e',0};
4531 /* FIXME: also need to publish if the product is in advertise mode */
4532 if (!msi_check_publish(package
))
4533 return ERROR_SUCCESS
;
4535 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
, &hkey
, TRUE
);
4536 if (rc
!= ERROR_SUCCESS
)
4539 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4540 NULL
, &props
, TRUE
);
4541 if (rc
!= ERROR_SUCCESS
)
4544 msi_reg_set_val_str( props
, INSTALLPROPERTY_LOCALPACKAGEW
, package
->db
->localfile
);
4545 msi_free( package
->db
->localfile
);
4546 package
->db
->localfile
= NULL
;
4548 rc
= msi_publish_install_properties(package
, hkey
);
4549 if (rc
!= ERROR_SUCCESS
)
4552 rc
= msi_publish_install_properties(package
, props
);
4553 if (rc
!= ERROR_SUCCESS
)
4556 upgrade_code
= msi_dup_property(package
, szUpgradeCode
);
4559 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &upgrade
, TRUE
);
4560 squash_guid(package
->ProductCode
, squashed_pc
);
4561 msi_reg_set_val_str(upgrade
, squashed_pc
, NULL
);
4562 RegCloseKey(upgrade
);
4563 msi_free(upgrade_code
);
4567 uirow
= MSI_CreateRecord( 1 );
4568 MSI_RecordSetStringW( uirow
, 1, package
->ProductCode
);
4569 ui_actiondata( package
, szRegisterProduct
, uirow
);
4570 msiobj_release( &uirow
->hdr
);
4573 return ERROR_SUCCESS
;
4576 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4578 return execute_script(package
,INSTALL_SCRIPT
);
4581 static UINT
msi_unpublish_product(MSIPACKAGE
*package
)
4584 LPWSTR remove
= NULL
;
4585 LPWSTR
*features
= NULL
;
4586 BOOL full_uninstall
= TRUE
;
4587 MSIFEATURE
*feature
;
4589 static const WCHAR szUpgradeCode
[] =
4590 {'U','p','g','r','a','d','e','C','o','d','e',0};
4592 remove
= msi_dup_property(package
, szRemove
);
4594 return ERROR_SUCCESS
;
4596 features
= msi_split_string(remove
, ',');
4600 ERR("REMOVE feature list is empty!\n");
4601 return ERROR_FUNCTION_FAILED
;
4604 if (!lstrcmpW(features
[0], szAll
))
4605 full_uninstall
= TRUE
;
4608 LIST_FOR_EACH_ENTRY(feature
, &package
->features
, MSIFEATURE
, entry
)
4610 if (feature
->Action
!= INSTALLSTATE_ABSENT
)
4611 full_uninstall
= FALSE
;
4615 if (!full_uninstall
)
4618 MSIREG_DeleteProductKey(package
->ProductCode
);
4619 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4620 MSIREG_DeleteUninstallKey(package
->ProductCode
);
4622 if (package
->Context
== MSIINSTALLCONTEXT_MACHINE
)
4624 MSIREG_DeleteLocalClassesProductKey(package
->ProductCode
);
4625 MSIREG_DeleteLocalClassesFeaturesKey(package
->ProductCode
);
4629 MSIREG_DeleteUserProductKey(package
->ProductCode
);
4630 MSIREG_DeleteUserFeaturesKey(package
->ProductCode
);
4633 upgrade
= msi_dup_property(package
, szUpgradeCode
);
4636 MSIREG_DeleteUserUpgradeCodesKey(upgrade
);
4643 return ERROR_SUCCESS
;
4646 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4650 rc
= msi_unpublish_product(package
);
4651 if (rc
!= ERROR_SUCCESS
)
4654 /* turn off scheduling */
4655 package
->script
->CurrentlyScripting
= FALSE
;
4657 /* first do the same as an InstallExecute */
4658 rc
= ACTION_InstallExecute(package
);
4659 if (rc
!= ERROR_SUCCESS
)
4662 /* then handle Commit Actions */
4663 rc
= execute_script(package
,COMMIT_SCRIPT
);
4668 UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4670 static const WCHAR RunOnce
[] = {
4671 'S','o','f','t','w','a','r','e','\\',
4672 'M','i','c','r','o','s','o','f','t','\\',
4673 'W','i','n','d','o','w','s','\\',
4674 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4675 'R','u','n','O','n','c','e',0};
4676 static const WCHAR InstallRunOnce
[] = {
4677 'S','o','f','t','w','a','r','e','\\',
4678 'M','i','c','r','o','s','o','f','t','\\',
4679 'W','i','n','d','o','w','s','\\',
4680 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4681 'I','n','s','t','a','l','l','e','r','\\',
4682 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4684 static const WCHAR msiexec_fmt
[] = {
4686 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4687 '\"','%','s','\"',0};
4688 static const WCHAR install_fmt
[] = {
4689 '/','I',' ','\"','%','s','\"',' ',
4690 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4691 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4692 WCHAR buffer
[256], sysdir
[MAX_PATH
];
4694 WCHAR squished_pc
[100];
4696 squash_guid(package
->ProductCode
,squished_pc
);
4698 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
4699 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4700 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
4703 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4706 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4708 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4709 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
4711 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
4714 return ERROR_INSTALL_SUSPEND
;
4717 static UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
4723 * We are currently doing what should be done here in the top level Install
4724 * however for Administrative and uninstalls this step will be needed
4726 if (!package
->PackagePath
)
4727 return ERROR_SUCCESS
;
4729 msi_set_sourcedir_props(package
, TRUE
);
4731 attrib
= GetFileAttributesW(package
->db
->path
);
4732 if (attrib
== INVALID_FILE_ATTRIBUTES
)
4738 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4739 package
->Context
, MSICODE_PRODUCT
,
4740 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
4741 if (rc
== ERROR_MORE_DATA
)
4743 prompt
= msi_alloc(size
* sizeof(WCHAR
));
4744 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
4745 package
->Context
, MSICODE_PRODUCT
,
4746 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
4749 prompt
= strdupW(package
->db
->path
);
4751 msg
= generate_error_string(package
,1302,1,prompt
);
4752 while(attrib
== INVALID_FILE_ATTRIBUTES
)
4754 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
4757 rc
= ERROR_INSTALL_USEREXIT
;
4760 attrib
= GetFileAttributesW(package
->db
->path
);
4766 return ERROR_SUCCESS
;
4771 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
4774 LPWSTR buffer
, productid
= NULL
;
4775 UINT i
, rc
= ERROR_SUCCESS
;
4778 static const WCHAR szPropKeys
[][80] =
4780 {'P','r','o','d','u','c','t','I','D',0},
4781 {'U','S','E','R','N','A','M','E',0},
4782 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4786 static const WCHAR szRegKeys
[][80] =
4788 {'P','r','o','d','u','c','t','I','D',0},
4789 {'R','e','g','O','w','n','e','r',0},
4790 {'R','e','g','C','o','m','p','a','n','y',0},
4794 if (msi_check_unpublish(package
))
4796 MSIREG_DeleteUserDataProductKey(package
->ProductCode
);
4800 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
4804 rc
= MSIREG_OpenInstallProps(package
->ProductCode
, package
->Context
,
4806 if (rc
!= ERROR_SUCCESS
)
4809 for( i
= 0; szPropKeys
[i
][0]; i
++ )
4811 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
4812 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
4817 uirow
= MSI_CreateRecord( 1 );
4818 MSI_RecordSetStringW( uirow
, 1, productid
);
4819 ui_actiondata( package
, szRegisterUser
, uirow
);
4820 msiobj_release( &uirow
->hdr
);
4822 msi_free(productid
);
4828 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
4832 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
4833 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
4838 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4840 MSIPACKAGE
*package
= param
;
4841 LPCWSTR compgroupid
, component
, feature
, qualifier
, text
;
4842 LPWSTR advertise
= NULL
, output
= NULL
;
4850 feature
= MSI_RecordGetString(rec
, 5);
4851 feat
= get_loaded_feature(package
, feature
);
4853 return ERROR_SUCCESS
;
4855 if (feat
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
4856 feat
->ActionRequest
!= INSTALLSTATE_SOURCE
&&
4857 feat
->ActionRequest
!= INSTALLSTATE_ADVERTISED
)
4859 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature
));
4860 feat
->Action
= feat
->Installed
;
4861 return ERROR_SUCCESS
;
4864 component
= MSI_RecordGetString(rec
, 3);
4865 comp
= get_loaded_component(package
, component
);
4867 return ERROR_SUCCESS
;
4869 compgroupid
= MSI_RecordGetString(rec
,1);
4870 qualifier
= MSI_RecordGetString(rec
,2);
4872 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4873 if (rc
!= ERROR_SUCCESS
)
4876 text
= MSI_RecordGetString(rec
,4);
4877 advertise
= create_component_advertise_string(package
, comp
, feature
);
4879 sz
= strlenW(advertise
);
4882 sz
+= lstrlenW(text
);
4885 sz
*= sizeof(WCHAR
);
4887 output
= msi_alloc_zero(sz
);
4888 strcpyW(output
,advertise
);
4889 msi_free(advertise
);
4892 strcatW(output
,text
);
4894 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4901 uirow
= MSI_CreateRecord( 2 );
4902 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4903 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4904 ui_actiondata( package
, szPublishComponents
, uirow
);
4905 msiobj_release( &uirow
->hdr
);
4906 /* FIXME: call ui_progress? */
4912 * At present I am ignorning the advertised components part of this and only
4913 * focusing on the qualified component sets
4915 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4919 static const WCHAR ExecSeqQuery
[] =
4920 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4921 '`','P','u','b','l','i','s','h',
4922 'C','o','m','p','o','n','e','n','t','`',0};
4924 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4925 if (rc
!= ERROR_SUCCESS
)
4926 return ERROR_SUCCESS
;
4928 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4929 msiobj_release(&view
->hdr
);
4934 static UINT
ITERATE_UnpublishComponent( MSIRECORD
*rec
, LPVOID param
)
4936 static const WCHAR szInstallerComponents
[] = {
4937 'S','o','f','t','w','a','r','e','\\',
4938 'M','i','c','r','o','s','o','f','t','\\',
4939 'I','n','s','t','a','l','l','e','r','\\',
4940 'C','o','m','p','o','n','e','n','t','s','\\',0};
4942 MSIPACKAGE
*package
= param
;
4943 LPCWSTR compgroupid
, component
, feature
, qualifier
;
4947 WCHAR squashed
[GUID_SIZE
], keypath
[MAX_PATH
];
4950 feature
= MSI_RecordGetString( rec
, 5 );
4951 feat
= get_loaded_feature( package
, feature
);
4953 return ERROR_SUCCESS
;
4955 if (feat
->ActionRequest
!= INSTALLSTATE_ABSENT
)
4957 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature
));
4958 feat
->Action
= feat
->Installed
;
4959 return ERROR_SUCCESS
;
4962 component
= MSI_RecordGetString( rec
, 3 );
4963 comp
= get_loaded_component( package
, component
);
4965 return ERROR_SUCCESS
;
4967 compgroupid
= MSI_RecordGetString( rec
, 1 );
4968 qualifier
= MSI_RecordGetString( rec
, 2 );
4970 squash_guid( compgroupid
, squashed
);
4971 strcpyW( keypath
, szInstallerComponents
);
4972 strcatW( keypath
, squashed
);
4974 res
= RegDeleteKeyW( HKEY_CURRENT_USER
, keypath
);
4975 if (res
!= ERROR_SUCCESS
)
4977 WARN("Unable to delete component key %d\n", res
);
4980 uirow
= MSI_CreateRecord( 2 );
4981 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4982 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4983 ui_actiondata( package
, szUnpublishComponents
, uirow
);
4984 msiobj_release( &uirow
->hdr
);
4986 return ERROR_SUCCESS
;
4989 static UINT
ACTION_UnpublishComponents( MSIPACKAGE
*package
)
4993 static const WCHAR query
[] =
4994 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4995 '`','P','u','b','l','i','s','h',
4996 'C','o','m','p','o','n','e','n','t','`',0};
4998 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
4999 if (rc
!= ERROR_SUCCESS
)
5000 return ERROR_SUCCESS
;
5002 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_UnpublishComponent
, package
);
5003 msiobj_release( &view
->hdr
);
5008 static UINT
ITERATE_InstallService(MSIRECORD
*rec
, LPVOID param
)
5010 MSIPACKAGE
*package
= param
;
5013 SC_HANDLE hscm
, service
= NULL
;
5014 LPCWSTR comp
, depends
, pass
;
5015 LPWSTR name
= NULL
, disp
= NULL
;
5016 LPCWSTR load_order
, serv_name
, key
;
5017 DWORD serv_type
, start_type
;
5020 static const WCHAR query
[] =
5021 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5022 '`','C','o','m','p','o','n','e','n','t','`',' ',
5023 'W','H','E','R','E',' ',
5024 '`','C','o','m','p','o','n','e','n','t','`',' ',
5025 '=','\'','%','s','\'',0};
5027 hscm
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASEW
, GENERIC_WRITE
);
5030 ERR("Failed to open the SC Manager!\n");
5034 start_type
= MSI_RecordGetInteger(rec
, 5);
5035 if (start_type
== SERVICE_BOOT_START
|| start_type
== SERVICE_SYSTEM_START
)
5038 depends
= MSI_RecordGetString(rec
, 8);
5039 if (depends
&& *depends
)
5040 FIXME("Dependency list unhandled!\n");
5042 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5043 deformat_string(package
, MSI_RecordGetString(rec
, 3), &disp
);
5044 serv_type
= MSI_RecordGetInteger(rec
, 4);
5045 err_control
= MSI_RecordGetInteger(rec
, 6);
5046 load_order
= MSI_RecordGetString(rec
, 7);
5047 serv_name
= MSI_RecordGetString(rec
, 9);
5048 pass
= MSI_RecordGetString(rec
, 10);
5049 comp
= MSI_RecordGetString(rec
, 12);
5051 /* fetch the service path */
5052 row
= MSI_QueryGetRecord(package
->db
, query
, comp
);
5055 ERR("Control query failed!\n");
5059 key
= MSI_RecordGetString(row
, 6);
5061 file
= get_loaded_file(package
, key
);
5062 msiobj_release(&row
->hdr
);
5065 ERR("Failed to load the service file\n");
5069 service
= CreateServiceW(hscm
, name
, disp
, GENERIC_ALL
, serv_type
,
5070 start_type
, err_control
, file
->TargetPath
,
5071 load_order
, NULL
, NULL
, serv_name
, pass
);
5074 if (GetLastError() != ERROR_SERVICE_EXISTS
)
5075 ERR("Failed to create service %s: %d\n", debugstr_w(name
), GetLastError());
5079 CloseServiceHandle(service
);
5080 CloseServiceHandle(hscm
);
5084 return ERROR_SUCCESS
;
5087 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
5091 static const WCHAR ExecSeqQuery
[] =
5092 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5093 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5095 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5096 if (rc
!= ERROR_SUCCESS
)
5097 return ERROR_SUCCESS
;
5099 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallService
, package
);
5100 msiobj_release(&view
->hdr
);
5105 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5106 static LPCWSTR
*msi_service_args_to_vector(LPWSTR args
, DWORD
*numargs
)
5108 LPCWSTR
*vector
, *temp_vector
;
5112 static const WCHAR separator
[] = {'[','~',']',0};
5115 sep_len
= sizeof(separator
) / sizeof(WCHAR
) - 1;
5120 vector
= msi_alloc(sizeof(LPWSTR
));
5128 vector
[*numargs
- 1] = p
;
5130 if ((q
= strstrW(p
, separator
)))
5134 temp_vector
= msi_realloc(vector
, (*numargs
+ 1) * sizeof(LPWSTR
));
5140 vector
= temp_vector
;
5149 static UINT
ITERATE_StartService(MSIRECORD
*rec
, LPVOID param
)
5151 MSIPACKAGE
*package
= param
;
5153 SC_HANDLE scm
= NULL
, service
= NULL
;
5154 LPCWSTR component
, *vector
= NULL
;
5156 DWORD event
, numargs
;
5157 UINT r
= ERROR_FUNCTION_FAILED
;
5159 component
= MSI_RecordGetString(rec
, 6);
5160 comp
= get_loaded_component(package
, component
);
5162 return ERROR_SUCCESS
;
5164 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
5166 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
5167 comp
->Action
= comp
->Installed
;
5168 return ERROR_SUCCESS
;
5170 comp
->Action
= INSTALLSTATE_LOCAL
;
5172 deformat_string(package
, MSI_RecordGetString(rec
, 2), &name
);
5173 deformat_string(package
, MSI_RecordGetString(rec
, 4), &args
);
5174 event
= MSI_RecordGetInteger(rec
, 3);
5176 if (!(event
& msidbServiceControlEventStart
))
5182 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_CONNECT
);
5185 ERR("Failed to open the service control manager\n");
5189 service
= OpenServiceW(scm
, name
, SERVICE_START
);
5192 ERR("Failed to open service %s (%u)\n", debugstr_w(name
), GetLastError());
5196 vector
= msi_service_args_to_vector(args
, &numargs
);
5198 if (!StartServiceW(service
, numargs
, vector
) &&
5199 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING
)
5201 ERR("Failed to start service %s (%u)\n", debugstr_w(name
), GetLastError());
5208 CloseServiceHandle(service
);
5209 CloseServiceHandle(scm
);
5217 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
5222 static const WCHAR query
[] = {
5223 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5224 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5226 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5227 if (rc
!= ERROR_SUCCESS
)
5228 return ERROR_SUCCESS
;
5230 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StartService
, package
);
5231 msiobj_release(&view
->hdr
);
5236 static BOOL
stop_service_dependents(SC_HANDLE scm
, SC_HANDLE service
)
5238 DWORD i
, needed
, count
;
5239 ENUM_SERVICE_STATUSW
*dependencies
;
5243 if (EnumDependentServicesW(service
, SERVICE_ACTIVE
, NULL
,
5244 0, &needed
, &count
))
5247 if (GetLastError() != ERROR_MORE_DATA
)
5250 dependencies
= msi_alloc(needed
);
5254 if (!EnumDependentServicesW(service
, SERVICE_ACTIVE
, dependencies
,
5255 needed
, &needed
, &count
))
5258 for (i
= 0; i
< count
; i
++)
5260 depserv
= OpenServiceW(scm
, dependencies
[i
].lpServiceName
,
5261 SERVICE_STOP
| SERVICE_QUERY_STATUS
);
5265 if (!ControlService(depserv
, SERVICE_CONTROL_STOP
, &ss
))
5272 msi_free(dependencies
);
5276 static UINT
stop_service( LPCWSTR name
)
5278 SC_HANDLE scm
= NULL
, service
= NULL
;
5279 SERVICE_STATUS status
;
5280 SERVICE_STATUS_PROCESS ssp
;
5283 scm
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5286 WARN("Failed to open the SCM: %d\n", GetLastError());
5290 service
= OpenServiceW(scm
, name
,
5292 SERVICE_QUERY_STATUS
|
5293 SERVICE_ENUMERATE_DEPENDENTS
);
5296 WARN("Failed to open service (%s): %d\n", debugstr_w(name
), GetLastError());
5300 if (!QueryServiceStatusEx(service
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&ssp
,
5301 sizeof(SERVICE_STATUS_PROCESS
), &needed
))
5303 WARN("Failed to query service status (%s): %d\n", debugstr_w(name
), GetLastError());
5307 if (ssp
.dwCurrentState
== SERVICE_STOPPED
)
5310 stop_service_dependents(scm
, service
);
5312 if (!ControlService(service
, SERVICE_CONTROL_STOP
, &status
))
5313 WARN("Failed to stop service (%s): %d\n", debugstr_w(name
), GetLastError());
5316 CloseServiceHandle(service
);
5317 CloseServiceHandle(scm
);
5319 return ERROR_SUCCESS
;
5322 static UINT
ITERATE_StopService( MSIRECORD
*rec
, LPVOID param
)
5324 MSIPACKAGE
*package
= param
;
5330 event
= MSI_RecordGetInteger( rec
, 3 );
5331 if (!(event
& msidbServiceControlEventStop
))
5332 return ERROR_SUCCESS
;
5334 component
= MSI_RecordGetString( rec
, 6 );
5335 comp
= get_loaded_component( package
, component
);
5337 return ERROR_SUCCESS
;
5339 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5341 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5342 comp
->Action
= comp
->Installed
;
5343 return ERROR_SUCCESS
;
5345 comp
->Action
= INSTALLSTATE_ABSENT
;
5347 deformat_string( package
, MSI_RecordGetString( rec
, 2 ), &name
);
5348 stop_service( name
);
5351 return ERROR_SUCCESS
;
5354 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
5359 static const WCHAR query
[] = {
5360 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5361 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5363 rc
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
5364 if (rc
!= ERROR_SUCCESS
)
5365 return ERROR_SUCCESS
;
5367 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_StopService
, package
);
5368 msiobj_release(&view
->hdr
);
5373 static UINT
ITERATE_DeleteService( MSIRECORD
*rec
, LPVOID param
)
5375 MSIPACKAGE
*package
= param
;
5379 LPWSTR name
= NULL
, display_name
= NULL
;
5381 SC_HANDLE scm
= NULL
, service
= NULL
;
5383 event
= MSI_RecordGetInteger( rec
, 3 );
5384 if (!(event
& msidbServiceControlEventDelete
))
5385 return ERROR_SUCCESS
;
5387 component
= MSI_RecordGetString(rec
, 6);
5388 comp
= get_loaded_component(package
, component
);
5390 return ERROR_SUCCESS
;
5392 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
5394 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
5395 comp
->Action
= comp
->Installed
;
5396 return ERROR_SUCCESS
;
5398 comp
->Action
= INSTALLSTATE_ABSENT
;
5400 deformat_string( package
, MSI_RecordGetString(rec
, 2), &name
);
5401 stop_service( name
);
5403 scm
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
5406 WARN("Failed to open the SCM: %d\n", GetLastError());
5411 if (!GetServiceDisplayNameW( scm
, name
, NULL
, &len
) &&
5412 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
5414 if ((display_name
= msi_alloc( ++len
* sizeof(WCHAR
))))
5415 GetServiceDisplayNameW( scm
, name
, display_name
, &len
);
5418 service
= OpenServiceW( scm
, name
, DELETE
);
5421 WARN("Failed to open service (%s): %u\n", debugstr_w(name
), GetLastError());
5425 if (!DeleteService( service
))
5426 WARN("Failed to delete service (%s): %u\n", debugstr_w(name
), GetLastError());
5429 uirow
= MSI_CreateRecord( 2 );
5430 MSI_RecordSetStringW( uirow
, 1, display_name
);
5431 MSI_RecordSetStringW( uirow
, 2, name
);
5432 ui_actiondata( package
, szDeleteServices
, uirow
);
5433 msiobj_release( &uirow
->hdr
);
5435 CloseServiceHandle( service
);
5436 CloseServiceHandle( scm
);
5438 msi_free( display_name
);
5440 return ERROR_SUCCESS
;
5443 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
5448 static const WCHAR query
[] = {
5449 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5450 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5452 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
5453 if (rc
!= ERROR_SUCCESS
)
5454 return ERROR_SUCCESS
;
5456 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_DeleteService
, package
);
5457 msiobj_release( &view
->hdr
);
5462 static MSIFILE
*msi_find_file( MSIPACKAGE
*package
, LPCWSTR filename
)
5466 LIST_FOR_EACH_ENTRY(file
, &package
->files
, MSIFILE
, entry
)
5468 if (!lstrcmpW(file
->File
, filename
))
5475 static UINT
ITERATE_InstallODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5477 MSIPACKAGE
*package
= param
;
5478 LPWSTR driver
, driver_path
, ptr
;
5479 WCHAR outpath
[MAX_PATH
];
5480 MSIFILE
*driver_file
, *setup_file
;
5484 UINT r
= ERROR_SUCCESS
;
5486 static const WCHAR driver_fmt
[] = {
5487 'D','r','i','v','e','r','=','%','s',0};
5488 static const WCHAR setup_fmt
[] = {
5489 'S','e','t','u','p','=','%','s',0};
5490 static const WCHAR usage_fmt
[] = {
5491 'F','i','l','e','U','s','a','g','e','=','1',0};
5493 desc
= MSI_RecordGetString(rec
, 3);
5495 driver_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5496 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5500 ERR("ODBC Driver entry not found!\n");
5501 return ERROR_FUNCTION_FAILED
;
5504 len
= lstrlenW(desc
) + lstrlenW(driver_fmt
) + lstrlenW(driver_file
->FileName
);
5506 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5507 len
+= lstrlenW(usage_fmt
) + 2; /* \0\0 */
5509 driver
= msi_alloc(len
* sizeof(WCHAR
));
5511 return ERROR_OUTOFMEMORY
;
5514 lstrcpyW(ptr
, desc
);
5515 ptr
+= lstrlenW(ptr
) + 1;
5517 len
= sprintfW(ptr
, driver_fmt
, driver_file
->FileName
);
5522 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5526 lstrcpyW(ptr
, usage_fmt
);
5527 ptr
+= lstrlenW(ptr
) + 1;
5530 driver_path
= strdupW(driver_file
->TargetPath
);
5531 ptr
= strrchrW(driver_path
, '\\');
5532 if (ptr
) *ptr
= '\0';
5534 if (!SQLInstallDriverExW(driver
, driver_path
, outpath
, MAX_PATH
,
5535 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5537 ERR("Failed to install SQL driver!\n");
5538 r
= ERROR_FUNCTION_FAILED
;
5541 uirow
= MSI_CreateRecord( 5 );
5542 MSI_RecordSetStringW( uirow
, 1, desc
);
5543 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5544 MSI_RecordSetStringW( uirow
, 3, driver_path
);
5545 ui_actiondata( package
, szInstallODBC
, uirow
);
5546 msiobj_release( &uirow
->hdr
);
5549 msi_free(driver_path
);
5554 static UINT
ITERATE_InstallODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5556 MSIPACKAGE
*package
= param
;
5557 LPWSTR translator
, translator_path
, ptr
;
5558 WCHAR outpath
[MAX_PATH
];
5559 MSIFILE
*translator_file
, *setup_file
;
5563 UINT r
= ERROR_SUCCESS
;
5565 static const WCHAR translator_fmt
[] = {
5566 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5567 static const WCHAR setup_fmt
[] = {
5568 'S','e','t','u','p','=','%','s',0};
5570 desc
= MSI_RecordGetString(rec
, 3);
5572 translator_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 4));
5573 setup_file
= msi_find_file(package
, MSI_RecordGetString(rec
, 5));
5575 if (!translator_file
)
5577 ERR("ODBC Translator entry not found!\n");
5578 return ERROR_FUNCTION_FAILED
;
5581 len
= lstrlenW(desc
) + lstrlenW(translator_fmt
) + lstrlenW(translator_file
->FileName
) + 2; /* \0\0 */
5583 len
+= lstrlenW(setup_fmt
) + lstrlenW(setup_file
->FileName
);
5585 translator
= msi_alloc(len
* sizeof(WCHAR
));
5587 return ERROR_OUTOFMEMORY
;
5590 lstrcpyW(ptr
, desc
);
5591 ptr
+= lstrlenW(ptr
) + 1;
5593 len
= sprintfW(ptr
, translator_fmt
, translator_file
->FileName
);
5598 len
= sprintfW(ptr
, setup_fmt
, setup_file
->FileName
);
5603 translator_path
= strdupW(translator_file
->TargetPath
);
5604 ptr
= strrchrW(translator_path
, '\\');
5605 if (ptr
) *ptr
= '\0';
5607 if (!SQLInstallTranslatorExW(translator
, translator_path
, outpath
, MAX_PATH
,
5608 NULL
, ODBC_INSTALL_COMPLETE
, &usage
))
5610 ERR("Failed to install SQL translator!\n");
5611 r
= ERROR_FUNCTION_FAILED
;
5614 uirow
= MSI_CreateRecord( 5 );
5615 MSI_RecordSetStringW( uirow
, 1, desc
);
5616 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5617 MSI_RecordSetStringW( uirow
, 3, translator_path
);
5618 ui_actiondata( package
, szInstallODBC
, uirow
);
5619 msiobj_release( &uirow
->hdr
);
5621 msi_free(translator
);
5622 msi_free(translator_path
);
5627 static UINT
ITERATE_InstallODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5629 MSIPACKAGE
*package
= param
;
5631 LPCWSTR desc
, driver
;
5632 WORD request
= ODBC_ADD_SYS_DSN
;
5635 UINT r
= ERROR_SUCCESS
;
5638 static const WCHAR attrs_fmt
[] = {
5639 'D','S','N','=','%','s',0 };
5641 desc
= MSI_RecordGetString(rec
, 3);
5642 driver
= MSI_RecordGetString(rec
, 4);
5643 registration
= MSI_RecordGetInteger(rec
, 5);
5645 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_ADD_SYS_DSN
;
5646 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_ADD_DSN
;
5648 len
= lstrlenW(attrs_fmt
) + lstrlenW(desc
) + 2; /* \0\0 */
5649 attrs
= msi_alloc(len
* sizeof(WCHAR
));
5651 return ERROR_OUTOFMEMORY
;
5653 len
= sprintfW(attrs
, attrs_fmt
, desc
);
5656 if (!SQLConfigDataSourceW(NULL
, request
, driver
, attrs
))
5658 ERR("Failed to install SQL data source!\n");
5659 r
= ERROR_FUNCTION_FAILED
;
5662 uirow
= MSI_CreateRecord( 5 );
5663 MSI_RecordSetStringW( uirow
, 1, desc
);
5664 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5665 MSI_RecordSetInteger( uirow
, 3, request
);
5666 ui_actiondata( package
, szInstallODBC
, uirow
);
5667 msiobj_release( &uirow
->hdr
);
5674 static UINT
ACTION_InstallODBC( MSIPACKAGE
*package
)
5679 static const WCHAR driver_query
[] = {
5680 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5681 'O','D','B','C','D','r','i','v','e','r',0 };
5683 static const WCHAR translator_query
[] = {
5684 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5685 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5687 static const WCHAR source_query
[] = {
5688 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5689 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5691 rc
= MSI_DatabaseOpenViewW(package
->db
, driver_query
, &view
);
5692 if (rc
!= ERROR_SUCCESS
)
5693 return ERROR_SUCCESS
;
5695 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDriver
, package
);
5696 msiobj_release(&view
->hdr
);
5698 rc
= MSI_DatabaseOpenViewW(package
->db
, translator_query
, &view
);
5699 if (rc
!= ERROR_SUCCESS
)
5700 return ERROR_SUCCESS
;
5702 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCTranslator
, package
);
5703 msiobj_release(&view
->hdr
);
5705 rc
= MSI_DatabaseOpenViewW(package
->db
, source_query
, &view
);
5706 if (rc
!= ERROR_SUCCESS
)
5707 return ERROR_SUCCESS
;
5709 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_InstallODBCDataSource
, package
);
5710 msiobj_release(&view
->hdr
);
5715 static UINT
ITERATE_RemoveODBCDriver( MSIRECORD
*rec
, LPVOID param
)
5717 MSIPACKAGE
*package
= param
;
5722 desc
= MSI_RecordGetString( rec
, 3 );
5723 if (!SQLRemoveDriverW( desc
, FALSE
, &usage
))
5725 WARN("Failed to remove ODBC driver\n");
5729 FIXME("Usage count reached 0\n");
5732 uirow
= MSI_CreateRecord( 2 );
5733 MSI_RecordSetStringW( uirow
, 1, desc
);
5734 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5735 ui_actiondata( package
, szRemoveODBC
, uirow
);
5736 msiobj_release( &uirow
->hdr
);
5738 return ERROR_SUCCESS
;
5741 static UINT
ITERATE_RemoveODBCTranslator( MSIRECORD
*rec
, LPVOID param
)
5743 MSIPACKAGE
*package
= param
;
5748 desc
= MSI_RecordGetString( rec
, 3 );
5749 if (!SQLRemoveTranslatorW( desc
, &usage
))
5751 WARN("Failed to remove ODBC translator\n");
5755 FIXME("Usage count reached 0\n");
5758 uirow
= MSI_CreateRecord( 2 );
5759 MSI_RecordSetStringW( uirow
, 1, desc
);
5760 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5761 ui_actiondata( package
, szRemoveODBC
, uirow
);
5762 msiobj_release( &uirow
->hdr
);
5764 return ERROR_SUCCESS
;
5767 static UINT
ITERATE_RemoveODBCDataSource( MSIRECORD
*rec
, LPVOID param
)
5769 MSIPACKAGE
*package
= param
;
5772 LPCWSTR desc
, driver
;
5773 WORD request
= ODBC_REMOVE_SYS_DSN
;
5777 static const WCHAR attrs_fmt
[] = {
5778 'D','S','N','=','%','s',0 };
5780 desc
= MSI_RecordGetString( rec
, 3 );
5781 driver
= MSI_RecordGetString( rec
, 4 );
5782 registration
= MSI_RecordGetInteger( rec
, 5 );
5784 if (registration
== msidbODBCDataSourceRegistrationPerMachine
) request
= ODBC_REMOVE_SYS_DSN
;
5785 else if (registration
== msidbODBCDataSourceRegistrationPerUser
) request
= ODBC_REMOVE_DSN
;
5787 len
= strlenW( attrs_fmt
) + strlenW( desc
) + 2; /* \0\0 */
5788 attrs
= msi_alloc( len
* sizeof(WCHAR
) );
5790 return ERROR_OUTOFMEMORY
;
5792 FIXME("Use ODBCSourceAttribute table\n");
5794 len
= sprintfW( attrs
, attrs_fmt
, desc
);
5797 if (!SQLConfigDataSourceW( NULL
, request
, driver
, attrs
))
5799 WARN("Failed to remove ODBC data source\n");
5803 uirow
= MSI_CreateRecord( 3 );
5804 MSI_RecordSetStringW( uirow
, 1, desc
);
5805 MSI_RecordSetStringW( uirow
, 2, MSI_RecordGetString(rec
, 2) );
5806 MSI_RecordSetInteger( uirow
, 3, request
);
5807 ui_actiondata( package
, szRemoveODBC
, uirow
);
5808 msiobj_release( &uirow
->hdr
);
5810 return ERROR_SUCCESS
;
5813 static UINT
ACTION_RemoveODBC( MSIPACKAGE
*package
)
5818 static const WCHAR driver_query
[] = {
5819 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5820 'O','D','B','C','D','r','i','v','e','r',0 };
5822 static const WCHAR translator_query
[] = {
5823 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5824 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5826 static const WCHAR source_query
[] = {
5827 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5828 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5830 rc
= MSI_DatabaseOpenViewW( package
->db
, driver_query
, &view
);
5831 if (rc
!= ERROR_SUCCESS
)
5832 return ERROR_SUCCESS
;
5834 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDriver
, package
);
5835 msiobj_release( &view
->hdr
);
5837 rc
= MSI_DatabaseOpenViewW( package
->db
, translator_query
, &view
);
5838 if (rc
!= ERROR_SUCCESS
)
5839 return ERROR_SUCCESS
;
5841 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCTranslator
, package
);
5842 msiobj_release( &view
->hdr
);
5844 rc
= MSI_DatabaseOpenViewW( package
->db
, source_query
, &view
);
5845 if (rc
!= ERROR_SUCCESS
)
5846 return ERROR_SUCCESS
;
5848 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveODBCDataSource
, package
);
5849 msiobj_release( &view
->hdr
);
5854 #define ENV_ACT_SETALWAYS 0x1
5855 #define ENV_ACT_SETABSENT 0x2
5856 #define ENV_ACT_REMOVE 0x4
5857 #define ENV_ACT_REMOVEMATCH 0x8
5859 #define ENV_MOD_MACHINE 0x20000000
5860 #define ENV_MOD_APPEND 0x40000000
5861 #define ENV_MOD_PREFIX 0x80000000
5862 #define ENV_MOD_MASK 0xC0000000
5864 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5866 static UINT
env_parse_flags( LPCWSTR
*name
, LPCWSTR
*value
, DWORD
*flags
)
5868 LPCWSTR cptr
= *name
;
5870 static const WCHAR prefix
[] = {'[','~',']',0};
5871 static const int prefix_len
= 3;
5877 *flags
|= ENV_ACT_SETALWAYS
;
5878 else if (*cptr
== '+')
5879 *flags
|= ENV_ACT_SETABSENT
;
5880 else if (*cptr
== '-')
5881 *flags
|= ENV_ACT_REMOVE
;
5882 else if (*cptr
== '!')
5883 *flags
|= ENV_ACT_REMOVEMATCH
;
5884 else if (*cptr
== '*')
5885 *flags
|= ENV_MOD_MACHINE
;
5895 ERR("Missing environment variable\n");
5896 return ERROR_FUNCTION_FAILED
;
5901 LPCWSTR ptr
= *value
;
5902 if (!strncmpW(ptr
, prefix
, prefix_len
))
5904 if (ptr
[prefix_len
] == szSemiColon
[0])
5906 *flags
|= ENV_MOD_APPEND
;
5907 *value
+= lstrlenW(prefix
);
5914 else if (lstrlenW(*value
) >= prefix_len
)
5916 ptr
+= lstrlenW(ptr
) - prefix_len
;
5917 if (!lstrcmpW(ptr
, prefix
))
5919 if ((ptr
-1) > *value
&& *(ptr
-1) == szSemiColon
[0])
5921 *flags
|= ENV_MOD_PREFIX
;
5922 /* the "[~]" will be removed by deformat_string */;
5932 if (check_flag_combo(*flags
, ENV_ACT_SETALWAYS
| ENV_ACT_SETABSENT
) ||
5933 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETABSENT
) ||
5934 check_flag_combo(*flags
, ENV_ACT_REMOVEMATCH
| ENV_ACT_SETALWAYS
) ||
5935 check_flag_combo(*flags
, ENV_ACT_SETABSENT
| ENV_MOD_MASK
))
5937 ERR("Invalid flags: %08x\n", *flags
);
5938 return ERROR_FUNCTION_FAILED
;
5942 *flags
= ENV_ACT_SETALWAYS
| ENV_ACT_REMOVE
;
5944 return ERROR_SUCCESS
;
5947 static UINT
open_env_key( DWORD flags
, HKEY
*key
)
5949 static const WCHAR user_env
[] =
5950 {'E','n','v','i','r','o','n','m','e','n','t',0};
5951 static const WCHAR machine_env
[] =
5952 {'S','y','s','t','e','m','\\',
5953 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5954 'C','o','n','t','r','o','l','\\',
5955 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5956 'E','n','v','i','r','o','n','m','e','n','t',0};
5961 if (flags
& ENV_MOD_MACHINE
)
5964 root
= HKEY_LOCAL_MACHINE
;
5969 root
= HKEY_CURRENT_USER
;
5972 res
= RegOpenKeyExW( root
, env
, 0, KEY_ALL_ACCESS
, key
);
5973 if (res
!= ERROR_SUCCESS
)
5975 WARN("Failed to open key %s (%d)\n", debugstr_w(env
), res
);
5976 return ERROR_FUNCTION_FAILED
;
5979 return ERROR_SUCCESS
;
5982 static UINT
ITERATE_WriteEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
5984 MSIPACKAGE
*package
= param
;
5985 LPCWSTR name
, value
, component
;
5986 LPWSTR data
= NULL
, newval
= NULL
, deformatted
= NULL
, ptr
;
5987 DWORD flags
, type
, size
;
5994 component
= MSI_RecordGetString(rec
, 4);
5995 comp
= get_loaded_component(package
, component
);
5997 return ERROR_SUCCESS
;
5999 if (comp
->ActionRequest
!= INSTALLSTATE_LOCAL
)
6001 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6002 comp
->Action
= comp
->Installed
;
6003 return ERROR_SUCCESS
;
6005 comp
->Action
= INSTALLSTATE_LOCAL
;
6007 name
= MSI_RecordGetString(rec
, 2);
6008 value
= MSI_RecordGetString(rec
, 3);
6010 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6012 res
= env_parse_flags(&name
, &value
, &flags
);
6013 if (res
!= ERROR_SUCCESS
|| !value
)
6016 if (value
&& !deformat_string(package
, value
, &deformatted
))
6018 res
= ERROR_OUTOFMEMORY
;
6022 value
= deformatted
;
6024 res
= open_env_key( flags
, &env
);
6025 if (res
!= ERROR_SUCCESS
)
6028 if (flags
& ENV_MOD_MACHINE
)
6029 action
|= 0x20000000;
6033 res
= RegQueryValueExW(env
, name
, NULL
, &type
, NULL
, &size
);
6034 if ((res
!= ERROR_SUCCESS
&& res
!= ERROR_FILE_NOT_FOUND
) ||
6035 (res
== ERROR_SUCCESS
&& type
!= REG_SZ
&& type
!= REG_EXPAND_SZ
))
6038 if ((res
== ERROR_FILE_NOT_FOUND
|| !(flags
& ENV_MOD_MASK
)))
6042 /* Nothing to do. */
6045 res
= ERROR_SUCCESS
;
6049 /* If we are appending but the string was empty, strip ; */
6050 if ((flags
& ENV_MOD_APPEND
) && (value
[0] == szSemiColon
[0])) value
++;
6052 size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
6053 newval
= strdupW(value
);
6056 res
= ERROR_OUTOFMEMORY
;
6064 /* Contrary to MSDN, +-variable to [~];path works */
6065 if (flags
& ENV_ACT_SETABSENT
&& !(flags
& ENV_MOD_MASK
))
6067 res
= ERROR_SUCCESS
;
6071 data
= msi_alloc(size
);
6075 return ERROR_OUTOFMEMORY
;
6078 res
= RegQueryValueExW(env
, name
, NULL
, &type
, (LPVOID
)data
, &size
);
6079 if (res
!= ERROR_SUCCESS
)
6082 if (flags
& ENV_ACT_REMOVEMATCH
&& (!value
|| !lstrcmpW(data
, value
)))
6085 res
= RegDeleteValueW(env
, name
);
6086 if (res
!= ERROR_SUCCESS
)
6087 WARN("Failed to remove value %s (%d)\n", debugstr_w(name
), res
);
6091 size
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
6092 if (flags
& ENV_MOD_MASK
)
6096 if (flags
& ENV_MOD_APPEND
) multiplier
++;
6097 if (flags
& ENV_MOD_PREFIX
) multiplier
++;
6098 mod_size
= lstrlenW(value
) * multiplier
;
6099 size
+= mod_size
* sizeof(WCHAR
);
6102 newval
= msi_alloc(size
);
6106 res
= ERROR_OUTOFMEMORY
;
6110 if (flags
& ENV_MOD_PREFIX
)
6112 lstrcpyW(newval
, value
);
6113 ptr
= newval
+ lstrlenW(value
);
6114 action
|= 0x80000000;
6117 lstrcpyW(ptr
, data
);
6119 if (flags
& ENV_MOD_APPEND
)
6121 lstrcatW(newval
, value
);
6122 action
|= 0x40000000;
6125 TRACE("setting %s to %s\n", debugstr_w(name
), debugstr_w(newval
));
6126 res
= RegSetValueExW(env
, name
, 0, type
, (LPVOID
)newval
, size
);
6129 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name
), debugstr_w(newval
), res
);
6133 uirow
= MSI_CreateRecord( 3 );
6134 MSI_RecordSetStringW( uirow
, 1, name
);
6135 MSI_RecordSetStringW( uirow
, 2, newval
);
6136 MSI_RecordSetInteger( uirow
, 3, action
);
6137 ui_actiondata( package
, szWriteEnvironmentStrings
, uirow
);
6138 msiobj_release( &uirow
->hdr
);
6140 if (env
) RegCloseKey(env
);
6141 msi_free(deformatted
);
6147 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
6151 static const WCHAR ExecSeqQuery
[] =
6152 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6153 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6154 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6155 if (rc
!= ERROR_SUCCESS
)
6156 return ERROR_SUCCESS
;
6158 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteEnvironmentString
, package
);
6159 msiobj_release(&view
->hdr
);
6164 static UINT
ITERATE_RemoveEnvironmentString( MSIRECORD
*rec
, LPVOID param
)
6166 MSIPACKAGE
*package
= param
;
6167 LPCWSTR name
, value
, component
;
6168 LPWSTR deformatted
= NULL
;
6177 component
= MSI_RecordGetString( rec
, 4 );
6178 comp
= get_loaded_component( package
, component
);
6180 return ERROR_SUCCESS
;
6182 if (comp
->ActionRequest
!= INSTALLSTATE_ABSENT
)
6184 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component
));
6185 comp
->Action
= comp
->Installed
;
6186 return ERROR_SUCCESS
;
6188 comp
->Action
= INSTALLSTATE_ABSENT
;
6190 name
= MSI_RecordGetString( rec
, 2 );
6191 value
= MSI_RecordGetString( rec
, 3 );
6193 TRACE("name %s value %s\n", debugstr_w(name
), debugstr_w(value
));
6195 r
= env_parse_flags( &name
, &value
, &flags
);
6196 if (r
!= ERROR_SUCCESS
)
6199 if (!(flags
& ENV_ACT_REMOVE
))
6201 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name
));
6202 return ERROR_SUCCESS
;
6205 if (value
&& !deformat_string( package
, value
, &deformatted
))
6206 return ERROR_OUTOFMEMORY
;
6208 value
= deformatted
;
6210 r
= open_env_key( flags
, &env
);
6211 if (r
!= ERROR_SUCCESS
)
6217 if (flags
& ENV_MOD_MACHINE
)
6218 action
|= 0x20000000;
6220 TRACE("Removing %s\n", debugstr_w(name
));
6222 res
= RegDeleteValueW( env
, name
);
6223 if (res
!= ERROR_SUCCESS
)
6225 WARN("Failed to delete value %s (%d)\n", debugstr_w(name
), res
);
6230 uirow
= MSI_CreateRecord( 3 );
6231 MSI_RecordSetStringW( uirow
, 1, name
);
6232 MSI_RecordSetStringW( uirow
, 2, value
);
6233 MSI_RecordSetInteger( uirow
, 3, action
);
6234 ui_actiondata( package
, szRemoveEnvironmentStrings
, uirow
);
6235 msiobj_release( &uirow
->hdr
);
6237 if (env
) RegCloseKey( env
);
6238 msi_free( deformatted
);
6242 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
6246 static const WCHAR query
[] =
6247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6248 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6250 rc
= MSI_DatabaseOpenViewW( package
->db
, query
, &view
);
6251 if (rc
!= ERROR_SUCCESS
)
6252 return ERROR_SUCCESS
;
6254 rc
= MSI_IterateRecords( view
, NULL
, ITERATE_RemoveEnvironmentString
, package
);
6255 msiobj_release( &view
->hdr
);
6260 typedef struct tagMSIASSEMBLY
6263 MSICOMPONENT
*component
;
6264 MSIFEATURE
*feature
;
6268 LPWSTR display_name
;
6273 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**ppAsmCache
,
6275 static HRESULT (WINAPI
*pLoadLibraryShim
)(LPCWSTR szDllName
, LPCWSTR szVersion
,
6276 LPVOID pvReserved
, HMODULE
*phModDll
);
6278 static BOOL
init_functionpointers(void)
6284 static const WCHAR szFusion
[] = {'f','u','s','i','o','n','.','d','l','l',0};
6286 hmscoree
= LoadLibraryA("mscoree.dll");
6289 WARN("mscoree.dll not available\n");
6293 pLoadLibraryShim
= (void *)GetProcAddress(hmscoree
, "LoadLibraryShim");
6294 if (!pLoadLibraryShim
)
6296 WARN("LoadLibraryShim not available\n");
6297 FreeLibrary(hmscoree
);
6301 hr
= pLoadLibraryShim(szFusion
, NULL
, NULL
, &hfusion
);
6304 WARN("fusion.dll not available\n");
6305 FreeLibrary(hmscoree
);
6309 pCreateAssemblyCache
= (void *)GetProcAddress(hfusion
, "CreateAssemblyCache");
6311 FreeLibrary(hmscoree
);
6315 static UINT
install_assembly(MSIPACKAGE
*package
, MSIASSEMBLY
*assembly
,
6318 IAssemblyCache
*cache
;
6321 UINT r
= ERROR_FUNCTION_FAILED
;
6323 TRACE("installing assembly: %s\n", debugstr_w(path
));
6325 uirow
= MSI_CreateRecord( 2 );
6326 MSI_RecordSetStringW( uirow
, 2, assembly
->display_name
);
6327 ui_actiondata( package
, szMsiPublishAssemblies
, uirow
);
6328 msiobj_release( &uirow
->hdr
);
6330 if (assembly
->feature
)
6331 msi_feature_set_state(package
, assembly
->feature
, INSTALLSTATE_LOCAL
);
6333 if (assembly
->manifest
)
6334 FIXME("Manifest unhandled\n");
6336 if (assembly
->application
)
6338 FIXME("Assembly should be privately installed\n");
6339 return ERROR_SUCCESS
;
6342 if (assembly
->attributes
== msidbAssemblyAttributesWin32
)
6344 FIXME("Win32 assemblies not handled\n");
6345 return ERROR_SUCCESS
;
6348 hr
= pCreateAssemblyCache(&cache
, 0);
6352 hr
= IAssemblyCache_InstallAssembly(cache
, 0, path
, NULL
);
6354 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path
), hr
);
6359 IAssemblyCache_Release(cache
);
6363 typedef struct tagASSEMBLY_LIST
6365 MSIPACKAGE
*package
;
6366 IAssemblyCache
*cache
;
6367 struct list
*assemblies
;
6370 typedef struct tagASSEMBLY_NAME
6378 static UINT
parse_assembly_name(MSIRECORD
*rec
, LPVOID param
)
6380 ASSEMBLY_NAME
*asmname
= param
;
6381 LPCWSTR name
= MSI_RecordGetString(rec
, 2);
6382 LPWSTR val
= msi_dup_record_field(rec
, 3);
6384 static const WCHAR Name
[] = {'N','a','m','e',0};
6385 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
6386 static const WCHAR Culture
[] = {'C','u','l','t','u','r','e',0};
6387 static const WCHAR PublicKeyToken
[] = {
6388 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6390 if (!strcmpiW(name
, Name
))
6391 asmname
->name
= val
;
6392 else if (!strcmpiW(name
, Version
))
6393 asmname
->version
= val
;
6394 else if (!strcmpiW(name
, Culture
))
6395 asmname
->culture
= val
;
6396 else if (!strcmpiW(name
, PublicKeyToken
))
6397 asmname
->pubkeytoken
= val
;
6401 return ERROR_SUCCESS
;
6404 static void append_str(LPWSTR
*str
, DWORD
*size
, LPCWSTR append
)
6408 *size
= lstrlenW(append
) + 1;
6409 *str
= msi_alloc((*size
) * sizeof(WCHAR
));
6410 lstrcpyW(*str
, append
);
6414 (*size
) += lstrlenW(append
);
6415 *str
= msi_realloc(*str
, (*size
) * sizeof(WCHAR
));
6416 lstrcatW(*str
, append
);
6419 static WCHAR
*get_assembly_display_name( MSIDATABASE
*db
, MSICOMPONENT
*comp
)
6421 static const WCHAR separator
[] = {',',' ',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
[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
6425 static const WCHAR query
[] = {
6426 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6427 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6428 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6429 '=','\'','%','s','\'',0};
6432 LPWSTR display_name
;
6436 display_name
= NULL
;
6437 memset( &name
, 0, sizeof(ASSEMBLY_NAME
) );
6439 r
= MSI_OpenQuery( db
, &view
, query
, comp
->Component
);
6440 if (r
!= ERROR_SUCCESS
)
6443 MSI_IterateRecords( view
, NULL
, parse_assembly_name
, &name
);
6444 msiobj_release( &view
->hdr
);
6448 ERR("No assembly name specified!\n");
6452 append_str( &display_name
, &size
, name
.name
);
6456 append_str( &display_name
, &size
, separator
);
6457 append_str( &display_name
, &size
, Version
);
6458 append_str( &display_name
, &size
, name
.version
);
6462 append_str( &display_name
, &size
, separator
);
6463 append_str( &display_name
, &size
, Culture
);
6464 append_str( &display_name
, &size
, name
.culture
);
6466 if (name
.pubkeytoken
)
6468 append_str( &display_name
, &size
, separator
);
6469 append_str( &display_name
, &size
, PublicKeyToken
);
6470 append_str( &display_name
, &size
, name
.pubkeytoken
);
6473 msi_free( name
.name
);
6474 msi_free( name
.version
);
6475 msi_free( name
.culture
);
6476 msi_free( name
.pubkeytoken
);
6478 return display_name
;
6481 static BOOL
check_assembly_installed( MSIDATABASE
*db
, IAssemblyCache
*cache
, MSICOMPONENT
*comp
)
6483 ASSEMBLY_INFO asminfo
;
6488 disp
= get_assembly_display_name( db
, comp
);
6492 memset( &asminfo
, 0, sizeof(ASSEMBLY_INFO
) );
6493 asminfo
.cbAssemblyInfo
= sizeof(ASSEMBLY_INFO
);
6495 hr
= IAssemblyCache_QueryAssemblyInfo( cache
, QUERYASMINFO_FLAG_VALIDATE
, disp
, &asminfo
);
6497 found
= (asminfo
.dwAssemblyFlags
== ASSEMBLYINFO_FLAG_INSTALLED
);
6503 static UINT
load_assembly(MSIRECORD
*rec
, LPVOID param
)
6505 ASSEMBLY_LIST
*list
= param
;
6506 MSIASSEMBLY
*assembly
;
6509 assembly
= msi_alloc_zero(sizeof(MSIASSEMBLY
));
6511 return ERROR_OUTOFMEMORY
;
6513 component
= MSI_RecordGetString(rec
, 1);
6514 assembly
->component
= get_loaded_component(list
->package
, component
);
6515 if (!assembly
->component
)
6516 return ERROR_SUCCESS
;
6518 if (assembly
->component
->ActionRequest
!= INSTALLSTATE_LOCAL
&&
6519 assembly
->component
->ActionRequest
!= INSTALLSTATE_SOURCE
)
6521 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component
));
6522 assembly
->component
->Action
= assembly
->component
->Installed
;
6523 return ERROR_SUCCESS
;
6525 assembly
->component
->Action
= assembly
->component
->ActionRequest
;
6527 assembly
->feature
= find_feature_by_name(list
->package
, MSI_RecordGetString(rec
, 2));
6528 assembly
->file
= msi_find_file(list
->package
, assembly
->component
->KeyPath
);
6530 if (!assembly
->file
)
6532 ERR("File %s not found\n", debugstr_w(assembly
->component
->KeyPath
));
6533 return ERROR_FUNCTION_FAILED
;
6536 assembly
->manifest
= strdupW(MSI_RecordGetString(rec
, 3));
6537 assembly
->application
= strdupW(MSI_RecordGetString(rec
, 4));
6538 assembly
->attributes
= MSI_RecordGetInteger(rec
, 5);
6540 if (assembly
->application
)
6543 DWORD size
= sizeof(version
)/sizeof(WCHAR
);
6545 /* FIXME: we should probably check the manifest file here */
6547 if (!MsiGetFileVersionW(assembly
->file
->TargetPath
, version
, &size
, NULL
, NULL
) &&
6548 (!assembly
->file
->Version
|| strcmpW(version
, assembly
->file
->Version
) >= 0))
6550 assembly
->installed
= TRUE
;
6554 assembly
->installed
= check_assembly_installed(list
->package
->db
,
6556 assembly
->component
);
6558 list_add_head(list
->assemblies
, &assembly
->entry
);
6559 return ERROR_SUCCESS
;
6562 static UINT
load_assemblies(MSIPACKAGE
*package
, struct list
*assemblies
)
6564 IAssemblyCache
*cache
= NULL
;
6570 static const WCHAR query
[] =
6571 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6572 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6574 r
= MSI_DatabaseOpenViewW(package
->db
, query
, &view
);
6575 if (r
!= ERROR_SUCCESS
)
6576 return ERROR_SUCCESS
;
6578 hr
= pCreateAssemblyCache(&cache
, 0);
6580 return ERROR_FUNCTION_FAILED
;
6582 list
.package
= package
;
6584 list
.assemblies
= assemblies
;
6586 r
= MSI_IterateRecords(view
, NULL
, load_assembly
, &list
);
6587 msiobj_release(&view
->hdr
);
6589 IAssemblyCache_Release(cache
);
6594 static void free_assemblies(struct list
*assemblies
)
6596 struct list
*item
, *cursor
;
6598 LIST_FOR_EACH_SAFE(item
, cursor
, assemblies
)
6600 MSIASSEMBLY
*assembly
= LIST_ENTRY(item
, MSIASSEMBLY
, entry
);
6602 list_remove(&assembly
->entry
);
6603 msi_free(assembly
->application
);
6604 msi_free(assembly
->manifest
);
6605 msi_free(assembly
->display_name
);
6610 static BOOL
find_assembly(struct list
*assemblies
, LPCWSTR file
, MSIASSEMBLY
**out
)
6612 MSIASSEMBLY
*assembly
;
6614 LIST_FOR_EACH_ENTRY(assembly
, assemblies
, MSIASSEMBLY
, entry
)
6616 if (!lstrcmpW(assembly
->file
->File
, file
))
6626 static BOOL
installassembly_cb(MSIPACKAGE
*package
, LPCWSTR file
, DWORD action
,
6627 LPWSTR
*path
, DWORD
*attrs
, PVOID user
)
6629 MSIASSEMBLY
*assembly
;
6630 WCHAR temppath
[MAX_PATH
];
6631 struct list
*assemblies
= user
;
6634 if (!find_assembly(assemblies
, file
, &assembly
))
6637 GetTempPathW(MAX_PATH
, temppath
);
6638 PathAddBackslashW(temppath
);
6639 lstrcatW(temppath
, assembly
->file
->FileName
);
6641 if (action
== MSICABEXTRACT_BEGINEXTRACT
)
6643 if (assembly
->installed
)
6646 *path
= strdupW(temppath
);
6647 *attrs
= assembly
->file
->Attributes
;
6649 else if (action
== MSICABEXTRACT_FILEEXTRACTED
)
6651 assembly
->installed
= TRUE
;
6653 r
= install_assembly(package
, assembly
, temppath
);
6654 if (r
!= ERROR_SUCCESS
)
6655 ERR("Failed to install assembly\n");
6661 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
6664 struct list assemblies
= LIST_INIT(assemblies
);
6665 MSIASSEMBLY
*assembly
;
6668 if (!init_functionpointers() || !pCreateAssemblyCache
)
6669 return ERROR_FUNCTION_FAILED
;
6671 r
= load_assemblies(package
, &assemblies
);
6672 if (r
!= ERROR_SUCCESS
)
6675 if (list_empty(&assemblies
))
6678 mi
= msi_alloc_zero(sizeof(MSIMEDIAINFO
));
6681 r
= ERROR_OUTOFMEMORY
;
6685 LIST_FOR_EACH_ENTRY(assembly
, &assemblies
, MSIASSEMBLY
, entry
)
6687 if (assembly
->installed
&& !mi
->is_continuous
)
6690 if (assembly
->file
->Sequence
> mi
->last_sequence
|| mi
->is_continuous
||
6691 (assembly
->file
->IsCompressed
&& !mi
->is_extracted
))
6695 r
= ready_media(package
, assembly
->file
, mi
);
6696 if (r
!= ERROR_SUCCESS
)
6698 ERR("Failed to ready media\n");
6703 data
.package
= package
;
6704 data
.cb
= installassembly_cb
;
6705 data
.user
= &assemblies
;
6707 if (assembly
->file
->IsCompressed
&&
6708 !msi_cabextract(package
, mi
, &data
))
6710 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi
->cabinet
));
6711 r
= ERROR_FUNCTION_FAILED
;
6716 if (!assembly
->file
->IsCompressed
)
6718 LPWSTR source
= resolve_file_source(package
, assembly
->file
);
6720 r
= install_assembly(package
, assembly
, source
);
6721 if (r
!= ERROR_SUCCESS
)
6722 ERR("Failed to install assembly\n");
6727 /* FIXME: write Installer assembly reg values */
6731 free_assemblies(&assemblies
);
6735 static UINT
ACTION_ValidateProductID( MSIPACKAGE
*package
)
6737 LPWSTR key
, template, id
;
6738 UINT r
= ERROR_SUCCESS
;
6740 id
= msi_dup_property( package
, szProductID
);
6744 return ERROR_SUCCESS
;
6746 template = msi_dup_property( package
, szPIDTemplate
);
6747 key
= msi_dup_property( package
, szPIDKEY
);
6749 if (key
&& template)
6751 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key
) );
6752 r
= MSI_SetPropertyW( package
, szProductID
, key
);
6754 msi_free( template );
6759 static UINT
ACTION_ScheduleReboot( MSIPACKAGE
*package
)
6762 package
->need_reboot
= 1;
6763 return ERROR_SUCCESS
;
6766 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
6768 static const WCHAR szAvailableFreeReg
[] =
6769 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6771 int space
= msi_get_property_int( package
, szAvailableFreeReg
, 0 );
6773 TRACE("%p %d kilobytes\n", package
, space
);
6775 uirow
= MSI_CreateRecord( 1 );
6776 MSI_RecordSetInteger( uirow
, 1, space
);
6777 ui_actiondata( package
, szAllocateRegistrySpace
, uirow
);
6778 msiobj_release( &uirow
->hdr
);
6780 return ERROR_SUCCESS
;
6783 static UINT
ACTION_DisableRollback( MSIPACKAGE
*package
)
6785 FIXME("%p\n", package
);
6786 return ERROR_SUCCESS
;
6789 static UINT
ACTION_InstallAdminPackage( MSIPACKAGE
*package
)
6791 FIXME("%p\n", package
);
6792 return ERROR_SUCCESS
;
6795 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
6796 LPCSTR action
, LPCWSTR table
)
6798 static const WCHAR query
[] = {
6799 'S','E','L','E','C','T',' ','*',' ',
6800 'F','R','O','M',' ','`','%','s','`',0 };
6801 MSIQUERY
*view
= NULL
;
6805 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
6806 if (r
== ERROR_SUCCESS
)
6808 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
6809 msiobj_release(&view
->hdr
);
6813 FIXME("%s -> %u ignored %s table values\n",
6814 action
, count
, debugstr_w(table
));
6816 return ERROR_SUCCESS
;
6819 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
6821 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
6822 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
6825 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
6827 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
6828 return msi_unimplemented_action_stub( package
, "BindImage", table
);
6831 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
6833 static const WCHAR table
[] = {
6834 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6835 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
6838 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
6840 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6841 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
6844 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
6846 static const WCHAR table
[] = {
6847 'M','s','i','A','s','s','e','m','b','l','y',0 };
6848 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
6851 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
6853 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
6854 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
6857 static UINT
ACTION_RegisterComPlus( MSIPACKAGE
*package
)
6859 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6860 return msi_unimplemented_action_stub( package
, "RegisterComPlus", table
);
6863 static UINT
ACTION_UnregisterComPlus( MSIPACKAGE
*package
)
6865 static const WCHAR table
[] = { 'C','o','m','p','l','u','s',0 };
6866 return msi_unimplemented_action_stub( package
, "UnregisterComPlus", table
);
6869 static UINT
ACTION_InstallSFPCatalogFile( MSIPACKAGE
*package
)
6871 static const WCHAR table
[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6872 return msi_unimplemented_action_stub( package
, "InstallSFPCatalogFile", table
);
6875 static UINT
ACTION_RemoveExistingProducts( MSIPACKAGE
*package
)
6877 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
6878 return msi_unimplemented_action_stub( package
, "RemoveExistingProducts", table
);
6881 static UINT
ACTION_SetODBCFolders( MSIPACKAGE
*package
)
6883 static const WCHAR table
[] = { 'D','i','r','e','c','t','o','r','y',0 };
6884 return msi_unimplemented_action_stub( package
, "SetODBCFolders", table
);
6887 static UINT
ACTION_UnregisterClassInfo( MSIPACKAGE
*package
)
6889 static const WCHAR table
[] = { 'A','p','p','I','d',0 };
6890 return msi_unimplemented_action_stub( package
, "UnregisterClassInfo", table
);
6893 static UINT
ACTION_UnregisterExtensionInfo( MSIPACKAGE
*package
)
6895 static const WCHAR table
[] = { 'E','x','t','e','n','s','i','o','n',0 };
6896 return msi_unimplemented_action_stub( package
, "UnregisterExtensionInfo", table
);
6899 static UINT
ACTION_UnregisterMIMEInfo( MSIPACKAGE
*package
)
6901 static const WCHAR table
[] = { 'M','I','M','E',0 };
6902 return msi_unimplemented_action_stub( package
, "UnregisterMIMEInfo", table
);
6905 static UINT
ACTION_UnregisterProgIdInfo( MSIPACKAGE
*package
)
6907 static const WCHAR table
[] = { 'P','r','o','g','I','d',0 };
6908 return msi_unimplemented_action_stub( package
, "UnregisterProgIdInfo", table
);
6911 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
6915 const WCHAR
*action
;
6916 UINT (*handler
)(MSIPACKAGE
*);
6920 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
6921 { szAppSearch
, ACTION_AppSearch
},
6922 { szBindImage
, ACTION_BindImage
},
6923 { szCCPSearch
, ACTION_CCPSearch
},
6924 { szCostFinalize
, ACTION_CostFinalize
},
6925 { szCostInitialize
, ACTION_CostInitialize
},
6926 { szCreateFolders
, ACTION_CreateFolders
},
6927 { szCreateShortcuts
, ACTION_CreateShortcuts
},
6928 { szDeleteServices
, ACTION_DeleteServices
},
6929 { szDisableRollback
, ACTION_DisableRollback
},
6930 { szDuplicateFiles
, ACTION_DuplicateFiles
},
6931 { szExecuteAction
, ACTION_ExecuteAction
},
6932 { szFileCost
, ACTION_FileCost
},
6933 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
6934 { szForceReboot
, ACTION_ForceReboot
},
6935 { szInstallAdminPackage
, ACTION_InstallAdminPackage
},
6936 { szInstallExecute
, ACTION_InstallExecute
},
6937 { szInstallExecuteAgain
, ACTION_InstallExecute
},
6938 { szInstallFiles
, ACTION_InstallFiles
},
6939 { szInstallFinalize
, ACTION_InstallFinalize
},
6940 { szInstallInitialize
, ACTION_InstallInitialize
},
6941 { szInstallSFPCatalogFile
, ACTION_InstallSFPCatalogFile
},
6942 { szInstallValidate
, ACTION_InstallValidate
},
6943 { szIsolateComponents
, ACTION_IsolateComponents
},
6944 { szLaunchConditions
, ACTION_LaunchConditions
},
6945 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
6946 { szMoveFiles
, ACTION_MoveFiles
},
6947 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
6948 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
6949 { szInstallODBC
, ACTION_InstallODBC
},
6950 { szInstallServices
, ACTION_InstallServices
},
6951 { szPatchFiles
, ACTION_PatchFiles
},
6952 { szProcessComponents
, ACTION_ProcessComponents
},
6953 { szPublishComponents
, ACTION_PublishComponents
},
6954 { szPublishFeatures
, ACTION_PublishFeatures
},
6955 { szPublishProduct
, ACTION_PublishProduct
},
6956 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
6957 { szRegisterComPlus
, ACTION_RegisterComPlus
},
6958 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
6959 { szRegisterFonts
, ACTION_RegisterFonts
},
6960 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
6961 { szRegisterProduct
, ACTION_RegisterProduct
},
6962 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
6963 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
6964 { szRegisterUser
, ACTION_RegisterUser
},
6965 { szRemoveDuplicateFiles
, ACTION_RemoveDuplicateFiles
},
6966 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
6967 { szRemoveExistingProducts
, ACTION_RemoveExistingProducts
},
6968 { szRemoveFiles
, ACTION_RemoveFiles
},
6969 { szRemoveFolders
, ACTION_RemoveFolders
},
6970 { szRemoveIniValues
, ACTION_RemoveIniValues
},
6971 { szRemoveODBC
, ACTION_RemoveODBC
},
6972 { szRemoveRegistryValues
, ACTION_RemoveRegistryValues
},
6973 { szRemoveShortcuts
, ACTION_RemoveShortcuts
},
6974 { szResolveSource
, ACTION_ResolveSource
},
6975 { szRMCCPSearch
, ACTION_RMCCPSearch
},
6976 { szScheduleReboot
, ACTION_ScheduleReboot
},
6977 { szSelfRegModules
, ACTION_SelfRegModules
},
6978 { szSelfUnregModules
, ACTION_SelfUnregModules
},
6979 { szSetODBCFolders
, ACTION_SetODBCFolders
},
6980 { szStartServices
, ACTION_StartServices
},
6981 { szStopServices
, ACTION_StopServices
},
6982 { szUnpublishComponents
, ACTION_UnpublishComponents
},
6983 { szUnpublishFeatures
, ACTION_UnpublishFeatures
},
6984 { szUnregisterClassInfo
, ACTION_UnregisterClassInfo
},
6985 { szUnregisterComPlus
, ACTION_UnregisterComPlus
},
6986 { szUnregisterExtensionInfo
, ACTION_UnregisterExtensionInfo
},
6987 { szUnregisterFonts
, ACTION_UnregisterFonts
},
6988 { szUnregisterMIMEInfo
, ACTION_UnregisterMIMEInfo
},
6989 { szUnregisterProgIdInfo
, ACTION_UnregisterProgIdInfo
},
6990 { szUnregisterTypeLibraries
, ACTION_UnregisterTypeLibraries
},
6991 { szValidateProductID
, ACTION_ValidateProductID
},
6992 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
6993 { szWriteIniValues
, ACTION_WriteIniValues
},
6994 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
6998 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
6999 UINT
* rc
, BOOL force
)
7005 if (!run
&& !package
->script
->CurrentlyScripting
)
7010 if (strcmpW(action
,szInstallFinalize
) == 0 ||
7011 strcmpW(action
,szInstallExecute
) == 0 ||
7012 strcmpW(action
,szInstallExecuteAgain
) == 0)
7017 while (StandardActions
[i
].action
!= NULL
)
7019 if (strcmpW(StandardActions
[i
].action
, action
)==0)
7023 ui_actioninfo(package
, action
, TRUE
, 0);
7024 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
7025 ui_actioninfo(package
, action
, FALSE
, *rc
);
7029 ui_actionstart(package
, action
);
7030 if (StandardActions
[i
].handler
)
7032 *rc
= StandardActions
[i
].handler(package
);
7036 FIXME("unhandled standard action %s\n",debugstr_w(action
));
7037 *rc
= ERROR_SUCCESS
;
7048 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
, BOOL force
)
7050 UINT rc
= ERROR_SUCCESS
;
7053 TRACE("Performing action (%s)\n", debugstr_w(action
));
7055 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
7058 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, force
);
7062 WARN("unhandled msi action %s\n", debugstr_w(action
));
7063 rc
= ERROR_FUNCTION_NOT_CALLED
;
7069 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
, UINT script
)
7071 UINT rc
= ERROR_SUCCESS
;
7072 BOOL handled
= FALSE
;
7074 TRACE("Performing action (%s)\n", debugstr_w(action
));
7076 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
7079 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, script
, FALSE
);
7081 if( !handled
&& ACTION_DialogBox(package
, action
) == ERROR_SUCCESS
)
7086 WARN("unhandled msi action %s\n", debugstr_w(action
));
7087 rc
= ERROR_FUNCTION_NOT_CALLED
;
7093 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
7095 UINT rc
= ERROR_SUCCESS
;
7098 static const WCHAR ExecSeqQuery
[] =
7099 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7100 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7101 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7102 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7103 static const WCHAR UISeqQuery
[] =
7104 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7105 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7106 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7107 ' ', '=',' ','%','i',0};
7109 if (needs_ui_sequence(package
))
7110 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
7112 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
7116 LPCWSTR action
, cond
;
7118 TRACE("Running the actions\n");
7120 /* check conditions */
7121 cond
= MSI_RecordGetString(row
, 2);
7123 /* this is a hack to skip errors in the condition code */
7124 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
7126 msiobj_release(&row
->hdr
);
7127 return ERROR_SUCCESS
;
7130 action
= MSI_RecordGetString(row
, 1);
7133 ERR("failed to fetch action\n");
7134 msiobj_release(&row
->hdr
);
7135 return ERROR_FUNCTION_FAILED
;
7138 if (needs_ui_sequence(package
))
7139 rc
= ACTION_PerformUIAction(package
, action
, -1);
7141 rc
= ACTION_PerformAction(package
, action
, -1, FALSE
);
7143 msiobj_release(&row
->hdr
);
7149 /****************************************************
7150 * TOP level entry points
7151 *****************************************************/
7153 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
7154 LPCWSTR szCommandLine
)
7159 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
7160 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
7162 MSI_SetPropertyW(package
, szAction
, szInstall
);
7164 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
7171 dir
= strdupW(szPackagePath
);
7172 p
= strrchrW(dir
, '\\');
7176 file
= szPackagePath
+ (p
- dir
);
7181 dir
= msi_alloc(MAX_PATH
* sizeof(WCHAR
));
7182 GetCurrentDirectoryW(MAX_PATH
, dir
);
7183 lstrcatW(dir
, szBackSlash
);
7184 file
= szPackagePath
;
7187 msi_free( package
->PackagePath
);
7188 package
->PackagePath
= msi_alloc((lstrlenW(dir
) + lstrlenW(file
) + 1) * sizeof(WCHAR
));
7189 if (!package
->PackagePath
)
7192 return ERROR_OUTOFMEMORY
;
7195 lstrcpyW(package
->PackagePath
, dir
);
7196 lstrcatW(package
->PackagePath
, file
);
7199 msi_set_sourcedir_props(package
, FALSE
);
7202 msi_parse_command_line( package
, szCommandLine
, FALSE
);
7204 msi_apply_transforms( package
);
7205 msi_apply_patches( package
);
7207 if (!szCommandLine
&& msi_get_property_int( package
, szInstalled
, 0 ))
7209 TRACE("setting reinstall property\n");
7210 MSI_SetPropertyW( package
, szReinstall
, szAll
);
7213 /* properties may have been added by a transform */
7214 msi_clone_properties( package
);
7215 msi_set_context( package
);
7217 if (needs_ui_sequence( package
))
7219 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
7220 rc
= ACTION_ProcessUISequence(package
);
7221 ui_exists
= ui_sequence_exists(package
);
7222 if (rc
== ERROR_SUCCESS
|| !ui_exists
)
7224 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
7225 rc
= ACTION_ProcessExecSequence(package
, ui_exists
);
7229 rc
= ACTION_ProcessExecSequence(package
, FALSE
);
7231 package
->script
->CurrentlyScripting
= FALSE
;
7233 /* process the ending type action */
7234 if (rc
== ERROR_SUCCESS
)
7235 ACTION_PerformActionSequence(package
, -1);
7236 else if (rc
== ERROR_INSTALL_USEREXIT
)
7237 ACTION_PerformActionSequence(package
, -2);
7238 else if (rc
== ERROR_INSTALL_SUSPEND
)
7239 ACTION_PerformActionSequence(package
, -4);
7241 ACTION_PerformActionSequence(package
, -3);
7243 /* finish up running custom actions */
7244 ACTION_FinishCustomActions(package
);
7246 if (rc
== ERROR_SUCCESS
&& package
->need_reboot
)
7247 return ERROR_SUCCESS_REBOOT_REQUIRED
;