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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
37 #include "wine/debug.h"
42 #include "wine/unicode.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
54 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
55 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
56 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
);
59 * consts and values used
61 static const WCHAR c_colon
[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders
[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize
[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles
[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles
[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues
[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize
[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost
[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize
[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate
[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions
[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents
[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries
[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo
[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo
[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts
[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct
[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues
[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules
[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures
[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct
[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute
[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain
[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize
[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot
[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource
[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 const WCHAR szAppSearch
[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace
[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage
[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch
[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices
[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback
[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction
[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts
[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage
[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile
[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 static const WCHAR szIsolateComponents
[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates
[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles
[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies
[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies
[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC
[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices
[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles
[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents
[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus
[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo
[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 static const WCHAR szRegisterFonts
[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo
[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser
[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles
[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings
[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts
[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles
[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders
[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues
[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC
[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues
[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts
[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch
[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot
[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules
[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders
[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices
[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices
[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents
[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures
[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo
[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 static const WCHAR szUnregisterComPlus
[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo
[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts
[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo
[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo
[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 static const WCHAR szUnregisterTypeLibraries
[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID
[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings
[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
240 STANDARDACTIONHANDLER handler
;
243 static struct _actions StandardActions
[];
246 /********************************************************
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
252 static const WCHAR Query_t
[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
259 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
262 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
263 msiobj_release(&row
->hdr
);
266 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
270 static const WCHAR template_s
[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 static const WCHAR template_e
[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 static const WCHAR format
[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
282 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
284 sprintfW(message
,template_s
,timet
,action
);
286 sprintfW(message
,template_e
,timet
,action
,rc
);
288 row
= MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row
,1,message
);
291 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
292 msiobj_release(&row
->hdr
);
295 static int msi_get_property_int( MSIPACKAGE
*package
, LPCWSTR prop
, int def
)
297 LPWSTR str
= msi_dup_property( package
, prop
);
298 int val
= str
? atoiW( str
) : def
;
303 static UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
)
308 LPWSTR prop
= NULL
, val
= NULL
;
311 return ERROR_SUCCESS
;
323 TRACE("Looking at %s\n",debugstr_w(ptr
));
325 ptr2
= strchrW(ptr
,'=');
328 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
335 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
336 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
342 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
355 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
356 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
359 if (lstrlenW(prop
) > 0)
361 TRACE("Found commandline property (%s) = (%s)\n",
362 debugstr_w(prop
), debugstr_w(val
));
363 MSI_SetPropertyW(package
,prop
,val
);
369 return ERROR_SUCCESS
;
373 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
375 LPWSTR p
, *ret
= NULL
;
381 /* count the number of substrings */
382 for ( p
= (LPWSTR
)str
, count
= 0; p
; count
++ )
384 p
= strchrW( p
, sep
);
389 /* allocate space for an array of substring pointers and the substrings */
390 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
391 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
395 /* copy the string and set the pointers */
396 p
= (LPWSTR
) &ret
[count
+1];
398 for( count
= 0; (ret
[count
] = p
); count
++ )
400 p
= strchrW( p
, sep
);
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_table_apply_transform( package
->db
, stg
);
427 IStorage_Release( stg
);
431 ERR("failed to open substorage %s\n", debugstr_w(name
));
436 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
438 static const WCHAR szProdID
[] = { 'P','r','o','d','u','c','t','I','D',0 };
439 LPWSTR guid_list
, *guids
, product_id
;
440 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
442 product_id
= msi_dup_property( package
, szProdID
);
445 /* FIXME: the property ProductID should be written into the DB somewhere */
446 ERR("no product ID to check\n");
447 return ERROR_SUCCESS
;
450 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
451 guids
= msi_split_string( guid_list
, ';' );
452 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
454 if (!lstrcmpW( guids
[i
], product_id
))
458 msi_free( guid_list
);
459 msi_free( product_id
);
464 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
467 LPWSTR str
, *substorage
;
468 UINT i
, r
= ERROR_SUCCESS
;
470 si
= MSI_GetSummaryInformationW( patch_db
, 0 );
472 return ERROR_FUNCTION_FAILED
;
474 msi_check_patch_applicable( package
, si
);
476 /* enumerate the substorage */
477 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
478 substorage
= msi_split_string( str
, ';' );
479 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
480 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
481 msi_free( substorage
);
484 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
486 msiobj_release( &si
->hdr
);
491 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
493 MSIDATABASE
*patch_db
= NULL
;
496 TRACE("%p %s\n", package
, debugstr_w( file
) );
499 * We probably want to make sure we only open a patch collection here.
500 * Patch collections (.msp) and databases (.msi) have different GUIDs
501 * but currently MSI_OpenDatabaseW will accept both.
503 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
504 if ( r
!= ERROR_SUCCESS
)
506 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
510 msi_parse_patch_summary( package
, patch_db
);
511 msiobj_release( &patch_db
->hdr
);
513 return ERROR_SUCCESS
;
516 /* get the PATCH property, and apply all the patches it specifies */
517 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
519 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
520 LPWSTR patch_list
, *patches
;
521 UINT i
, r
= ERROR_SUCCESS
;
523 patch_list
= msi_dup_property( package
, szPatch
);
525 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
527 patches
= msi_split_string( patch_list
, ';' );
528 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
529 r
= msi_apply_patch_package( package
, patches
[i
] );
532 msi_free( patch_list
);
537 static UINT
msi_apply_transforms( MSIPACKAGE
*package
)
539 static const WCHAR szTransforms
[] = {
540 'T','R','A','N','S','F','O','R','M','S',0 };
541 LPWSTR xform_list
, *xforms
;
542 UINT i
, r
= ERROR_SUCCESS
;
544 xform_list
= msi_dup_property( package
, szTransforms
);
545 xforms
= msi_split_string( xform_list
, ';' );
547 for( i
=0; xforms
&& xforms
[i
] && r
== ERROR_SUCCESS
; i
++ )
549 if (xforms
[i
][0] == ':')
550 r
= msi_apply_substorage_transform( package
, package
->db
, &xforms
[i
][1] );
552 r
= MSI_DatabaseApplyTransformW( package
->db
, xforms
[i
], 0 );
556 msi_free( xform_list
);
561 /****************************************************
562 * TOP level entry points
563 *****************************************************/
565 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
566 LPCWSTR szCommandLine
)
570 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
571 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
572 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
574 MSI_SetPropertyW(package
, szAction
, szInstall
);
576 package
->script
= msi_alloc(sizeof(MSISCRIPT
));
577 memset(package
->script
,0,sizeof(MSISCRIPT
));
579 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
583 LPWSTR p
, check
, path
;
585 package
->PackagePath
= strdupW(szPackagePath
);
586 path
= strdupW(szPackagePath
);
587 p
= strrchrW(path
,'\\');
596 path
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
597 GetCurrentDirectoryW(MAX_PATH
,path
);
601 check
= msi_dup_property( package
, cszSourceDir
);
603 MSI_SetPropertyW(package
, cszSourceDir
, path
);
608 msi_parse_command_line( package
, szCommandLine
);
610 msi_apply_transforms( package
);
611 msi_apply_patches( package
);
613 if ( msi_get_property_int(package
, szUILevel
, 0) >= INSTALLUILEVEL_REDUCED
)
615 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
616 rc
= ACTION_ProcessUISequence(package
);
618 if (rc
== ERROR_SUCCESS
)
620 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
621 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
625 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
629 /* install was halted but should be considered a success */
633 package
->script
->CurrentlyScripting
= FALSE
;
635 /* process the ending type action */
636 if (rc
== ERROR_SUCCESS
)
637 ACTION_PerformActionSequence(package
,-1,ui
);
638 else if (rc
== ERROR_INSTALL_USEREXIT
)
639 ACTION_PerformActionSequence(package
,-2,ui
);
640 else if (rc
== ERROR_INSTALL_SUSPEND
)
641 ACTION_PerformActionSequence(package
,-4,ui
);
643 ACTION_PerformActionSequence(package
,-3,ui
);
645 /* finish up running custom actions */
646 ACTION_FinishCustomActions(package
);
651 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
653 UINT rc
= ERROR_SUCCESS
;
655 static const WCHAR ExecSeqQuery
[] =
656 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
657 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
658 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
659 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
661 static const WCHAR UISeqQuery
[] =
662 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
663 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
664 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
665 ' ', '=',' ','%','i',0};
668 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
670 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
674 LPCWSTR action
, cond
;
676 TRACE("Running the actions\n");
678 /* check conditions */
679 cond
= MSI_RecordGetString(row
,2);
682 /* this is a hack to skip errors in the condition code */
683 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
687 action
= MSI_RecordGetString(row
,1);
690 ERR("failed to fetch action\n");
691 rc
= ERROR_FUNCTION_FAILED
;
696 rc
= ACTION_PerformUIAction(package
,action
);
698 rc
= ACTION_PerformAction(package
,action
,FALSE
);
700 msiobj_release(&row
->hdr
);
711 } iterate_action_param
;
713 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
715 iterate_action_param
*iap
= (iterate_action_param
*)param
;
717 LPCWSTR cond
, action
;
719 action
= MSI_RecordGetString(row
,1);
722 ERR("Error is retrieving action name\n");
723 return ERROR_FUNCTION_FAILED
;
726 /* check conditions */
727 cond
= MSI_RecordGetString(row
,2);
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
733 TRACE("Skipping action: %s (condition is false)\n",
735 return ERROR_SUCCESS
;
740 rc
= ACTION_PerformUIAction(iap
->package
,action
);
742 rc
= ACTION_PerformAction(iap
->package
,action
,FALSE
);
744 msi_dialog_check_messages( NULL
);
746 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
747 rc
= iap
->package
->CurrentInstallState
;
749 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
752 if (rc
!= ERROR_SUCCESS
)
753 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
758 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
762 static const WCHAR query
[] =
763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
765 ' ','W','H','E','R','E',' ',
766 '`','S','e','q','u','e','n','c','e','`',' ',
767 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
768 '`','S','e','q','u','e','n','c','e','`',0};
769 iterate_action_param iap
;
772 * FIXME: probably should be checking UILevel in the
773 * ACTION_PerformUIAction/ACTION_PerformAction
774 * rather than saving the UI level here. Those
775 * two functions can be merged too.
777 iap
.package
= package
;
780 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
782 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
783 if (r
== ERROR_SUCCESS
)
785 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
786 msiobj_release(&view
->hdr
);
792 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
796 static const WCHAR ExecSeqQuery
[] =
797 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
798 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
799 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
800 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
801 'O','R','D','E','R',' ', 'B','Y',' ',
802 '`','S','e','q','u','e','n','c','e','`',0 };
804 static const WCHAR IVQuery
[] =
805 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
806 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
807 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
808 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
809 ' ','\'', 'I','n','s','t','a','l','l',
810 'V','a','l','i','d','a','t','e','\'', 0};
812 iterate_action_param iap
;
814 iap
.package
= package
;
817 if (package
->script
->ExecuteSequenceRun
)
819 TRACE("Execute Sequence already Run\n");
820 return ERROR_SUCCESS
;
823 package
->script
->ExecuteSequenceRun
= TRUE
;
825 /* get the sequence number */
828 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
830 return ERROR_FUNCTION_FAILED
;
831 seq
= MSI_RecordGetInteger(row
,1);
832 msiobj_release(&row
->hdr
);
835 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
836 if (rc
== ERROR_SUCCESS
)
838 TRACE("Running the actions\n");
840 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
841 msiobj_release(&view
->hdr
);
847 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
851 static const WCHAR ExecSeqQuery
[] =
852 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
853 '`','I','n','s','t','a','l','l',
854 'U','I','S','e','q','u','e','n','c','e','`',
855 ' ','W','H','E','R','E',' ',
856 '`','S','e','q','u','e','n','c','e','`',' ',
857 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
858 '`','S','e','q','u','e','n','c','e','`',0};
859 iterate_action_param iap
;
861 iap
.package
= package
;
864 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
866 if (rc
== ERROR_SUCCESS
)
868 TRACE("Running the actions\n");
870 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
871 msiobj_release(&view
->hdr
);
877 /********************************************************
878 * ACTION helper functions and functions that perform the actions
879 *******************************************************/
880 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
881 UINT
* rc
, BOOL force
)
889 ERR("package was null!\n");
893 if (!run
&& !package
->script
->CurrentlyScripting
)
898 if (strcmpW(action
,szInstallFinalize
) == 0 ||
899 strcmpW(action
,szInstallExecute
) == 0 ||
900 strcmpW(action
,szInstallExecuteAgain
) == 0)
905 while (StandardActions
[i
].action
!= NULL
)
907 if (strcmpW(StandardActions
[i
].action
, action
)==0)
911 ui_actioninfo(package
, action
, TRUE
, 0);
912 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
913 ui_actioninfo(package
, action
, FALSE
, *rc
);
917 ui_actionstart(package
, action
);
918 if (StandardActions
[i
].handler
)
920 *rc
= StandardActions
[i
].handler(package
);
924 FIXME("unhandled standard action %s\n",debugstr_w(action
));
936 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
937 UINT
* rc
, BOOL force
)
942 arc
= ACTION_CustomAction(package
,action
, force
);
944 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
953 * A lot of actions are really important even if they don't do anything
954 * explicit... Lots of properties are set at the beginning of the installation
955 * CostFinalize does a bunch of work to translate the directories and such
957 * But until I get write access to the database that is hard, so I am going to
958 * hack it to see if I can get something to run.
960 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, BOOL force
)
962 UINT rc
= ERROR_SUCCESS
;
965 TRACE("Performing action (%s)\n",debugstr_w(action
));
967 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
970 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, force
);
974 FIXME("unhandled msi action %s\n",debugstr_w(action
));
975 rc
= ERROR_FUNCTION_NOT_CALLED
;
981 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
983 UINT rc
= ERROR_SUCCESS
;
984 BOOL handled
= FALSE
;
986 TRACE("Performing action (%s)\n",debugstr_w(action
));
988 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
991 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, FALSE
);
993 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
998 FIXME("unhandled msi action %s\n",debugstr_w(action
));
999 rc
= ERROR_FUNCTION_NOT_CALLED
;
1007 * Actual Action Handlers
1010 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1012 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1018 dir
= MSI_RecordGetString(row
,1);
1021 ERR("Unable to get folder id\n");
1022 return ERROR_SUCCESS
;
1025 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1028 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1029 return ERROR_SUCCESS
;
1032 TRACE("Folder is %s\n",debugstr_w(full_path
));
1035 uirow
= MSI_CreateRecord(1);
1036 MSI_RecordSetStringW(uirow
,1,full_path
);
1037 ui_actiondata(package
,szCreateFolders
,uirow
);
1038 msiobj_release( &uirow
->hdr
);
1040 if (folder
->State
== 0)
1041 create_full_pathW(full_path
);
1045 msi_free(full_path
);
1046 return ERROR_SUCCESS
;
1049 /* FIXME: probably should merge this with the above function */
1050 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1052 UINT rc
= ERROR_SUCCESS
;
1054 LPWSTR install_path
;
1056 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, &folder
);
1058 return ERROR_FUNCTION_FAILED
;
1060 /* create the path */
1061 if (folder
->State
== 0)
1063 create_full_pathW(install_path
);
1066 msi_free(install_path
);
1071 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1075 /* create all the folders required by the components are going to install */
1076 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1078 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1080 msi_create_directory( package
, comp
->Directory
);
1083 return ERROR_SUCCESS
;
1087 * Also we cannot enable/disable components either, so for now I am just going
1088 * to do all the directories for all the components.
1090 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1092 static const WCHAR ExecSeqQuery
[] =
1093 {'S','E','L','E','C','T',' ',
1094 '`','D','i','r','e','c','t','o','r','y','_','`',
1095 ' ','F','R','O','M',' ',
1096 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1100 /* create all the empty folders specified in the CreateFolder table */
1101 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1102 if (rc
!= ERROR_SUCCESS
)
1103 return ERROR_SUCCESS
;
1105 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1106 msiobj_release(&view
->hdr
);
1108 msi_create_component_directories( package
);
1113 static MSICOMPONENT
* load_component( MSIRECORD
* row
)
1117 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1121 /* fill in the data */
1122 comp
->Component
= msi_dup_record_field( row
, 1 );
1124 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1126 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1127 comp
->Directory
= msi_dup_record_field( row
, 3 );
1128 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1129 comp
->Condition
= msi_dup_record_field( row
, 5 );
1130 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1132 comp
->Installed
= INSTALLSTATE_ABSENT
;
1133 comp
->Action
= INSTALLSTATE_UNKNOWN
;
1134 comp
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1136 comp
->Enabled
= TRUE
;
1142 MSIPACKAGE
*package
;
1143 MSIFEATURE
*feature
;
1146 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1150 cl
= msi_alloc( sizeof (*cl
) );
1152 return ERROR_NOT_ENOUGH_MEMORY
;
1153 cl
->component
= comp
;
1154 list_add_tail( &feature
->Components
, &cl
->entry
);
1156 return ERROR_SUCCESS
;
1159 static UINT
iterate_component_check( MSIRECORD
*row
, LPVOID param
)
1161 _ilfs
* ilfs
= (_ilfs
*)param
;
1162 MSIPACKAGE
*package
= ilfs
->package
;
1163 MSIFEATURE
*feature
= ilfs
->feature
;
1166 comp
= load_component( row
);
1168 return ERROR_FUNCTION_FAILED
;
1170 list_add_tail( &package
->components
, &comp
->entry
);
1171 add_feature_component( feature
, comp
);
1173 TRACE("Loaded new component %p\n", comp
);
1175 return ERROR_SUCCESS
;
1178 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1180 _ilfs
* ilfs
= (_ilfs
*)param
;
1185 static const WCHAR Query
[] =
1186 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1187 '`','C','o','m','p','o','n','e','n','t','`',' ',
1188 'W','H','E','R','E',' ',
1189 '`','C','o','m','p','o','n','e','n','t','`',' ',
1190 '=','\'','%','s','\'',0};
1192 component
= MSI_RecordGetString(row
,1);
1194 /* check to see if the component is already loaded */
1195 comp
= get_loaded_component( ilfs
->package
, component
);
1198 TRACE("Component %s already loaded\n", debugstr_w(component
) );
1199 add_feature_component( ilfs
->feature
, comp
);
1200 return ERROR_SUCCESS
;
1203 rc
= MSI_OpenQuery(ilfs
->package
->db
, &view
, Query
, component
);
1204 if (rc
!= ERROR_SUCCESS
)
1205 return ERROR_SUCCESS
;
1207 rc
= MSI_IterateRecords(view
, NULL
, iterate_component_check
, ilfs
);
1208 msiobj_release( &view
->hdr
);
1210 return ERROR_SUCCESS
;
1213 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1215 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1216 MSIFEATURE
* feature
;
1217 static const WCHAR Query1
[] =
1218 {'S','E','L','E','C','T',' ',
1219 '`','C','o','m','p','o','n','e','n','t','_','`',
1220 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1221 'C','o','m','p','o','n','e','n','t','s','`',' ',
1222 'W','H','E','R','E',' ',
1223 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1228 /* fill in the data */
1230 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1232 return ERROR_NOT_ENOUGH_MEMORY
;
1234 list_init( &feature
->Components
);
1236 feature
->Feature
= msi_dup_record_field( row
, 1 );
1238 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1240 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1241 feature
->Title
= msi_dup_record_field( row
, 3 );
1242 feature
->Description
= msi_dup_record_field( row
, 4 );
1244 if (!MSI_RecordIsNull(row
,5))
1245 feature
->Display
= MSI_RecordGetInteger(row
,5);
1247 feature
->Level
= MSI_RecordGetInteger(row
,6);
1248 feature
->Directory
= msi_dup_record_field( row
, 7 );
1249 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1251 feature
->Installed
= INSTALLSTATE_ABSENT
;
1252 feature
->Action
= INSTALLSTATE_UNKNOWN
;
1253 feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1255 list_add_tail( &package
->features
, &feature
->entry
);
1257 /* load feature components */
1259 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1260 if (rc
!= ERROR_SUCCESS
)
1261 return ERROR_SUCCESS
;
1263 ilfs
.package
= package
;
1264 ilfs
.feature
= feature
;
1266 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1267 msiobj_release(&view
->hdr
);
1269 return ERROR_SUCCESS
;
1272 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1274 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1278 /* fill in the data */
1280 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1282 return ERROR_NOT_ENOUGH_MEMORY
;
1284 file
->File
= msi_dup_record_field( row
, 1 );
1286 component
= MSI_RecordGetString( row
, 2 );
1287 file
->Component
= get_loaded_component( package
, component
);
1289 if (!file
->Component
)
1290 ERR("Unfound Component %s\n",debugstr_w(component
));
1292 file
->FileName
= msi_dup_record_field( row
, 3 );
1293 reduce_to_longfilename( file
->FileName
);
1295 file
->ShortName
= msi_dup_record_field( row
, 3 );
1296 reduce_to_shortfilename( file
->ShortName
);
1298 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1299 file
->Version
= msi_dup_record_field( row
, 5 );
1300 file
->Language
= msi_dup_record_field( row
, 6 );
1301 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1302 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1304 file
->state
= msifs_invalid
;
1306 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1308 list_add_tail( &package
->files
, &file
->entry
);
1310 return ERROR_SUCCESS
;
1313 static UINT
load_all_files(MSIPACKAGE
*package
)
1317 static const WCHAR Query
[] =
1318 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1319 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1320 '`','S','e','q','u','e','n','c','e','`', 0};
1323 return ERROR_INVALID_HANDLE
;
1325 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1326 if (rc
!= ERROR_SUCCESS
)
1327 return ERROR_SUCCESS
;
1329 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1330 msiobj_release(&view
->hdr
);
1332 return ERROR_SUCCESS
;
1337 * I am not doing any of the costing functionality yet.
1338 * Mostly looking at doing the Component and Feature loading
1340 * The native MSI does A LOT of modification to tables here. Mostly adding
1341 * a lot of temporary columns to the Feature and Component tables.
1343 * note: Native msi also tracks the short filename. But I am only going to
1344 * track the long ones. Also looking at this directory table
1345 * it appears that the directory table does not get the parents
1346 * resolved base on property only based on their entries in the
1349 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1353 static const WCHAR Query_all
[] =
1354 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1355 '`','F','e','a','t','u','r','e','`',0};
1356 static const WCHAR szCosting
[] =
1357 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1358 static const WCHAR szZero
[] = { '0', 0 };
1360 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1361 return ERROR_SUCCESS
;
1363 MSI_SetPropertyW(package
, szCosting
, szZero
);
1364 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1366 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1367 if (rc
!= ERROR_SUCCESS
)
1370 rc
= MSI_IterateRecords(view
, NULL
, load_feature
, package
);
1371 msiobj_release(&view
->hdr
);
1373 load_all_files(package
);
1375 return ERROR_SUCCESS
;
1378 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1381 UINT rc
= ERROR_SUCCESS
;
1383 TRACE("Executing Script %i\n",script
);
1385 if (!package
->script
)
1387 ERR("no script!\n");
1388 return ERROR_FUNCTION_FAILED
;
1391 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1394 action
= package
->script
->Actions
[script
][i
];
1395 ui_actionstart(package
, action
);
1396 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1397 rc
= ACTION_PerformAction(package
, action
, TRUE
);
1398 msi_free(package
->script
->Actions
[script
][i
]);
1399 if (rc
!= ERROR_SUCCESS
)
1402 msi_free(package
->script
->Actions
[script
]);
1404 package
->script
->ActionCount
[script
] = 0;
1405 package
->script
->Actions
[script
] = NULL
;
1409 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1411 return ERROR_SUCCESS
;
1415 static MSIFOLDER
*load_folder( MSIPACKAGE
*package
, LPCWSTR dir
)
1417 static const WCHAR Query
[] =
1418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1419 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1420 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1421 ' ','=',' ','\'','%','s','\'',
1423 LPWSTR ptargetdir
, targetdir
, srcdir
;
1425 LPWSTR shortname
= NULL
;
1426 MSIRECORD
* row
= 0;
1429 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1431 folder
= get_loaded_folder( package
, dir
);
1435 TRACE("Working to load %s\n",debugstr_w(dir
));
1437 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1441 folder
->Directory
= strdupW(dir
);
1443 row
= MSI_QueryGetRecord(package
->db
, Query
, dir
);
1447 ptargetdir
= targetdir
= msi_dup_record_field(row
,3);
1449 /* split src and target dir */
1450 if (strchrW(targetdir
,':'))
1452 srcdir
=strchrW(targetdir
,':');
1459 /* for now only pick long filename versions */
1460 if (strchrW(targetdir
,'|'))
1462 shortname
= targetdir
;
1463 targetdir
= strchrW(targetdir
,'|');
1467 /* for the sourcedir pick the short filename */
1468 if (srcdir
&& strchrW(srcdir
,'|'))
1470 LPWSTR p
= strchrW(srcdir
,'|');
1474 /* now check for root dirs */
1475 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1480 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1481 msi_free( folder
->TargetDefault
);
1482 folder
->TargetDefault
= strdupW(targetdir
);
1486 folder
->SourceDefault
= strdupW(srcdir
);
1488 folder
->SourceDefault
= strdupW(shortname
);
1490 folder
->SourceDefault
= strdupW(targetdir
);
1491 msi_free(ptargetdir
);
1492 TRACE(" SourceDefault = %s\n", debugstr_w( folder
->SourceDefault
));
1494 parent
= MSI_RecordGetString(row
,2);
1497 folder
->Parent
= load_folder( package
, parent
);
1498 if ( folder
->Parent
)
1499 TRACE("loaded parent %p %s\n", folder
->Parent
,
1500 debugstr_w(folder
->Parent
->Directory
));
1502 ERR("failed to load parent folder %s\n", debugstr_w(parent
));
1505 folder
->Property
= msi_dup_property( package
, dir
);
1507 msiobj_release(&row
->hdr
);
1509 list_add_tail( &package
->folders
, &folder
->entry
);
1511 TRACE("%s returning %p\n",debugstr_w(dir
),folder
);
1516 /* scan for and update current install states */
1517 static void ACTION_UpdateInstallStates(MSIPACKAGE
*package
)
1520 MSIFEATURE
*feature
;
1522 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1525 res
= MsiGetComponentPathW( package
->ProductCode
,
1526 comp
->ComponentId
, NULL
, NULL
);
1528 res
= INSTALLSTATE_ABSENT
;
1529 comp
->Installed
= res
;
1532 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1535 INSTALLSTATE res
= -10;
1537 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1539 comp
= cl
->component
;
1542 res
= comp
->Installed
;
1545 if (res
== comp
->Installed
)
1548 if (res
!= comp
->Installed
)
1549 res
= INSTALLSTATE_INCOMPLETE
;
1552 feature
->Installed
= res
;
1556 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1559 static const WCHAR all
[]={'A','L','L',0};
1561 MSIFEATURE
*feature
;
1563 override
= msi_dup_property( package
, property
);
1567 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1569 if (strcmpiW(override
,all
)==0)
1571 feature
->ActionRequest
= state
;
1572 feature
->Action
= state
;
1576 LPWSTR ptr
= override
;
1577 LPWSTR ptr2
= strchrW(override
,',');
1581 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1582 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1584 feature
->ActionRequest
= state
;
1585 feature
->Action
= state
;
1591 ptr2
= strchrW(ptr
,',');
1603 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
1606 static const WCHAR szlevel
[] =
1607 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1608 static const WCHAR szAddLocal
[] =
1609 {'A','D','D','L','O','C','A','L',0};
1610 static const WCHAR szRemove
[] =
1611 {'R','E','M','O','V','E',0};
1612 static const WCHAR szReinstall
[] =
1613 {'R','E','I','N','S','T','A','L','L',0};
1614 BOOL override
= FALSE
;
1615 MSICOMPONENT
* component
;
1616 MSIFEATURE
*feature
;
1619 /* I do not know if this is where it should happen.. but */
1621 TRACE("Checking Install Level\n");
1623 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1625 /* ok hereis the _real_ rub
1626 * all these activation/deactivation things happen in order and things
1627 * later on the list override things earlier on the list.
1628 * 1) INSTALLLEVEL processing
1638 * 11) FILEADDDEFAULT
1639 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1640 * ignored for all the features. seems strange, especially since it is not
1641 * documented anywhere, but it is how it works.
1643 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1644 * REMOVE are the big ones, since we don't handle administrative installs
1647 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1648 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1649 override
|= process_state_property(package
,szReinstall
,INSTALLSTATE_LOCAL
);
1653 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1655 BOOL feature_state
= ((feature
->Level
> 0) &&
1656 (feature
->Level
<= install_level
));
1658 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1660 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1662 feature
->ActionRequest
= INSTALLSTATE_SOURCE
;
1663 feature
->Action
= INSTALLSTATE_SOURCE
;
1665 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1667 feature
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1668 feature
->Action
= INSTALLSTATE_ADVERTISED
;
1672 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
1673 feature
->Action
= INSTALLSTATE_LOCAL
;
1680 /* set the Preselected Property */
1681 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1682 static const WCHAR szOne
[] = { '1', 0 };
1684 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1688 * now we want to enable or disable components base on feature
1691 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1695 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1696 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
1697 feature
->ActionRequest
);
1699 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1701 component
= cl
->component
;
1703 if (!component
->Enabled
)
1705 component
->Action
= INSTALLSTATE_UNKNOWN
;
1706 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1710 if (feature
->Action
== INSTALLSTATE_LOCAL
)
1712 component
->Action
= INSTALLSTATE_LOCAL
;
1713 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
1715 else if (feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
1717 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1718 (component
->Action
== INSTALLSTATE_ABSENT
) ||
1719 (component
->Action
== INSTALLSTATE_ADVERTISED
))
1722 component
->Action
= INSTALLSTATE_SOURCE
;
1723 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
1726 else if (feature
->ActionRequest
== INSTALLSTATE_ADVERTISED
)
1728 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1729 (component
->Action
== INSTALLSTATE_ABSENT
))
1732 component
->Action
= INSTALLSTATE_ADVERTISED
;
1733 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1736 else if (feature
->ActionRequest
== INSTALLSTATE_ABSENT
)
1738 if (component
->Action
== INSTALLSTATE_UNKNOWN
)
1740 component
->Action
= INSTALLSTATE_ABSENT
;
1741 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
1748 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1750 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1751 debugstr_w(component
->Component
), component
->Installed
,
1752 component
->Action
, component
->ActionRequest
);
1756 return ERROR_SUCCESS
;
1759 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1761 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1765 name
= MSI_RecordGetString(row
,1);
1767 /* This helper function now does ALL the work */
1768 TRACE("Dir %s ...\n",debugstr_w(name
));
1769 load_folder(package
,name
);
1770 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
1771 TRACE("resolves to %s\n",debugstr_w(path
));
1774 return ERROR_SUCCESS
;
1777 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1779 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1781 MSIFEATURE
*feature
;
1783 name
= MSI_RecordGetString( row
, 1 );
1785 feature
= get_loaded_feature( package
, name
);
1787 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1791 Condition
= MSI_RecordGetString(row
,3);
1793 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1795 int level
= MSI_RecordGetInteger(row
,2);
1796 TRACE("Reseting feature %s to level %i\n", debugstr_w(name
), level
);
1797 feature
->Level
= level
;
1800 return ERROR_SUCCESS
;
1805 * A lot is done in this function aside from just the costing.
1806 * The costing needs to be implemented at some point but for now I am going
1807 * to focus on the directory building
1810 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1812 static const WCHAR ExecSeqQuery
[] =
1813 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1814 '`','D','i','r','e','c','t','o','r','y','`',0};
1815 static const WCHAR ConditionQuery
[] =
1816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1817 '`','C','o','n','d','i','t','i','o','n','`',0};
1818 static const WCHAR szCosting
[] =
1819 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1820 static const WCHAR szlevel
[] =
1821 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1822 static const WCHAR szOne
[] = { '1', 0 };
1829 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1830 return ERROR_SUCCESS
;
1832 TRACE("Building Directory properties\n");
1834 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1835 if (rc
== ERROR_SUCCESS
)
1837 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
1839 msiobj_release(&view
->hdr
);
1842 TRACE("File calculations\n");
1844 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1846 MSICOMPONENT
* comp
= file
->Component
;
1852 /* calculate target */
1853 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
1855 msi_free(file
->TargetPath
);
1857 TRACE("file %s is named %s\n",
1858 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
1860 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1864 TRACE("file %s resolves to %s\n",
1865 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
1867 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1869 file
->state
= msifs_missing
;
1870 comp
->Cost
+= file
->FileSize
;
1880 static WCHAR name
[] = {'\\',0};
1881 static const WCHAR name_fmt
[] =
1882 {'%','u','.','%','u','.','%','u','.','%','u',0};
1883 WCHAR filever
[0x100];
1884 VS_FIXEDFILEINFO
*lpVer
;
1886 TRACE("Version comparison..\n");
1887 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
1888 version
= msi_alloc(versize
);
1889 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
1891 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
1893 sprintfW(filever
,name_fmt
,
1894 HIWORD(lpVer
->dwFileVersionMS
),
1895 LOWORD(lpVer
->dwFileVersionMS
),
1896 HIWORD(lpVer
->dwFileVersionLS
),
1897 LOWORD(lpVer
->dwFileVersionLS
));
1899 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1900 debugstr_w(filever
));
1901 if (strcmpiW(filever
,file
->Version
)<0)
1903 file
->state
= msifs_overwrite
;
1904 /* FIXME: cost should be diff in size */
1905 comp
->Cost
+= file
->FileSize
;
1908 file
->state
= msifs_present
;
1912 file
->state
= msifs_present
;
1915 TRACE("Evaluating Condition Table\n");
1917 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
1918 if (rc
== ERROR_SUCCESS
)
1920 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
1922 msiobj_release(&view
->hdr
);
1925 TRACE("Enabling or Disabling Components\n");
1926 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1928 if (comp
->Condition
)
1930 if (MSI_EvaluateConditionW(package
,
1931 comp
->Condition
) == MSICONDITION_FALSE
)
1933 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
1934 comp
->Enabled
= FALSE
;
1939 MSI_SetPropertyW(package
,szCosting
,szOne
);
1940 /* set default run level if not set */
1941 level
= msi_dup_property( package
, szlevel
);
1943 MSI_SetPropertyW(package
,szlevel
, szOne
);
1946 ACTION_UpdateInstallStates(package
);
1948 return SetFeatureStates(package
);
1951 /* OK this value is "interpreted" and then formatted based on the
1952 first few characters */
1953 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
1957 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
1963 LPWSTR deformated
= NULL
;
1966 deformat_string(package
, &value
[2], &deformated
);
1968 /* binary value type */
1972 *size
= (strlenW(ptr
)/2)+1;
1974 *size
= strlenW(ptr
)/2;
1976 data
= msi_alloc(*size
);
1982 /* if uneven pad with a zero in front */
1988 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
1990 TRACE("Uneven byte count\n");
1998 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2001 msi_free(deformated
);
2003 TRACE("Data %li bytes(%i)\n",*size
,count
);
2010 deformat_string(package
, &value
[1], &deformated
);
2013 *size
= sizeof(DWORD
);
2014 data
= msi_alloc(*size
);
2020 if ( (*p
< '0') || (*p
> '9') )
2026 if (deformated
[0] == '-')
2029 TRACE("DWORD %li\n",*(LPDWORD
)data
);
2031 msi_free(deformated
);
2036 static const WCHAR szMulti
[] = {'[','~',']',0};
2045 *type
=REG_EXPAND_SZ
;
2053 if (strstrW(value
,szMulti
))
2054 *type
= REG_MULTI_SZ
;
2056 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2061 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2063 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2064 static const WCHAR szHCR
[] =
2065 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2066 'R','O','O','T','\\',0};
2067 static const WCHAR szHCU
[] =
2068 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2069 'U','S','E','R','\\',0};
2070 static const WCHAR szHLM
[] =
2071 {'H','K','E','Y','_','L','O','C','A','L','_',
2072 'M','A','C','H','I','N','E','\\',0};
2073 static const WCHAR szHU
[] =
2074 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2076 LPSTR value_data
= NULL
;
2077 HKEY root_key
, hkey
;
2080 LPCWSTR szRoot
, component
, name
, key
, value
;
2085 BOOL check_first
= FALSE
;
2088 ui_progress(package
,2,0,0,0);
2095 component
= MSI_RecordGetString(row
, 6);
2096 comp
= get_loaded_component(package
,component
);
2098 return ERROR_SUCCESS
;
2100 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2102 TRACE("Skipping write due to disabled component %s\n",
2103 debugstr_w(component
));
2105 comp
->Action
= comp
->Installed
;
2107 return ERROR_SUCCESS
;
2110 comp
->Action
= INSTALLSTATE_LOCAL
;
2112 name
= MSI_RecordGetString(row
, 4);
2113 if( MSI_RecordIsNull(row
,5) && name
)
2115 /* null values can have special meanings */
2116 if (name
[0]=='-' && name
[1] == 0)
2117 return ERROR_SUCCESS
;
2118 else if ((name
[0]=='+' && name
[1] == 0) ||
2119 (name
[0] == '*' && name
[1] == 0))
2124 root
= MSI_RecordGetInteger(row
,2);
2125 key
= MSI_RecordGetString(row
, 3);
2127 /* get the root key */
2132 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2133 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2134 if (all_users
&& all_users
[0] == '1')
2136 root_key
= HKEY_LOCAL_MACHINE
;
2141 root_key
= HKEY_CURRENT_USER
;
2144 msi_free(all_users
);
2147 case 0: root_key
= HKEY_CLASSES_ROOT
;
2150 case 1: root_key
= HKEY_CURRENT_USER
;
2153 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2156 case 3: root_key
= HKEY_USERS
;
2160 ERR("Unknown root %i\n",root
);
2166 return ERROR_SUCCESS
;
2168 deformat_string(package
, key
, &deformated
);
2169 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2170 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2171 strcpyW(uikey
,szRoot
);
2172 strcatW(uikey
,deformated
);
2174 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2176 ERR("Could not create key %s\n",debugstr_w(deformated
));
2177 msi_free(deformated
);
2179 return ERROR_SUCCESS
;
2181 msi_free(deformated
);
2183 value
= MSI_RecordGetString(row
,5);
2185 value_data
= parse_value(package
, value
, &type
, &size
);
2188 static const WCHAR szEmpty
[] = {0};
2189 value_data
= (LPSTR
)strdupW(szEmpty
);
2194 deformat_string(package
, name
, &deformated
);
2196 /* get the double nulls to terminate SZ_MULTI */
2197 if (type
== REG_MULTI_SZ
)
2198 size
+=sizeof(WCHAR
);
2202 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2204 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2209 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2210 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2212 TRACE("value %s of %s checked already exists\n",
2213 debugstr_w(deformated
), debugstr_w(uikey
));
2217 TRACE("Checked and setting value %s of %s\n",
2218 debugstr_w(deformated
), debugstr_w(uikey
));
2219 if (deformated
|| size
)
2220 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2225 uirow
= MSI_CreateRecord(3);
2226 MSI_RecordSetStringW(uirow
,2,deformated
);
2227 MSI_RecordSetStringW(uirow
,1,uikey
);
2230 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2232 MSI_RecordSetStringW(uirow
,3,value
);
2234 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2235 msiobj_release( &uirow
->hdr
);
2237 msi_free(value_data
);
2238 msi_free(deformated
);
2241 return ERROR_SUCCESS
;
2244 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2248 static const WCHAR ExecSeqQuery
[] =
2249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2250 '`','R','e','g','i','s','t','r','y','`',0 };
2253 return ERROR_INVALID_HANDLE
;
2255 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2256 if (rc
!= ERROR_SUCCESS
)
2257 return ERROR_SUCCESS
;
2259 /* increment progress bar each time action data is sent */
2260 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2262 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2264 msiobj_release(&view
->hdr
);
2268 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2270 package
->script
->CurrentlyScripting
= TRUE
;
2272 return ERROR_SUCCESS
;
2276 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2281 static const WCHAR q1
[]=
2282 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2283 '`','R','e','g','i','s','t','r','y','`',0};
2286 MSIFEATURE
*feature
;
2289 TRACE("InstallValidate\n");
2291 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2292 if (rc
== ERROR_SUCCESS
)
2294 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2295 msiobj_release( &view
->hdr
);
2296 total
+= progress
* REG_PROGRESS_VALUE
;
2299 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2300 total
+= COMPONENT_PROGRESS_VALUE
;
2302 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2303 total
+= file
->FileSize
;
2305 ui_progress(package
,0,total
,0,0);
2307 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2309 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2310 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2311 feature
->ActionRequest
);
2314 return ERROR_SUCCESS
;
2317 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2319 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2320 LPCWSTR cond
= NULL
;
2321 LPCWSTR message
= NULL
;
2322 static const WCHAR title
[]=
2323 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2325 cond
= MSI_RecordGetString(row
,1);
2327 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
2330 message
= MSI_RecordGetString(row
,2);
2331 deformat_string(package
,message
,&deformated
);
2332 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2333 msi_free(deformated
);
2334 return ERROR_FUNCTION_FAILED
;
2337 return ERROR_SUCCESS
;
2340 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2343 MSIQUERY
* view
= NULL
;
2344 static const WCHAR ExecSeqQuery
[] =
2345 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2346 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2348 TRACE("Checking launch conditions\n");
2350 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2351 if (rc
!= ERROR_SUCCESS
)
2352 return ERROR_SUCCESS
;
2354 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2355 msiobj_release(&view
->hdr
);
2360 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2364 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
2366 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2368 MSIRECORD
* row
= 0;
2370 LPWSTR deformated
,buffer
,deformated_name
;
2372 static const WCHAR ExecSeqQuery
[] =
2373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2374 '`','R','e','g','i','s','t','r','y','`',' ',
2375 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2376 ' ','=',' ' ,'\'','%','s','\'',0 };
2377 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2378 static const WCHAR fmt2
[]=
2379 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2381 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2385 root
= MSI_RecordGetInteger(row
,2);
2386 key
= MSI_RecordGetString(row
, 3);
2387 name
= MSI_RecordGetString(row
, 4);
2388 deformat_string(package
, key
, &deformated
);
2389 deformat_string(package
, name
, &deformated_name
);
2391 len
= strlenW(deformated
) + 6;
2392 if (deformated_name
)
2393 len
+=strlenW(deformated_name
);
2395 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2397 if (deformated_name
)
2398 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2400 sprintfW(buffer
,fmt
,root
,deformated
);
2402 msi_free(deformated
);
2403 msi_free(deformated_name
);
2404 msiobj_release(&row
->hdr
);
2408 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2410 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2415 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2418 return strdupW( file
->TargetPath
);
2423 static HKEY
openSharedDLLsKey(void)
2426 static const WCHAR path
[] =
2427 {'S','o','f','t','w','a','r','e','\\',
2428 'M','i','c','r','o','s','o','f','t','\\',
2429 'W','i','n','d','o','w','s','\\',
2430 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2431 'S','h','a','r','e','d','D','L','L','s',0};
2433 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2437 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2442 DWORD sz
= sizeof(count
);
2445 hkey
= openSharedDLLsKey();
2446 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2447 if (rc
!= ERROR_SUCCESS
)
2453 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2457 hkey
= openSharedDLLsKey();
2459 msi_reg_set_val_dword( hkey
, path
, count
);
2461 RegDeleteValueW(hkey
,path
);
2467 * Return TRUE if the count should be written out and FALSE if not
2469 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2471 MSIFEATURE
*feature
;
2475 /* only refcount DLLs */
2476 if (comp
->KeyPath
== NULL
||
2477 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2478 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2482 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2483 write
= (count
> 0);
2485 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2489 /* increment counts */
2490 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2494 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2497 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2499 if ( cl
->component
== comp
)
2504 /* decrement counts */
2505 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2509 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2512 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2514 if ( cl
->component
== comp
)
2519 /* ref count all the files in the component */
2524 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2526 if (file
->Component
== comp
)
2527 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2531 /* add a count for permenent */
2532 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2535 comp
->RefCount
= count
;
2538 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2542 * Ok further analysis makes me think that this work is
2543 * actually done in the PublishComponents and PublishFeatures
2544 * step, and not here. It appears like the keypath and all that is
2545 * resolved in this step, however actually written in the Publish steps.
2546 * But we will leave it here for now because it is unclear
2548 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2550 WCHAR squished_pc
[GUID_SIZE
];
2551 WCHAR squished_cc
[GUID_SIZE
];
2554 HKEY hkey
=0,hkey2
=0;
2556 /* writes the Component and Features values to the registry */
2558 rc
= MSIREG_OpenComponents(&hkey
);
2559 if (rc
!= ERROR_SUCCESS
)
2562 squash_guid(package
->ProductCode
,squished_pc
);
2563 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2565 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2567 ui_progress(package
,2,0,0,0);
2568 if (comp
->ComponentId
)
2572 squash_guid(comp
->ComponentId
,squished_cc
);
2574 msi_free(comp
->FullKeypath
);
2575 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2577 /* do the refcounting */
2578 ACTION_RefCountComponent( package
, comp
);
2580 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2581 debugstr_w(comp
->Component
),
2582 debugstr_w(squished_cc
),
2583 debugstr_w(comp
->FullKeypath
),
2586 * Write the keypath out if the component is to be registered
2587 * and delete the key if the component is to be deregistered
2589 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2591 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2592 if (rc
!= ERROR_SUCCESS
)
2595 if (comp
->FullKeypath
)
2597 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2599 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2601 static const WCHAR szPermKey
[] =
2602 { '0','0','0','0','0','0','0','0','0','0','0','0',
2603 '0','0','0','0','0','0','0','0','0','0','0','0',
2604 '0','0','0','0','0','0','0','0',0};
2606 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2612 uirow
= MSI_CreateRecord(3);
2613 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2614 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2615 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2616 ui_actiondata(package
,szProcessComponents
,uirow
);
2617 msiobj_release( &uirow
->hdr
);
2620 else if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2624 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2625 if (rc
!= ERROR_SUCCESS
)
2628 RegDeleteValueW(hkey2
,squished_pc
);
2630 /* if the key is empty delete it */
2631 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2633 if (res
== ERROR_NO_MORE_ITEMS
)
2634 RegDeleteKeyW(hkey
,squished_cc
);
2637 uirow
= MSI_CreateRecord(2);
2638 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2639 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2640 ui_actiondata(package
,szProcessComponents
,uirow
);
2641 msiobj_release( &uirow
->hdr
);
2658 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2659 LPWSTR lpszName
, LONG_PTR lParam
)
2662 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2663 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2667 if (!IS_INTRESOURCE(lpszName
))
2669 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2673 sz
= strlenW(tl_struct
->source
)+4;
2674 sz
*= sizeof(WCHAR
);
2676 if ((INT
)lpszName
== 1)
2677 tl_struct
->path
= strdupW(tl_struct
->source
);
2680 tl_struct
->path
= msi_alloc(sz
);
2681 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2684 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2685 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2686 if (!SUCCEEDED(res
))
2688 msi_free(tl_struct
->path
);
2689 tl_struct
->path
= NULL
;
2694 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2695 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2697 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2701 msi_free(tl_struct
->path
);
2702 tl_struct
->path
= NULL
;
2704 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2705 ITypeLib_Release(tl_struct
->ptLib
);
2710 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2712 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2716 typelib_struct tl_struct
;
2718 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2720 component
= MSI_RecordGetString(row
,3);
2721 comp
= get_loaded_component(package
,component
);
2723 return ERROR_SUCCESS
;
2725 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2727 TRACE("Skipping typelib reg due to disabled component\n");
2729 comp
->Action
= comp
->Installed
;
2731 return ERROR_SUCCESS
;
2734 comp
->Action
= INSTALLSTATE_LOCAL
;
2736 file
= get_loaded_file( package
, comp
->KeyPath
);
2738 return ERROR_SUCCESS
;
2740 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2744 guid
= MSI_RecordGetString(row
,1);
2745 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2746 tl_struct
.source
= strdupW( file
->TargetPath
);
2747 tl_struct
.path
= NULL
;
2749 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2750 (LONG_PTR
)&tl_struct
);
2758 helpid
= MSI_RecordGetString(row
,6);
2761 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
2762 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2765 if (!SUCCEEDED(res
))
2766 ERR("Failed to register type library %s\n",
2767 debugstr_w(tl_struct
.path
));
2770 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2772 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2775 ITypeLib_Release(tl_struct
.ptLib
);
2776 msi_free(tl_struct
.path
);
2779 ERR("Failed to load type library %s\n",
2780 debugstr_w(tl_struct
.source
));
2782 FreeLibrary(module
);
2783 msi_free(tl_struct
.source
);
2786 ERR("Could not load file! %s\n", debugstr_w(file
->TargetPath
));
2788 return ERROR_SUCCESS
;
2791 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2794 * OK this is a bit confusing.. I am given a _Component key and I believe
2795 * that the file that is being registered as a type library is the "key file
2796 * of that component" which I interpret to mean "The file in the KeyPath of
2801 static const WCHAR Query
[] =
2802 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2803 '`','T','y','p','e','L','i','b','`',0};
2805 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2806 if (rc
!= ERROR_SUCCESS
)
2807 return ERROR_SUCCESS
;
2809 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2810 msiobj_release(&view
->hdr
);
2814 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
2816 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2817 LPWSTR target_file
, target_folder
, filename
;
2818 LPCWSTR buffer
, extension
;
2820 static const WCHAR szlnk
[]={'.','l','n','k',0};
2825 buffer
= MSI_RecordGetString(row
,4);
2826 comp
= get_loaded_component(package
,buffer
);
2828 return ERROR_SUCCESS
;
2830 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2832 TRACE("Skipping shortcut creation due to disabled component\n");
2834 comp
->Action
= comp
->Installed
;
2836 return ERROR_SUCCESS
;
2839 comp
->Action
= INSTALLSTATE_LOCAL
;
2841 ui_actiondata(package
,szCreateShortcuts
,row
);
2843 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
2844 &IID_IShellLinkW
, (LPVOID
*) &sl
);
2848 ERR("Is IID_IShellLink\n");
2849 return ERROR_SUCCESS
;
2852 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
2855 ERR("Is IID_IPersistFile\n");
2856 return ERROR_SUCCESS
;
2859 buffer
= MSI_RecordGetString(row
,2);
2860 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
2862 /* may be needed because of a bug somehwere else */
2863 create_full_pathW(target_folder
);
2865 filename
= msi_dup_record_field( row
, 3 );
2866 reduce_to_longfilename(filename
);
2868 extension
= strchrW(filename
,'.');
2869 if (!extension
|| strcmpiW(extension
,szlnk
))
2871 int len
= strlenW(filename
);
2872 filename
= msi_realloc(filename
, len
* sizeof(WCHAR
) + sizeof(szlnk
));
2873 memcpy(filename
+ len
, szlnk
, sizeof(szlnk
));
2875 target_file
= build_directory_name(2, target_folder
, filename
);
2876 msi_free(target_folder
);
2879 buffer
= MSI_RecordGetString(row
,5);
2880 if (strchrW(buffer
,'['))
2883 deformat_string(package
,buffer
,&deformated
);
2884 IShellLinkW_SetPath(sl
,deformated
);
2885 msi_free(deformated
);
2889 FIXME("poorly handled shortcut format, advertised shortcut\n");
2890 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
2893 if (!MSI_RecordIsNull(row
,6))
2896 buffer
= MSI_RecordGetString(row
,6);
2897 deformat_string(package
,buffer
,&deformated
);
2898 IShellLinkW_SetArguments(sl
,deformated
);
2899 msi_free(deformated
);
2902 if (!MSI_RecordIsNull(row
,7))
2904 buffer
= MSI_RecordGetString(row
,7);
2905 IShellLinkW_SetDescription(sl
,buffer
);
2908 if (!MSI_RecordIsNull(row
,8))
2909 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
2911 if (!MSI_RecordIsNull(row
,9))
2916 buffer
= MSI_RecordGetString(row
,9);
2918 Path
= build_icon_path(package
,buffer
);
2919 index
= MSI_RecordGetInteger(row
,10);
2921 IShellLinkW_SetIconLocation(sl
,Path
,index
);
2925 if (!MSI_RecordIsNull(row
,11))
2926 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
2928 if (!MSI_RecordIsNull(row
,12))
2931 buffer
= MSI_RecordGetString(row
,12);
2932 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
2933 IShellLinkW_SetWorkingDirectory(sl
,Path
);
2937 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
2938 IPersistFile_Save(pf
,target_file
,FALSE
);
2940 msi_free(target_file
);
2942 IPersistFile_Release( pf
);
2943 IShellLinkW_Release( sl
);
2945 return ERROR_SUCCESS
;
2948 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
2953 static const WCHAR Query
[] =
2954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2955 '`','S','h','o','r','t','c','u','t','`',0};
2957 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2958 if (rc
!= ERROR_SUCCESS
)
2959 return ERROR_SUCCESS
;
2961 res
= CoInitialize( NULL
);
2964 ERR("CoInitialize failed\n");
2965 return ERROR_FUNCTION_FAILED
;
2968 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
2969 msiobj_release(&view
->hdr
);
2976 static UINT
ITERATE_PublishProduct(MSIRECORD
*row
, LPVOID param
)
2978 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2987 FileName
= MSI_RecordGetString(row
,1);
2990 ERR("Unable to get FileName\n");
2991 return ERROR_SUCCESS
;
2994 FilePath
= build_icon_path(package
,FileName
);
2996 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
2998 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2999 FILE_ATTRIBUTE_NORMAL
, NULL
);
3001 if (the_file
== INVALID_HANDLE_VALUE
)
3003 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3005 return ERROR_SUCCESS
;
3012 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3013 if (rc
!= ERROR_SUCCESS
)
3015 ERR("Failed to get stream\n");
3016 CloseHandle(the_file
);
3017 DeleteFileW(FilePath
);
3020 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3021 } while (sz
== 1024);
3025 CloseHandle(the_file
);
3027 uirow
= MSI_CreateRecord(1);
3028 MSI_RecordSetStringW(uirow
,1,FileName
);
3029 ui_actiondata(package
,szPublishProduct
,uirow
);
3030 msiobj_release( &uirow
->hdr
);
3032 return ERROR_SUCCESS
;
3036 * 99% of the work done here is only done for
3037 * advertised installs. However this is where the
3038 * Icon table is processed and written out
3039 * so that is what I am going to do here.
3041 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3045 static const WCHAR Query
[]=
3046 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3047 '`','I','c','o','n','`',0};
3048 /* for registry stuff */
3051 static const WCHAR szProductLanguage
[] =
3052 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3053 static const WCHAR szARPProductIcon
[] =
3054 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3055 static const WCHAR szProductVersion
[] =
3056 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3060 MSIHANDLE hDb
, hSumInfo
;
3062 /* write out icon files */
3064 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3065 if (rc
== ERROR_SUCCESS
)
3067 MSI_IterateRecords(view
, NULL
, ITERATE_PublishProduct
, package
);
3068 msiobj_release(&view
->hdr
);
3071 /* ok there is a lot more done here but i need to figure out what */
3073 rc
= MSIREG_OpenProductsKey(package
->ProductCode
,&hkey
,TRUE
);
3074 if (rc
!= ERROR_SUCCESS
)
3077 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
,&hukey
,TRUE
);
3078 if (rc
!= ERROR_SUCCESS
)
3082 buffer
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3083 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3086 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3087 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3089 buffer
= msi_dup_property( package
, szARPProductIcon
);
3092 LPWSTR path
= build_icon_path(package
,buffer
);
3093 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3098 buffer
= msi_dup_property( package
, szProductVersion
);
3101 DWORD verdword
= build_version_dword(buffer
);
3102 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3106 /* FIXME: Need to write more keys to the user registry */
3108 hDb
= alloc_msihandle( &package
->db
->hdr
);
3109 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
3110 MsiCloseHandle(hDb
);
3111 if (rc
== ERROR_SUCCESS
)
3113 WCHAR guidbuffer
[0x200];
3115 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
3117 if (rc
== ERROR_SUCCESS
)
3119 WCHAR squashed
[GUID_SIZE
];
3120 /* for now we only care about the first guid */
3121 LPWSTR ptr
= strchrW(guidbuffer
,';');
3123 squash_guid(guidbuffer
,squashed
);
3124 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGECODEW
, squashed
);
3128 ERR("Unable to query Revision_Number...\n");
3131 MsiCloseHandle(hSumInfo
);
3135 ERR("Unable to open Summary Information\n");
3147 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3149 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3150 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
3151 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3152 LPWSTR folder
, fullname
= NULL
;
3156 static const WCHAR szWindowsFolder
[] =
3157 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3159 component
= MSI_RecordGetString(row
, 8);
3160 comp
= get_loaded_component(package
,component
);
3162 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3164 TRACE("Skipping ini file due to disabled component %s\n",
3165 debugstr_w(component
));
3167 comp
->Action
= comp
->Installed
;
3169 return ERROR_SUCCESS
;
3172 comp
->Action
= INSTALLSTATE_LOCAL
;
3174 identifier
= MSI_RecordGetString(row
,1);
3175 filename
= MSI_RecordGetString(row
,2);
3176 dirproperty
= MSI_RecordGetString(row
,3);
3177 section
= MSI_RecordGetString(row
,4);
3178 key
= MSI_RecordGetString(row
,5);
3179 value
= MSI_RecordGetString(row
,6);
3180 action
= MSI_RecordGetInteger(row
,7);
3182 deformat_string(package
,section
,&deformated_section
);
3183 deformat_string(package
,key
,&deformated_key
);
3184 deformat_string(package
,value
,&deformated_value
);
3188 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
3190 folder
= msi_dup_property( package
, dirproperty
);
3193 folder
= msi_dup_property( package
, szWindowsFolder
);
3197 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3201 fullname
= build_directory_name(2, folder
, filename
);
3205 TRACE("Adding value %s to section %s in %s\n",
3206 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3207 debugstr_w(fullname
));
3208 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3209 deformated_value
, fullname
);
3211 else if (action
== 1)
3214 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3215 returned
, 10, fullname
);
3216 if (returned
[0] == 0)
3218 TRACE("Adding value %s to section %s in %s\n",
3219 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3220 debugstr_w(fullname
));
3222 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3223 deformated_value
, fullname
);
3226 else if (action
== 3)
3227 FIXME("Append to existing section not yet implemented\n");
3229 uirow
= MSI_CreateRecord(4);
3230 MSI_RecordSetStringW(uirow
,1,identifier
);
3231 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3232 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3233 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3234 ui_actiondata(package
,szWriteIniValues
,uirow
);
3235 msiobj_release( &uirow
->hdr
);
3239 msi_free(deformated_key
);
3240 msi_free(deformated_value
);
3241 msi_free(deformated_section
);
3242 return ERROR_SUCCESS
;
3245 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3249 static const WCHAR ExecSeqQuery
[] =
3250 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3251 '`','I','n','i','F','i','l','e','`',0};
3253 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3254 if (rc
!= ERROR_SUCCESS
)
3256 TRACE("no IniFile table\n");
3257 return ERROR_SUCCESS
;
3260 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3261 msiobj_release(&view
->hdr
);
3265 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3267 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3272 static const WCHAR ExeStr
[] =
3273 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3274 static const WCHAR close
[] = {'\"',0};
3276 PROCESS_INFORMATION info
;
3281 memset(&si
,0,sizeof(STARTUPINFOW
));
3283 filename
= MSI_RecordGetString(row
,1);
3284 file
= get_loaded_file( package
, filename
);
3288 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3289 return ERROR_SUCCESS
;
3292 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3294 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3295 strcpyW(FullName
,ExeStr
);
3296 strcatW( FullName
, file
->TargetPath
);
3297 strcatW(FullName
,close
);
3299 TRACE("Registering %s\n",debugstr_w(FullName
));
3300 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3304 msi_dialog_check_messages(info
.hProcess
);
3309 uirow
= MSI_CreateRecord( 2 );
3310 uipath
= strdupW( file
->TargetPath
);
3311 p
= strrchrW(uipath
,'\\');
3314 MSI_RecordSetStringW( uirow
, 1, &p
[2] );
3315 MSI_RecordSetStringW( uirow
, 2, uipath
);
3316 ui_actiondata( package
, szSelfRegModules
, uirow
);
3317 msiobj_release( &uirow
->hdr
);
3319 /* FIXME: call ui_progress? */
3321 return ERROR_SUCCESS
;
3324 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3328 static const WCHAR ExecSeqQuery
[] =
3329 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3330 '`','S','e','l','f','R','e','g','`',0};
3332 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3333 if (rc
!= ERROR_SUCCESS
)
3335 TRACE("no SelfReg table\n");
3336 return ERROR_SUCCESS
;
3339 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3340 msiobj_release(&view
->hdr
);
3342 return ERROR_SUCCESS
;
3345 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3347 MSIFEATURE
*feature
;
3352 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
,&hkey
,TRUE
);
3353 if (rc
!= ERROR_SUCCESS
)
3356 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
,&hukey
,TRUE
);
3357 if (rc
!= ERROR_SUCCESS
)
3360 /* here the guids are base 85 encoded */
3361 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3367 BOOL absent
= FALSE
;
3370 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3371 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3372 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3376 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3380 if (feature
->Feature_Parent
)
3381 size
+= strlenW( feature
->Feature_Parent
)+2;
3383 data
= msi_alloc(size
* sizeof(WCHAR
));
3386 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3388 MSICOMPONENT
* component
= cl
->component
;
3391 memset(buf
,0,sizeof(buf
));
3392 if (component
->ComponentId
)
3394 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3395 CLSIDFromString(component
->ComponentId
, &clsid
);
3396 encode_base85_guid(&clsid
,buf
);
3397 TRACE("to %s\n",debugstr_w(buf
));
3401 if (feature
->Feature_Parent
)
3403 static const WCHAR sep
[] = {'\2',0};
3405 strcatW(data
,feature
->Feature_Parent
);
3408 msi_reg_set_val_str( hkey
, feature
->Feature
, data
);
3412 if (feature
->Feature_Parent
)
3413 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3416 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3417 (LPBYTE
)feature
->Feature_Parent
,size
);
3421 size
+= 2*sizeof(WCHAR
);
3422 data
= msi_alloc(size
);
3425 if (feature
->Feature_Parent
)
3426 strcpyW( &data
[1], feature
->Feature_Parent
);
3427 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3433 uirow
= MSI_CreateRecord( 1 );
3434 MSI_RecordSetStringW( uirow
, 1, feature
->Feature
);
3435 ui_actiondata( package
, szPublishFeatures
, uirow
);
3436 msiobj_release( &uirow
->hdr
);
3437 /* FIXME: call ui_progress? */
3446 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
3448 static const WCHAR installerPathFmt
[] = {
3449 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3450 static const WCHAR fmt
[] = {
3452 'I','n','s','t','a','l','l','e','r','\\',
3453 '%','x','.','m','s','i',0};
3454 static const WCHAR szOriginalDatabase
[] =
3455 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3456 WCHAR windir
[MAX_PATH
], path
[MAX_PATH
], packagefile
[MAX_PATH
];
3461 /* copy the package locally */
3462 num
= GetTickCount() & 0xffff;
3466 GetWindowsDirectoryW( windir
, MAX_PATH
);
3467 snprintfW( packagefile
, MAX_PATH
, fmt
, windir
, num
);
3470 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
3471 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
3472 if (handle
!= INVALID_HANDLE_VALUE
)
3474 CloseHandle(handle
);
3477 if (GetLastError() != ERROR_FILE_EXISTS
&&
3478 GetLastError() != ERROR_SHARING_VIOLATION
)
3480 if (!(++num
& 0xffff)) num
= 1;
3481 sprintfW(packagefile
,fmt
,num
);
3482 } while (num
!= start
);
3484 snprintfW( path
, MAX_PATH
, installerPathFmt
, windir
);
3485 create_full_pathW(path
);
3487 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
3489 msiFilePath
= msi_dup_property( package
, szOriginalDatabase
);
3490 r
= CopyFileW( msiFilePath
, packagefile
, FALSE
);
3491 msi_free( msiFilePath
);
3495 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3496 debugstr_w(msiFilePath
), debugstr_w(packagefile
), GetLastError());
3497 return ERROR_FUNCTION_FAILED
;
3500 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3501 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
3502 return ERROR_SUCCESS
;
3505 static UINT
msi_write_uninstall_property_vals( MSIPACKAGE
*package
, HKEY hkey
)
3507 LPWSTR prop
, val
, key
;
3508 static const LPCSTR propval
[] = {
3509 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3510 "ARPCONTACT", "Contact",
3511 "ARPCOMMENTS", "Comments",
3512 "ProductName", "DisplayName",
3513 "ProductVersion", "DisplayVersion",
3514 "ARPHELPLINK", "HelpLink",
3515 "ARPHELPTELEPHONE", "HelpTelephone",
3516 "ARPINSTALLLOCATION", "InstallLocation",
3517 "SourceDir", "InstallSource",
3518 "Manufacturer", "Publisher",
3519 "ARPREADME", "Readme",
3521 "ARPURLINFOABOUT", "URLInfoAbout",
3522 "ARPURLUPDATEINFO", "URLUpdateInfo",
3525 const LPCSTR
*p
= propval
;
3529 prop
= strdupAtoW( *p
++ );
3530 key
= strdupAtoW( *p
++ );
3531 val
= msi_dup_property( package
, prop
);
3532 msi_reg_set_val_str( hkey
, key
, val
);
3537 return ERROR_SUCCESS
;
3540 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
3543 LPWSTR buffer
= NULL
;
3546 static const WCHAR szWindowsInstaller
[] =
3547 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3548 static const WCHAR szUpgradeCode
[] =
3549 {'U','p','g','r','a','d','e','C','o','d','e',0};
3550 static const WCHAR modpath_fmt
[] =
3551 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3552 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3553 static const WCHAR szModifyPath
[] =
3554 {'M','o','d','i','f','y','P','a','t','h',0};
3555 static const WCHAR szUninstallString
[] =
3556 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3557 static const WCHAR szEstimatedSize
[] =
3558 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3559 static const WCHAR szProductLanguage
[] =
3560 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3561 static const WCHAR szProductVersion
[] =
3562 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3565 static const WCHAR date_fmt
[] = {'%','i','%','i','%','i',0};
3566 LPWSTR upgrade_code
;
3569 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3570 if (rc
!= ERROR_SUCCESS
)
3573 /* dump all the info i can grab */
3574 /* FIXME: Flesh out more information */
3576 msi_write_uninstall_property_vals( package
, hkey
);
3578 msi_reg_set_val_dword( hkey
, szWindowsInstaller
, 1 );
3580 msi_make_package_local( package
, hkey
);
3582 /* do ModifyPath and UninstallString */
3583 size
= deformat_string(package
,modpath_fmt
,&buffer
);
3584 RegSetValueExW(hkey
,szModifyPath
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3585 RegSetValueExW(hkey
,szUninstallString
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3588 /* FIXME: Write real Estimated Size when we have it */
3589 msi_reg_set_val_dword( hkey
, szEstimatedSize
, 0 );
3591 GetLocalTime(&systime
);
3592 sprintfW(szDate
,date_fmt
,systime
.wYear
,systime
.wMonth
,systime
.wDay
);
3593 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_INSTALLDATEW
, szDate
);
3595 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3596 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3598 buffer
= msi_dup_property( package
, szProductVersion
);
3601 DWORD verdword
= build_version_dword(buffer
);
3603 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3604 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>>24 );
3605 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>>16)&0x00FF );
3609 /* Handle Upgrade Codes */
3610 upgrade_code
= msi_dup_property( package
, szUpgradeCode
);
3615 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3616 squash_guid(package
->ProductCode
,squashed
);
3617 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3619 MSIREG_OpenUserUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3620 squash_guid(package
->ProductCode
,squashed
);
3621 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3624 msi_free(upgrade_code
);
3629 /* FIXME: call ui_actiondata */
3631 return ERROR_SUCCESS
;
3634 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
3636 return execute_script(package
,INSTALL_SCRIPT
);
3639 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
3643 /* turn off scheduleing */
3644 package
->script
->CurrentlyScripting
= FALSE
;
3646 /* first do the same as an InstallExecute */
3647 rc
= ACTION_InstallExecute(package
);
3648 if (rc
!= ERROR_SUCCESS
)
3651 /* then handle Commit Actions */
3652 rc
= execute_script(package
,COMMIT_SCRIPT
);
3657 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
3659 static const WCHAR RunOnce
[] = {
3660 'S','o','f','t','w','a','r','e','\\',
3661 'M','i','c','r','o','s','o','f','t','\\',
3662 'W','i','n','d','o','w','s','\\',
3663 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3664 'R','u','n','O','n','c','e',0};
3665 static const WCHAR InstallRunOnce
[] = {
3666 'S','o','f','t','w','a','r','e','\\',
3667 'M','i','c','r','o','s','o','f','t','\\',
3668 'W','i','n','d','o','w','s','\\',
3669 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3670 'I','n','s','t','a','l','l','e','r','\\',
3671 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3673 static const WCHAR msiexec_fmt
[] = {
3675 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3676 '\"','%','s','\"',0};
3677 static const WCHAR install_fmt
[] = {
3678 '/','I',' ','\"','%','s','\"',' ',
3679 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3680 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3681 WCHAR buffer
[256], sysdir
[MAX_PATH
];
3683 WCHAR squished_pc
[100];
3685 squash_guid(package
->ProductCode
,squished_pc
);
3687 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
3688 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
3689 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
3692 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3695 TRACE("Reboot command %s\n",debugstr_w(buffer
));
3697 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
3698 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
3700 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3703 return ERROR_INSTALL_SUSPEND
;
3706 UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
3711 * we are currently doing what should be done here in the top level Install
3712 * however for Adminastrative and uninstalls this step will be needed
3714 if (!package
->PackagePath
)
3715 return ERROR_SUCCESS
;
3717 attrib
= GetFileAttributesW(package
->PackagePath
);
3718 if (attrib
== INVALID_FILE_ATTRIBUTES
)
3724 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3725 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3726 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
3727 if (rc
== ERROR_MORE_DATA
)
3729 prompt
= msi_alloc(size
* sizeof(WCHAR
));
3730 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3731 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3732 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
3735 prompt
= strdupW(package
->PackagePath
);
3737 msg
= generate_error_string(package
,1302,1,prompt
);
3738 while(attrib
== INVALID_FILE_ATTRIBUTES
)
3740 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
3743 rc
= ERROR_INSTALL_USEREXIT
;
3746 attrib
= GetFileAttributesW(package
->PackagePath
);
3752 return ERROR_SUCCESS
;
3757 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
3764 static const WCHAR szPropKeys
[][80] =
3766 {'P','r','o','d','u','c','t','I','D',0},
3767 {'U','S','E','R','N','A','M','E',0},
3768 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3772 static const WCHAR szRegKeys
[][80] =
3774 {'P','r','o','d','u','c','t','I','D',0},
3775 {'R','e','g','O','w','n','e','r',0},
3776 {'R','e','g','C','o','m','p','a','n','y',0},
3780 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
3782 return ERROR_SUCCESS
;
3784 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3785 if (rc
!= ERROR_SUCCESS
)
3788 for( i
= 0; szPropKeys
[i
][0]; i
++ )
3790 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
3791 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
3796 msi_free(productid
);
3799 /* FIXME: call ui_actiondata */
3801 return ERROR_SUCCESS
;
3805 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
3809 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
3810 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
3816 * Code based off of code located here
3817 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3819 * Using string index 4 (full font name) instead of 1 (family name)
3821 static LPWSTR
load_ttfname_from(LPCWSTR filename
)
3827 typedef struct _tagTT_OFFSET_TABLE
{
3828 USHORT uMajorVersion
;
3829 USHORT uMinorVersion
;
3830 USHORT uNumOfTables
;
3831 USHORT uSearchRange
;
3832 USHORT uEntrySelector
;
3836 typedef struct _tagTT_TABLE_DIRECTORY
{
3837 char szTag
[4]; /* table name */
3838 ULONG uCheckSum
; /* Check sum */
3839 ULONG uOffset
; /* Offset from beginning of file */
3840 ULONG uLength
; /* length of the table in bytes */
3841 }TT_TABLE_DIRECTORY
;
3843 typedef struct _tagTT_NAME_TABLE_HEADER
{
3844 USHORT uFSelector
; /* format selector. Always 0 */
3845 USHORT uNRCount
; /* Name Records count */
3846 USHORT uStorageOffset
; /* Offset for strings storage,
3847 * from start of the table */
3848 }TT_NAME_TABLE_HEADER
;
3850 typedef struct _tagTT_NAME_RECORD
{
3855 USHORT uStringLength
;
3856 USHORT uStringOffset
; /* from start of storage area */
3859 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3860 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3862 handle
= CreateFileW(filename
,GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
3863 FILE_ATTRIBUTE_NORMAL
, 0 );
3864 if (handle
!= INVALID_HANDLE_VALUE
)
3866 TT_TABLE_DIRECTORY tblDir
;
3867 BOOL bFound
= FALSE
;
3868 TT_OFFSET_TABLE ttOffsetTable
;
3871 ReadFile(handle
,&ttOffsetTable
, sizeof(TT_OFFSET_TABLE
),&dwRead
,NULL
);
3872 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
3873 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
3874 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
3876 if (ttOffsetTable
.uMajorVersion
!= 1 ||
3877 ttOffsetTable
.uMinorVersion
!= 0)
3880 for (i
=0; i
< ttOffsetTable
.uNumOfTables
; i
++)
3882 ReadFile(handle
,&tblDir
, sizeof(TT_TABLE_DIRECTORY
),&dwRead
,NULL
);
3883 if (strncmp(tblDir
.szTag
,"name",4)==0)
3886 tblDir
.uLength
= SWAPLONG(tblDir
.uLength
);
3887 tblDir
.uOffset
= SWAPLONG(tblDir
.uOffset
);
3894 TT_NAME_TABLE_HEADER ttNTHeader
;
3895 TT_NAME_RECORD ttRecord
;
3897 SetFilePointer(handle
, tblDir
.uOffset
, NULL
, FILE_BEGIN
);
3898 ReadFile(handle
,&ttNTHeader
, sizeof(TT_NAME_TABLE_HEADER
),
3901 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
3902 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
3904 for(i
=0; i
<ttNTHeader
.uNRCount
; i
++)
3906 ReadFile(handle
,&ttRecord
, sizeof(TT_NAME_RECORD
),&dwRead
,NULL
);
3907 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
3908 /* 4 is the Full Font Name */
3909 if(ttRecord
.uNameID
== 4)
3913 static LPCSTR tt
= " (TrueType)";
3915 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
3916 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
3917 nPos
= SetFilePointer(handle
, 0, NULL
, FILE_CURRENT
);
3918 SetFilePointer(handle
, tblDir
.uOffset
+
3919 ttRecord
.uStringOffset
+
3920 ttNTHeader
.uStorageOffset
,
3922 buf
= msi_alloc( ttRecord
.uStringLength
+ 1 + strlen(tt
) );
3923 memset(buf
, 0, ttRecord
.uStringLength
+ 1 + strlen(tt
));
3924 ReadFile(handle
, buf
, ttRecord
.uStringLength
, &dwRead
, NULL
);
3925 if (strlen(buf
) > 0)
3928 ret
= strdupAtoW(buf
);
3934 SetFilePointer(handle
,nPos
, NULL
, FILE_BEGIN
);
3938 CloseHandle(handle
);
3941 ERR("Unable to open font file %s\n", debugstr_w(filename
));
3943 TRACE("Returning fontname %s\n",debugstr_w(ret
));
3947 static UINT
ITERATE_RegisterFonts(MSIRECORD
*row
, LPVOID param
)
3949 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3953 static const WCHAR regfont1
[] =
3954 {'S','o','f','t','w','a','r','e','\\',
3955 'M','i','c','r','o','s','o','f','t','\\',
3956 'W','i','n','d','o','w','s',' ','N','T','\\',
3957 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3958 'F','o','n','t','s',0};
3959 static const WCHAR regfont2
[] =
3960 {'S','o','f','t','w','a','r','e','\\',
3961 'M','i','c','r','o','s','o','f','t','\\',
3962 'W','i','n','d','o','w','s','\\',
3963 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3964 'F','o','n','t','s',0};
3970 filename
= MSI_RecordGetString( row
, 1 );
3971 file
= get_loaded_file( package
, filename
);
3974 ERR("Unable to load file\n");
3975 return ERROR_SUCCESS
;
3978 /* check to make sure that component is installed */
3979 if (!ACTION_VerifyComponentForAction( file
->Component
, INSTALLSTATE_LOCAL
))
3981 TRACE("Skipping: Component not scheduled for install\n");
3982 return ERROR_SUCCESS
;
3985 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont1
,&hkey1
);
3986 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont2
,&hkey2
);
3988 if (MSI_RecordIsNull(row
,2))
3989 name
= load_ttfname_from( file
->TargetPath
);
3991 name
= msi_dup_record_field(row
,2);
3995 msi_reg_set_val_str( hkey1
, name
, file
->FileName
);
3996 msi_reg_set_val_str( hkey2
, name
, file
->FileName
);
4004 uirow
= MSI_CreateRecord( 1 );
4005 uipath
= strdupW( file
->TargetPath
);
4006 p
= strrchrW(uipath
,'\\');
4009 MSI_RecordSetStringW( uirow
, 1, p
);
4010 ui_actiondata( package
, szRegisterFonts
, uirow
);
4011 msiobj_release( &uirow
->hdr
);
4013 /* FIXME: call ui_progress? */
4015 return ERROR_SUCCESS
;
4018 static UINT
ACTION_RegisterFonts(MSIPACKAGE
*package
)
4022 static const WCHAR ExecSeqQuery
[] =
4023 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4024 '`','F','o','n','t','`',0};
4026 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4027 if (rc
!= ERROR_SUCCESS
)
4029 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc
);
4030 return ERROR_SUCCESS
;
4033 MSI_IterateRecords(view
, NULL
, ITERATE_RegisterFonts
, package
);
4034 msiobj_release(&view
->hdr
);
4036 return ERROR_SUCCESS
;
4039 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
4041 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
4042 LPCWSTR compgroupid
=NULL
;
4043 LPCWSTR feature
=NULL
;
4044 LPCWSTR text
= NULL
;
4045 LPCWSTR qualifier
= NULL
;
4046 LPCWSTR component
= NULL
;
4047 LPWSTR advertise
= NULL
;
4048 LPWSTR output
= NULL
;
4050 UINT rc
= ERROR_SUCCESS
;
4055 component
= MSI_RecordGetString(rec
,3);
4056 comp
= get_loaded_component(package
,component
);
4058 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
) &&
4059 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_SOURCE
) &&
4060 !ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ADVERTISED
))
4062 TRACE("Skipping: Component %s not scheduled for install\n",
4063 debugstr_w(component
));
4065 return ERROR_SUCCESS
;
4068 compgroupid
= MSI_RecordGetString(rec
,1);
4069 qualifier
= MSI_RecordGetString(rec
,2);
4071 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
4072 if (rc
!= ERROR_SUCCESS
)
4075 text
= MSI_RecordGetString(rec
,4);
4076 feature
= MSI_RecordGetString(rec
,5);
4078 advertise
= create_component_advertise_string(package
, comp
, feature
);
4080 sz
= strlenW(advertise
);
4083 sz
+= lstrlenW(text
);
4086 sz
*= sizeof(WCHAR
);
4088 output
= msi_alloc(sz
);
4089 memset(output
,0,sz
);
4090 strcpyW(output
,advertise
);
4091 msi_free(advertise
);
4094 strcatW(output
,text
);
4096 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
4103 uirow
= MSI_CreateRecord( 2 );
4104 MSI_RecordSetStringW( uirow
, 1, compgroupid
);
4105 MSI_RecordSetStringW( uirow
, 2, qualifier
);
4106 ui_actiondata( package
, szPublishComponents
, uirow
);
4107 msiobj_release( &uirow
->hdr
);
4108 /* FIXME: call ui_progress? */
4114 * At present I am ignorning the advertised components part of this and only
4115 * focusing on the qualified component sets
4117 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
4121 static const WCHAR ExecSeqQuery
[] =
4122 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4123 '`','P','u','b','l','i','s','h',
4124 'C','o','m','p','o','n','e','n','t','`',0};
4126 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4127 if (rc
!= ERROR_SUCCESS
)
4128 return ERROR_SUCCESS
;
4130 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
4131 msiobj_release(&view
->hdr
);
4136 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
4137 LPCSTR action
, LPCWSTR table
)
4139 static const WCHAR query
[] = {
4140 'S','E','L','E','C','T',' ','*',' ',
4141 'F','R','O','M',' ','`','%','s','`',0 };
4142 MSIQUERY
*view
= NULL
;
4146 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
4147 if (r
== ERROR_SUCCESS
)
4149 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
4150 msiobj_release(&view
->hdr
);
4154 FIXME("%s -> %lu ignored %s table values\n",
4155 action
, count
, debugstr_w(table
));
4157 return ERROR_SUCCESS
;
4160 static UINT
ACTION_AllocateRegistrySpace( MSIPACKAGE
*package
)
4162 TRACE("%p\n", package
);
4163 return ERROR_SUCCESS
;
4166 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
4168 static const WCHAR table
[] =
4169 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4170 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
4173 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
4175 static const WCHAR table
[] = { 'M','o','v','e','F','i','l','e',0 };
4176 return msi_unimplemented_action_stub( package
, "MoveFiles", table
);
4179 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
4181 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
4182 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
4185 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
4187 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
4188 return msi_unimplemented_action_stub( package
, "BindImage", table
);
4191 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
4193 static const WCHAR table
[] = {
4194 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4195 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
4198 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
4200 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
4201 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
4204 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
4206 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
4207 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
4210 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
4212 static const WCHAR table
[] = {
4213 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4214 return msi_unimplemented_action_stub( package
, "InstallServices", table
);
4217 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
4219 static const WCHAR table
[] = {
4220 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4221 return msi_unimplemented_action_stub( package
, "StartServices", table
);
4224 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4226 static const WCHAR table
[] = {
4227 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4228 return msi_unimplemented_action_stub( package
, "StopServices", table
);
4231 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
4233 static const WCHAR table
[] = {
4234 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4235 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
4238 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
4240 static const WCHAR table
[] = {
4241 'E','n','v','i','r','o','n','m','e','n','t',0 };
4242 return msi_unimplemented_action_stub( package
, "WriteEnvironmentStrings", table
);
4245 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
4247 static const WCHAR table
[] = {
4248 'E','n','v','i','r','o','n','m','e','n','t',0 };
4249 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
4252 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
4254 static const WCHAR table
[] = {
4255 'M','s','i','A','s','s','e','m','b','l','y',0 };
4256 return msi_unimplemented_action_stub( package
, "MsiPublishAssemblies", table
);
4259 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
4261 static const WCHAR table
[] = {
4262 'M','s','i','A','s','s','e','m','b','l','y',0 };
4263 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
4266 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
4268 static const WCHAR table
[] = { 'F','o','n','t',0 };
4269 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
4272 static UINT
ACTION_CCPSearch( MSIPACKAGE
*package
)
4274 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
4275 return msi_unimplemented_action_stub( package
, "CCPSearch", table
);
4278 static UINT
ACTION_RMCCPSearch( MSIPACKAGE
*package
)
4280 static const WCHAR table
[] = { 'C','C','P','S','e','a','r','c','h',0 };
4281 return msi_unimplemented_action_stub( package
, "RMCCPSearch", table
);
4284 static struct _actions StandardActions
[] = {
4285 { szAllocateRegistrySpace
, ACTION_AllocateRegistrySpace
},
4286 { szAppSearch
, ACTION_AppSearch
},
4287 { szBindImage
, ACTION_BindImage
},
4288 { szCCPSearch
, ACTION_CCPSearch
},
4289 { szCostFinalize
, ACTION_CostFinalize
},
4290 { szCostInitialize
, ACTION_CostInitialize
},
4291 { szCreateFolders
, ACTION_CreateFolders
},
4292 { szCreateShortcuts
, ACTION_CreateShortcuts
},
4293 { szDeleteServices
, ACTION_DeleteServices
},
4294 { szDisableRollback
, NULL
},
4295 { szDuplicateFiles
, ACTION_DuplicateFiles
},
4296 { szExecuteAction
, ACTION_ExecuteAction
},
4297 { szFileCost
, ACTION_FileCost
},
4298 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
4299 { szForceReboot
, ACTION_ForceReboot
},
4300 { szInstallAdminPackage
, NULL
},
4301 { szInstallExecute
, ACTION_InstallExecute
},
4302 { szInstallExecuteAgain
, ACTION_InstallExecute
},
4303 { szInstallFiles
, ACTION_InstallFiles
},
4304 { szInstallFinalize
, ACTION_InstallFinalize
},
4305 { szInstallInitialize
, ACTION_InstallInitialize
},
4306 { szInstallSFPCatalogFile
, NULL
},
4307 { szInstallValidate
, ACTION_InstallValidate
},
4308 { szIsolateComponents
, ACTION_IsolateComponents
},
4309 { szLaunchConditions
, ACTION_LaunchConditions
},
4310 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
4311 { szMoveFiles
, ACTION_MoveFiles
},
4312 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
4313 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
4314 { szInstallODBC
, NULL
},
4315 { szInstallServices
, ACTION_InstallServices
},
4316 { szPatchFiles
, ACTION_PatchFiles
},
4317 { szProcessComponents
, ACTION_ProcessComponents
},
4318 { szPublishComponents
, ACTION_PublishComponents
},
4319 { szPublishFeatures
, ACTION_PublishFeatures
},
4320 { szPublishProduct
, ACTION_PublishProduct
},
4321 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
4322 { szRegisterComPlus
, NULL
},
4323 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
4324 { szRegisterFonts
, ACTION_RegisterFonts
},
4325 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
4326 { szRegisterProduct
, ACTION_RegisterProduct
},
4327 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
4328 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
4329 { szRegisterUser
, ACTION_RegisterUser
},
4330 { szRemoveDuplicateFiles
, NULL
},
4331 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
4332 { szRemoveExistingProducts
, NULL
},
4333 { szRemoveFiles
, ACTION_RemoveFiles
},
4334 { szRemoveFolders
, NULL
},
4335 { szRemoveIniValues
, ACTION_RemoveIniValues
},
4336 { szRemoveODBC
, NULL
},
4337 { szRemoveRegistryValues
, NULL
},
4338 { szRemoveShortcuts
, NULL
},
4339 { szResolveSource
, ACTION_ResolveSource
},
4340 { szRMCCPSearch
, ACTION_RMCCPSearch
},
4341 { szScheduleReboot
, NULL
},
4342 { szSelfRegModules
, ACTION_SelfRegModules
},
4343 { szSelfUnregModules
, ACTION_SelfUnregModules
},
4344 { szSetODBCFolders
, NULL
},
4345 { szStartServices
, ACTION_StartServices
},
4346 { szStopServices
, ACTION_StopServices
},
4347 { szUnpublishComponents
, NULL
},
4348 { szUnpublishFeatures
, NULL
},
4349 { szUnregisterClassInfo
, NULL
},
4350 { szUnregisterComPlus
, NULL
},
4351 { szUnregisterExtensionInfo
, NULL
},
4352 { szUnregisterFonts
, ACTION_UnregisterFonts
},
4353 { szUnregisterMIMEInfo
, NULL
},
4354 { szUnregisterProgIdInfo
, NULL
},
4355 { szUnregisterTypeLibraries
, NULL
},
4356 { szValidateProductID
, NULL
},
4357 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
4358 { szWriteIniValues
, ACTION_WriteIniValues
},
4359 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},