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 ce_actiontext(MSIPACKAGE
* package
, LPCWSTR action
)
252 static const WCHAR szActionText
[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
256 row
= MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row
,1,action
);
258 ControlEvent_FireSubscribedEvent(package
,szActionText
, row
);
259 msiobj_release(&row
->hdr
);
262 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
264 static const WCHAR template_s
[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
267 static const WCHAR format
[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t
[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
280 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
282 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
286 ActionText
= MSI_RecordGetString(row
,2);
287 deformat_string(package
, ActionText
, &deformated
);
289 sprintfW(message
,template_s
,timet
,action
,deformated
);
290 ce_actiontext(package
, deformated
);
291 msiobj_release(&row
->hdr
);
293 row
= MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row
,1,message
);
296 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
297 msiobj_release(&row
->hdr
);
298 msi_free(deformated
);
301 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
305 static const WCHAR template_s
[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
308 static const WCHAR template_e
[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
312 static const WCHAR format
[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
317 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
319 sprintfW(message
,template_s
,timet
,action
);
321 sprintfW(message
,template_e
,timet
,action
,rc
);
323 row
= MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row
,1,message
);
326 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
327 msiobj_release(&row
->hdr
);
330 static int msi_get_property_int( MSIPACKAGE
*package
, LPCWSTR prop
, int def
)
332 LPWSTR str
= msi_dup_property( package
, prop
);
333 int val
= str
? atoiW( str
) : def
;
338 static UINT
msi_parse_command_line( MSIPACKAGE
*package
, LPCWSTR szCommandLine
)
343 LPWSTR prop
= NULL
, val
= NULL
;
346 return ERROR_SUCCESS
;
358 TRACE("Looking at %s\n",debugstr_w(ptr
));
360 ptr2
= strchrW(ptr
,'=');
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr
));
370 prop
= msi_alloc((len
+1)*sizeof(WCHAR
));
371 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
377 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
390 val
= msi_alloc((len
+1)*sizeof(WCHAR
));
391 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
394 if (lstrlenW(prop
) > 0)
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop
), debugstr_w(val
));
398 MSI_SetPropertyW(package
,prop
,val
);
404 return ERROR_SUCCESS
;
408 static LPWSTR
* msi_split_string( LPCWSTR str
, WCHAR sep
)
410 LPWSTR p
, *ret
= NULL
;
416 /* count the number of substrings */
417 for ( p
= (LPWSTR
)str
, count
= 0; p
; count
++ )
419 p
= strchrW( p
, sep
);
424 /* allocate space for an array of substring pointers and the substrings */
425 ret
= msi_alloc( (count
+1) * sizeof (LPWSTR
) +
426 (lstrlenW(str
)+1) * sizeof(WCHAR
) );
430 /* copy the string and set the pointers */
431 p
= (LPWSTR
) &ret
[count
+1];
433 for( count
= 0; (ret
[count
] = p
); count
++ )
435 p
= strchrW( p
, sep
);
443 static UINT
msi_apply_substorage_transform( MSIPACKAGE
*package
,
444 MSIDATABASE
*patch_db
, LPCWSTR name
)
446 UINT ret
= ERROR_FUNCTION_FAILED
;
447 IStorage
*stg
= NULL
;
450 TRACE("%p %s\n", package
, debugstr_w(name
) );
454 ERR("expected a colon in %s\n", debugstr_w(name
));
455 return ERROR_FUNCTION_FAILED
;
458 r
= IStorage_OpenStorage( patch_db
->storage
, name
, NULL
, STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
461 ret
= msi_table_apply_transform( package
->db
, stg
);
462 IStorage_Release( stg
);
466 ERR("failed to open substorage %s\n", debugstr_w(name
));
471 static UINT
msi_check_patch_applicable( MSIPACKAGE
*package
, MSISUMMARYINFO
*si
)
473 static const WCHAR szProdID
[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list
, *guids
, product_id
;
475 UINT i
, ret
= ERROR_FUNCTION_FAILED
;
477 product_id
= msi_dup_property( package
, szProdID
);
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS
;
485 guid_list
= msi_suminfo_dup_string( si
, PID_TEMPLATE
);
486 guids
= msi_split_string( guid_list
, ';' );
487 for ( i
= 0; guids
[i
] && ret
!= ERROR_SUCCESS
; i
++ )
489 if (!lstrcmpW( guids
[i
], product_id
))
493 msi_free( guid_list
);
494 msi_free( product_id
);
499 static UINT
msi_parse_patch_summary( MSIPACKAGE
*package
, MSIDATABASE
*patch_db
)
502 LPWSTR str
, *substorage
;
503 UINT i
, r
= ERROR_SUCCESS
;
505 si
= MSI_GetSummaryInformationW( patch_db
, 0 );
507 return ERROR_FUNCTION_FAILED
;
509 msi_check_patch_applicable( package
, si
);
511 /* enumerate the substorage */
512 str
= msi_suminfo_dup_string( si
, PID_LASTAUTHOR
);
513 substorage
= msi_split_string( str
, ';' );
514 for ( i
= 0; substorage
&& substorage
[i
] && r
== ERROR_SUCCESS
; i
++ )
515 r
= msi_apply_substorage_transform( package
, patch_db
, substorage
[i
] );
516 msi_free( substorage
);
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
521 msiobj_release( &si
->hdr
);
526 static UINT
msi_apply_patch_package( MSIPACKAGE
*package
, LPCWSTR file
)
528 MSIDATABASE
*patch_db
= NULL
;
531 TRACE("%p %s\n", package
, debugstr_w( file
) );
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
538 r
= MSI_OpenDatabaseW( file
, MSIDBOPEN_READONLY
, &patch_db
);
539 if ( r
!= ERROR_SUCCESS
)
541 ERR("failed to open patch collection %s\n", debugstr_w( file
) );
545 msi_parse_patch_summary( package
, patch_db
);
546 msiobj_release( &patch_db
->hdr
);
548 return ERROR_SUCCESS
;
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT
msi_apply_patches( MSIPACKAGE
*package
)
554 static const WCHAR szPatch
[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list
, *patches
;
556 UINT i
, r
= ERROR_SUCCESS
;
558 patch_list
= msi_dup_property( package
, szPatch
);
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list
) );
562 patches
= msi_split_string( patch_list
, ';' );
563 for( i
=0; patches
&& patches
[i
] && r
== ERROR_SUCCESS
; i
++ )
564 r
= msi_apply_patch_package( package
, patches
[i
] );
567 msi_free( patch_list
);
572 /****************************************************
573 * TOP level entry points
574 *****************************************************/
576 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
577 LPCWSTR szCommandLine
)
581 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
582 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
583 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
585 MSI_SetPropertyW(package
, szAction
, szInstall
);
587 package
->script
= msi_alloc(sizeof(MSISCRIPT
));
588 memset(package
->script
,0,sizeof(MSISCRIPT
));
590 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
594 LPWSTR p
, check
, path
;
596 package
->PackagePath
= strdupW(szPackagePath
);
597 path
= strdupW(szPackagePath
);
598 p
= strrchrW(path
,'\\');
607 path
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
608 GetCurrentDirectoryW(MAX_PATH
,path
);
612 check
= msi_dup_property( package
, cszSourceDir
);
614 MSI_SetPropertyW(package
, cszSourceDir
, path
);
619 msi_parse_command_line( package
, szCommandLine
);
621 msi_apply_patches( package
);
623 if ( msi_get_property_int(package
, szUILevel
, 0) >= INSTALLUILEVEL_REDUCED
)
625 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
626 rc
= ACTION_ProcessUISequence(package
);
628 if (rc
== ERROR_SUCCESS
)
630 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
631 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
635 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
639 /* install was halted but should be considered a success */
643 package
->script
->CurrentlyScripting
= FALSE
;
645 /* process the ending type action */
646 if (rc
== ERROR_SUCCESS
)
647 ACTION_PerformActionSequence(package
,-1,ui
);
648 else if (rc
== ERROR_INSTALL_USEREXIT
)
649 ACTION_PerformActionSequence(package
,-2,ui
);
650 else if (rc
== ERROR_INSTALL_SUSPEND
)
651 ACTION_PerformActionSequence(package
,-4,ui
);
653 ACTION_PerformActionSequence(package
,-3,ui
);
655 /* finish up running custom actions */
656 ACTION_FinishCustomActions(package
);
661 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
663 UINT rc
= ERROR_SUCCESS
;
665 static const WCHAR ExecSeqQuery
[] =
666 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
667 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
668 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
669 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
671 static const WCHAR UISeqQuery
[] =
672 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
673 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
674 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
675 ' ', '=',' ','%','i',0};
678 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
680 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
684 LPCWSTR action
, cond
;
686 TRACE("Running the actions\n");
688 /* check conditions */
689 cond
= MSI_RecordGetString(row
,2);
692 /* this is a hack to skip errors in the condition code */
693 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
697 action
= MSI_RecordGetString(row
,1);
700 ERR("failed to fetch action\n");
701 rc
= ERROR_FUNCTION_FAILED
;
706 rc
= ACTION_PerformUIAction(package
,action
);
708 rc
= ACTION_PerformAction(package
,action
,FALSE
);
710 msiobj_release(&row
->hdr
);
721 } iterate_action_param
;
723 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
725 iterate_action_param
*iap
= (iterate_action_param
*)param
;
727 LPCWSTR cond
, action
;
729 action
= MSI_RecordGetString(row
,1);
732 ERR("Error is retrieving action name\n");
733 return ERROR_FUNCTION_FAILED
;
736 /* check conditions */
737 cond
= MSI_RecordGetString(row
,2);
740 /* this is a hack to skip errors in the condition code */
741 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
743 TRACE("Skipping action: %s (condition is false)\n",
745 return ERROR_SUCCESS
;
750 rc
= ACTION_PerformUIAction(iap
->package
,action
);
752 rc
= ACTION_PerformAction(iap
->package
,action
,FALSE
);
754 msi_dialog_check_messages( NULL
);
756 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
757 rc
= iap
->package
->CurrentInstallState
;
759 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
762 if (rc
!= ERROR_SUCCESS
)
763 ERR("Execution halted, action %s returned %i\n", debugstr_w(action
), rc
);
768 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
772 static const WCHAR query
[] =
773 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
775 ' ','W','H','E','R','E',' ',
776 '`','S','e','q','u','e','n','c','e','`',' ',
777 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
778 '`','S','e','q','u','e','n','c','e','`',0};
779 iterate_action_param iap
;
782 * FIXME: probably should be checking UILevel in the
783 * ACTION_PerformUIAction/ACTION_PerformAction
784 * rather than saving the UI level here. Those
785 * two functions can be merged too.
787 iap
.package
= package
;
790 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
792 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
793 if (r
== ERROR_SUCCESS
)
795 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
796 msiobj_release(&view
->hdr
);
802 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
806 static const WCHAR ExecSeqQuery
[] =
807 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
808 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
809 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
810 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
811 'O','R','D','E','R',' ', 'B','Y',' ',
812 '`','S','e','q','u','e','n','c','e','`',0 };
814 static const WCHAR IVQuery
[] =
815 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
816 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
817 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
818 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
819 ' ','\'', 'I','n','s','t','a','l','l',
820 'V','a','l','i','d','a','t','e','\'', 0};
822 iterate_action_param iap
;
824 iap
.package
= package
;
827 if (package
->script
->ExecuteSequenceRun
)
829 TRACE("Execute Sequence already Run\n");
830 return ERROR_SUCCESS
;
833 package
->script
->ExecuteSequenceRun
= TRUE
;
835 /* get the sequence number */
838 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
840 return ERROR_FUNCTION_FAILED
;
841 seq
= MSI_RecordGetInteger(row
,1);
842 msiobj_release(&row
->hdr
);
845 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
846 if (rc
== ERROR_SUCCESS
)
848 TRACE("Running the actions\n");
850 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
851 msiobj_release(&view
->hdr
);
857 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
861 static const WCHAR ExecSeqQuery
[] =
862 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
863 '`','I','n','s','t','a','l','l',
864 'U','I','S','e','q','u','e','n','c','e','`',
865 ' ','W','H','E','R','E',' ',
866 '`','S','e','q','u','e','n','c','e','`',' ',
867 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
868 '`','S','e','q','u','e','n','c','e','`',0};
869 iterate_action_param iap
;
871 iap
.package
= package
;
874 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
876 if (rc
== ERROR_SUCCESS
)
878 TRACE("Running the actions\n");
880 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
881 msiobj_release(&view
->hdr
);
887 /********************************************************
888 * ACTION helper functions and functions that perform the actions
889 *******************************************************/
890 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
891 UINT
* rc
, BOOL force
)
899 ERR("package was null!\n");
903 if (!run
&& !package
->script
->CurrentlyScripting
)
908 if (strcmpW(action
,szInstallFinalize
) == 0 ||
909 strcmpW(action
,szInstallExecute
) == 0 ||
910 strcmpW(action
,szInstallExecuteAgain
) == 0)
915 while (StandardActions
[i
].action
!= NULL
)
917 if (strcmpW(StandardActions
[i
].action
, action
)==0)
921 ui_actioninfo(package
, action
, TRUE
, 0);
922 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
923 ui_actioninfo(package
, action
, FALSE
, *rc
);
927 ui_actionstart(package
, action
);
928 if (StandardActions
[i
].handler
)
930 *rc
= StandardActions
[i
].handler(package
);
934 FIXME("unhandled standard action %s\n",debugstr_w(action
));
946 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
947 UINT
* rc
, BOOL force
)
952 arc
= ACTION_CustomAction(package
,action
, force
);
954 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
963 * A lot of actions are really important even if they don't do anything
964 * explicit... Lots of properties are set at the beginning of the installation
965 * CostFinalize does a bunch of work to translate the directories and such
967 * But until I get write access to the database that is hard, so I am going to
968 * hack it to see if I can get something to run.
970 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, BOOL force
)
972 UINT rc
= ERROR_SUCCESS
;
975 TRACE("Performing action (%s)\n",debugstr_w(action
));
977 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
980 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, force
);
984 FIXME("unhandled msi action %s\n",debugstr_w(action
));
985 rc
= ERROR_FUNCTION_NOT_CALLED
;
991 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
993 UINT rc
= ERROR_SUCCESS
;
994 BOOL handled
= FALSE
;
996 TRACE("Performing action (%s)\n",debugstr_w(action
));
998 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1001 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, FALSE
);
1003 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
1008 FIXME("unhandled msi action %s\n",debugstr_w(action
));
1009 rc
= ERROR_FUNCTION_NOT_CALLED
;
1017 * Actual Action Handlers
1020 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
1022 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1028 dir
= MSI_RecordGetString(row
,1);
1031 ERR("Unable to get folder id\n");
1032 return ERROR_SUCCESS
;
1035 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1038 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1039 return ERROR_SUCCESS
;
1042 TRACE("Folder is %s\n",debugstr_w(full_path
));
1045 uirow
= MSI_CreateRecord(1);
1046 MSI_RecordSetStringW(uirow
,1,full_path
);
1047 ui_actiondata(package
,szCreateFolders
,uirow
);
1048 msiobj_release( &uirow
->hdr
);
1050 if (folder
->State
== 0)
1051 create_full_pathW(full_path
);
1055 msi_free(full_path
);
1056 return ERROR_SUCCESS
;
1059 /* FIXME: probably should merge this with the above function */
1060 static UINT
msi_create_directory( MSIPACKAGE
* package
, LPCWSTR dir
)
1062 UINT rc
= ERROR_SUCCESS
;
1064 LPWSTR install_path
;
1066 install_path
= resolve_folder(package
, dir
, FALSE
, FALSE
, &folder
);
1068 return ERROR_FUNCTION_FAILED
;
1070 /* create the path */
1071 if (folder
->State
== 0)
1073 create_full_pathW(install_path
);
1076 msi_free(install_path
);
1081 UINT
msi_create_component_directories( MSIPACKAGE
*package
)
1085 /* create all the folders required by the components are going to install */
1086 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1088 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
1090 msi_create_directory( package
, comp
->Directory
);
1093 return ERROR_SUCCESS
;
1097 * Also we cannot enable/disable components either, so for now I am just going
1098 * to do all the directories for all the components.
1100 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1102 static const WCHAR ExecSeqQuery
[] =
1103 {'S','E','L','E','C','T',' ',
1104 '`','D','i','r','e','c','t','o','r','y','_','`',
1105 ' ','F','R','O','M',' ',
1106 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1110 /* create all the empty folders specified in the CreateFolder table */
1111 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1112 if (rc
!= ERROR_SUCCESS
)
1113 return ERROR_SUCCESS
;
1115 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
1116 msiobj_release(&view
->hdr
);
1118 msi_create_component_directories( package
);
1123 static MSICOMPONENT
* load_component( MSIRECORD
* row
)
1127 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
1131 /* fill in the data */
1132 comp
->Component
= msi_dup_record_field( row
, 1 );
1134 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
1136 comp
->ComponentId
= msi_dup_record_field( row
, 2 );
1137 comp
->Directory
= msi_dup_record_field( row
, 3 );
1138 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
1139 comp
->Condition
= msi_dup_record_field( row
, 5 );
1140 comp
->KeyPath
= msi_dup_record_field( row
, 6 );
1142 comp
->Installed
= INSTALLSTATE_ABSENT
;
1143 comp
->Action
= INSTALLSTATE_UNKNOWN
;
1144 comp
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1146 comp
->Enabled
= TRUE
;
1152 MSIPACKAGE
*package
;
1153 MSIFEATURE
*feature
;
1156 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
1160 cl
= msi_alloc( sizeof (*cl
) );
1162 return ERROR_NOT_ENOUGH_MEMORY
;
1163 cl
->component
= comp
;
1164 list_add_tail( &feature
->Components
, &cl
->entry
);
1166 return ERROR_SUCCESS
;
1169 static UINT
iterate_component_check( MSIRECORD
*row
, LPVOID param
)
1171 _ilfs
* ilfs
= (_ilfs
*)param
;
1172 MSIPACKAGE
*package
= ilfs
->package
;
1173 MSIFEATURE
*feature
= ilfs
->feature
;
1176 comp
= load_component( row
);
1178 return ERROR_FUNCTION_FAILED
;
1180 list_add_tail( &package
->components
, &comp
->entry
);
1181 add_feature_component( feature
, comp
);
1183 TRACE("Loaded new component %p\n", comp
);
1185 return ERROR_SUCCESS
;
1188 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
1190 _ilfs
* ilfs
= (_ilfs
*)param
;
1195 static const WCHAR Query
[] =
1196 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1197 '`','C','o','m','p','o','n','e','n','t','`',' ',
1198 'W','H','E','R','E',' ',
1199 '`','C','o','m','p','o','n','e','n','t','`',' ',
1200 '=','\'','%','s','\'',0};
1202 component
= MSI_RecordGetString(row
,1);
1204 /* check to see if the component is already loaded */
1205 comp
= get_loaded_component( ilfs
->package
, component
);
1208 TRACE("Component %s already loaded\n", debugstr_w(component
) );
1209 add_feature_component( ilfs
->feature
, comp
);
1210 return ERROR_SUCCESS
;
1213 rc
= MSI_OpenQuery(ilfs
->package
->db
, &view
, Query
, component
);
1214 if (rc
!= ERROR_SUCCESS
)
1215 return ERROR_SUCCESS
;
1217 rc
= MSI_IterateRecords(view
, NULL
, iterate_component_check
, ilfs
);
1218 msiobj_release( &view
->hdr
);
1220 return ERROR_SUCCESS
;
1223 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1225 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1226 MSIFEATURE
* feature
;
1227 static const WCHAR Query1
[] =
1228 {'S','E','L','E','C','T',' ',
1229 '`','C','o','m','p','o','n','e','n','t','_','`',
1230 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1231 'C','o','m','p','o','n','e','n','t','s','`',' ',
1232 'W','H','E','R','E',' ',
1233 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1238 /* fill in the data */
1240 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1242 return ERROR_NOT_ENOUGH_MEMORY
;
1244 list_init( &feature
->Components
);
1246 feature
->Feature
= msi_dup_record_field( row
, 1 );
1248 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1250 feature
->Feature_Parent
= msi_dup_record_field( row
, 2 );
1251 feature
->Title
= msi_dup_record_field( row
, 3 );
1252 feature
->Description
= msi_dup_record_field( row
, 4 );
1254 if (!MSI_RecordIsNull(row
,5))
1255 feature
->Display
= MSI_RecordGetInteger(row
,5);
1257 feature
->Level
= MSI_RecordGetInteger(row
,6);
1258 feature
->Directory
= msi_dup_record_field( row
, 7 );
1259 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1261 feature
->Installed
= INSTALLSTATE_ABSENT
;
1262 feature
->Action
= INSTALLSTATE_UNKNOWN
;
1263 feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1265 list_add_tail( &package
->features
, &feature
->entry
);
1267 /* load feature components */
1269 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1270 if (rc
!= ERROR_SUCCESS
)
1271 return ERROR_SUCCESS
;
1273 ilfs
.package
= package
;
1274 ilfs
.feature
= feature
;
1276 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1277 msiobj_release(&view
->hdr
);
1279 return ERROR_SUCCESS
;
1282 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1284 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1288 /* fill in the data */
1290 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1292 return ERROR_NOT_ENOUGH_MEMORY
;
1294 file
->File
= msi_dup_record_field( row
, 1 );
1296 component
= MSI_RecordGetString( row
, 2 );
1297 file
->Component
= get_loaded_component( package
, component
);
1299 if (!file
->Component
)
1300 ERR("Unfound Component %s\n",debugstr_w(component
));
1302 file
->FileName
= msi_dup_record_field( row
, 3 );
1303 reduce_to_longfilename( file
->FileName
);
1305 file
->ShortName
= msi_dup_record_field( row
, 3 );
1306 reduce_to_shortfilename( file
->ShortName
);
1308 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1309 file
->Version
= msi_dup_record_field( row
, 5 );
1310 file
->Language
= msi_dup_record_field( row
, 6 );
1311 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1312 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1314 file
->state
= msifs_invalid
;
1316 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1318 list_add_tail( &package
->files
, &file
->entry
);
1320 return ERROR_SUCCESS
;
1323 static UINT
load_all_files(MSIPACKAGE
*package
)
1327 static const WCHAR Query
[] =
1328 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1330 '`','S','e','q','u','e','n','c','e','`', 0};
1333 return ERROR_INVALID_HANDLE
;
1335 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1336 if (rc
!= ERROR_SUCCESS
)
1337 return ERROR_SUCCESS
;
1339 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1340 msiobj_release(&view
->hdr
);
1342 return ERROR_SUCCESS
;
1347 * I am not doing any of the costing functionality yet.
1348 * Mostly looking at doing the Component and Feature loading
1350 * The native MSI does A LOT of modification to tables here. Mostly adding
1351 * a lot of temporary columns to the Feature and Component tables.
1353 * note: Native msi also tracks the short filename. But I am only going to
1354 * track the long ones. Also looking at this directory table
1355 * it appears that the directory table does not get the parents
1356 * resolved base on property only based on their entries in the
1359 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1363 static const WCHAR Query_all
[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','e','a','t','u','r','e','`',0};
1366 static const WCHAR szCosting
[] =
1367 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1368 static const WCHAR szZero
[] = { '0', 0 };
1370 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1371 return ERROR_SUCCESS
;
1373 MSI_SetPropertyW(package
, szCosting
, szZero
);
1374 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1376 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1377 if (rc
!= ERROR_SUCCESS
)
1380 rc
= MSI_IterateRecords(view
, NULL
, load_feature
, package
);
1381 msiobj_release(&view
->hdr
);
1383 load_all_files(package
);
1385 return ERROR_SUCCESS
;
1388 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1391 UINT rc
= ERROR_SUCCESS
;
1393 TRACE("Executing Script %i\n",script
);
1395 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1398 action
= package
->script
->Actions
[script
][i
];
1399 ui_actionstart(package
, action
);
1400 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1401 rc
= ACTION_PerformAction(package
, action
, TRUE
);
1402 msi_free(package
->script
->Actions
[script
][i
]);
1403 if (rc
!= ERROR_SUCCESS
)
1406 msi_free(package
->script
->Actions
[script
]);
1408 package
->script
->ActionCount
[script
] = 0;
1409 package
->script
->Actions
[script
] = NULL
;
1413 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1415 return ERROR_SUCCESS
;
1419 static MSIFOLDER
*load_folder( MSIPACKAGE
*package
, LPCWSTR dir
)
1421 static const WCHAR Query
[] =
1422 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1423 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1424 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1425 ' ','=',' ','\'','%','s','\'',
1427 LPWSTR ptargetdir
, targetdir
, srcdir
;
1429 LPWSTR shortname
= NULL
;
1430 MSIRECORD
* row
= 0;
1433 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1435 folder
= get_loaded_folder( package
, dir
);
1439 TRACE("Working to load %s\n",debugstr_w(dir
));
1441 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1445 folder
->Directory
= strdupW(dir
);
1447 row
= MSI_QueryGetRecord(package
->db
, Query
, dir
);
1451 ptargetdir
= targetdir
= msi_dup_record_field(row
,3);
1453 /* split src and target dir */
1454 if (strchrW(targetdir
,':'))
1456 srcdir
=strchrW(targetdir
,':');
1463 /* for now only pick long filename versions */
1464 if (strchrW(targetdir
,'|'))
1466 shortname
= targetdir
;
1467 targetdir
= strchrW(targetdir
,'|');
1471 /* for the sourcedir pick the short filename */
1472 if (srcdir
&& strchrW(srcdir
,'|'))
1474 LPWSTR p
= strchrW(srcdir
,'|');
1478 /* now check for root dirs */
1479 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1484 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1485 msi_free( folder
->TargetDefault
);
1486 folder
->TargetDefault
= strdupW(targetdir
);
1490 folder
->SourceDefault
= strdupW(srcdir
);
1492 folder
->SourceDefault
= strdupW(shortname
);
1494 folder
->SourceDefault
= strdupW(targetdir
);
1495 msi_free(ptargetdir
);
1496 TRACE(" SourceDefault = %s\n", debugstr_w( folder
->SourceDefault
));
1498 parent
= MSI_RecordGetString(row
,2);
1501 folder
->Parent
= load_folder( package
, parent
);
1502 if ( folder
->Parent
)
1503 TRACE("loaded parent %p %s\n", folder
->Parent
,
1504 debugstr_w(folder
->Parent
->Directory
));
1506 ERR("failed to load parent folder %s\n", debugstr_w(parent
));
1509 folder
->Property
= msi_dup_property( package
, dir
);
1511 msiobj_release(&row
->hdr
);
1513 list_add_tail( &package
->folders
, &folder
->entry
);
1515 TRACE("%s returning %p\n",debugstr_w(dir
),folder
);
1520 /* scan for and update current install states */
1521 static void ACTION_UpdateInstallStates(MSIPACKAGE
*package
)
1524 MSIFEATURE
*feature
;
1526 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1529 res
= MsiGetComponentPathW( package
->ProductCode
,
1530 comp
->ComponentId
, NULL
, NULL
);
1532 res
= INSTALLSTATE_ABSENT
;
1533 comp
->Installed
= res
;
1536 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1539 INSTALLSTATE res
= -10;
1541 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1543 comp
= cl
->component
;
1546 res
= comp
->Installed
;
1549 if (res
== comp
->Installed
)
1552 if (res
!= comp
->Installed
)
1553 res
= INSTALLSTATE_INCOMPLETE
;
1556 feature
->Installed
= res
;
1560 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1563 static const WCHAR all
[]={'A','L','L',0};
1565 MSIFEATURE
*feature
;
1567 override
= msi_dup_property( package
, property
);
1571 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1573 if (strcmpiW(override
,all
)==0)
1575 feature
->ActionRequest
= state
;
1576 feature
->Action
= state
;
1580 LPWSTR ptr
= override
;
1581 LPWSTR ptr2
= strchrW(override
,',');
1585 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1586 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1588 feature
->ActionRequest
= state
;
1589 feature
->Action
= state
;
1595 ptr2
= strchrW(ptr
,',');
1607 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
1610 static const WCHAR szlevel
[] =
1611 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1612 static const WCHAR szAddLocal
[] =
1613 {'A','D','D','L','O','C','A','L',0};
1614 static const WCHAR szRemove
[] =
1615 {'R','E','M','O','V','E',0};
1616 static const WCHAR szReinstall
[] =
1617 {'R','E','I','N','S','T','A','L','L',0};
1618 BOOL override
= FALSE
;
1619 MSICOMPONENT
* component
;
1620 MSIFEATURE
*feature
;
1623 /* I do not know if this is where it should happen.. but */
1625 TRACE("Checking Install Level\n");
1627 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1629 /* ok hereis the _real_ rub
1630 * all these activation/deactivation things happen in order and things
1631 * later on the list override things earlier on the list.
1632 * 1) INSTALLLEVEL processing
1642 * 11) FILEADDDEFAULT
1643 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1644 * ignored for all the features. seems strange, especially since it is not
1645 * documented anywhere, but it is how it works.
1647 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1648 * REMOVE are the big ones, since we don't handle administrative installs
1651 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1652 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1653 override
|= process_state_property(package
,szReinstall
,INSTALLSTATE_LOCAL
);
1657 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1659 BOOL feature_state
= ((feature
->Level
> 0) &&
1660 (feature
->Level
<= install_level
));
1662 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1664 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1666 feature
->ActionRequest
= INSTALLSTATE_SOURCE
;
1667 feature
->Action
= INSTALLSTATE_SOURCE
;
1669 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1671 feature
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1672 feature
->Action
= INSTALLSTATE_ADVERTISED
;
1676 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
1677 feature
->Action
= INSTALLSTATE_LOCAL
;
1684 /* set the Preselected Property */
1685 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1686 static const WCHAR szOne
[] = { '1', 0 };
1688 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1692 * now we want to enable or disable components base on feature
1695 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1699 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1700 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
1701 feature
->ActionRequest
);
1703 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1705 component
= cl
->component
;
1707 if (!component
->Enabled
)
1709 component
->Action
= INSTALLSTATE_UNKNOWN
;
1710 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1714 if (feature
->Action
== INSTALLSTATE_LOCAL
)
1716 component
->Action
= INSTALLSTATE_LOCAL
;
1717 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
1719 else if (feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
1721 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1722 (component
->Action
== INSTALLSTATE_ABSENT
) ||
1723 (component
->Action
== INSTALLSTATE_ADVERTISED
))
1726 component
->Action
= INSTALLSTATE_SOURCE
;
1727 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
1730 else if (feature
->ActionRequest
== INSTALLSTATE_ADVERTISED
)
1732 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1733 (component
->Action
== INSTALLSTATE_ABSENT
))
1736 component
->Action
= INSTALLSTATE_ADVERTISED
;
1737 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1740 else if (feature
->ActionRequest
== INSTALLSTATE_ABSENT
)
1742 if (component
->Action
== INSTALLSTATE_UNKNOWN
)
1744 component
->Action
= INSTALLSTATE_ABSENT
;
1745 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
1752 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1754 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1755 debugstr_w(component
->Component
), component
->Installed
,
1756 component
->Action
, component
->ActionRequest
);
1760 return ERROR_SUCCESS
;
1763 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1765 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1769 name
= MSI_RecordGetString(row
,1);
1771 /* This helper function now does ALL the work */
1772 TRACE("Dir %s ...\n",debugstr_w(name
));
1773 load_folder(package
,name
);
1774 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
1775 TRACE("resolves to %s\n",debugstr_w(path
));
1778 return ERROR_SUCCESS
;
1781 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1783 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1785 MSIFEATURE
*feature
;
1787 name
= MSI_RecordGetString( row
, 1 );
1789 feature
= get_loaded_feature( package
, name
);
1791 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1795 Condition
= MSI_RecordGetString(row
,3);
1797 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1799 int level
= MSI_RecordGetInteger(row
,2);
1800 TRACE("Reseting feature %s to level %i\n", debugstr_w(name
), level
);
1801 feature
->Level
= level
;
1804 return ERROR_SUCCESS
;
1809 * A lot is done in this function aside from just the costing.
1810 * The costing needs to be implemented at some point but for now I am going
1811 * to focus on the directory building
1814 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1816 static const WCHAR ExecSeqQuery
[] =
1817 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1818 '`','D','i','r','e','c','t','o','r','y','`',0};
1819 static const WCHAR ConditionQuery
[] =
1820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1821 '`','C','o','n','d','i','t','i','o','n','`',0};
1822 static const WCHAR szCosting
[] =
1823 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1824 static const WCHAR szlevel
[] =
1825 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1826 static const WCHAR szOne
[] = { '1', 0 };
1833 if ( 1 == msi_get_property_int( package
, szCosting
, 0 ) )
1834 return ERROR_SUCCESS
;
1836 TRACE("Building Directory properties\n");
1838 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1839 if (rc
== ERROR_SUCCESS
)
1841 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
1843 msiobj_release(&view
->hdr
);
1846 TRACE("File calculations\n");
1848 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1850 MSICOMPONENT
* comp
= file
->Component
;
1856 /* calculate target */
1857 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
1859 msi_free(file
->TargetPath
);
1861 TRACE("file %s is named %s\n",
1862 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
1864 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1868 TRACE("file %s resolves to %s\n",
1869 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
1871 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1873 file
->state
= msifs_missing
;
1874 comp
->Cost
+= file
->FileSize
;
1884 static WCHAR name
[] = {'\\',0};
1885 static const WCHAR name_fmt
[] =
1886 {'%','u','.','%','u','.','%','u','.','%','u',0};
1887 WCHAR filever
[0x100];
1888 VS_FIXEDFILEINFO
*lpVer
;
1890 TRACE("Version comparison..\n");
1891 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
1892 version
= msi_alloc(versize
);
1893 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
1895 VerQueryValueW(version
, (LPWSTR
)name
, (LPVOID
*)&lpVer
, &sz
);
1897 sprintfW(filever
,name_fmt
,
1898 HIWORD(lpVer
->dwFileVersionMS
),
1899 LOWORD(lpVer
->dwFileVersionMS
),
1900 HIWORD(lpVer
->dwFileVersionLS
),
1901 LOWORD(lpVer
->dwFileVersionLS
));
1903 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1904 debugstr_w(filever
));
1905 if (strcmpiW(filever
,file
->Version
)<0)
1907 file
->state
= msifs_overwrite
;
1908 /* FIXME: cost should be diff in size */
1909 comp
->Cost
+= file
->FileSize
;
1912 file
->state
= msifs_present
;
1916 file
->state
= msifs_present
;
1919 TRACE("Evaluating Condition Table\n");
1921 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
1922 if (rc
== ERROR_SUCCESS
)
1924 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
1926 msiobj_release(&view
->hdr
);
1929 TRACE("Enabling or Disabling Components\n");
1930 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1932 if (comp
->Condition
)
1934 if (MSI_EvaluateConditionW(package
,
1935 comp
->Condition
) == MSICONDITION_FALSE
)
1937 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
1938 comp
->Enabled
= FALSE
;
1943 MSI_SetPropertyW(package
,szCosting
,szOne
);
1944 /* set default run level if not set */
1945 level
= msi_dup_property( package
, szlevel
);
1947 MSI_SetPropertyW(package
,szlevel
, szOne
);
1950 ACTION_UpdateInstallStates(package
);
1952 return SetFeatureStates(package
);
1955 /* OK this value is "interpreted" and then formatted based on the
1956 first few characters */
1957 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
1961 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
1967 LPWSTR deformated
= NULL
;
1970 deformat_string(package
, &value
[2], &deformated
);
1972 /* binary value type */
1976 *size
= (strlenW(ptr
)/2)+1;
1978 *size
= strlenW(ptr
)/2;
1980 data
= msi_alloc(*size
);
1986 /* if uneven pad with a zero in front */
1992 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
1994 TRACE("Uneven byte count\n");
2002 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2005 msi_free(deformated
);
2007 TRACE("Data %li bytes(%i)\n",*size
,count
);
2014 deformat_string(package
, &value
[1], &deformated
);
2017 *size
= sizeof(DWORD
);
2018 data
= msi_alloc(*size
);
2024 if ( (*p
< '0') || (*p
> '9') )
2030 if (deformated
[0] == '-')
2033 TRACE("DWORD %li\n",*(LPDWORD
)data
);
2035 msi_free(deformated
);
2040 static const WCHAR szMulti
[] = {'[','~',']',0};
2049 *type
=REG_EXPAND_SZ
;
2057 if (strstrW(value
,szMulti
))
2058 *type
= REG_MULTI_SZ
;
2060 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2065 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
2067 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2068 static const WCHAR szHCR
[] =
2069 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2070 'R','O','O','T','\\',0};
2071 static const WCHAR szHCU
[] =
2072 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2073 'U','S','E','R','\\',0};
2074 static const WCHAR szHLM
[] =
2075 {'H','K','E','Y','_','L','O','C','A','L','_',
2076 'M','A','C','H','I','N','E','\\',0};
2077 static const WCHAR szHU
[] =
2078 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2080 LPSTR value_data
= NULL
;
2081 HKEY root_key
, hkey
;
2084 LPCWSTR szRoot
, component
, name
, key
, value
;
2089 BOOL check_first
= FALSE
;
2092 ui_progress(package
,2,0,0,0);
2099 component
= MSI_RecordGetString(row
, 6);
2100 comp
= get_loaded_component(package
,component
);
2102 return ERROR_SUCCESS
;
2104 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2106 TRACE("Skipping write due to disabled component %s\n",
2107 debugstr_w(component
));
2109 comp
->Action
= comp
->Installed
;
2111 return ERROR_SUCCESS
;
2114 comp
->Action
= INSTALLSTATE_LOCAL
;
2116 name
= MSI_RecordGetString(row
, 4);
2117 if( MSI_RecordIsNull(row
,5) && name
)
2119 /* null values can have special meanings */
2120 if (name
[0]=='-' && name
[1] == 0)
2121 return ERROR_SUCCESS
;
2122 else if ((name
[0]=='+' && name
[1] == 0) ||
2123 (name
[0] == '*' && name
[1] == 0))
2128 root
= MSI_RecordGetInteger(row
,2);
2129 key
= MSI_RecordGetString(row
, 3);
2131 /* get the root key */
2136 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
2137 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
2138 if (all_users
&& all_users
[0] == '1')
2140 root_key
= HKEY_LOCAL_MACHINE
;
2145 root_key
= HKEY_CURRENT_USER
;
2148 msi_free(all_users
);
2151 case 0: root_key
= HKEY_CLASSES_ROOT
;
2154 case 1: root_key
= HKEY_CURRENT_USER
;
2157 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2160 case 3: root_key
= HKEY_USERS
;
2164 ERR("Unknown root %i\n",root
);
2170 return ERROR_SUCCESS
;
2172 deformat_string(package
, key
, &deformated
);
2173 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
2174 uikey
= msi_alloc(size
*sizeof(WCHAR
));
2175 strcpyW(uikey
,szRoot
);
2176 strcatW(uikey
,deformated
);
2178 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
2180 ERR("Could not create key %s\n",debugstr_w(deformated
));
2181 msi_free(deformated
);
2183 return ERROR_SUCCESS
;
2185 msi_free(deformated
);
2187 value
= MSI_RecordGetString(row
,5);
2189 value_data
= parse_value(package
, value
, &type
, &size
);
2192 static const WCHAR szEmpty
[] = {0};
2193 value_data
= (LPSTR
)strdupW(szEmpty
);
2198 deformat_string(package
, name
, &deformated
);
2200 /* get the double nulls to terminate SZ_MULTI */
2201 if (type
== REG_MULTI_SZ
)
2202 size
+=sizeof(WCHAR
);
2206 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2208 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2213 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2214 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2216 TRACE("value %s of %s checked already exists\n",
2217 debugstr_w(deformated
), debugstr_w(uikey
));
2221 TRACE("Checked and setting value %s of %s\n",
2222 debugstr_w(deformated
), debugstr_w(uikey
));
2223 if (deformated
|| size
)
2224 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2229 uirow
= MSI_CreateRecord(3);
2230 MSI_RecordSetStringW(uirow
,2,deformated
);
2231 MSI_RecordSetStringW(uirow
,1,uikey
);
2234 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2236 MSI_RecordSetStringW(uirow
,3,value
);
2238 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2239 msiobj_release( &uirow
->hdr
);
2241 msi_free(value_data
);
2242 msi_free(deformated
);
2245 return ERROR_SUCCESS
;
2248 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2252 static const WCHAR ExecSeqQuery
[] =
2253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2254 '`','R','e','g','i','s','t','r','y','`',0 };
2257 return ERROR_INVALID_HANDLE
;
2259 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2260 if (rc
!= ERROR_SUCCESS
)
2261 return ERROR_SUCCESS
;
2263 /* increment progress bar each time action data is sent */
2264 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2266 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2268 msiobj_release(&view
->hdr
);
2272 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2274 package
->script
->CurrentlyScripting
= TRUE
;
2276 return ERROR_SUCCESS
;
2280 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2285 static const WCHAR q1
[]=
2286 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2287 '`','R','e','g','i','s','t','r','y','`',0};
2290 MSIFEATURE
*feature
;
2293 TRACE("InstallValidate\n");
2295 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2296 if (rc
== ERROR_SUCCESS
)
2298 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2299 msiobj_release( &view
->hdr
);
2300 total
+= progress
* REG_PROGRESS_VALUE
;
2303 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2304 total
+= COMPONENT_PROGRESS_VALUE
;
2306 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2307 total
+= file
->FileSize
;
2309 ui_progress(package
,0,total
,0,0);
2311 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2313 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2314 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2315 feature
->ActionRequest
);
2318 return ERROR_SUCCESS
;
2321 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2323 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2324 LPCWSTR cond
= NULL
;
2325 LPCWSTR message
= NULL
;
2326 static const WCHAR title
[]=
2327 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2329 cond
= MSI_RecordGetString(row
,1);
2331 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
2334 message
= MSI_RecordGetString(row
,2);
2335 deformat_string(package
,message
,&deformated
);
2336 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2337 msi_free(deformated
);
2338 return ERROR_FUNCTION_FAILED
;
2341 return ERROR_SUCCESS
;
2344 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2347 MSIQUERY
* view
= NULL
;
2348 static const WCHAR ExecSeqQuery
[] =
2349 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2350 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2352 TRACE("Checking launch conditions\n");
2354 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2355 if (rc
!= ERROR_SUCCESS
)
2356 return ERROR_SUCCESS
;
2358 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2359 msiobj_release(&view
->hdr
);
2364 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2368 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
2370 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2372 MSIRECORD
* row
= 0;
2374 LPWSTR deformated
,buffer
,deformated_name
;
2376 static const WCHAR ExecSeqQuery
[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','R','e','g','i','s','t','r','y','`',' ',
2379 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2380 ' ','=',' ' ,'\'','%','s','\'',0 };
2381 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2382 static const WCHAR fmt2
[]=
2383 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2385 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2389 root
= MSI_RecordGetInteger(row
,2);
2390 key
= MSI_RecordGetString(row
, 3);
2391 name
= MSI_RecordGetString(row
, 4);
2392 deformat_string(package
, key
, &deformated
);
2393 deformat_string(package
, name
, &deformated_name
);
2395 len
= strlenW(deformated
) + 6;
2396 if (deformated_name
)
2397 len
+=strlenW(deformated_name
);
2399 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2401 if (deformated_name
)
2402 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2404 sprintfW(buffer
,fmt
,root
,deformated
);
2406 msi_free(deformated
);
2407 msi_free(deformated_name
);
2408 msiobj_release(&row
->hdr
);
2412 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2414 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2419 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2422 return strdupW( file
->TargetPath
);
2427 static HKEY
openSharedDLLsKey(void)
2430 static const WCHAR path
[] =
2431 {'S','o','f','t','w','a','r','e','\\',
2432 'M','i','c','r','o','s','o','f','t','\\',
2433 'W','i','n','d','o','w','s','\\',
2434 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2435 'S','h','a','r','e','d','D','L','L','s',0};
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2441 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2446 DWORD sz
= sizeof(count
);
2449 hkey
= openSharedDLLsKey();
2450 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2451 if (rc
!= ERROR_SUCCESS
)
2457 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2461 hkey
= openSharedDLLsKey();
2463 msi_reg_set_val_dword( hkey
, path
, count
);
2465 RegDeleteValueW(hkey
,path
);
2471 * Return TRUE if the count should be written out and FALSE if not
2473 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2475 MSIFEATURE
*feature
;
2479 /* only refcount DLLs */
2480 if (comp
->KeyPath
== NULL
||
2481 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2482 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2486 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2487 write
= (count
> 0);
2489 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2493 /* increment counts */
2494 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2498 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2501 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2503 if ( cl
->component
== comp
)
2508 /* decrement counts */
2509 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2513 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2516 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2518 if ( cl
->component
== comp
)
2523 /* ref count all the files in the component */
2528 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2530 if (file
->Component
== comp
)
2531 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2535 /* add a count for permenent */
2536 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2539 comp
->RefCount
= count
;
2542 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2546 * Ok further analysis makes me think that this work is
2547 * actually done in the PublishComponents and PublishFeatures
2548 * step, and not here. It appears like the keypath and all that is
2549 * resolved in this step, however actually written in the Publish steps.
2550 * But we will leave it here for now because it is unclear
2552 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2554 WCHAR squished_pc
[GUID_SIZE
];
2555 WCHAR squished_cc
[GUID_SIZE
];
2558 HKEY hkey
=0,hkey2
=0;
2560 /* writes the Component and Features values to the registry */
2562 rc
= MSIREG_OpenComponents(&hkey
);
2563 if (rc
!= ERROR_SUCCESS
)
2566 squash_guid(package
->ProductCode
,squished_pc
);
2567 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2569 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2571 ui_progress(package
,2,0,0,0);
2572 if (comp
->ComponentId
)
2576 squash_guid(comp
->ComponentId
,squished_cc
);
2578 msi_free(comp
->FullKeypath
);
2579 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2581 /* do the refcounting */
2582 ACTION_RefCountComponent( package
, comp
);
2584 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2585 debugstr_w(comp
->Component
),
2586 debugstr_w(squished_cc
),
2587 debugstr_w(comp
->FullKeypath
),
2590 * Write the keypath out if the component is to be registered
2591 * and delete the key if the component is to be deregistered
2593 if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2595 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2596 if (rc
!= ERROR_SUCCESS
)
2599 if (comp
->FullKeypath
)
2601 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2603 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2605 static const WCHAR szPermKey
[] =
2606 { '0','0','0','0','0','0','0','0','0','0','0','0',
2607 '0','0','0','0','0','0','0','0','0','0','0','0',
2608 '0','0','0','0','0','0','0','0',0};
2610 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2616 uirow
= MSI_CreateRecord(3);
2617 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2618 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2619 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2620 ui_actiondata(package
,szProcessComponents
,uirow
);
2621 msiobj_release( &uirow
->hdr
);
2624 else if (ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_ABSENT
))
2628 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2629 if (rc
!= ERROR_SUCCESS
)
2632 RegDeleteValueW(hkey2
,squished_pc
);
2634 /* if the key is empty delete it */
2635 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2637 if (res
== ERROR_NO_MORE_ITEMS
)
2638 RegDeleteKeyW(hkey
,squished_cc
);
2641 uirow
= MSI_CreateRecord(2);
2642 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2643 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2644 ui_actiondata(package
,szProcessComponents
,uirow
);
2645 msiobj_release( &uirow
->hdr
);
2662 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2663 LPWSTR lpszName
, LONG_PTR lParam
)
2666 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2667 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2671 if (!IS_INTRESOURCE(lpszName
))
2673 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2677 sz
= strlenW(tl_struct
->source
)+4;
2678 sz
*= sizeof(WCHAR
);
2680 if ((INT
)lpszName
== 1)
2681 tl_struct
->path
= strdupW(tl_struct
->source
);
2684 tl_struct
->path
= msi_alloc(sz
);
2685 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2688 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2689 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2690 if (!SUCCEEDED(res
))
2692 msi_free(tl_struct
->path
);
2693 tl_struct
->path
= NULL
;
2698 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2699 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2701 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2705 msi_free(tl_struct
->path
);
2706 tl_struct
->path
= NULL
;
2708 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2709 ITypeLib_Release(tl_struct
->ptLib
);
2714 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2716 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2720 typelib_struct tl_struct
;
2722 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2724 component
= MSI_RecordGetString(row
,3);
2725 comp
= get_loaded_component(package
,component
);
2727 return ERROR_SUCCESS
;
2729 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2731 TRACE("Skipping typelib reg due to disabled component\n");
2733 comp
->Action
= comp
->Installed
;
2735 return ERROR_SUCCESS
;
2738 comp
->Action
= INSTALLSTATE_LOCAL
;
2740 file
= get_loaded_file( package
, comp
->KeyPath
);
2742 return ERROR_SUCCESS
;
2744 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2748 guid
= MSI_RecordGetString(row
,1);
2749 CLSIDFromString((LPWSTR
)guid
, &tl_struct
.clsid
);
2750 tl_struct
.source
= strdupW( file
->TargetPath
);
2751 tl_struct
.path
= NULL
;
2753 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2754 (LONG_PTR
)&tl_struct
);
2762 helpid
= MSI_RecordGetString(row
,6);
2765 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
2766 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2769 if (!SUCCEEDED(res
))
2770 ERR("Failed to register type library %s\n",
2771 debugstr_w(tl_struct
.path
));
2774 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2776 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2779 ITypeLib_Release(tl_struct
.ptLib
);
2780 msi_free(tl_struct
.path
);
2783 ERR("Failed to load type library %s\n",
2784 debugstr_w(tl_struct
.source
));
2786 FreeLibrary(module
);
2787 msi_free(tl_struct
.source
);
2790 ERR("Could not load file! %s\n", debugstr_w(file
->TargetPath
));
2792 return ERROR_SUCCESS
;
2795 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2798 * OK this is a bit confusing.. I am given a _Component key and I believe
2799 * that the file that is being registered as a type library is the "key file
2800 * of that component" which I interpret to mean "The file in the KeyPath of
2805 static const WCHAR Query
[] =
2806 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2807 '`','T','y','p','e','L','i','b','`',0};
2809 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2810 if (rc
!= ERROR_SUCCESS
)
2811 return ERROR_SUCCESS
;
2813 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2814 msiobj_release(&view
->hdr
);
2818 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
2820 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2821 LPWSTR target_file
, target_folder
;
2823 WCHAR filename
[0x100];
2826 static const WCHAR szlnk
[]={'.','l','n','k',0};
2831 buffer
= MSI_RecordGetString(row
,4);
2832 comp
= get_loaded_component(package
,buffer
);
2834 return ERROR_SUCCESS
;
2836 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
2838 TRACE("Skipping shortcut creation due to disabled component\n");
2840 comp
->Action
= comp
->Installed
;
2842 return ERROR_SUCCESS
;
2845 comp
->Action
= INSTALLSTATE_LOCAL
;
2847 ui_actiondata(package
,szCreateShortcuts
,row
);
2849 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
2850 &IID_IShellLinkW
, (LPVOID
*) &sl
);
2854 ERR("Is IID_IShellLink\n");
2855 return ERROR_SUCCESS
;
2858 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
2861 ERR("Is IID_IPersistFile\n");
2862 return ERROR_SUCCESS
;
2865 buffer
= MSI_RecordGetString(row
,2);
2866 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
2868 /* may be needed because of a bug somehwere else */
2869 create_full_pathW(target_folder
);
2872 MSI_RecordGetStringW(row
,3,filename
,&sz
);
2873 reduce_to_longfilename(filename
);
2874 if (!strchrW(filename
,'.') || strcmpiW(strchrW(filename
,'.'),szlnk
))
2875 strcatW(filename
,szlnk
);
2876 target_file
= build_directory_name(2, target_folder
, filename
);
2877 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
;
2986 FileName
= MSI_RecordGetString(row
,1);
2989 ERR("Unable to get FileName\n");
2990 return ERROR_SUCCESS
;
2993 FilePath
= build_icon_path(package
,FileName
);
2995 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
2997 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2998 FILE_ATTRIBUTE_NORMAL
, NULL
);
3000 if (the_file
== INVALID_HANDLE_VALUE
)
3002 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
3004 return ERROR_SUCCESS
;
3011 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
3012 if (rc
!= ERROR_SUCCESS
)
3014 ERR("Failed to get stream\n");
3015 CloseHandle(the_file
);
3016 DeleteFileW(FilePath
);
3019 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
3020 } while (sz
== 1024);
3024 CloseHandle(the_file
);
3025 return ERROR_SUCCESS
;
3029 * 99% of the work done here is only done for
3030 * advertised installs. However this is where the
3031 * Icon table is processed and written out
3032 * so that is what I am going to do here.
3034 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
3038 static const WCHAR Query
[]=
3039 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3040 '`','I','c','o','n','`',0};
3041 /* for registry stuff */
3044 static const WCHAR szProductLanguage
[] =
3045 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3046 static const WCHAR szARPProductIcon
[] =
3047 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3048 static const WCHAR szProductVersion
[] =
3049 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3053 MSIHANDLE hDb
, hSumInfo
;
3055 /* write out icon files */
3057 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3058 if (rc
== ERROR_SUCCESS
)
3060 MSI_IterateRecords(view
, NULL
, ITERATE_PublishProduct
, package
);
3061 msiobj_release(&view
->hdr
);
3064 /* ok there is a lot more done here but i need to figure out what */
3066 rc
= MSIREG_OpenProductsKey(package
->ProductCode
,&hkey
,TRUE
);
3067 if (rc
!= ERROR_SUCCESS
)
3070 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
,&hukey
,TRUE
);
3071 if (rc
!= ERROR_SUCCESS
)
3075 buffer
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTNAMEW
);
3076 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
3079 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3080 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3082 buffer
= msi_dup_property( package
, szARPProductIcon
);
3085 LPWSTR path
= build_icon_path(package
,buffer
);
3086 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
3091 buffer
= msi_dup_property( package
, szProductVersion
);
3094 DWORD verdword
= build_version_dword(buffer
);
3095 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3099 FIXME("Need to write more keys to the user registry\n");
3101 hDb
= alloc_msihandle( &package
->db
->hdr
);
3102 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
3103 MsiCloseHandle(hDb
);
3104 if (rc
== ERROR_SUCCESS
)
3106 WCHAR guidbuffer
[0x200];
3108 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
3110 if (rc
== ERROR_SUCCESS
)
3112 WCHAR squashed
[GUID_SIZE
];
3113 /* for now we only care about the first guid */
3114 LPWSTR ptr
= strchrW(guidbuffer
,';');
3116 squash_guid(guidbuffer
,squashed
);
3117 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGECODEW
, squashed
);
3121 ERR("Unable to query Revision_Number...\n");
3124 MsiCloseHandle(hSumInfo
);
3128 ERR("Unable to open Summary Information\n");
3140 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
3142 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3143 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
3144 LPWSTR deformated_section
, deformated_key
, deformated_value
;
3145 LPWSTR folder
, fullname
= NULL
;
3149 static const WCHAR szWindowsFolder
[] =
3150 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3152 component
= MSI_RecordGetString(row
, 8);
3153 comp
= get_loaded_component(package
,component
);
3155 if (!ACTION_VerifyComponentForAction( comp
, INSTALLSTATE_LOCAL
))
3157 TRACE("Skipping ini file due to disabled component %s\n",
3158 debugstr_w(component
));
3160 comp
->Action
= comp
->Installed
;
3162 return ERROR_SUCCESS
;
3165 comp
->Action
= INSTALLSTATE_LOCAL
;
3167 identifier
= MSI_RecordGetString(row
,1);
3168 filename
= MSI_RecordGetString(row
,2);
3169 dirproperty
= MSI_RecordGetString(row
,3);
3170 section
= MSI_RecordGetString(row
,4);
3171 key
= MSI_RecordGetString(row
,5);
3172 value
= MSI_RecordGetString(row
,6);
3173 action
= MSI_RecordGetInteger(row
,7);
3175 deformat_string(package
,section
,&deformated_section
);
3176 deformat_string(package
,key
,&deformated_key
);
3177 deformat_string(package
,value
,&deformated_value
);
3181 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
3183 folder
= msi_dup_property( package
, dirproperty
);
3186 folder
= msi_dup_property( package
, szWindowsFolder
);
3190 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3194 fullname
= build_directory_name(2, folder
, filename
);
3198 TRACE("Adding value %s to section %s in %s\n",
3199 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3200 debugstr_w(fullname
));
3201 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3202 deformated_value
, fullname
);
3204 else if (action
== 1)
3207 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3208 returned
, 10, fullname
);
3209 if (returned
[0] == 0)