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 const static WCHAR szCreateFolders
[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 const static 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 const static 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 const static WCHAR szCostInitialize
[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 const static WCHAR szFileCost
[] =
77 {'F','i','l','e','C','o','s','t',0};
78 const static WCHAR szInstallInitialize
[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 const static WCHAR szInstallValidate
[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 const static WCHAR szLaunchConditions
[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 const static WCHAR szProcessComponents
[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 const static 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 const static WCHAR szCreateShortcuts
[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 const static WCHAR szPublishProduct
[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 const static WCHAR szWriteIniValues
[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 const static WCHAR szSelfRegModules
[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 const static WCHAR szPublishFeatures
[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 const static WCHAR szRegisterProduct
[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 const static WCHAR szInstallExecute
[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 const static 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 const static WCHAR szInstallFinalize
[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 const static WCHAR szForceReboot
[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 const static 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 const static 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 const static WCHAR szBindImage
[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 const static WCHAR szCCPSearch
[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 const static WCHAR szDeleteServices
[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 const static WCHAR szDisableRollback
[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 const static 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 const static 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 const static WCHAR szInstallSFPCatalogFile
[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 const static 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 const static 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 const static 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 const static WCHAR szInstallODBC
[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 const static 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 const static WCHAR szPublishComponents
[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 const static 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 const static 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 const static 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 const static 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 const static WCHAR szRemoveFolders
[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 const static WCHAR szRemoveIniValues
[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 const static WCHAR szRemoveODBC
[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 const static 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 const static WCHAR szRemoveShortcuts
[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 const static WCHAR szRMCCPSearch
[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 const static WCHAR szScheduleReboot
[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 const static WCHAR szSelfUnregModules
[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 const static WCHAR szSetODBCFolders
[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 const static WCHAR szStartServices
[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 const static WCHAR szStopServices
[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 const static 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 const static 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 const static 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 const static 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 const static 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 const static WCHAR szValidateProductID
[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 const static 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
;
407 /****************************************************
408 * TOP level entry points
409 *****************************************************/
411 UINT
MSI_InstallPackage( MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
412 LPCWSTR szCommandLine
)
416 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
417 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
418 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
420 MSI_SetPropertyW(package
, szAction
, szInstall
);
422 package
->script
= msi_alloc(sizeof(MSISCRIPT
));
423 memset(package
->script
,0,sizeof(MSISCRIPT
));
425 package
->script
->InWhatSequence
= SEQUENCE_INSTALL
;
429 LPWSTR p
, check
, path
;
431 package
->PackagePath
= strdupW(szPackagePath
);
432 path
= strdupW(szPackagePath
);
433 p
= strrchrW(path
,'\\');
442 path
= msi_alloc(MAX_PATH
*sizeof(WCHAR
));
443 GetCurrentDirectoryW(MAX_PATH
,path
);
447 check
= msi_dup_property( package
, cszSourceDir
);
449 MSI_SetPropertyW(package
, cszSourceDir
, path
);
454 msi_parse_command_line( package
, szCommandLine
);
456 if ( msi_get_property_int(package
, szUILevel
, 0) >= INSTALLUILEVEL_REDUCED
)
458 package
->script
->InWhatSequence
|= SEQUENCE_UI
;
459 rc
= ACTION_ProcessUISequence(package
);
461 if (rc
== ERROR_SUCCESS
)
463 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
464 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
468 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
472 /* install was halted but should be considered a success */
476 package
->script
->CurrentlyScripting
= FALSE
;
478 /* process the ending type action */
479 if (rc
== ERROR_SUCCESS
)
480 ACTION_PerformActionSequence(package
,-1,ui
);
481 else if (rc
== ERROR_INSTALL_USEREXIT
)
482 ACTION_PerformActionSequence(package
,-2,ui
);
483 else if (rc
== ERROR_INSTALL_SUSPEND
)
484 ACTION_PerformActionSequence(package
,-4,ui
);
486 ACTION_PerformActionSequence(package
,-3,ui
);
488 /* finish up running custom actions */
489 ACTION_FinishCustomActions(package
);
494 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
496 UINT rc
= ERROR_SUCCESS
;
498 static const WCHAR ExecSeqQuery
[] =
499 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
500 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
501 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
502 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
504 static const WCHAR UISeqQuery
[] =
505 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
506 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
507 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
508 ' ', '=',' ','%','i',0};
511 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
513 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
517 LPCWSTR action
, cond
;
519 TRACE("Running the actions\n");
521 /* check conditions */
522 cond
= MSI_RecordGetString(row
,2);
525 /* this is a hack to skip errors in the condition code */
526 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
530 action
= MSI_RecordGetString(row
,1);
533 ERR("failed to fetch action\n");
534 rc
= ERROR_FUNCTION_FAILED
;
539 rc
= ACTION_PerformUIAction(package
,action
);
541 rc
= ACTION_PerformAction(package
,action
,FALSE
);
543 msiobj_release(&row
->hdr
);
554 } iterate_action_param
;
556 static UINT
ITERATE_Actions(MSIRECORD
*row
, LPVOID param
)
558 iterate_action_param
*iap
= (iterate_action_param
*)param
;
560 LPCWSTR cond
, action
;
562 action
= MSI_RecordGetString(row
,1);
565 ERR("Error is retrieving action name\n");
566 return ERROR_FUNCTION_FAILED
;
569 /* check conditions */
570 cond
= MSI_RecordGetString(row
,2);
573 /* this is a hack to skip errors in the condition code */
574 if (MSI_EvaluateConditionW(iap
->package
, cond
) == MSICONDITION_FALSE
)
576 TRACE("Skipping action: %s (condition is false)\n",
578 return ERROR_SUCCESS
;
583 rc
= ACTION_PerformUIAction(iap
->package
,action
);
585 rc
= ACTION_PerformAction(iap
->package
,action
,FALSE
);
587 msi_dialog_check_messages( NULL
);
589 if (iap
->package
->CurrentInstallState
!= ERROR_SUCCESS
)
590 rc
= iap
->package
->CurrentInstallState
;
592 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
595 if (rc
!= ERROR_SUCCESS
)
596 ERR("Execution halted due to error (%i)\n",rc
);
601 UINT
MSI_Sequence( MSIPACKAGE
*package
, LPCWSTR szTable
, INT iSequenceMode
)
605 static const WCHAR query
[] =
606 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
608 ' ','W','H','E','R','E',' ',
609 '`','S','e','q','u','e','n','c','e','`',' ',
610 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
611 '`','S','e','q','u','e','n','c','e','`',0};
612 iterate_action_param iap
;
615 * FIXME: probably should be checking UILevel in the
616 * ACTION_PerformUIAction/ACTION_PerformAction
617 * rather than saving the UI level here. Those
618 * two functions can be merged too.
620 iap
.package
= package
;
623 TRACE("%p %s %i\n", package
, debugstr_w(szTable
), iSequenceMode
);
625 r
= MSI_OpenQuery( package
->db
, &view
, query
, szTable
);
626 if (r
== ERROR_SUCCESS
)
628 r
= MSI_IterateRecords( view
, NULL
, ITERATE_Actions
, &iap
);
629 msiobj_release(&view
->hdr
);
635 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
639 static const WCHAR ExecSeqQuery
[] =
640 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
641 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
642 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
643 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
644 'O','R','D','E','R',' ', 'B','Y',' ',
645 '`','S','e','q','u','e','n','c','e','`',0 };
647 static const WCHAR IVQuery
[] =
648 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
649 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
650 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
651 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
652 ' ','\'', 'I','n','s','t','a','l','l',
653 'V','a','l','i','d','a','t','e','\'', 0};
655 iterate_action_param iap
;
657 iap
.package
= package
;
660 if (package
->script
->ExecuteSequenceRun
)
662 TRACE("Execute Sequence already Run\n");
663 return ERROR_SUCCESS
;
666 package
->script
->ExecuteSequenceRun
= TRUE
;
668 /* get the sequence number */
671 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
673 return ERROR_FUNCTION_FAILED
;
674 seq
= MSI_RecordGetInteger(row
,1);
675 msiobj_release(&row
->hdr
);
678 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
679 if (rc
== ERROR_SUCCESS
)
681 TRACE("Running the actions\n");
683 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
684 msiobj_release(&view
->hdr
);
690 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
694 static const WCHAR ExecSeqQuery
[] =
695 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
696 '`','I','n','s','t','a','l','l',
697 'U','I','S','e','q','u','e','n','c','e','`',
698 ' ','W','H','E','R','E',' ',
699 '`','S','e','q','u','e','n','c','e','`',' ',
700 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
701 '`','S','e','q','u','e','n','c','e','`',0};
702 iterate_action_param iap
;
704 iap
.package
= package
;
707 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
709 if (rc
== ERROR_SUCCESS
)
711 TRACE("Running the actions \n");
713 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_Actions
, &iap
);
714 msiobj_release(&view
->hdr
);
720 /********************************************************
721 * ACTION helper functions and functions that perform the actions
722 *******************************************************/
723 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
724 UINT
* rc
, BOOL force
)
730 if (!run
&& !package
->script
->CurrentlyScripting
)
735 if (strcmpW(action
,szInstallFinalize
) == 0 ||
736 strcmpW(action
,szInstallExecute
) == 0 ||
737 strcmpW(action
,szInstallExecuteAgain
) == 0)
742 while (StandardActions
[i
].action
!= NULL
)
744 if (strcmpW(StandardActions
[i
].action
, action
)==0)
748 ui_actioninfo(package
, action
, TRUE
, 0);
749 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
750 ui_actioninfo(package
, action
, FALSE
, *rc
);
754 ui_actionstart(package
, action
);
755 if (StandardActions
[i
].handler
)
757 *rc
= StandardActions
[i
].handler(package
);
761 FIXME("unhandled standard action %s\n",debugstr_w(action
));
773 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
774 UINT
* rc
, BOOL force
)
779 arc
= ACTION_CustomAction(package
,action
, force
);
781 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
790 * A lot of actions are really important even if they don't do anything
791 * explicit... Lots of properties are set at the beginning of the installation
792 * CostFinalize does a bunch of work to translate the directories and such
794 * But until I get write access to the database that is hard, so I am going to
795 * hack it to see if I can get something to run.
797 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, BOOL force
)
799 UINT rc
= ERROR_SUCCESS
;
802 TRACE("Performing action (%s)\n",debugstr_w(action
));
804 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
807 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, force
);
811 FIXME("unhandled msi action %s\n",debugstr_w(action
));
812 rc
= ERROR_FUNCTION_NOT_CALLED
;
818 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
820 UINT rc
= ERROR_SUCCESS
;
821 BOOL handled
= FALSE
;
823 TRACE("Performing action (%s)\n",debugstr_w(action
));
825 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
828 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, FALSE
);
830 if( !handled
&& ACTION_DialogBox(package
,action
) == ERROR_SUCCESS
)
835 FIXME("unhandled msi action %s\n",debugstr_w(action
));
836 rc
= ERROR_FUNCTION_NOT_CALLED
;
844 * Actual Action Handlers
847 static UINT
ITERATE_CreateFolders(MSIRECORD
*row
, LPVOID param
)
849 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
855 dir
= MSI_RecordGetString(row
,1);
858 ERR("Unable to get folder id \n");
859 return ERROR_SUCCESS
;
862 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
865 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
866 return ERROR_SUCCESS
;
869 TRACE("Folder is %s\n",debugstr_w(full_path
));
872 uirow
= MSI_CreateRecord(1);
873 MSI_RecordSetStringW(uirow
,1,full_path
);
874 ui_actiondata(package
,szCreateFolders
,uirow
);
875 msiobj_release( &uirow
->hdr
);
877 if (folder
->State
== 0)
878 create_full_pathW(full_path
);
883 return ERROR_SUCCESS
;
888 * Also we cannot enable/disable components either, so for now I am just going
889 * to do all the directories for all the components.
891 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
893 static const WCHAR ExecSeqQuery
[] =
894 {'S','E','L','E','C','T',' ',
895 '`','D','i','r','e','c','t','o','r','y','_','`',
896 ' ','F','R','O','M',' ',
897 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
901 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
902 if (rc
!= ERROR_SUCCESS
)
903 return ERROR_SUCCESS
;
905 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateFolders
, package
);
906 msiobj_release(&view
->hdr
);
911 static MSICOMPONENT
* load_component( MSIRECORD
* row
)
915 comp
= msi_alloc_zero( sizeof(MSICOMPONENT
) );
919 /* fill in the data */
920 comp
->Component
= load_dynamic_stringW( row
, 1 );
922 TRACE("Loading Component %s\n", debugstr_w(comp
->Component
));
924 comp
->ComponentId
= load_dynamic_stringW( row
, 2 );
925 comp
->Directory
= load_dynamic_stringW( row
, 3 );
926 comp
->Attributes
= MSI_RecordGetInteger(row
,4);
927 comp
->Condition
= load_dynamic_stringW( row
, 5 );
928 comp
->KeyPath
= load_dynamic_stringW( row
, 6 );
930 comp
->Installed
= INSTALLSTATE_ABSENT
;
931 comp
->Action
= INSTALLSTATE_UNKNOWN
;
932 comp
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
934 comp
->Enabled
= TRUE
;
944 static UINT
add_feature_component( MSIFEATURE
*feature
, MSICOMPONENT
*comp
)
948 cl
= msi_alloc( sizeof (*cl
) );
950 return ERROR_NOT_ENOUGH_MEMORY
;
951 cl
->component
= comp
;
952 list_add_tail( &feature
->Components
, &cl
->entry
);
954 return ERROR_SUCCESS
;
957 static UINT
iterate_component_check( MSIRECORD
*row
, LPVOID param
)
959 _ilfs
* ilfs
= (_ilfs
*)param
;
960 MSIPACKAGE
*package
= ilfs
->package
;
961 MSIFEATURE
*feature
= ilfs
->feature
;
964 comp
= load_component( row
);
966 return ERROR_FUNCTION_FAILED
;
968 list_add_tail( &package
->components
, &comp
->entry
);
969 add_feature_component( feature
, comp
);
971 TRACE("Loaded new component %p\n", comp
);
973 return ERROR_SUCCESS
;
976 static UINT
iterate_load_featurecomponents(MSIRECORD
*row
, LPVOID param
)
978 _ilfs
* ilfs
= (_ilfs
*)param
;
983 static const WCHAR Query
[] =
984 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
985 '`','C','o','m','p','o','n','e','n','t','`',' ',
986 'W','H','E','R','E',' ',
987 '`','C','o','m','p','o','n','e','n','t','`',' ',
988 '=','\'','%','s','\'',0};
990 component
= MSI_RecordGetString(row
,1);
992 /* check to see if the component is already loaded */
993 comp
= get_loaded_component( ilfs
->package
, component
);
996 TRACE("Component %s already loaded\n", debugstr_w(component
) );
997 add_feature_component( ilfs
->feature
, comp
);
998 return ERROR_SUCCESS
;
1001 rc
= MSI_OpenQuery(ilfs
->package
->db
, &view
, Query
, component
);
1002 if (rc
!= ERROR_SUCCESS
)
1003 return ERROR_SUCCESS
;
1005 rc
= MSI_IterateRecords(view
, NULL
, iterate_component_check
, ilfs
);
1006 msiobj_release( &view
->hdr
);
1008 return ERROR_SUCCESS
;
1011 static UINT
load_feature(MSIRECORD
* row
, LPVOID param
)
1013 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1014 MSIFEATURE
* feature
;
1015 static const WCHAR Query1
[] =
1016 {'S','E','L','E','C','T',' ',
1017 '`','C','o','m','p','o','n','e','n','t','_','`',
1018 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1019 'C','o','m','p','o','n','e','n','t','s','`',' ',
1020 'W','H','E','R','E',' ',
1021 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1026 /* fill in the data */
1028 feature
= msi_alloc_zero( sizeof (MSIFEATURE
) );
1030 return ERROR_NOT_ENOUGH_MEMORY
;
1032 list_init( &feature
->Components
);
1034 feature
->Feature
= load_dynamic_stringW( row
, 1 );
1036 TRACE("Loading feature %s\n",debugstr_w(feature
->Feature
));
1038 feature
->Feature_Parent
= load_dynamic_stringW( row
, 2 );
1039 feature
->Title
= load_dynamic_stringW( row
, 3 );
1040 feature
->Description
= load_dynamic_stringW( row
, 4 );
1042 if (!MSI_RecordIsNull(row
,5))
1043 feature
->Display
= MSI_RecordGetInteger(row
,5);
1045 feature
->Level
= MSI_RecordGetInteger(row
,6);
1046 feature
->Directory
= load_dynamic_stringW( row
, 7 );
1047 feature
->Attributes
= MSI_RecordGetInteger(row
,8);
1049 feature
->Installed
= INSTALLSTATE_ABSENT
;
1050 feature
->Action
= INSTALLSTATE_UNKNOWN
;
1051 feature
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1053 list_add_tail( &package
->features
, &feature
->entry
);
1055 /* load feature components */
1057 rc
= MSI_OpenQuery( package
->db
, &view
, Query1
, feature
->Feature
);
1058 if (rc
!= ERROR_SUCCESS
)
1059 return ERROR_SUCCESS
;
1061 ilfs
.package
= package
;
1062 ilfs
.feature
= feature
;
1064 MSI_IterateRecords(view
, NULL
, iterate_load_featurecomponents
, &ilfs
);
1065 msiobj_release(&view
->hdr
);
1067 return ERROR_SUCCESS
;
1070 static UINT
load_file(MSIRECORD
*row
, LPVOID param
)
1072 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
1076 /* fill in the data */
1078 file
= msi_alloc_zero( sizeof (MSIFILE
) );
1080 return ERROR_NOT_ENOUGH_MEMORY
;
1082 file
->File
= load_dynamic_stringW( row
, 1 );
1084 component
= MSI_RecordGetString( row
, 2 );
1085 file
->Component
= get_loaded_component( package
, component
);
1087 if (!file
->Component
)
1088 ERR("Unfound Component %s\n",debugstr_w(component
));
1090 file
->FileName
= load_dynamic_stringW( row
, 3 );
1091 reduce_to_longfilename( file
->FileName
);
1093 file
->ShortName
= load_dynamic_stringW( row
, 3 );
1094 reduce_to_shortfilename( file
->ShortName
);
1096 file
->FileSize
= MSI_RecordGetInteger( row
, 4 );
1097 file
->Version
= load_dynamic_stringW( row
, 5 );
1098 file
->Language
= load_dynamic_stringW( row
, 6 );
1099 file
->Attributes
= MSI_RecordGetInteger( row
, 7 );
1100 file
->Sequence
= MSI_RecordGetInteger( row
, 8 );
1104 TRACE("File Loaded (%s)\n",debugstr_w(file
->File
));
1106 list_add_tail( &package
->files
, &file
->entry
);
1108 return ERROR_SUCCESS
;
1111 static UINT
load_all_files(MSIPACKAGE
*package
)
1115 static const WCHAR Query
[] =
1116 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1117 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1118 '`','S','e','q','u','e','n','c','e','`', 0};
1121 return ERROR_INVALID_HANDLE
;
1123 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1124 if (rc
!= ERROR_SUCCESS
)
1125 return ERROR_SUCCESS
;
1127 rc
= MSI_IterateRecords(view
, NULL
, load_file
, package
);
1128 msiobj_release(&view
->hdr
);
1130 return ERROR_SUCCESS
;
1135 * I am not doing any of the costing functionality yet.
1136 * Mostly looking at doing the Component and Feature loading
1138 * The native MSI does A LOT of modification to tables here. Mostly adding
1139 * a lot of temporary columns to the Feature and Component tables.
1141 * note: Native msi also tracks the short filename. But I am only going to
1142 * track the long ones. Also looking at this directory table
1143 * it appears that the directory table does not get the parents
1144 * resolved base on property only based on their entries in the
1147 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1151 static const WCHAR Query_all
[] =
1152 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1153 '`','F','e','a','t','u','r','e','`',0};
1154 static const WCHAR szCosting
[] =
1155 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1156 static const WCHAR szZero
[] = { '0', 0 };
1160 MSI_GetPropertyW(package
, szCosting
, buffer
, &sz
);
1162 return ERROR_SUCCESS
;
1164 MSI_SetPropertyW(package
, szCosting
, szZero
);
1165 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1167 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1168 if (rc
!= ERROR_SUCCESS
)
1171 rc
= MSI_IterateRecords(view
, NULL
, load_feature
, package
);
1172 msiobj_release(&view
->hdr
);
1174 load_all_files(package
);
1176 return ERROR_SUCCESS
;
1179 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
1182 UINT rc
= ERROR_SUCCESS
;
1184 TRACE("Executing Script %i\n",script
);
1186 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
1189 action
= package
->script
->Actions
[script
][i
];
1190 ui_actionstart(package
, action
);
1191 TRACE("Executing Action (%s)\n",debugstr_w(action
));
1192 rc
= ACTION_PerformAction(package
, action
, TRUE
);
1193 msi_free(package
->script
->Actions
[script
][i
]);
1194 if (rc
!= ERROR_SUCCESS
)
1197 msi_free(package
->script
->Actions
[script
]);
1199 package
->script
->ActionCount
[script
] = 0;
1200 package
->script
->Actions
[script
] = NULL
;
1204 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1206 return ERROR_SUCCESS
;
1210 static MSIFOLDER
*load_folder( MSIPACKAGE
*package
, LPCWSTR dir
)
1212 static const WCHAR Query
[] =
1213 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1214 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1215 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1216 ' ','=',' ','\'','%','s','\'',
1218 LPWSTR ptargetdir
, targetdir
, srcdir
;
1220 LPWSTR shortname
= NULL
;
1221 MSIRECORD
* row
= 0;
1224 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1226 folder
= get_loaded_folder( package
, dir
);
1230 TRACE("Working to load %s\n",debugstr_w(dir
));
1232 folder
= msi_alloc_zero( sizeof (MSIFOLDER
) );
1236 folder
->Directory
= strdupW(dir
);
1238 row
= MSI_QueryGetRecord(package
->db
, Query
, dir
);
1242 ptargetdir
= targetdir
= load_dynamic_stringW(row
,3);
1244 /* split src and target dir */
1245 if (strchrW(targetdir
,':'))
1247 srcdir
=strchrW(targetdir
,':');
1254 /* for now only pick long filename versions */
1255 if (strchrW(targetdir
,'|'))
1257 shortname
= targetdir
;
1258 targetdir
= strchrW(targetdir
,'|');
1262 /* for the sourcedir pick the short filename */
1263 if (srcdir
&& strchrW(srcdir
,'|'))
1265 LPWSTR p
= strchrW(srcdir
,'|');
1269 /* now check for root dirs */
1270 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1275 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1276 msi_free( folder
->TargetDefault
);
1277 folder
->TargetDefault
= strdupW(targetdir
);
1281 folder
->SourceDefault
= strdupW(srcdir
);
1283 folder
->SourceDefault
= strdupW(shortname
);
1285 folder
->SourceDefault
= strdupW(targetdir
);
1286 msi_free(ptargetdir
);
1287 TRACE(" SourceDefault = %s\n", debugstr_w( folder
->SourceDefault
));
1289 parent
= MSI_RecordGetString(row
,2);
1292 folder
->Parent
= load_folder( package
, parent
);
1293 if ( folder
->Parent
)
1294 TRACE("loaded parent %p %s\n", folder
->Parent
,
1295 debugstr_w(folder
->Parent
->Directory
));
1297 ERR("failed to load parent folder %s\n", debugstr_w(parent
));
1300 folder
->Property
= msi_dup_property( package
, dir
);
1302 msiobj_release(&row
->hdr
);
1304 list_add_tail( &package
->folders
, &folder
->entry
);
1306 TRACE("%s returning %p\n",debugstr_w(dir
),folder
);
1311 /* scan for and update current install states */
1312 static void ACTION_UpdateInstallStates(MSIPACKAGE
*package
)
1315 MSIFEATURE
*feature
;
1317 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1320 res
= MsiGetComponentPathW( package
->ProductCode
,
1321 comp
->ComponentId
, NULL
, NULL
);
1323 res
= INSTALLSTATE_ABSENT
;
1324 comp
->Installed
= res
;
1327 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1330 INSTALLSTATE res
= -10;
1332 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1334 comp
= cl
->component
;
1337 res
= comp
->Installed
;
1340 if (res
== comp
->Installed
)
1343 if (res
!= comp
->Installed
)
1344 res
= INSTALLSTATE_INCOMPLETE
;
1347 feature
->Installed
= res
;
1351 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
1354 static const WCHAR all
[]={'A','L','L',0};
1356 MSIFEATURE
*feature
;
1358 override
= msi_dup_property( package
, property
);
1362 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1364 if (strcmpiW(override
,all
)==0)
1366 feature
->ActionRequest
= state
;
1367 feature
->Action
= state
;
1371 LPWSTR ptr
= override
;
1372 LPWSTR ptr2
= strchrW(override
,',');
1376 if ((ptr2
&& strncmpW(ptr
,feature
->Feature
, ptr2
-ptr
)==0)
1377 || (!ptr2
&& strcmpW(ptr
,feature
->Feature
)==0))
1379 feature
->ActionRequest
= state
;
1380 feature
->Action
= state
;
1386 ptr2
= strchrW(ptr
,',');
1398 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
1401 static const WCHAR szlevel
[] =
1402 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1403 static const WCHAR szAddLocal
[] =
1404 {'A','D','D','L','O','C','A','L',0};
1405 static const WCHAR szRemove
[] =
1406 {'R','E','M','O','V','E',0};
1407 BOOL override
= FALSE
;
1408 MSICOMPONENT
* component
;
1409 MSIFEATURE
*feature
;
1412 /* I do not know if this is where it should happen.. but */
1414 TRACE("Checking Install Level\n");
1416 install_level
= msi_get_property_int( package
, szlevel
, 1 );
1418 /* ok hereis the _real_ rub
1419 * all these activation/deactivation things happen in order and things
1420 * later on the list override things earlier on the list.
1421 * 1) INSTALLLEVEL processing
1431 * 11) FILEADDDEFAULT
1432 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1433 * ignored for all the features. seems strange, especially since it is not
1434 * documented anywhere, but it is how it works.
1436 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1437 * REMOVE are the big ones, since we don't handle administrative installs
1440 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
1441 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
1445 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1447 BOOL feature_state
= ((feature
->Level
> 0) &&
1448 (feature
->Level
<= install_level
));
1450 if ((feature_state
) && (feature
->Action
== INSTALLSTATE_UNKNOWN
))
1452 if (feature
->Attributes
& msidbFeatureAttributesFavorSource
)
1454 feature
->ActionRequest
= INSTALLSTATE_SOURCE
;
1455 feature
->Action
= INSTALLSTATE_SOURCE
;
1457 else if (feature
->Attributes
& msidbFeatureAttributesFavorAdvertise
)
1459 feature
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1460 feature
->Action
= INSTALLSTATE_ADVERTISED
;
1464 feature
->ActionRequest
= INSTALLSTATE_LOCAL
;
1465 feature
->Action
= INSTALLSTATE_LOCAL
;
1472 /* set the Preselected Property */
1473 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1474 static const WCHAR szOne
[] = { '1', 0 };
1476 MSI_SetPropertyW(package
,szPreselected
,szOne
);
1480 * now we want to enable or disable components base on feature
1483 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
1487 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1488 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
1489 feature
->ActionRequest
);
1491 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
1493 component
= cl
->component
;
1495 if (!component
->Enabled
)
1497 component
->Action
= INSTALLSTATE_UNKNOWN
;
1498 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
1502 if (feature
->Action
== INSTALLSTATE_LOCAL
)
1504 component
->Action
= INSTALLSTATE_LOCAL
;
1505 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
1507 else if (feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
1509 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1510 (component
->Action
== INSTALLSTATE_ABSENT
) ||
1511 (component
->Action
== INSTALLSTATE_ADVERTISED
))
1514 component
->Action
= INSTALLSTATE_SOURCE
;
1515 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
1518 else if (feature
->ActionRequest
== INSTALLSTATE_ADVERTISED
)
1520 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
1521 (component
->Action
== INSTALLSTATE_ABSENT
))
1524 component
->Action
= INSTALLSTATE_ADVERTISED
;
1525 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
1528 else if (feature
->ActionRequest
== INSTALLSTATE_ABSENT
)
1530 if (component
->Action
== INSTALLSTATE_UNKNOWN
)
1532 component
->Action
= INSTALLSTATE_ABSENT
;
1533 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
1540 LIST_FOR_EACH_ENTRY( component
, &package
->components
, MSICOMPONENT
, entry
)
1542 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1543 debugstr_w(component
->Component
), component
->Installed
,
1544 component
->Action
, component
->ActionRequest
);
1548 return ERROR_SUCCESS
;
1551 static UINT
ITERATE_CostFinalizeDirectories(MSIRECORD
*row
, LPVOID param
)
1553 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1557 name
= MSI_RecordGetString(row
,1);
1559 /* This helper function now does ALL the work */
1560 TRACE("Dir %s ...\n",debugstr_w(name
));
1561 load_folder(package
,name
);
1562 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
1563 TRACE("resolves to %s\n",debugstr_w(path
));
1566 return ERROR_SUCCESS
;
1569 static UINT
ITERATE_CostFinalizeConditions(MSIRECORD
*row
, LPVOID param
)
1571 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1573 MSIFEATURE
*feature
;
1575 name
= MSI_RecordGetString( row
, 1 );
1577 feature
= get_loaded_feature( package
, name
);
1579 ERR("FAILED to find loaded feature %s\n",debugstr_w(name
));
1583 Condition
= MSI_RecordGetString(row
,3);
1585 if (MSI_EvaluateConditionW(package
,Condition
) == MSICONDITION_TRUE
)
1587 int level
= MSI_RecordGetInteger(row
,2);
1588 TRACE("Reseting feature %s to level %i\n", debugstr_w(name
), level
);
1589 feature
->Level
= level
;
1592 return ERROR_SUCCESS
;
1597 * A lot is done in this function aside from just the costing.
1598 * The costing needs to be implemented at some point but for now I am going
1599 * to focus on the directory building
1602 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1604 static const WCHAR ExecSeqQuery
[] =
1605 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1606 '`','D','i','r','e','c','t','o','r','y','`',0};
1607 static const WCHAR ConditionQuery
[] =
1608 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1609 '`','C','o','n','d','i','t','i','o','n','`',0};
1610 static const WCHAR szCosting
[] =
1611 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1612 static const WCHAR szlevel
[] =
1613 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1614 static const WCHAR szOne
[] = { '1', 0 };
1623 MSI_GetPropertyW(package
, szCosting
, buffer
, &sz
);
1625 return ERROR_SUCCESS
;
1627 TRACE("Building Directory properties\n");
1629 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1630 if (rc
== ERROR_SUCCESS
)
1632 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeDirectories
,
1634 msiobj_release(&view
->hdr
);
1637 TRACE("File calculations\n");
1639 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
1641 MSICOMPONENT
* comp
= file
->Component
;
1647 /* calculate target */
1648 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
1650 msi_free(file
->TargetPath
);
1652 TRACE("file %s is named %s\n",
1653 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
1655 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
1659 TRACE("file %s resolves to %s\n",
1660 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
1662 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
1665 comp
->Cost
+= file
->FileSize
;
1675 static const WCHAR name
[] =
1677 static const WCHAR name_fmt
[] =
1678 {'%','u','.','%','u','.','%','u','.','%','u',0};
1679 WCHAR filever
[0x100];
1680 VS_FIXEDFILEINFO
*lpVer
;
1682 TRACE("Version comparison.. \n");
1683 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
1684 version
= msi_alloc(versize
);
1685 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
1687 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
1689 sprintfW(filever
,name_fmt
,
1690 HIWORD(lpVer
->dwFileVersionMS
),
1691 LOWORD(lpVer
->dwFileVersionMS
),
1692 HIWORD(lpVer
->dwFileVersionLS
),
1693 LOWORD(lpVer
->dwFileVersionLS
));
1695 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
1696 debugstr_w(filever
));
1697 if (strcmpiW(filever
,file
->Version
)<0)
1700 FIXME("cost should be diff in size\n");
1701 comp
->Cost
+= file
->FileSize
;
1711 TRACE("Evaluating Condition Table\n");
1713 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
1714 if (rc
== ERROR_SUCCESS
)
1716 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CostFinalizeConditions
,
1718 msiobj_release(&view
->hdr
);
1721 TRACE("Enabling or Disabling Components\n");
1722 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
1724 if (comp
->Condition
)
1726 if (MSI_EvaluateConditionW(package
,
1727 comp
->Condition
) == MSICONDITION_FALSE
)
1729 TRACE("Disabling component %s\n", debugstr_w(comp
->Component
));
1730 comp
->Enabled
= FALSE
;
1735 MSI_SetPropertyW(package
,szCosting
,szOne
);
1736 /* set default run level if not set */
1737 level
= msi_dup_property( package
, szlevel
);
1739 MSI_SetPropertyW(package
,szlevel
, szOne
);
1742 ACTION_UpdateInstallStates(package
);
1744 return SetFeatureStates(package
);
1747 /* OK this value is "interpreted" and then formatted based on the
1748 first few characters */
1749 static LPSTR
parse_value(MSIPACKAGE
*package
, LPCWSTR value
, DWORD
*type
,
1753 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
1759 LPWSTR deformated
= NULL
;
1762 deformat_string(package
, &value
[2], &deformated
);
1764 /* binary value type */
1768 *size
= (strlenW(ptr
)/2)+1;
1770 *size
= strlenW(ptr
)/2;
1772 data
= msi_alloc(*size
);
1778 /* if uneven pad with a zero in front */
1784 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
1786 TRACE("Uneven byte count\n");
1794 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
1797 msi_free(deformated
);
1799 TRACE("Data %li bytes(%i)\n",*size
,count
);
1806 deformat_string(package
, &value
[1], &deformated
);
1809 *size
= sizeof(DWORD
);
1810 data
= msi_alloc(*size
);
1816 if ( (*p
< '0') || (*p
> '9') )
1822 if (deformated
[0] == '-')
1825 TRACE("DWORD %li\n",*(LPDWORD
)data
);
1827 msi_free(deformated
);
1832 static const WCHAR szMulti
[] = {'[','~',']',0};
1841 *type
=REG_EXPAND_SZ
;
1849 if (strstrW(value
,szMulti
))
1850 *type
= REG_MULTI_SZ
;
1852 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
1857 static UINT
ITERATE_WriteRegistryValues(MSIRECORD
*row
, LPVOID param
)
1859 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
1860 static const WCHAR szHCR
[] =
1861 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
1862 'R','O','O','T','\\',0};
1863 static const WCHAR szHCU
[] =
1864 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
1865 'U','S','E','R','\\',0};
1866 static const WCHAR szHLM
[] =
1867 {'H','K','E','Y','_','L','O','C','A','L','_',
1868 'M','A','C','H','I','N','E','\\',0};
1869 static const WCHAR szHU
[] =
1870 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
1872 LPSTR value_data
= NULL
;
1873 HKEY root_key
, hkey
;
1876 LPCWSTR szRoot
, component
, name
, key
, value
;
1881 BOOL check_first
= FALSE
;
1884 ui_progress(package
,2,0,0,0);
1891 component
= MSI_RecordGetString(row
, 6);
1892 comp
= get_loaded_component(package
,component
);
1894 return ERROR_SUCCESS
;
1896 if (!ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_LOCAL
))
1898 TRACE("Skipping write due to disabled component %s\n",
1899 debugstr_w(component
));
1901 comp
->Action
= comp
->Installed
;
1903 return ERROR_SUCCESS
;
1906 comp
->Action
= INSTALLSTATE_LOCAL
;
1908 name
= MSI_RecordGetString(row
, 4);
1909 if( MSI_RecordIsNull(row
,5) && name
)
1911 /* null values can have special meanings */
1912 if (name
[0]=='-' && name
[1] == 0)
1913 return ERROR_SUCCESS
;
1914 else if ((name
[0]=='+' && name
[1] == 0) ||
1915 (name
[0] == '*' && name
[1] == 0))
1920 root
= MSI_RecordGetInteger(row
,2);
1921 key
= MSI_RecordGetString(row
, 3);
1923 /* get the root key */
1928 static const WCHAR szALLUSER
[] = {'A','L','L','U','S','E','R','S',0};
1929 LPWSTR all_users
= msi_dup_property( package
, szALLUSER
);
1930 if (all_users
&& all_users
[0] == '1')
1932 root_key
= HKEY_LOCAL_MACHINE
;
1937 root_key
= HKEY_CURRENT_USER
;
1940 msi_free(all_users
);
1943 case 0: root_key
= HKEY_CLASSES_ROOT
;
1946 case 1: root_key
= HKEY_CURRENT_USER
;
1949 case 2: root_key
= HKEY_LOCAL_MACHINE
;
1952 case 3: root_key
= HKEY_USERS
;
1956 ERR("Unknown root %i\n",root
);
1962 return ERROR_SUCCESS
;
1964 deformat_string(package
, key
, &deformated
);
1965 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
1966 uikey
= msi_alloc(size
*sizeof(WCHAR
));
1967 strcpyW(uikey
,szRoot
);
1968 strcatW(uikey
,deformated
);
1970 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
1972 ERR("Could not create key %s\n",debugstr_w(deformated
));
1973 msi_free(deformated
);
1975 return ERROR_SUCCESS
;
1977 msi_free(deformated
);
1979 value
= MSI_RecordGetString(row
,5);
1981 value_data
= parse_value(package
, value
, &type
, &size
);
1984 static const WCHAR szEmpty
[] = {0};
1985 value_data
= (LPSTR
)strdupW(szEmpty
);
1990 deformat_string(package
, name
, &deformated
);
1992 /* get the double nulls to terminate SZ_MULTI */
1993 if (type
== REG_MULTI_SZ
)
1994 size
+=sizeof(WCHAR
);
1998 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
2000 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
)value_data
, size
);
2005 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
2006 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
2008 TRACE("value %s of %s checked already exists\n",
2009 debugstr_w(deformated
), debugstr_w(uikey
));
2013 TRACE("Checked and setting value %s of %s\n",
2014 debugstr_w(deformated
), debugstr_w(uikey
));
2015 if (deformated
|| size
)
2016 RegSetValueExW(hkey
, deformated
, 0, type
, (LPBYTE
) value_data
, size
);
2021 uirow
= MSI_CreateRecord(3);
2022 MSI_RecordSetStringW(uirow
,2,deformated
);
2023 MSI_RecordSetStringW(uirow
,1,uikey
);
2026 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
2028 MSI_RecordSetStringW(uirow
,3,value
);
2030 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
2031 msiobj_release( &uirow
->hdr
);
2033 msi_free(value_data
);
2034 msi_free(deformated
);
2037 return ERROR_SUCCESS
;
2040 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2044 static const WCHAR ExecSeqQuery
[] =
2045 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2046 '`','R','e','g','i','s','t','r','y','`',0 };
2049 return ERROR_INVALID_HANDLE
;
2051 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2052 if (rc
!= ERROR_SUCCESS
)
2053 return ERROR_SUCCESS
;
2055 /* increment progress bar each time action data is sent */
2056 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2058 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteRegistryValues
, package
);
2060 msiobj_release(&view
->hdr
);
2064 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
2066 package
->script
->CurrentlyScripting
= TRUE
;
2068 return ERROR_SUCCESS
;
2072 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
2077 static const WCHAR q1
[]=
2078 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2079 '`','R','e','g','i','s','t','r','y','`',0};
2082 MSIFEATURE
*feature
;
2085 TRACE("InstallValidate\n");
2087 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
2088 if (rc
== ERROR_SUCCESS
)
2090 MSI_IterateRecords( view
, &progress
, NULL
, package
);
2091 msiobj_release( &view
->hdr
);
2092 total
+= progress
* REG_PROGRESS_VALUE
;
2095 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2096 total
+= COMPONENT_PROGRESS_VALUE
;
2098 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2099 total
+= file
->FileSize
;
2101 ui_progress(package
,0,total
,0,0);
2103 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2105 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2106 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2107 feature
->ActionRequest
);
2110 return ERROR_SUCCESS
;
2113 static UINT
ITERATE_LaunchConditions(MSIRECORD
*row
, LPVOID param
)
2115 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2116 LPCWSTR cond
= NULL
;
2117 LPCWSTR message
= NULL
;
2118 static const WCHAR title
[]=
2119 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2121 cond
= MSI_RecordGetString(row
,1);
2123 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
2126 message
= MSI_RecordGetString(row
,2);
2127 deformat_string(package
,message
,&deformated
);
2128 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
2129 msi_free(deformated
);
2130 return ERROR_FUNCTION_FAILED
;
2133 return ERROR_SUCCESS
;
2136 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
2139 MSIQUERY
* view
= NULL
;
2140 static const WCHAR ExecSeqQuery
[] =
2141 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2142 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2144 TRACE("Checking launch conditions\n");
2146 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2147 if (rc
!= ERROR_SUCCESS
)
2148 return ERROR_SUCCESS
;
2150 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_LaunchConditions
, package
);
2151 msiobj_release(&view
->hdr
);
2156 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, MSICOMPONENT
*cmp
)
2160 return resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
2162 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
2164 MSIRECORD
* row
= 0;
2166 LPWSTR deformated
,buffer
,deformated_name
;
2168 static const WCHAR ExecSeqQuery
[] =
2169 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2170 '`','R','e','g','i','s','t','r','y','`',' ',
2171 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2172 ' ','=',' ' ,'\'','%','s','\'',0 };
2173 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
2174 static const WCHAR fmt2
[]=
2175 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2177 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
2181 root
= MSI_RecordGetInteger(row
,2);
2182 key
= MSI_RecordGetString(row
, 3);
2183 name
= MSI_RecordGetString(row
, 4);
2184 deformat_string(package
, key
, &deformated
);
2185 deformat_string(package
, name
, &deformated_name
);
2187 len
= strlenW(deformated
) + 6;
2188 if (deformated_name
)
2189 len
+=strlenW(deformated_name
);
2191 buffer
= msi_alloc( len
*sizeof(WCHAR
));
2193 if (deformated_name
)
2194 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
2196 sprintfW(buffer
,fmt
,root
,deformated
);
2198 msi_free(deformated
);
2199 msi_free(deformated_name
);
2200 msiobj_release(&row
->hdr
);
2204 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2206 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2211 MSIFILE
*file
= get_loaded_file( package
, cmp
->KeyPath
);
2214 return strdupW( file
->TargetPath
);
2219 static HKEY
openSharedDLLsKey(void)
2222 static const WCHAR path
[] =
2223 {'S','o','f','t','w','a','r','e','\\',
2224 'M','i','c','r','o','s','o','f','t','\\',
2225 'W','i','n','d','o','w','s','\\',
2226 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2227 'S','h','a','r','e','d','D','L','L','s',0};
2229 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
2233 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
2238 DWORD sz
= sizeof(count
);
2241 hkey
= openSharedDLLsKey();
2242 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
2243 if (rc
!= ERROR_SUCCESS
)
2249 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
2253 hkey
= openSharedDLLsKey();
2255 msi_reg_set_val_dword( hkey
, path
, count
);
2257 RegDeleteValueW(hkey
,path
);
2263 * Return TRUE if the count should be written out and FALSE if not
2265 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, MSICOMPONENT
*comp
)
2267 MSIFEATURE
*feature
;
2271 /* only refcount DLLs */
2272 if (comp
->KeyPath
== NULL
||
2273 comp
->Attributes
& msidbComponentAttributesRegistryKeyPath
||
2274 comp
->Attributes
& msidbComponentAttributesODBCDataSource
)
2278 count
= ACTION_GetSharedDLLsCount( comp
->FullKeypath
);
2279 write
= (count
> 0);
2281 if (comp
->Attributes
& msidbComponentAttributesSharedDllRefCount
)
2285 /* increment counts */
2286 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2290 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
))
2293 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2295 if ( cl
->component
== comp
)
2300 /* decrement counts */
2301 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
2305 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ABSENT
))
2308 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
2310 if ( cl
->component
== comp
)
2315 /* ref count all the files in the component */
2320 LIST_FOR_EACH_ENTRY( file
, &package
->files
, MSIFILE
, entry
)
2322 if (file
->Component
== comp
)
2323 ACTION_WriteSharedDLLsCount( file
->TargetPath
, count
);
2327 /* add a count for permenent */
2328 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2331 comp
->RefCount
= count
;
2334 ACTION_WriteSharedDLLsCount( comp
->FullKeypath
, comp
->RefCount
);
2338 * Ok further analysis makes me think that this work is
2339 * actually done in the PublishComponents and PublishFeatures
2340 * step, and not here. It appears like the keypath and all that is
2341 * resolved in this step, however actually written in the Publish steps.
2342 * But we will leave it here for now because it is unclear
2344 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
2346 WCHAR squished_pc
[GUID_SIZE
];
2347 WCHAR squished_cc
[GUID_SIZE
];
2350 HKEY hkey
=0,hkey2
=0;
2353 return ERROR_INVALID_HANDLE
;
2355 /* writes the Component and Features values to the registry */
2357 rc
= MSIREG_OpenComponents(&hkey
);
2358 if (rc
!= ERROR_SUCCESS
)
2361 squash_guid(package
->ProductCode
,squished_pc
);
2362 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
2364 LIST_FOR_EACH_ENTRY( comp
, &package
->components
, MSICOMPONENT
, entry
)
2366 ui_progress(package
,2,0,0,0);
2367 if (comp
->ComponentId
)
2371 squash_guid(comp
->ComponentId
,squished_cc
);
2373 msi_free(comp
->FullKeypath
);
2374 comp
->FullKeypath
= resolve_keypath( package
, comp
);
2376 /* do the refcounting */
2377 ACTION_RefCountComponent( package
, comp
);
2379 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2380 debugstr_w(comp
->Component
),
2381 debugstr_w(squished_cc
),
2382 debugstr_w(comp
->FullKeypath
),
2385 * Write the keypath out if the component is to be registered
2386 * and delete the key if the component is to be deregistered
2388 if (ACTION_VerifyComponentForAction(package
, comp
,
2389 INSTALLSTATE_LOCAL
))
2391 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
2392 if (rc
!= ERROR_SUCCESS
)
2395 if (comp
->FullKeypath
)
2397 msi_reg_set_val_str( hkey2
, squished_pc
, comp
->FullKeypath
);
2399 if (comp
->Attributes
& msidbComponentAttributesPermanent
)
2401 static const WCHAR szPermKey
[] =
2402 { '0','0','0','0','0','0','0','0','0','0','0','0',
2403 '0','0','0','0','0','0','0','0','0','0','0','0',
2404 '0','0','0','0','0','0','0','0',0};
2406 msi_reg_set_val_str( hkey2
, szPermKey
, comp
->FullKeypath
);
2412 uirow
= MSI_CreateRecord(3);
2413 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2414 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2415 MSI_RecordSetStringW(uirow
,3,comp
->FullKeypath
);
2416 ui_actiondata(package
,szProcessComponents
,uirow
);
2417 msiobj_release( &uirow
->hdr
);
2420 else if (ACTION_VerifyComponentForAction(package
, comp
,
2421 INSTALLSTATE_ABSENT
))
2425 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
2426 if (rc
!= ERROR_SUCCESS
)
2429 RegDeleteValueW(hkey2
,squished_pc
);
2431 /* if the key is empty delete it */
2432 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
2434 if (res
== ERROR_NO_MORE_ITEMS
)
2435 RegDeleteKeyW(hkey
,squished_cc
);
2438 uirow
= MSI_CreateRecord(2);
2439 MSI_RecordSetStringW(uirow
,1,package
->ProductCode
);
2440 MSI_RecordSetStringW(uirow
,2,comp
->ComponentId
);
2441 ui_actiondata(package
,szProcessComponents
,uirow
);
2442 msiobj_release( &uirow
->hdr
);
2459 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
2460 LPWSTR lpszName
, LONG_PTR lParam
)
2463 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
2464 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
2468 if (!IS_INTRESOURCE(lpszName
))
2470 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
2474 sz
= strlenW(tl_struct
->source
)+4;
2475 sz
*= sizeof(WCHAR
);
2477 if ((INT
)lpszName
== 1)
2478 tl_struct
->path
= strdupW(tl_struct
->source
);
2481 tl_struct
->path
= msi_alloc(sz
);
2482 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
2485 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
2486 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
2487 if (!SUCCEEDED(res
))
2489 msi_free(tl_struct
->path
);
2490 tl_struct
->path
= NULL
;
2495 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
2496 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
2498 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2502 msi_free(tl_struct
->path
);
2503 tl_struct
->path
= NULL
;
2505 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
2506 ITypeLib_Release(tl_struct
->ptLib
);
2511 static UINT
ITERATE_RegisterTypeLibraries(MSIRECORD
*row
, LPVOID param
)
2513 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2517 typelib_struct tl_struct
;
2519 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
2521 component
= MSI_RecordGetString(row
,3);
2522 comp
= get_loaded_component(package
,component
);
2524 return ERROR_SUCCESS
;
2526 if (!ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_LOCAL
))
2528 TRACE("Skipping typelib reg due to disabled component\n");
2530 comp
->Action
= comp
->Installed
;
2532 return ERROR_SUCCESS
;
2535 comp
->Action
= INSTALLSTATE_LOCAL
;
2537 file
= get_loaded_file( package
, comp
->KeyPath
);
2539 return ERROR_SUCCESS
;
2541 module
= LoadLibraryExW( file
->TargetPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
2545 guid
= load_dynamic_stringW(row
,1);
2546 CLSIDFromString(guid
, &tl_struct
.clsid
);
2548 tl_struct
.source
= strdupW( file
->TargetPath
);
2549 tl_struct
.path
= NULL
;
2551 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
2552 (LONG_PTR
)&tl_struct
);
2554 if (tl_struct
.path
!= NULL
)
2560 helpid
= MSI_RecordGetString(row
,6);
2563 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
2564 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
2567 if (!SUCCEEDED(res
))
2568 ERR("Failed to register type library %s\n",
2569 debugstr_w(tl_struct
.path
));
2572 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
2574 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
2577 ITypeLib_Release(tl_struct
.ptLib
);
2578 msi_free(tl_struct
.path
);
2581 ERR("Failed to load type library %s\n",
2582 debugstr_w(tl_struct
.source
));
2584 FreeLibrary(module
);
2585 msi_free(tl_struct
.source
);
2588 ERR("Could not load file! %s\n", debugstr_w(file
->TargetPath
));
2590 return ERROR_SUCCESS
;
2593 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
2596 * OK this is a bit confusing.. I am given a _Component key and I believe
2597 * that the file that is being registered as a type library is the "key file
2598 * of that component" which I interpret to mean "The file in the KeyPath of
2603 static const WCHAR Query
[] =
2604 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2605 '`','T','y','p','e','L','i','b','`',0};
2608 return ERROR_INVALID_HANDLE
;
2610 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2611 if (rc
!= ERROR_SUCCESS
)
2612 return ERROR_SUCCESS
;
2614 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_RegisterTypeLibraries
, package
);
2615 msiobj_release(&view
->hdr
);
2619 static UINT
ITERATE_CreateShortcuts(MSIRECORD
*row
, LPVOID param
)
2621 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2622 LPWSTR target_file
, target_folder
;
2624 WCHAR filename
[0x100];
2627 static const WCHAR szlnk
[]={'.','l','n','k',0};
2632 buffer
= MSI_RecordGetString(row
,4);
2633 comp
= get_loaded_component(package
,buffer
);
2635 return ERROR_SUCCESS
;
2637 if (!ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_LOCAL
))
2639 TRACE("Skipping shortcut creation due to disabled component\n");
2641 comp
->Action
= comp
->Installed
;
2643 return ERROR_SUCCESS
;
2646 comp
->Action
= INSTALLSTATE_LOCAL
;
2648 ui_actiondata(package
,szCreateShortcuts
,row
);
2650 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
2651 &IID_IShellLinkW
, (LPVOID
*) &sl
);
2655 ERR("Is IID_IShellLink\n");
2656 return ERROR_SUCCESS
;
2659 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
2662 ERR("Is IID_IPersistFile\n");
2663 return ERROR_SUCCESS
;
2666 buffer
= MSI_RecordGetString(row
,2);
2667 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
2669 /* may be needed because of a bug somehwere else */
2670 create_full_pathW(target_folder
);
2673 MSI_RecordGetStringW(row
,3,filename
,&sz
);
2674 reduce_to_longfilename(filename
);
2675 if (!strchrW(filename
,'.') || strcmpiW(strchrW(filename
,'.'),szlnk
))
2676 strcatW(filename
,szlnk
);
2677 target_file
= build_directory_name(2, target_folder
, filename
);
2678 msi_free(target_folder
);
2680 buffer
= MSI_RecordGetString(row
,5);
2681 if (strchrW(buffer
,'['))
2684 deformat_string(package
,buffer
,&deformated
);
2685 IShellLinkW_SetPath(sl
,deformated
);
2686 msi_free(deformated
);
2690 FIXME("poorly handled shortcut format, advertised shortcut\n");
2691 IShellLinkW_SetPath(sl
,comp
->FullKeypath
);
2694 if (!MSI_RecordIsNull(row
,6))
2697 buffer
= MSI_RecordGetString(row
,6);
2698 deformat_string(package
,buffer
,&deformated
);
2699 IShellLinkW_SetArguments(sl
,deformated
);
2700 msi_free(deformated
);
2703 if (!MSI_RecordIsNull(row
,7))
2705 buffer
= MSI_RecordGetString(row
,7);
2706 IShellLinkW_SetDescription(sl
,buffer
);
2709 if (!MSI_RecordIsNull(row
,8))
2710 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
2712 if (!MSI_RecordIsNull(row
,9))
2717 buffer
= MSI_RecordGetString(row
,9);
2719 Path
= build_icon_path(package
,buffer
);
2720 index
= MSI_RecordGetInteger(row
,10);
2722 IShellLinkW_SetIconLocation(sl
,Path
,index
);
2726 if (!MSI_RecordIsNull(row
,11))
2727 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
2729 if (!MSI_RecordIsNull(row
,12))
2732 buffer
= MSI_RecordGetString(row
,12);
2733 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
2734 IShellLinkW_SetWorkingDirectory(sl
,Path
);
2738 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
2739 IPersistFile_Save(pf
,target_file
,FALSE
);
2741 msi_free(target_file
);
2743 IPersistFile_Release( pf
);
2744 IShellLinkW_Release( sl
);
2746 return ERROR_SUCCESS
;
2749 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
2754 static const WCHAR Query
[] =
2755 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2756 '`','S','h','o','r','t','c','u','t','`',0};
2759 return ERROR_INVALID_HANDLE
;
2761 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2762 if (rc
!= ERROR_SUCCESS
)
2763 return ERROR_SUCCESS
;
2765 res
= CoInitialize( NULL
);
2768 ERR("CoInitialize failed\n");
2769 return ERROR_FUNCTION_FAILED
;
2772 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_CreateShortcuts
, package
);
2773 msiobj_release(&view
->hdr
);
2780 static UINT
ITERATE_PublishProduct(MSIRECORD
*row
, LPVOID param
)
2782 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
2790 FileName
= MSI_RecordGetString(row
,1);
2793 ERR("Unable to get FileName\n");
2794 return ERROR_SUCCESS
;
2797 FilePath
= build_icon_path(package
,FileName
);
2799 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
2801 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2802 FILE_ATTRIBUTE_NORMAL
, NULL
);
2804 if (the_file
== INVALID_HANDLE_VALUE
)
2806 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
2808 return ERROR_SUCCESS
;
2815 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
2816 if (rc
!= ERROR_SUCCESS
)
2818 ERR("Failed to get stream\n");
2819 CloseHandle(the_file
);
2820 DeleteFileW(FilePath
);
2823 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
2824 } while (sz
== 1024);
2828 CloseHandle(the_file
);
2829 return ERROR_SUCCESS
;
2833 * 99% of the work done here is only done for
2834 * advertised installs. However this is where the
2835 * Icon table is processed and written out
2836 * so that is what I am going to do here.
2838 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
2842 static const WCHAR Query
[]=
2843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2844 '`','I','c','o','n','`',0};
2845 /* for registry stuff */
2848 static const WCHAR szProductLanguage
[] =
2849 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
2850 static const WCHAR szARPProductIcon
[] =
2851 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
2852 static const WCHAR szProductVersion
[] =
2853 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
2857 MSIHANDLE hDb
, hSumInfo
;
2860 return ERROR_INVALID_HANDLE
;
2862 /* write out icon files */
2864 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2865 if (rc
== ERROR_SUCCESS
)
2867 MSI_IterateRecords(view
, NULL
, ITERATE_PublishProduct
, package
);
2868 msiobj_release(&view
->hdr
);
2871 /* ok there is a lot more done here but i need to figure out what */
2873 rc
= MSIREG_OpenProductsKey(package
->ProductCode
,&hkey
,TRUE
);
2874 if (rc
!= ERROR_SUCCESS
)
2877 rc
= MSIREG_OpenUserProductsKey(package
->ProductCode
,&hukey
,TRUE
);
2878 if (rc
!= ERROR_SUCCESS
)
2882 buffer
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTNAMEW
);
2883 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTNAMEW
, buffer
);
2886 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
2887 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
2889 buffer
= msi_dup_property( package
, szARPProductIcon
);
2892 LPWSTR path
= build_icon_path(package
,buffer
);
2893 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PRODUCTICONW
, path
);
2898 buffer
= msi_dup_property( package
, szProductVersion
);
2901 DWORD verdword
= build_version_dword(buffer
);
2902 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
2906 FIXME("Need to write more keys to the user registry\n");
2908 hDb
= alloc_msihandle( &package
->db
->hdr
);
2909 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
2910 MsiCloseHandle(hDb
);
2911 if (rc
== ERROR_SUCCESS
)
2913 WCHAR guidbuffer
[0x200];
2915 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
2917 if (rc
== ERROR_SUCCESS
)
2919 WCHAR squashed
[GUID_SIZE
];
2920 /* for now we only care about the first guid */
2921 LPWSTR ptr
= strchrW(guidbuffer
,';');
2923 squash_guid(guidbuffer
,squashed
);
2924 msi_reg_set_val_str( hukey
, INSTALLPROPERTY_PACKAGECODEW
, squashed
);
2928 ERR("Unable to query Revision_Number... \n");
2931 MsiCloseHandle(hSumInfo
);
2935 ERR("Unable to open Summary Information\n");
2947 static UINT
ITERATE_WriteIniValues(MSIRECORD
*row
, LPVOID param
)
2949 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
2950 LPCWSTR component
,section
,key
,value
,identifier
,filename
,dirproperty
;
2951 LPWSTR deformated_section
, deformated_key
, deformated_value
;
2952 LPWSTR folder
, fullname
= NULL
;
2956 static const WCHAR szWindowsFolder
[] =
2957 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
2959 component
= MSI_RecordGetString(row
, 8);
2960 comp
= get_loaded_component(package
,component
);
2962 if (!ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_LOCAL
))
2964 TRACE("Skipping ini file due to disabled component %s\n",
2965 debugstr_w(component
));
2967 comp
->Action
= comp
->Installed
;
2969 return ERROR_SUCCESS
;
2972 comp
->Action
= INSTALLSTATE_LOCAL
;
2974 identifier
= MSI_RecordGetString(row
,1);
2975 filename
= MSI_RecordGetString(row
,2);
2976 dirproperty
= MSI_RecordGetString(row
,3);
2977 section
= MSI_RecordGetString(row
,4);
2978 key
= MSI_RecordGetString(row
,5);
2979 value
= MSI_RecordGetString(row
,6);
2980 action
= MSI_RecordGetInteger(row
,7);
2982 deformat_string(package
,section
,&deformated_section
);
2983 deformat_string(package
,key
,&deformated_key
);
2984 deformat_string(package
,value
,&deformated_value
);
2988 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
2990 folder
= msi_dup_property( package
, dirproperty
);
2993 folder
= msi_dup_property( package
, szWindowsFolder
);
2997 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
3001 fullname
= build_directory_name(2, folder
, filename
);
3005 TRACE("Adding value %s to section %s in %s\n",
3006 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3007 debugstr_w(fullname
));
3008 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3009 deformated_value
, fullname
);
3011 else if (action
== 1)
3014 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
3015 returned
, 10, fullname
);
3016 if (returned
[0] == 0)
3018 TRACE("Adding value %s to section %s in %s\n",
3019 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
3020 debugstr_w(fullname
));
3022 WritePrivateProfileStringW(deformated_section
, deformated_key
,
3023 deformated_value
, fullname
);
3026 else if (action
== 3)
3027 FIXME("Append to existing section not yet implemented\n");
3029 uirow
= MSI_CreateRecord(4);
3030 MSI_RecordSetStringW(uirow
,1,identifier
);
3031 MSI_RecordSetStringW(uirow
,2,deformated_section
);
3032 MSI_RecordSetStringW(uirow
,3,deformated_key
);
3033 MSI_RecordSetStringW(uirow
,4,deformated_value
);
3034 ui_actiondata(package
,szWriteIniValues
,uirow
);
3035 msiobj_release( &uirow
->hdr
);
3039 msi_free(deformated_key
);
3040 msi_free(deformated_value
);
3041 msi_free(deformated_section
);
3042 return ERROR_SUCCESS
;
3045 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
3049 static const WCHAR ExecSeqQuery
[] =
3050 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3051 '`','I','n','i','F','i','l','e','`',0};
3053 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3054 if (rc
!= ERROR_SUCCESS
)
3056 TRACE("no IniFile table\n");
3057 return ERROR_SUCCESS
;
3060 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_WriteIniValues
, package
);
3061 msiobj_release(&view
->hdr
);
3065 static UINT
ITERATE_SelfRegModules(MSIRECORD
*row
, LPVOID param
)
3067 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3072 static const WCHAR ExeStr
[] =
3073 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3074 static const WCHAR close
[] = {'\"',0};
3076 PROCESS_INFORMATION info
;
3079 memset(&si
,0,sizeof(STARTUPINFOW
));
3081 filename
= MSI_RecordGetString(row
,1);
3082 file
= get_loaded_file( package
, filename
);
3086 ERR("Unable to find file id %s\n",debugstr_w(filename
));
3087 return ERROR_SUCCESS
;
3090 len
= strlenW(ExeStr
) + strlenW( file
->TargetPath
) + 2;
3092 FullName
= msi_alloc(len
*sizeof(WCHAR
));
3093 strcpyW(FullName
,ExeStr
);
3094 strcatW( FullName
, file
->TargetPath
);
3095 strcatW(FullName
,close
);
3097 TRACE("Registering %s\n",debugstr_w(FullName
));
3098 brc
= CreateProcessW(NULL
, FullName
, NULL
, NULL
, FALSE
, 0, NULL
, c_colon
,
3102 msi_dialog_check_messages(info
.hProcess
);
3105 return ERROR_SUCCESS
;
3108 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
3112 static const WCHAR ExecSeqQuery
[] =
3113 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3114 '`','S','e','l','f','R','e','g','`',0};
3116 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3117 if (rc
!= ERROR_SUCCESS
)
3119 TRACE("no SelfReg table\n");
3120 return ERROR_SUCCESS
;
3123 MSI_IterateRecords(view
, NULL
, ITERATE_SelfRegModules
, package
);
3124 msiobj_release(&view
->hdr
);
3126 return ERROR_SUCCESS
;
3129 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
3131 MSIFEATURE
*feature
;
3137 return ERROR_INVALID_HANDLE
;
3139 rc
= MSIREG_OpenFeaturesKey(package
->ProductCode
,&hkey
,TRUE
);
3140 if (rc
!= ERROR_SUCCESS
)
3143 rc
= MSIREG_OpenUserFeaturesKey(package
->ProductCode
,&hukey
,TRUE
);
3144 if (rc
!= ERROR_SUCCESS
)
3147 /* here the guids are base 85 encoded */
3148 LIST_FOR_EACH_ENTRY( feature
, &package
->features
, MSIFEATURE
, entry
)
3154 BOOL absent
= FALSE
;
3156 if (!ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_LOCAL
) &&
3157 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_SOURCE
) &&
3158 !ACTION_VerifyFeatureForAction( feature
, INSTALLSTATE_ADVERTISED
))
3162 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3166 if (feature
->Feature_Parent
)
3167 size
+= strlenW( feature
->Feature_Parent
)+2;
3169 data
= msi_alloc(size
* sizeof(WCHAR
));
3172 LIST_FOR_EACH_ENTRY( cl
, &feature
->Components
, ComponentList
, entry
)
3174 MSICOMPONENT
* component
= cl
->component
;
3177 memset(buf
,0,sizeof(buf
));
3178 if (component
->ComponentId
)
3180 TRACE("From %s\n",debugstr_w(component
->ComponentId
));
3181 CLSIDFromString(component
->ComponentId
, &clsid
);
3182 encode_base85_guid(&clsid
,buf
);
3183 TRACE("to %s\n",debugstr_w(buf
));
3187 if (feature
->Feature_Parent
)
3189 static const WCHAR sep
[] = {'\2',0};
3191 strcatW(data
,feature
->Feature_Parent
);
3194 msi_reg_set_val_str( hkey
, feature
->Feature
, data
);
3198 if (feature
->Feature_Parent
)
3199 size
= strlenW(feature
->Feature_Parent
)*sizeof(WCHAR
);
3202 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3203 (LPBYTE
)feature
->Feature_Parent
,size
);
3207 size
+= 2*sizeof(WCHAR
);
3208 data
= msi_alloc(size
);
3211 if (feature
->Feature_Parent
)
3212 strcpyW( &data
[1], feature
->Feature_Parent
);
3213 RegSetValueExW(hukey
,feature
->Feature
,0,REG_SZ
,
3225 static UINT
msi_make_package_local( MSIPACKAGE
*package
, HKEY hkey
)
3227 static const WCHAR installerPathFmt
[] = {
3228 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3229 static const WCHAR fmt
[] = {
3231 'I','n','s','t','a','l','l','e','r','\\',
3232 '%','x','.','m','s','i',0};
3233 static const WCHAR szOriginalDatabase
[] =
3234 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3235 WCHAR windir
[MAX_PATH
], path
[MAX_PATH
], packagefile
[MAX_PATH
];
3240 /* copy the package locally */
3241 num
= GetTickCount() & 0xffff;
3245 GetWindowsDirectoryW( windir
, MAX_PATH
);
3246 snprintfW( packagefile
, MAX_PATH
, fmt
, windir
, num
);
3249 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
3250 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
3251 if (handle
!= INVALID_HANDLE_VALUE
)
3253 CloseHandle(handle
);
3256 if (GetLastError() != ERROR_FILE_EXISTS
&&
3257 GetLastError() != ERROR_SHARING_VIOLATION
)
3259 if (!(++num
& 0xffff)) num
= 1;
3260 sprintfW(packagefile
,fmt
,num
);
3261 } while (num
!= start
);
3263 snprintfW( path
, MAX_PATH
, installerPathFmt
, windir
);
3264 create_full_pathW(path
);
3266 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
3268 msiFilePath
= msi_dup_property( package
, szOriginalDatabase
);
3269 r
= CopyFileW( msiFilePath
, packagefile
, FALSE
);
3270 msi_free( msiFilePath
);
3274 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3275 debugstr_w(msiFilePath
), debugstr_w(packagefile
), GetLastError());
3276 return ERROR_FUNCTION_FAILED
;
3279 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3280 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_LOCALPACKAGEW
, packagefile
);
3281 return ERROR_SUCCESS
;
3284 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
3287 LPWSTR buffer
= NULL
;
3290 static const WCHAR szWindowsInstaller
[] =
3291 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3292 static const WCHAR szPropKeys
[][80] =
3294 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
3295 {'A','R','P','C','O','N','T','A','C','T',0},
3296 {'A','R','P','C','O','M','M','E','N','T','S',0},
3297 {'P','r','o','d','u','c','t','N','a','m','e',0},
3298 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
3299 {'A','R','P','H','E','L','P','L','I','N','K',0},
3300 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
3301 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
3302 {'S','o','u','r','c','e','D','i','r',0},
3303 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
3304 {'A','R','P','R','E','A','D','M','E',0},
3305 {'A','R','P','S','I','Z','E',0},
3306 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
3307 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
3311 static const WCHAR szRegKeys
[][80] =
3313 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
3314 {'C','o','n','t','a','c','t',0},
3315 {'C','o','m','m','e','n','t','s',0},
3316 {'D','i','s','p','l','a','y','N','a','m','e',0},
3317 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
3318 {'H','e','l','p','L','i','n','k',0},
3319 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
3320 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
3321 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
3322 {'P','u','b','l','i','s','h','e','r',0},
3323 {'R','e','a','d','m','e',0},
3324 {'S','i','z','e',0},
3325 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
3326 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
3329 static const WCHAR szUpgradeCode
[] =
3330 {'U','p','g','r','a','d','e','C','o','d','e',0};
3331 static const WCHAR modpath_fmt
[] =
3332 {'M','s','i','E','x','e','c','.','e','x','e',' ','/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3333 static const WCHAR szModifyPath
[] =
3334 {'M','o','d','i','f','y','P','a','t','h',0};
3335 static const WCHAR szUninstallString
[] =
3336 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3337 static const WCHAR szEstimatedSize
[] =
3338 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3339 static const WCHAR szProductLanguage
[] =
3340 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3341 static const WCHAR szProductVersion
[] =
3342 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3345 static const WCHAR date_fmt
[] = {'%','i','%','i','%','i',0};
3346 LPWSTR upgrade_code
;
3349 return ERROR_INVALID_HANDLE
;
3351 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3352 if (rc
!= ERROR_SUCCESS
)
3355 /* dump all the info i can grab */
3356 FIXME("Flesh out more information \n");
3358 for( i
=0; szPropKeys
[i
][0]; i
++ )
3360 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
3361 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
3365 msi_reg_set_val_dword( hkey
, szWindowsInstaller
, 1 );
3367 msi_make_package_local( package
, hkey
);
3369 /* do ModifyPath and UninstallString */
3370 size
= deformat_string(package
,modpath_fmt
,&buffer
);
3371 RegSetValueExW(hkey
,szModifyPath
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3372 RegSetValueExW(hkey
,szUninstallString
,0,REG_EXPAND_SZ
,(LPBYTE
)buffer
,size
);
3375 FIXME("Write real Estimated Size when we have it\n");
3376 msi_reg_set_val_dword( hkey
, szEstimatedSize
, 0 );
3378 GetLocalTime(&systime
);
3379 size
= 9*sizeof(WCHAR
);
3380 buffer
= msi_alloc(size
);
3381 sprintfW(buffer
,date_fmt
,systime
.wYear
,systime
.wMonth
,systime
.wDay
);
3382 msi_reg_set_val_str( hkey
, INSTALLPROPERTY_INSTALLDATEW
, buffer
);
3385 langid
= msi_get_property_int( package
, szProductLanguage
, 0 );
3386 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_LANGUAGEW
, langid
);
3388 buffer
= msi_dup_property( package
, szProductVersion
);
3391 DWORD verdword
= build_version_dword(buffer
);
3393 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONW
, verdword
);
3394 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMAJORW
, verdword
>>24 );
3395 msi_reg_set_val_dword( hkey
, INSTALLPROPERTY_VERSIONMINORW
, (verdword
>>16)&0x00FF );
3399 /* Handle Upgrade Codes */
3400 upgrade_code
= msi_dup_property( package
, szUpgradeCode
);
3405 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3406 squash_guid(package
->ProductCode
,squashed
);
3407 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3409 MSIREG_OpenUserUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
3410 squash_guid(package
->ProductCode
,squashed
);
3411 msi_reg_set_val_str( hkey2
, squashed
, NULL
);
3414 msi_free(upgrade_code
);
3420 return ERROR_SUCCESS
;
3423 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
3428 return ERROR_INVALID_HANDLE
;
3430 rc
= execute_script(package
,INSTALL_SCRIPT
);
3435 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
3440 return ERROR_INVALID_HANDLE
;
3442 /* turn off scheduleing */
3443 package
->script
->CurrentlyScripting
= FALSE
;
3445 /* first do the same as an InstallExecute */
3446 rc
= ACTION_InstallExecute(package
);
3447 if (rc
!= ERROR_SUCCESS
)
3450 /* then handle Commit Actions */
3451 rc
= execute_script(package
,COMMIT_SCRIPT
);
3456 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
3458 static const WCHAR RunOnce
[] = {
3459 'S','o','f','t','w','a','r','e','\\',
3460 'M','i','c','r','o','s','o','f','t','\\',
3461 'W','i','n','d','o','w','s','\\',
3462 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3463 'R','u','n','O','n','c','e',0};
3464 static const WCHAR InstallRunOnce
[] = {
3465 'S','o','f','t','w','a','r','e','\\',
3466 'M','i','c','r','o','s','o','f','t','\\',
3467 'W','i','n','d','o','w','s','\\',
3468 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3469 'I','n','s','t','a','l','l','e','r','\\',
3470 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3472 static const WCHAR msiexec_fmt
[] = {
3474 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3475 '\"','%','s','\"',0};
3476 static const WCHAR install_fmt
[] = {
3477 '/','I',' ','\"','%','s','\"',' ',
3478 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3479 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3480 WCHAR buffer
[256], sysdir
[MAX_PATH
];
3482 WCHAR squished_pc
[100];
3485 return ERROR_INVALID_HANDLE
;
3487 squash_guid(package
->ProductCode
,squished_pc
);
3489 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
3490 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
3491 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
3494 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3497 TRACE("Reboot command %s\n",debugstr_w(buffer
));
3499 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
3500 sprintfW(buffer
,install_fmt
,package
->ProductCode
,squished_pc
);
3502 msi_reg_set_val_str( hkey
, squished_pc
, buffer
);
3505 return ERROR_INSTALL_SUSPEND
;
3508 UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
3513 * we are currently doing what should be done here in the top level Install
3514 * however for Adminastrative and uninstalls this step will be needed
3516 if (!package
->PackagePath
)
3517 return ERROR_SUCCESS
;
3519 attrib
= GetFileAttributesW(package
->PackagePath
);
3520 if (attrib
== INVALID_FILE_ATTRIBUTES
)
3526 rc
= MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3527 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3528 INSTALLPROPERTY_DISKPROMPTW
,NULL
,&size
);
3529 if (rc
== ERROR_MORE_DATA
)
3531 prompt
= msi_alloc(size
* sizeof(WCHAR
));
3532 MsiSourceListGetInfoW(package
->ProductCode
, NULL
,
3533 MSIINSTALLCONTEXT_USERMANAGED
, MSICODE_PRODUCT
,
3534 INSTALLPROPERTY_DISKPROMPTW
,prompt
,&size
);
3537 prompt
= strdupW(package
->PackagePath
);
3539 msg
= generate_error_string(package
,1302,1,prompt
);
3540 while(attrib
== INVALID_FILE_ATTRIBUTES
)
3542 rc
= MessageBoxW(NULL
,msg
,NULL
,MB_OKCANCEL
);
3545 rc
= ERROR_INSTALL_USEREXIT
;
3548 attrib
= GetFileAttributesW(package
->PackagePath
);
3554 return ERROR_SUCCESS
;
3559 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
3566 static const WCHAR szPropKeys
[][80] =
3568 {'P','r','o','d','u','c','t','I','D',0},
3569 {'U','S','E','R','N','A','M','E',0},
3570 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3574 static const WCHAR szRegKeys
[][80] =
3576 {'P','r','o','d','u','c','t','I','D',0},
3577 {'R','e','g','O','w','n','e','r',0},
3578 {'R','e','g','C','o','m','p','a','n','y',0},
3583 return ERROR_INVALID_HANDLE
;
3585 productid
= msi_dup_property( package
, INSTALLPROPERTY_PRODUCTIDW
);
3587 return ERROR_SUCCESS
;
3589 rc
= MSIREG_OpenUninstallKey(package
->ProductCode
,&hkey
,TRUE
);
3590 if (rc
!= ERROR_SUCCESS
)
3593 for( i
= 0; szPropKeys
[i
][0]; i
++ )
3595 buffer
= msi_dup_property( package
, szPropKeys
[i
] );
3596 msi_reg_set_val_str( hkey
, szRegKeys
[i
], buffer
);
3601 msi_free(productid
);
3604 return ERROR_SUCCESS
;
3608 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
3610 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
3611 static const WCHAR szTwo
[] = {'2',0};
3614 level
= msi_dup_property( package
, szUILevel
);
3616 MSI_SetPropertyW(package
,szUILevel
,szTwo
);
3617 package
->script
->InWhatSequence
|= SEQUENCE_EXEC
;
3618 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
3619 MSI_SetPropertyW(package
,szUILevel
,level
);
3626 * Code based off of code located here
3627 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3629 * Using string index 4 (full font name) instead of 1 (family name)
3631 static LPWSTR
load_ttfname_from(LPCWSTR filename
)
3637 typedef struct _tagTT_OFFSET_TABLE
{
3638 USHORT uMajorVersion
;
3639 USHORT uMinorVersion
;
3640 USHORT uNumOfTables
;
3641 USHORT uSearchRange
;
3642 USHORT uEntrySelector
;
3646 typedef struct _tagTT_TABLE_DIRECTORY
{
3647 char szTag
[4]; /* table name */
3648 ULONG uCheckSum
; /* Check sum */
3649 ULONG uOffset
; /* Offset from beginning of file */
3650 ULONG uLength
; /* length of the table in bytes */
3651 }TT_TABLE_DIRECTORY
;
3653 typedef struct _tagTT_NAME_TABLE_HEADER
{
3654 USHORT uFSelector
; /* format selector. Always 0 */
3655 USHORT uNRCount
; /* Name Records count */
3656 USHORT uStorageOffset
; /* Offset for strings storage,
3657 * from start of the table */
3658 }TT_NAME_TABLE_HEADER
;
3660 typedef struct _tagTT_NAME_RECORD
{
3665 USHORT uStringLength
;
3666 USHORT uStringOffset
; /* from start of storage area */
3669 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3670 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3672 handle
= CreateFileW(filename
,GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
3673 FILE_ATTRIBUTE_NORMAL
, 0 );
3674 if (handle
!= INVALID_HANDLE_VALUE
)
3676 TT_TABLE_DIRECTORY tblDir
;
3677 BOOL bFound
= FALSE
;
3678 TT_OFFSET_TABLE ttOffsetTable
;
3680 ReadFile(handle
,&ttOffsetTable
, sizeof(TT_OFFSET_TABLE
),NULL
,NULL
);
3681 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
3682 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
3683 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
3685 if (ttOffsetTable
.uMajorVersion
!= 1 ||
3686 ttOffsetTable
.uMinorVersion
!= 0)
3689 for (i
=0; i
< ttOffsetTable
.uNumOfTables
; i
++)
3691 ReadFile(handle
,&tblDir
, sizeof(TT_TABLE_DIRECTORY
),NULL
,NULL
);
3692 if (strncmp(tblDir
.szTag
,"name",4)==0)
3695 tblDir
.uLength
= SWAPLONG(tblDir
.uLength
);
3696 tblDir
.uOffset
= SWAPLONG(tblDir
.uOffset
);
3703 TT_NAME_TABLE_HEADER ttNTHeader
;
3704 TT_NAME_RECORD ttRecord
;
3706 SetFilePointer(handle
, tblDir
.uOffset
, NULL
, FILE_BEGIN
);
3707 ReadFile(handle
,&ttNTHeader
, sizeof(TT_NAME_TABLE_HEADER
),
3710 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
3711 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
3713 for(i
=0; i
<ttNTHeader
.uNRCount
; i
++)
3715 ReadFile(handle
,&ttRecord
, sizeof(TT_NAME_RECORD
),NULL
,NULL
);
3716 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
3717 /* 4 is the Full Font Name */
3718 if(ttRecord
.uNameID
== 4)
3722 static LPCSTR tt
= " (TrueType)";
3724 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
3725 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
3726 nPos
= SetFilePointer(handle
, 0, NULL
, FILE_CURRENT
);
3727 SetFilePointer(handle
, tblDir
.uOffset
+
3728 ttRecord
.uStringOffset
+
3729 ttNTHeader
.uStorageOffset
,
3731 buf
= msi_alloc( ttRecord
.uStringLength
+ 1 + strlen(tt
) );
3732 memset(buf
, 0, ttRecord
.uStringLength
+ 1 + strlen(tt
));
3733 ReadFile(handle
, buf
, ttRecord
.uStringLength
, NULL
, NULL
);
3734 if (strlen(buf
) > 0)
3737 ret
= strdupAtoW(buf
);
3743 SetFilePointer(handle
,nPos
, NULL
, FILE_BEGIN
);
3747 CloseHandle(handle
);
3750 ERR("Unable to open font file %s\n", debugstr_w(filename
));
3752 TRACE("Returning fontname %s\n",debugstr_w(ret
));
3756 static UINT
ITERATE_RegisterFonts(MSIRECORD
*row
, LPVOID param
)
3758 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3762 static const WCHAR regfont1
[] =
3763 {'S','o','f','t','w','a','r','e','\\',
3764 'M','i','c','r','o','s','o','f','t','\\',
3765 'W','i','n','d','o','w','s',' ','N','T','\\',
3766 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3767 'F','o','n','t','s',0};
3768 static const WCHAR regfont2
[] =
3769 {'S','o','f','t','w','a','r','e','\\',
3770 'M','i','c','r','o','s','o','f','t','\\',
3771 'W','i','n','d','o','w','s','\\',
3772 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3773 'F','o','n','t','s',0};
3777 filename
= MSI_RecordGetString( row
, 1 );
3778 file
= get_loaded_file( package
, filename
);
3781 ERR("Unable to load file\n");
3782 return ERROR_SUCCESS
;
3785 /* check to make sure that component is installed */
3786 if (!ACTION_VerifyComponentForAction(package
,
3787 file
->Component
, INSTALLSTATE_LOCAL
))
3789 TRACE("Skipping: Component not scheduled for install\n");
3790 return ERROR_SUCCESS
;
3793 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont1
,&hkey1
);
3794 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont2
,&hkey2
);
3796 if (MSI_RecordIsNull(row
,2))
3797 name
= load_ttfname_from( file
->TargetPath
);
3799 name
= load_dynamic_stringW(row
,2);
3803 msi_reg_set_val_str( hkey1
, name
, file
->FileName
);
3804 msi_reg_set_val_str( hkey2
, name
, file
->FileName
);
3810 return ERROR_SUCCESS
;
3813 static UINT
ACTION_RegisterFonts(MSIPACKAGE
*package
)
3817 static const WCHAR ExecSeqQuery
[] =
3818 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3819 '`','F','o','n','t','`',0};
3821 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3822 if (rc
!= ERROR_SUCCESS
)
3824 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc
);
3825 return ERROR_SUCCESS
;
3828 MSI_IterateRecords(view
, NULL
, ITERATE_RegisterFonts
, package
);
3829 msiobj_release(&view
->hdr
);
3831 return ERROR_SUCCESS
;
3834 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
3836 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
3837 LPCWSTR compgroupid
=NULL
;
3838 LPCWSTR feature
=NULL
;
3839 LPCWSTR text
= NULL
;
3840 LPCWSTR qualifier
= NULL
;
3841 LPCWSTR component
= NULL
;
3842 LPWSTR advertise
= NULL
;
3843 LPWSTR output
= NULL
;
3845 UINT rc
= ERROR_SUCCESS
;
3849 component
= MSI_RecordGetString(rec
,3);
3850 comp
= get_loaded_component(package
,component
);
3852 if (!ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_LOCAL
) &&
3853 !ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_SOURCE
) &&
3854 !ACTION_VerifyComponentForAction(package
, comp
, INSTALLSTATE_ADVERTISED
))
3856 TRACE("Skipping: Component %s not scheduled for install\n",
3857 debugstr_w(component
));
3859 return ERROR_SUCCESS
;
3862 compgroupid
= MSI_RecordGetString(rec
,1);
3864 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
3865 if (rc
!= ERROR_SUCCESS
)
3868 text
= MSI_RecordGetString(rec
,4);
3869 qualifier
= MSI_RecordGetString(rec
,2);
3870 feature
= MSI_RecordGetString(rec
,5);
3872 advertise
= create_component_advertise_string(package
, comp
, feature
);
3874 sz
= strlenW(advertise
);
3877 sz
+= lstrlenW(text
);
3880 sz
*= sizeof(WCHAR
);
3882 output
= msi_alloc(sz
);
3883 memset(output
,0,sz
);
3884 strcpyW(output
,advertise
);
3885 msi_free(advertise
);
3888 strcatW(output
,text
);
3890 msi_reg_set_val_multi_str( hkey
, qualifier
, output
);
3900 * At present I am ignorning the advertised components part of this and only
3901 * focusing on the qualified component sets
3903 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
3907 static const WCHAR ExecSeqQuery
[] =
3908 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3909 '`','P','u','b','l','i','s','h',
3910 'C','o','m','p','o','n','e','n','t','`',0};
3912 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3913 if (rc
!= ERROR_SUCCESS
)
3914 return ERROR_SUCCESS
;
3916 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
3917 msiobj_release(&view
->hdr
);
3922 static UINT
msi_unimplemented_action_stub( MSIPACKAGE
*package
,
3923 LPCSTR action
, LPCWSTR table
)
3925 static const WCHAR query
[] = {
3926 'S','E','L','E','C','T',' ','*',' ',
3927 'F','R','O','M',' ','`','%','s','`',0 };
3928 MSIQUERY
*view
= NULL
;
3932 r
= MSI_OpenQuery( package
->db
, &view
, query
, table
);
3933 if (r
== ERROR_SUCCESS
)
3935 r
= MSI_IterateRecords(view
, &count
, NULL
, package
);
3936 msiobj_release(&view
->hdr
);
3940 FIXME("%s -> %lu ignored %s table values\n",
3941 action
, count
, debugstr_w(table
));
3943 return ERROR_SUCCESS
;
3946 static UINT
ACTION_RemoveIniValues( MSIPACKAGE
*package
)
3948 static const WCHAR table
[] =
3949 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
3950 return msi_unimplemented_action_stub( package
, "RemoveIniValues", table
);
3953 static UINT
ACTION_MoveFiles( MSIPACKAGE
*package
)
3955 static const WCHAR table
[] = { 'M','o','v','e','F','i','l','e',0 };
3956 return msi_unimplemented_action_stub( package
, "MoveFiles", table
);
3959 static UINT
ACTION_PatchFiles( MSIPACKAGE
*package
)
3961 static const WCHAR table
[] = { 'P','a','t','c','h',0 };
3962 return msi_unimplemented_action_stub( package
, "PatchFiles", table
);
3965 static UINT
ACTION_BindImage( MSIPACKAGE
*package
)
3967 static const WCHAR table
[] = { 'B','i','n','d','I','m','a','g','e',0 };
3968 return msi_unimplemented_action_stub( package
, "BindImage", table
);
3971 static UINT
ACTION_IsolateComponents( MSIPACKAGE
*package
)
3973 static const WCHAR table
[] = {
3974 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
3975 return msi_unimplemented_action_stub( package
, "IsolateComponents", table
);
3978 static UINT
ACTION_MigrateFeatureStates( MSIPACKAGE
*package
)
3980 static const WCHAR table
[] = { 'U','p','g','r','a','d','e',0 };
3981 return msi_unimplemented_action_stub( package
, "MigrateFeatureStates", table
);
3984 static UINT
ACTION_SelfUnregModules( MSIPACKAGE
*package
)
3986 static const WCHAR table
[] = { 'S','e','l','f','R','e','g',0 };
3987 return msi_unimplemented_action_stub( package
, "SelfUnregModules", table
);
3990 static UINT
ACTION_InstallServices( MSIPACKAGE
*package
)
3992 static const WCHAR table
[] = {
3993 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
3994 return msi_unimplemented_action_stub( package
, "InstallServices", table
);
3997 static UINT
ACTION_StartServices( MSIPACKAGE
*package
)
3999 static const WCHAR table
[] = {
4000 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4001 return msi_unimplemented_action_stub( package
, "StartServices", table
);
4004 static UINT
ACTION_StopServices( MSIPACKAGE
*package
)
4006 static const WCHAR table
[] = {
4007 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4008 return msi_unimplemented_action_stub( package
, "StopServices", table
);
4011 static UINT
ACTION_DeleteServices( MSIPACKAGE
*package
)
4013 static const WCHAR table
[] = {
4014 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4015 return msi_unimplemented_action_stub( package
, "DeleteServices", table
);
4018 static UINT
ACTION_WriteEnvironmentStrings( MSIPACKAGE
*package
)
4020 static const WCHAR table
[] = {
4021 'E','n','v','i','r','o','n','m','e','n','t',0 };
4022 return msi_unimplemented_action_stub( package
, "WriteEnvironmentStrings", table
);
4025 static UINT
ACTION_RemoveEnvironmentStrings( MSIPACKAGE
*package
)
4027 static const WCHAR table
[] = {
4028 'E','n','v','i','r','o','n','m','e','n','t',0 };
4029 return msi_unimplemented_action_stub( package
, "RemoveEnvironmentStrings", table
);
4032 static UINT
ACTION_MsiPublishAssemblies( MSIPACKAGE
*package
)
4034 static const WCHAR table
[] = {
4035 'M','s','i','A','s','s','e','m','b','l','y',0 };
4036 return msi_unimplemented_action_stub( package
, "MsiPublishAssemblies", table
);
4039 static UINT
ACTION_MsiUnpublishAssemblies( MSIPACKAGE
*package
)
4041 static const WCHAR table
[] = {
4042 'M','s','i','A','s','s','e','m','b','l','y',0 };
4043 return msi_unimplemented_action_stub( package
, "MsiUnpublishAssemblies", table
);
4046 static UINT
ACTION_UnregisterFonts( MSIPACKAGE
*package
)
4048 static const WCHAR table
[] = { 'F','o','n','t',0 };
4049 return msi_unimplemented_action_stub( package
, "UnregisterFonts", table
);
4052 static struct _actions StandardActions
[] = {
4053 { szAllocateRegistrySpace
, NULL
},
4054 { szAppSearch
, ACTION_AppSearch
},
4055 { szBindImage
, ACTION_BindImage
},
4056 { szCCPSearch
, NULL
},
4057 { szCostFinalize
, ACTION_CostFinalize
},
4058 { szCostInitialize
, ACTION_CostInitialize
},
4059 { szCreateFolders
, ACTION_CreateFolders
},
4060 { szCreateShortcuts
, ACTION_CreateShortcuts
},
4061 { szDeleteServices
, ACTION_DeleteServices
},
4062 { szDisableRollback
, NULL
},
4063 { szDuplicateFiles
, ACTION_DuplicateFiles
},
4064 { szExecuteAction
, ACTION_ExecuteAction
},
4065 { szFileCost
, ACTION_FileCost
},
4066 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
4067 { szForceReboot
, ACTION_ForceReboot
},
4068 { szInstallAdminPackage
, NULL
},
4069 { szInstallExecute
, ACTION_InstallExecute
},
4070 { szInstallExecuteAgain
, ACTION_InstallExecute
},
4071 { szInstallFiles
, ACTION_InstallFiles
},
4072 { szInstallFinalize
, ACTION_InstallFinalize
},
4073 { szInstallInitialize
, ACTION_InstallInitialize
},
4074 { szInstallSFPCatalogFile
, NULL
},
4075 { szInstallValidate
, ACTION_InstallValidate
},
4076 { szIsolateComponents
, ACTION_IsolateComponents
},
4077 { szLaunchConditions
, ACTION_LaunchConditions
},
4078 { szMigrateFeatureStates
, ACTION_MigrateFeatureStates
},
4079 { szMoveFiles
, ACTION_MoveFiles
},
4080 { szMsiPublishAssemblies
, ACTION_MsiPublishAssemblies
},
4081 { szMsiUnpublishAssemblies
, ACTION_MsiUnpublishAssemblies
},
4082 { szInstallODBC
, NULL
},
4083 { szInstallServices
, ACTION_InstallServices
},
4084 { szPatchFiles
, ACTION_PatchFiles
},
4085 { szProcessComponents
, ACTION_ProcessComponents
},
4086 { szPublishComponents
, ACTION_PublishComponents
},
4087 { szPublishFeatures
, ACTION_PublishFeatures
},
4088 { szPublishProduct
, ACTION_PublishProduct
},
4089 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
4090 { szRegisterComPlus
, NULL
},
4091 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
4092 { szRegisterFonts
, ACTION_RegisterFonts
},
4093 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
4094 { szRegisterProduct
, ACTION_RegisterProduct
},
4095 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
4096 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
4097 { szRegisterUser
, ACTION_RegisterUser
},
4098 { szRemoveDuplicateFiles
, NULL
},
4099 { szRemoveEnvironmentStrings
, ACTION_RemoveEnvironmentStrings
},
4100 { szRemoveExistingProducts
, NULL
},
4101 { szRemoveFiles
, NULL
},
4102 { szRemoveFolders
, NULL
},
4103 { szRemoveIniValues
, ACTION_RemoveIniValues
},
4104 { szRemoveODBC
, NULL
},
4105 { szRemoveRegistryValues
, NULL
},
4106 { szRemoveShortcuts
, NULL
},
4107 { szResolveSource
, ACTION_ResolveSource
},
4108 { szRMCCPSearch
, NULL
},
4109 { szScheduleReboot
, NULL
},
4110 { szSelfRegModules
, ACTION_SelfRegModules
},
4111 { szSelfUnregModules
, ACTION_SelfUnregModules
},
4112 { szSetODBCFolders
, NULL
},
4113 { szStartServices
, ACTION_StartServices
},
4114 { szStopServices
, ACTION_StopServices
},
4115 { szUnpublishComponents
, NULL
},
4116 { szUnpublishFeatures
, NULL
},
4117 { szUnregisterClassInfo
, NULL
},
4118 { szUnregisterComPlus
, NULL
},
4119 { szUnregisterExtensionInfo
, NULL
},
4120 { szUnregisterFonts
, ACTION_UnregisterFonts
},
4121 { szUnregisterMIMEInfo
, NULL
},
4122 { szUnregisterProgIdInfo
, NULL
},
4123 { szUnregisterTypeLibraries
, NULL
},
4124 { szValidateProductID
, NULL
},
4125 { szWriteEnvironmentStrings
, ACTION_WriteEnvironmentStrings
},
4126 { szWriteIniValues
, ACTION_WriteIniValues
},
4127 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},