2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 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
38 #include "wine/debug.h"
42 #include "msvcrt/fcntl.h"
49 #include "wine/unicode.h"
53 #define REG_PROGRESS_VALUE 13200
54 #define COMPONENT_PROGRESS_VALUE 24000
56 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
61 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
62 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
63 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
);
64 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
70 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
72 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
);
73 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
);
74 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
);
75 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
);
76 static UINT
ACTION_FileCost(MSIPACKAGE
*package
);
77 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
);
78 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
);
79 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
);
80 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
);
81 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
);
82 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
);
83 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
);
84 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
);
85 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
);
86 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
);
87 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
);
88 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
);
89 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
);
90 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
);
91 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
);
92 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
);
93 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
);
94 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
);
95 static UINT
ACTION_ResolveSource(MSIPACKAGE
*package
);
99 * consts and values used
101 static const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
102 static const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
103 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
104 static const WCHAR cszTempFolder
[]= {'T','e','m','p','F','o','l','d','e','r',0};
105 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
106 static const WCHAR c_collen
[] = {'C',':','\\',0};
108 static const WCHAR cszbs
[]={'\\',0};
110 const static WCHAR szCreateFolders
[] =
111 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
112 const static WCHAR szCostFinalize
[] =
113 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
114 const static WCHAR szInstallFiles
[] =
115 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
116 const static WCHAR szDuplicateFiles
[] =
117 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
118 const static WCHAR szWriteRegistryValues
[] =
119 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
120 const static WCHAR szCostInitialize
[] =
121 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
122 const static WCHAR szFileCost
[] =
123 {'F','i','l','e','C','o','s','t',0};
124 const static WCHAR szInstallInitialize
[] =
125 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
126 const static WCHAR szInstallValidate
[] =
127 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
128 const static WCHAR szLaunchConditions
[] =
129 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
130 const static WCHAR szProcessComponents
[] =
131 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
132 const static WCHAR szRegisterTypeLibraries
[] =
133 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
135 const static WCHAR szRegisterClassInfo
[] =
136 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
137 const static WCHAR szRegisterProgIdInfo
[] =
138 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
139 const static WCHAR szCreateShortcuts
[] =
140 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
141 const static WCHAR szPublishProduct
[] =
142 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
143 const static WCHAR szWriteIniValues
[] =
144 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
145 const static WCHAR szSelfRegModules
[] =
146 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
147 const static WCHAR szPublishFeatures
[] =
148 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
149 const static WCHAR szRegisterProduct
[] =
150 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
151 const static WCHAR szInstallExecute
[] =
152 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
153 const static WCHAR szInstallExecuteAgain
[] =
154 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
155 const static WCHAR szInstallFinalize
[] =
156 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
157 const static WCHAR szForceReboot
[] =
158 {'F','o','r','c','e','R','e','b','o','o','t',0};
159 const static WCHAR szResolveSource
[] =
160 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
161 const static WCHAR szAppSearch
[] =
162 {'A','p','p','S','e','a','r','c','h',0};
163 const static WCHAR szAllocateRegistrySpace
[] =
164 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
165 const static WCHAR szBindImage
[] =
166 {'B','i','n','d','I','m','a','g','e',0};
167 const static WCHAR szCCPSearch
[] =
168 {'C','C','P','S','e','a','r','c','h',0};
169 const static WCHAR szDeleteServices
[] =
170 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
171 const static WCHAR szDisableRollback
[] =
172 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
173 const static WCHAR szExecuteAction
[] =
174 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
175 const static WCHAR szFindRelatedProducts
[] =
176 {'F','i','n','d','R','e','l','a','t','e','d','P','r','o','d','u','c','t','s',0};
177 const static WCHAR szInstallAdminPackage
[] =
178 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
179 const static WCHAR szInstallSFPCatalogFile
[] =
180 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
181 const static WCHAR szIsolateComponents
[] =
182 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
183 const static WCHAR szMigrateFeatureStates
[] =
184 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
185 const static WCHAR szMoveFiles
[] =
186 {'M','o','v','e','F','i','l','e','s',0};
187 const static WCHAR szMsiPublishAssemblies
[] =
188 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
189 const static WCHAR szMsiUnpublishAssemblies
[] =
190 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
191 const static WCHAR szInstallODBC
[] =
192 {'I','n','s','t','a','l','l','O','D','B','C',0};
193 const static WCHAR szInstallServices
[] =
194 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
195 const static WCHAR szPatchFiles
[] =
196 {'P','a','t','c','h','F','i','l','e','s',0};
197 const static WCHAR szPublishComponents
[] =
198 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
199 const static WCHAR szRegisterComPlus
[] =
200 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
201 const static WCHAR szRegisterExtensionInfo
[] =
202 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
203 const static WCHAR szRegisterFonts
[] =
204 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
205 const static WCHAR szRegisterMIMEInfo
[] =
206 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
207 const static WCHAR szRegisterUser
[] =
208 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
209 const static WCHAR szRemoveDuplicateFiles
[] =
210 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
211 const static WCHAR szRemoveEnvironmentStrings
[] =
212 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
213 const static WCHAR szRemoveExistingProducts
[] =
214 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
215 const static WCHAR szRemoveFiles
[] =
216 {'R','e','m','o','v','e','F','i','l','e','s',0};
217 const static WCHAR szRemoveFolders
[] =
218 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
219 const static WCHAR szRemoveIniValues
[] =
220 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
221 const static WCHAR szRemoveODBC
[] =
222 {'R','e','m','o','v','e','O','D','B','C',0};
223 const static WCHAR szRemoveRegistryValues
[] =
224 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
225 const static WCHAR szRemoveShortcuts
[] =
226 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
227 const static WCHAR szRMCCPSearch
[] =
228 {'R','M','C','C','P','S','e','a','r','c','h',0};
229 const static WCHAR szScheduleReboot
[] =
230 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
231 const static WCHAR szSelfUnregModules
[] =
232 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
233 const static WCHAR szSetODBCFolders
[] =
234 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
235 const static WCHAR szStartServices
[] =
236 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
237 const static WCHAR szStopServices
[] =
238 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
239 const static WCHAR szUnpublishComponents
[] =
240 {'U','n','p','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
241 const static WCHAR szUnpublishFeatures
[] =
242 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
243 const static WCHAR szUnregisterClassInfo
[] =
244 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
245 const static WCHAR szUnregisterComPlus
[] =
246 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
247 const static WCHAR szUnregisterExtensionInfo
[] =
248 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
249 const static WCHAR szUnregisterFonts
[] =
250 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
251 const static WCHAR szUnregisterMIMEInfo
[] =
252 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
253 const static WCHAR szUnregisterProgIdInfo
[] =
254 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
255 const static WCHAR szUnregisterTypeLibraries
[] =
256 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
257 const static WCHAR szValidateProductID
[] =
258 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
259 const static WCHAR szWriteEnvironmentStrings
[] =
260 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
264 STANDARDACTIONHANDLER handler
;
267 struct _actions StandardActions
[] = {
268 { szAllocateRegistrySpace
, NULL
},
269 { szAppSearch
, ACTION_AppSearch
},
270 { szBindImage
, NULL
},
271 { szCCPSearch
, NULL
},
272 { szCostFinalize
, ACTION_CostFinalize
},
273 { szCostInitialize
, ACTION_CostInitialize
},
274 { szCreateFolders
, ACTION_CreateFolders
},
275 { szCreateShortcuts
, ACTION_CreateShortcuts
},
276 { szDeleteServices
, NULL
},
277 { szDisableRollback
, NULL
},
278 { szDuplicateFiles
, ACTION_DuplicateFiles
},
279 { szExecuteAction
, NULL
},
280 { szFileCost
, ACTION_FileCost
},
281 { szFindRelatedProducts
, NULL
},
282 { szForceReboot
, ACTION_ForceReboot
},
283 { szInstallAdminPackage
, NULL
},
284 { szInstallExecute
, ACTION_InstallExecute
},
285 { szInstallExecuteAgain
, ACTION_InstallExecute
},
286 { szInstallFiles
, ACTION_InstallFiles
},
287 { szInstallFinalize
, ACTION_InstallFinalize
},
288 { szInstallInitialize
, ACTION_InstallInitialize
},
289 { szInstallSFPCatalogFile
, NULL
},
290 { szInstallValidate
, ACTION_InstallValidate
},
291 { szIsolateComponents
, NULL
},
292 { szLaunchConditions
, ACTION_LaunchConditions
},
293 { szMigrateFeatureStates
, NULL
},
294 { szMoveFiles
, NULL
},
295 { szMsiPublishAssemblies
, NULL
},
296 { szMsiUnpublishAssemblies
, NULL
},
297 { szInstallODBC
, NULL
},
298 { szInstallServices
, NULL
},
299 { szPatchFiles
, NULL
},
300 { szProcessComponents
, ACTION_ProcessComponents
},
301 { szPublishComponents
, NULL
},
302 { szPublishFeatures
, ACTION_PublishFeatures
},
303 { szPublishProduct
, ACTION_PublishProduct
},
304 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
305 { szRegisterComPlus
, NULL
},
306 { szRegisterExtensionInfo
, NULL
},
307 { szRegisterFonts
, NULL
},
308 { szRegisterMIMEInfo
, NULL
},
309 { szRegisterProduct
, ACTION_RegisterProduct
},
310 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
311 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
312 { szRegisterUser
, NULL
},
313 { szRemoveDuplicateFiles
, NULL
},
314 { szRemoveEnvironmentStrings
, NULL
},
315 { szRemoveExistingProducts
, NULL
},
316 { szRemoveFiles
, NULL
},
317 { szRemoveFolders
, NULL
},
318 { szRemoveIniValues
, NULL
},
319 { szRemoveODBC
, NULL
},
320 { szRemoveRegistryValues
, NULL
},
321 { szRemoveShortcuts
, NULL
},
322 { szResolveSource
, ACTION_ResolveSource
},
323 { szRMCCPSearch
, NULL
},
324 { szScheduleReboot
, NULL
},
325 { szSelfRegModules
, ACTION_SelfRegModules
},
326 { szSelfUnregModules
, NULL
},
327 { szSetODBCFolders
, NULL
},
328 { szStartServices
, NULL
},
329 { szStopServices
, NULL
},
330 { szUnpublishComponents
, NULL
},
331 { szUnpublishFeatures
, NULL
},
332 { szUnregisterClassInfo
, NULL
},
333 { szUnregisterComPlus
, NULL
},
334 { szUnregisterExtensionInfo
, NULL
},
335 { szUnregisterFonts
, NULL
},
336 { szUnregisterMIMEInfo
, NULL
},
337 { szUnregisterProgIdInfo
, NULL
},
338 { szUnregisterTypeLibraries
, NULL
},
339 { szValidateProductID
, NULL
},
340 { szWriteEnvironmentStrings
, NULL
},
341 { szWriteIniValues
, ACTION_WriteIniValues
},
342 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
347 /********************************************************
348 * helper functions to get around current HACKS and such
349 ********************************************************/
350 inline static void reduce_to_longfilename(WCHAR
* filename
)
352 LPWSTR p
= strchrW(filename
,'|');
354 memmove(filename
, p
+1, (strlenW(p
+1)+1)*sizeof(WCHAR
));
357 WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
364 if (MSI_RecordIsNull(row
,index
))
367 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
369 /* having an empty string is different than NULL */
372 ret
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
));
378 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
379 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
380 if (rc
!=ERROR_SUCCESS
)
382 ERR("Unable to load dynamic string\n");
383 HeapFree(GetProcessHeap(), 0, ret
);
389 LPWSTR
load_dynamic_property(MSIPACKAGE
*package
, LPCWSTR prop
, UINT
* rc
)
395 r
= MSI_GetPropertyW(package
, prop
, NULL
, &sz
);
396 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
403 str
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
404 r
= MSI_GetPropertyW(package
, prop
, str
, &sz
);
405 if (r
!= ERROR_SUCCESS
)
407 HeapFree(GetProcessHeap(),0,str
);
415 int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
420 for (i
= 0; i
< package
->loaded_components
; i
++)
422 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
431 int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
436 for (i
= 0; i
< package
->loaded_features
; i
++)
438 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
447 int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
452 for (i
= 0; i
< package
->loaded_files
; i
++)
454 if (strcmpW(file
,package
->files
[i
].File
)==0)
463 int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
471 for (i
=0; i
< package
->loaded_files
; i
++)
472 if (strcmpW(package
->files
[i
].File
,name
)==0)
475 index
= package
->loaded_files
;
476 package
->loaded_files
++;
477 if (package
->loaded_files
== 1)
478 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
480 package
->files
= HeapReAlloc(GetProcessHeap(),0,
481 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
483 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
485 package
->files
[index
].File
= dupstrW(name
);
486 package
->files
[index
].TargetPath
= dupstrW(path
);
487 package
->files
[index
].Temporary
= TRUE
;
489 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
494 static void remove_tracked_tempfiles(MSIPACKAGE
* package
)
501 for (i
= 0; i
< package
->loaded_files
; i
++)
503 if (package
->files
[i
].Temporary
)
505 TRACE("Cleaning up %s\n",debugstr_w(package
->files
[i
].TargetPath
));
506 DeleteFileW(package
->files
[i
].TargetPath
);
512 /* wrapper to resist a need for a full rewrite right now */
513 DWORD
deformat_string(MSIPACKAGE
*package
, LPCWSTR ptr
, WCHAR
** data
)
517 MSIRECORD
*rec
= MSI_CreateRecord(1);
519 WCHAR size_buf
[2] = {' ',0};
521 MSI_RecordSetStringW(rec
,0,ptr
);
522 MSI_FormatRecordW(package
,rec
,size_buf
,&size
);
526 *data
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
528 MSI_FormatRecordW(package
,rec
,*data
,&size
);
531 msiobj_release( &rec
->hdr
);
532 return sizeof(WCHAR
)*size
;
534 msiobj_release( &rec
->hdr
);
541 /* Called when the package is being closed */
542 void ACTION_free_package_structures( MSIPACKAGE
* package
)
546 TRACE("Freeing package action data\n");
548 remove_tracked_tempfiles(package
);
550 /* No dynamic buffers in features */
551 if (package
->features
&& package
->loaded_features
> 0)
552 HeapFree(GetProcessHeap(),0,package
->features
);
554 for (i
= 0; i
< package
->loaded_folders
; i
++)
556 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Directory
);
557 HeapFree(GetProcessHeap(),0,package
->folders
[i
].TargetDefault
);
558 HeapFree(GetProcessHeap(),0,package
->folders
[i
].SourceDefault
);
559 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
560 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedSource
);
561 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Property
);
563 if (package
->folders
&& package
->loaded_folders
> 0)
564 HeapFree(GetProcessHeap(),0,package
->folders
);
566 /* no dynamic buffers in components */
567 if (package
->components
&& package
->loaded_components
> 0)
568 HeapFree(GetProcessHeap(),0,package
->components
);
570 for (i
= 0; i
< package
->loaded_files
; i
++)
572 HeapFree(GetProcessHeap(),0,package
->files
[i
].File
);
573 HeapFree(GetProcessHeap(),0,package
->files
[i
].FileName
);
574 HeapFree(GetProcessHeap(),0,package
->files
[i
].Version
);
575 HeapFree(GetProcessHeap(),0,package
->files
[i
].Language
);
576 HeapFree(GetProcessHeap(),0,package
->files
[i
].SourcePath
);
577 HeapFree(GetProcessHeap(),0,package
->files
[i
].TargetPath
);
580 if (package
->files
&& package
->loaded_files
> 0)
581 HeapFree(GetProcessHeap(),0,package
->files
);
583 for (i
= 0; i
< package
->DeferredActionCount
; i
++)
584 HeapFree(GetProcessHeap(),0,package
->DeferredAction
[i
]);
585 HeapFree(GetProcessHeap(),0,package
->DeferredAction
);
587 for (i
= 0; i
< package
->CommitActionCount
; i
++)
588 HeapFree(GetProcessHeap(),0,package
->CommitAction
[i
]);
589 HeapFree(GetProcessHeap(),0,package
->CommitAction
);
591 HeapFree(GetProcessHeap(),0,package
->PackagePath
);
594 static void ui_progress(MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
598 row
= MSI_CreateRecord(4);
599 MSI_RecordSetInteger(row
,1,a
);
600 MSI_RecordSetInteger(row
,2,b
);
601 MSI_RecordSetInteger(row
,3,c
);
602 MSI_RecordSetInteger(row
,4,d
);
603 MSI_ProcessMessage(package
, INSTALLMESSAGE_PROGRESS
, row
);
604 msiobj_release(&row
->hdr
);
607 static void ui_actiondata(MSIPACKAGE
*package
, LPCWSTR action
, MSIRECORD
* record
)
609 static const WCHAR Query_t
[] =
610 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
611 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
612 ' ','\'','%','s','\'',0};
619 if (!package
->LastAction
|| strcmpW(package
->LastAction
,action
))
621 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, action
);
622 if (rc
!= ERROR_SUCCESS
)
625 rc
= MSI_ViewExecute(view
, 0);
626 if (rc
!= ERROR_SUCCESS
)
631 rc
= MSI_ViewFetch(view
,&row
);
632 if (rc
!= ERROR_SUCCESS
)
638 if (MSI_RecordIsNull(row
,3))
640 msiobj_release(&row
->hdr
);
642 msiobj_release(&view
->hdr
);
646 /* update the cached actionformat */
647 HeapFree(GetProcessHeap(),0,package
->ActionFormat
);
648 package
->ActionFormat
= load_dynamic_stringW(row
,3);
650 HeapFree(GetProcessHeap(),0,package
->LastAction
);
651 package
->LastAction
= dupstrW(action
);
653 msiobj_release(&row
->hdr
);
655 msiobj_release(&view
->hdr
);
658 MSI_RecordSetStringW(record
,0,package
->ActionFormat
);
660 MSI_FormatRecordW(package
,record
,message
,&size
);
662 row
= MSI_CreateRecord(1);
663 MSI_RecordSetStringW(row
,1,message
);
665 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, row
);
666 msiobj_release(&row
->hdr
);
670 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
672 static const WCHAR template_s
[]=
673 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
674 static const WCHAR format
[] =
675 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
676 static const WCHAR Query_t
[] =
677 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
678 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
679 ' ','\'','%','s','\'',0};
685 WCHAR
*ActionText
=NULL
;
687 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
689 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, action
);
690 if (rc
!= ERROR_SUCCESS
)
692 rc
= MSI_ViewExecute(view
, 0);
693 if (rc
!= ERROR_SUCCESS
)
696 msiobj_release(&view
->hdr
);
699 rc
= MSI_ViewFetch(view
,&row
);
700 if (rc
!= ERROR_SUCCESS
)
703 msiobj_release(&view
->hdr
);
707 ActionText
= load_dynamic_stringW(row
,2);
708 msiobj_release(&row
->hdr
);
710 msiobj_release(&view
->hdr
);
712 sprintfW(message
,template_s
,timet
,action
,ActionText
);
714 row
= MSI_CreateRecord(1);
715 MSI_RecordSetStringW(row
,1,message
);
717 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
718 msiobj_release(&row
->hdr
);
719 HeapFree(GetProcessHeap(),0,ActionText
);
722 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
726 static const WCHAR template_s
[]=
727 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
729 static const WCHAR template_e
[]=
730 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
731 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
732 static const WCHAR format
[] =
733 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
737 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
739 sprintfW(message
,template_s
,timet
,action
);
741 sprintfW(message
,template_e
,timet
,action
,rc
);
743 row
= MSI_CreateRecord(1);
744 MSI_RecordSetStringW(row
,1,message
);
746 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
747 msiobj_release(&row
->hdr
);
751 * build_directory_name()
753 * This function is to save messing round with directory names
754 * It handles adding backslashes between path segments,
755 * and can add \ at the end of the directory name if told to.
757 * It takes a variable number of arguments.
758 * It always allocates a new string for the result, so make sure
759 * to free the return value when finished with it.
761 * The first arg is the number of path segments that follow.
762 * The arguments following count are a list of path segments.
763 * A path segment may be NULL.
765 * Path segments will be added with a \ separating them.
766 * A \ will not be added after the last segment, however if the
767 * last segment is NULL, then the last character will be a \
770 static LPWSTR
build_directory_name(DWORD count
, ...)
777 for(i
=0; i
<count
; i
++)
779 LPCWSTR str
= va_arg(va
,LPCWSTR
);
781 sz
+= strlenW(str
) + 1;
785 dir
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
789 for(i
=0; i
<count
; i
++)
791 LPCWSTR str
= va_arg(va
,LPCWSTR
);
795 if( ((i
+1)!=count
) && dir
[strlenW(dir
)-1]!='\\')
802 /****************************************************
803 * TOP level entry points
804 *****************************************************/
806 UINT
ACTION_DoTopLevelINSTALL(MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
807 LPCWSTR szCommandLine
)
812 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
813 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
814 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
816 MSI_SetPropertyW(package
, szAction
, szInstall
);
820 LPWSTR p
, check
, path
;
822 package
->PackagePath
= dupstrW(szPackagePath
);
823 path
= dupstrW(szPackagePath
);
824 p
= strrchrW(path
,'\\');
831 check
= load_dynamic_property(package
, cszSourceDir
,NULL
);
833 MSI_SetPropertyW(package
, cszSourceDir
, path
);
835 HeapFree(GetProcessHeap(), 0, check
);
837 HeapFree(GetProcessHeap(), 0, path
);
843 ptr
= (LPWSTR
)szCommandLine
;
850 TRACE("Looking at %s\n",debugstr_w(ptr
));
852 ptr2
= strchrW(ptr
,'=');
858 while (*ptr
== ' ') ptr
++;
860 prop
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
861 strncpyW(prop
,ptr
,len
);
867 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
880 val
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
881 strncpyW(val
,ptr2
,len
);
884 if (strlenW(prop
) > 0)
886 TRACE("Found commandline property (%s) = (%s)\n",
887 debugstr_w(prop
), debugstr_w(val
));
888 MSI_SetPropertyW(package
,prop
,val
);
890 HeapFree(GetProcessHeap(),0,val
);
891 HeapFree(GetProcessHeap(),0,prop
);
898 if (MSI_GetPropertyW(package
,szUILevel
,buffer
,&sz
) == ERROR_SUCCESS
)
900 if (atoiW(buffer
) >= INSTALLUILEVEL_REDUCED
)
902 rc
= ACTION_ProcessUISequence(package
);
903 if (rc
== ERROR_SUCCESS
)
904 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
907 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
910 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
914 /* install was halted but should be considered a success */
918 /* process the ending type action */
919 if (rc
== ERROR_SUCCESS
)
920 ACTION_PerformActionSequence(package
,-1);
921 else if (rc
== ERROR_INSTALL_USEREXIT
)
922 ACTION_PerformActionSequence(package
,-2);
923 else if (rc
== ERROR_FUNCTION_FAILED
)
924 ACTION_PerformActionSequence(package
,-3);
925 else if (rc
== ERROR_INSTALL_SUSPEND
)
926 ACTION_PerformActionSequence(package
,-4);
928 /* finish up running custom actions */
929 ACTION_FinishCustomActions(package
);
934 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
941 static const WCHAR ExecSeqQuery
[] = {
942 's','e','l','e','c','t',' ','*',' ',
944 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
945 'S','e','q','u','e','n','c','e',' ',
946 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
949 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
951 if (rc
== ERROR_SUCCESS
)
953 rc
= MSI_ViewExecute(view
, 0);
955 if (rc
!= ERROR_SUCCESS
)
958 msiobj_release(&view
->hdr
);
962 TRACE("Running the actions\n");
964 rc
= MSI_ViewFetch(view
,&row
);
965 if (rc
!= ERROR_SUCCESS
)
971 /* check conditions */
972 if (!MSI_RecordIsNull(row
,2))
975 cond
= load_dynamic_stringW(row
,2);
979 /* this is a hack to skip errors in the condition code */
980 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
982 HeapFree(GetProcessHeap(),0,cond
);
983 msiobj_release(&row
->hdr
);
987 HeapFree(GetProcessHeap(),0,cond
);
992 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
993 if (rc
!= ERROR_SUCCESS
)
995 ERR("Error is %x\n",rc
);
996 msiobj_release(&row
->hdr
);
1000 rc
= ACTION_PerformAction(package
,buffer
);
1001 msiobj_release(&row
->hdr
);
1003 MSI_ViewClose(view
);
1004 msiobj_release(&view
->hdr
);
1012 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
1016 static const WCHAR ExecSeqQuery
[] = {
1017 's','e','l','e','c','t',' ','*',' ',
1018 'f','r','o','m',' ',
1019 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1020 'S','e','q','u','e','n','c','e',' ',
1021 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
1022 '>',' ','%','i',' ','o','r','d','e','r',' ',
1023 'b','y',' ','S','e','q','u','e','n','c','e',0 };
1024 MSIRECORD
* row
= 0;
1025 static const WCHAR IVQuery
[] = {
1026 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
1027 'f','r','o','m',' ','I','n','s','t','a','l','l',
1028 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
1029 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
1030 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
1034 /* get the sequence number */
1037 rc
= MSI_DatabaseOpenViewW(package
->db
, IVQuery
, &view
);
1038 if (rc
!= ERROR_SUCCESS
)
1040 rc
= MSI_ViewExecute(view
, 0);
1041 if (rc
!= ERROR_SUCCESS
)
1043 MSI_ViewClose(view
);
1044 msiobj_release(&view
->hdr
);
1047 rc
= MSI_ViewFetch(view
,&row
);
1048 if (rc
!= ERROR_SUCCESS
)
1050 MSI_ViewClose(view
);
1051 msiobj_release(&view
->hdr
);
1054 seq
= MSI_RecordGetInteger(row
,1);
1055 msiobj_release(&row
->hdr
);
1056 MSI_ViewClose(view
);
1057 msiobj_release(&view
->hdr
);
1060 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
1061 if (rc
== ERROR_SUCCESS
)
1063 rc
= MSI_ViewExecute(view
, 0);
1065 if (rc
!= ERROR_SUCCESS
)
1067 MSI_ViewClose(view
);
1068 msiobj_release(&view
->hdr
);
1072 TRACE("Running the actions\n");
1076 WCHAR buffer
[0x100];
1079 rc
= MSI_ViewFetch(view
,&row
);
1080 if (rc
!= ERROR_SUCCESS
)
1086 /* check conditions */
1087 if (!MSI_RecordIsNull(row
,2))
1090 cond
= load_dynamic_stringW(row
,2);
1094 /* this is a hack to skip errors in the condition code */
1095 if (MSI_EvaluateConditionW(package
, cond
) ==
1098 HeapFree(GetProcessHeap(),0,cond
);
1099 msiobj_release(&row
->hdr
);
1103 HeapFree(GetProcessHeap(),0,cond
);
1108 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1109 if (rc
!= ERROR_SUCCESS
)
1111 ERR("Error is %x\n",rc
);
1112 msiobj_release(&row
->hdr
);
1116 rc
= ACTION_PerformAction(package
,buffer
);
1118 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1121 if (rc
!= ERROR_SUCCESS
)
1123 ERR("Execution halted due to error (%i)\n",rc
);
1124 msiobj_release(&row
->hdr
);
1128 msiobj_release(&row
->hdr
);
1131 MSI_ViewClose(view
);
1132 msiobj_release(&view
->hdr
);
1140 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
1144 static const WCHAR ExecSeqQuery
[] = {
1145 's','e','l','e','c','t',' ','*',' ',
1146 'f','r','o','m',' ','I','n','s','t','a','l','l',
1147 'U','I','S','e','q','u','e','n','c','e',' ',
1148 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
1149 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
1151 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1153 if (rc
== ERROR_SUCCESS
)
1155 rc
= MSI_ViewExecute(view
, 0);
1157 if (rc
!= ERROR_SUCCESS
)
1159 MSI_ViewClose(view
);
1160 msiobj_release(&view
->hdr
);
1164 TRACE("Running the actions \n");
1168 WCHAR buffer
[0x100];
1170 MSIRECORD
* row
= 0;
1172 rc
= MSI_ViewFetch(view
,&row
);
1173 if (rc
!= ERROR_SUCCESS
)
1179 /* check conditions */
1180 if (!MSI_RecordIsNull(row
,2))
1183 cond
= load_dynamic_stringW(row
,2);
1187 /* this is a hack to skip errors in the condition code */
1188 if (MSI_EvaluateConditionW(package
, cond
) ==
1191 HeapFree(GetProcessHeap(),0,cond
);
1192 msiobj_release(&row
->hdr
);
1196 HeapFree(GetProcessHeap(),0,cond
);
1201 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1202 if (rc
!= ERROR_SUCCESS
)
1204 ERR("Error is %x\n",rc
);
1205 msiobj_release(&row
->hdr
);
1209 rc
= ACTION_PerformUIAction(package
,buffer
);
1211 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1214 if (rc
!= ERROR_SUCCESS
)
1216 ERR("Execution halted due to error (%i)\n",rc
);
1217 msiobj_release(&row
->hdr
);
1221 msiobj_release(&row
->hdr
);
1224 MSI_ViewClose(view
);
1225 msiobj_release(&view
->hdr
);
1232 /********************************************************
1233 * ACTION helper functions and functions that perform the actions
1234 *******************************************************/
1235 BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
, UINT
* rc
)
1241 while (StandardActions
[i
].action
!= NULL
)
1243 if (strcmpW(StandardActions
[i
].action
, action
)==0)
1245 ui_actioninfo(package
, action
, TRUE
, 0);
1246 ui_actionstart(package
, action
);
1247 if (StandardActions
[i
].handler
)
1249 *rc
= StandardActions
[i
].handler(package
);
1253 FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action
));
1254 *rc
= ERROR_SUCCESS
;
1256 ui_actioninfo(package
, action
, FALSE
, *rc
);
1265 BOOL
ACTION_HandleDialogBox(MSIPACKAGE
*package
, LPCWSTR dialog
, UINT
* rc
)
1270 * for the UI when we get that working
1272 if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1274 *rc = package->CurrentInstallState;
1281 BOOL
ACTION_HandleCustomAction(MSIPACKAGE
* package
, LPCWSTR action
, UINT
* rc
)
1286 arc
= ACTION_CustomAction(package
,action
,FALSE
);
1288 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1297 * A lot of actions are really important even if they don't do anything
1298 * explicit... Lots of properties are set at the beginning of the installation
1299 * CostFinalize does a bunch of work to translate the directories and such
1301 * But until I get write access to the database that is hard, so I am going to
1302 * hack it to see if I can get something to run.
1304 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1306 UINT rc
= ERROR_SUCCESS
;
1309 TRACE("Performing action (%s)\n",debugstr_w(action
));
1311 handled
= ACTION_HandleStandardAction(package
, action
, &rc
);
1314 handled
= ACTION_HandleCustomAction(package
, action
, &rc
);
1318 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1319 rc
= ERROR_FUNCTION_NOT_CALLED
;
1322 package
->CurrentInstallState
= rc
;
1326 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1328 UINT rc
= ERROR_SUCCESS
;
1329 BOOL handled
= FALSE
;
1331 TRACE("Performing action (%s)\n",debugstr_w(action
));
1333 handled
= ACTION_HandleStandardAction(package
, action
, &rc
);
1336 handled
= ACTION_HandleCustomAction(package
, action
, &rc
);
1339 handled
= ACTION_HandleDialogBox(package
, action
, &rc
);
1343 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1344 rc
= ERROR_FUNCTION_NOT_CALLED
;
1347 package
->CurrentInstallState
= rc
;
1351 /***********************************************************************
1354 * Recursively create all directories in the path.
1356 * shamelessly stolen from setupapi/queue.c
1358 static BOOL
create_full_pathW(const WCHAR
*path
)
1364 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
1367 strcpyW(new_path
, path
);
1369 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1370 new_path
[len
- 1] = 0;
1372 while(!CreateDirectoryW(new_path
, NULL
))
1375 DWORD last_error
= GetLastError();
1376 if(last_error
== ERROR_ALREADY_EXISTS
)
1379 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1385 if(!(slash
= strrchrW(new_path
, '\\')))
1391 len
= slash
- new_path
;
1393 if(!create_full_pathW(new_path
))
1398 new_path
[len
] = '\\';
1401 HeapFree(GetProcessHeap(), 0, new_path
);
1406 * Also we cannot enable/disable components either, so for now I am just going
1407 * to do all the directories for all the components.
1409 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1411 static const WCHAR ExecSeqQuery
[] = {
1412 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1413 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1418 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1419 if (rc
!= ERROR_SUCCESS
)
1420 return ERROR_SUCCESS
;
1422 rc
= MSI_ViewExecute(view
, 0);
1423 if (rc
!= ERROR_SUCCESS
)
1425 MSI_ViewClose(view
);
1426 msiobj_release(&view
->hdr
);
1435 MSIRECORD
*row
= NULL
, *uirow
;
1437 rc
= MSI_ViewFetch(view
,&row
);
1438 if (rc
!= ERROR_SUCCESS
)
1445 rc
= MSI_RecordGetStringW(row
,1,dir
,&sz
);
1447 if (rc
!= ERROR_SUCCESS
)
1449 ERR("Unable to get folder id \n");
1450 msiobj_release(&row
->hdr
);
1455 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1458 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1459 msiobj_release(&row
->hdr
);
1463 TRACE("Folder is %s\n",debugstr_w(full_path
));
1466 uirow
= MSI_CreateRecord(1);
1467 MSI_RecordSetStringW(uirow
,1,full_path
);
1468 ui_actiondata(package
,szCreateFolders
,uirow
);
1469 msiobj_release( &uirow
->hdr
);
1471 if (folder
->State
== 0)
1472 create_full_pathW(full_path
);
1476 msiobj_release(&row
->hdr
);
1477 HeapFree(GetProcessHeap(),0,full_path
);
1479 MSI_ViewClose(view
);
1480 msiobj_release(&view
->hdr
);
1485 static int load_component(MSIPACKAGE
* package
, MSIRECORD
* row
)
1487 int index
= package
->loaded_components
;
1490 /* fill in the data */
1492 package
->loaded_components
++;
1493 if (package
->loaded_components
== 1)
1494 package
->components
= HeapAlloc(GetProcessHeap(),0,
1495 sizeof(MSICOMPONENT
));
1497 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1498 package
->components
, package
->loaded_components
*
1499 sizeof(MSICOMPONENT
));
1501 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1504 MSI_RecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1506 TRACE("Loading Component %s\n",
1507 debugstr_w(package
->components
[index
].Component
));
1510 if (!MSI_RecordIsNull(row
,2))
1511 MSI_RecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1514 MSI_RecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1516 package
->components
[index
].Attributes
= MSI_RecordGetInteger(row
,4);
1519 MSI_RecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
1522 MSI_RecordGetStringW(row
,6,package
->components
[index
].KeyPath
,&sz
);
1524 package
->components
[index
].Installed
= INSTALLSTATE_ABSENT
;
1525 package
->components
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1526 package
->components
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1528 package
->components
[index
].Enabled
= TRUE
;
1533 static void load_feature(MSIPACKAGE
* package
, MSIRECORD
* row
)
1535 int index
= package
->loaded_features
;
1537 static const WCHAR Query1
[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1538 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1539 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1540 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1541 static const WCHAR Query2
[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1542 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1543 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1550 /* fill in the data */
1552 package
->loaded_features
++;
1553 if (package
->loaded_features
== 1)
1554 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1556 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1557 package
->loaded_features
* sizeof(MSIFEATURE
));
1559 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1562 MSI_RecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1564 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1567 if (!MSI_RecordIsNull(row
,2))
1568 MSI_RecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1571 if (!MSI_RecordIsNull(row
,3))
1572 MSI_RecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
1575 if (!MSI_RecordIsNull(row
,4))
1576 MSI_RecordGetStringW(row
,4,package
->features
[index
].Description
,&sz
);
1578 if (!MSI_RecordIsNull(row
,5))
1579 package
->features
[index
].Display
= MSI_RecordGetInteger(row
,5);
1581 package
->features
[index
].Level
= MSI_RecordGetInteger(row
,6);
1584 if (!MSI_RecordIsNull(row
,7))
1585 MSI_RecordGetStringW(row
,7,package
->features
[index
].Directory
,&sz
);
1587 package
->features
[index
].Attributes
= MSI_RecordGetInteger(row
,8);
1589 package
->features
[index
].Installed
= INSTALLSTATE_ABSENT
;
1590 package
->features
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1591 package
->features
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1593 /* load feature components */
1595 rc
= MSI_OpenQuery(package
->db
, &view
, Query1
, package
->features
[index
].Feature
);
1596 if (rc
!= ERROR_SUCCESS
)
1598 rc
= MSI_ViewExecute(view
,0);
1599 if (rc
!= ERROR_SUCCESS
)
1601 MSI_ViewClose(view
);
1602 msiobj_release(&view
->hdr
);
1608 WCHAR buffer
[0x100];
1611 INT cnt
= package
->features
[index
].ComponentCount
;
1613 rc
= MSI_ViewFetch(view
,&row2
);
1614 if (rc
!= ERROR_SUCCESS
)
1618 MSI_RecordGetStringW(row2
,1,buffer
,&sz
);
1620 /* check to see if the component is already loaded */
1621 c_indx
= get_loaded_component(package
,buffer
);
1624 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer
),
1626 package
->features
[index
].Components
[cnt
] = c_indx
;
1627 package
->features
[index
].ComponentCount
++;
1631 rc
= MSI_OpenQuery(package
->db
, &view2
, Query2
, buffer
);
1632 if (rc
!= ERROR_SUCCESS
)
1634 msiobj_release( &row2
->hdr
);
1637 rc
= MSI_ViewExecute(view2
,0);
1638 if (rc
!= ERROR_SUCCESS
)
1640 msiobj_release( &row2
->hdr
);
1641 MSI_ViewClose(view2
);
1642 msiobj_release( &view2
->hdr
);
1649 rc
= MSI_ViewFetch(view2
,&row3
);
1650 if (rc
!= ERROR_SUCCESS
)
1652 c_indx
= load_component(package
,row3
);
1653 msiobj_release( &row3
->hdr
);
1655 package
->features
[index
].Components
[cnt
] = c_indx
;
1656 package
->features
[index
].ComponentCount
++;
1657 TRACE("Loaded new component to index %i\n",c_indx
);
1659 MSI_ViewClose(view2
);
1660 msiobj_release( &view2
->hdr
);
1661 msiobj_release( &row2
->hdr
);
1663 MSI_ViewClose(view
);
1664 msiobj_release(&view
->hdr
);
1668 * I am not doing any of the costing functionality yet.
1669 * Mostly looking at doing the Component and Feature loading
1671 * The native MSI does A LOT of modification to tables here. Mostly adding
1672 * a lot of temporary columns to the Feature and Component tables.
1674 * note: Native msi also tracks the short filename. But I am only going to
1675 * track the long ones. Also looking at this directory table
1676 * it appears that the directory table does not get the parents
1677 * resolved base on property only based on their entries in the
1680 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1685 static const WCHAR Query_all
[] = {
1686 'S','E','L','E','C','T',' ','*',' ',
1687 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
1688 static const WCHAR szCosting
[] = {
1689 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1690 static const WCHAR szZero
[] = { '0', 0 };
1692 MSI_SetPropertyW(package
, szCosting
, szZero
);
1693 MSI_SetPropertyW(package
, cszRootDrive
, c_collen
);
1695 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1696 if (rc
!= ERROR_SUCCESS
)
1698 rc
= MSI_ViewExecute(view
,0);
1699 if (rc
!= ERROR_SUCCESS
)
1701 MSI_ViewClose(view
);
1702 msiobj_release(&view
->hdr
);
1709 rc
= MSI_ViewFetch(view
,&row
);
1710 if (rc
!= ERROR_SUCCESS
)
1713 load_feature(package
,row
);
1714 msiobj_release(&row
->hdr
);
1716 MSI_ViewClose(view
);
1717 msiobj_release(&view
->hdr
);
1719 return ERROR_SUCCESS
;
1722 static UINT
load_file(MSIPACKAGE
* package
, MSIRECORD
* row
)
1724 DWORD index
= package
->loaded_files
;
1728 /* fill in the data */
1730 package
->loaded_files
++;
1731 if (package
->loaded_files
== 1)
1732 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
1734 package
->files
= HeapReAlloc(GetProcessHeap(),0,
1735 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
1737 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
1739 package
->files
[index
].File
= load_dynamic_stringW(row
, 1);
1740 buffer
= load_dynamic_stringW(row
, 2);
1742 package
->files
[index
].ComponentIndex
= -1;
1743 for (i
= 0; i
< package
->loaded_components
; i
++)
1744 if (strcmpW(package
->components
[i
].Component
,buffer
)==0)
1746 package
->files
[index
].ComponentIndex
= i
;
1749 if (package
->files
[index
].ComponentIndex
== -1)
1750 ERR("Unfound Component %s\n",debugstr_w(buffer
));
1751 HeapFree(GetProcessHeap(), 0, buffer
);
1753 package
->files
[index
].FileName
= load_dynamic_stringW(row
,3);
1755 reduce_to_longfilename(package
->files
[index
].FileName
);
1757 package
->files
[index
].FileSize
= MSI_RecordGetInteger(row
,4);
1758 package
->files
[index
].Version
= load_dynamic_stringW(row
, 5);
1759 package
->files
[index
].Language
= load_dynamic_stringW(row
, 6);
1760 package
->files
[index
].Attributes
= MSI_RecordGetInteger(row
,7);
1761 package
->files
[index
].Sequence
= MSI_RecordGetInteger(row
,8);
1763 package
->files
[index
].Temporary
= FALSE
;
1764 package
->files
[index
].State
= 0;
1766 TRACE("File Loaded (%s)\n",debugstr_w(package
->files
[index
].File
));
1768 return ERROR_SUCCESS
;
1771 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1776 static const WCHAR Query
[] = {
1777 'S','E','L','E','C','T',' ','*',' ',
1778 'F','R','O','M',' ','F','i','l','e',' ',
1779 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
1782 return ERROR_INVALID_HANDLE
;
1784 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1785 if (rc
!= ERROR_SUCCESS
)
1786 return ERROR_SUCCESS
;
1788 rc
= MSI_ViewExecute(view
, 0);
1789 if (rc
!= ERROR_SUCCESS
)
1791 MSI_ViewClose(view
);
1792 msiobj_release(&view
->hdr
);
1793 return ERROR_SUCCESS
;
1798 rc
= MSI_ViewFetch(view
,&row
);
1799 if (rc
!= ERROR_SUCCESS
)
1804 load_file(package
,row
);
1805 msiobj_release(&row
->hdr
);
1807 MSI_ViewClose(view
);
1808 msiobj_release(&view
->hdr
);
1810 return ERROR_SUCCESS
;
1813 static INT
load_folder(MSIPACKAGE
*package
, const WCHAR
* dir
)
1816 static const WCHAR Query
[] =
1817 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1818 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1819 'o','r','y','`',' ','=',' ','`','%','s','`',0};
1822 LPWSTR targetdir
, parent
, srcdir
;
1823 MSIRECORD
* row
= 0;
1827 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1829 for (i
= 0; i
< package
->loaded_folders
; i
++)
1831 if (strcmpW(package
->folders
[i
].Directory
,dir
)==0)
1833 TRACE(" %s retuning on index %lu\n",debugstr_w(dir
),i
);
1838 TRACE("Working to load %s\n",debugstr_w(dir
));
1840 index
= package
->loaded_folders
++;
1841 if (package
->loaded_folders
==1)
1842 package
->folders
= HeapAlloc(GetProcessHeap(),0,
1845 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
1846 package
->folders
, package
->loaded_folders
*
1849 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
1851 package
->folders
[index
].Directory
= dupstrW(dir
);
1853 rc
= MSI_OpenQuery(package
->db
, &view
, Query
, dir
);
1854 if (rc
!= ERROR_SUCCESS
)
1857 rc
= MSI_ViewExecute(view
, 0);
1858 if (rc
!= ERROR_SUCCESS
)
1860 MSI_ViewClose(view
);
1861 msiobj_release(&view
->hdr
);
1865 rc
= MSI_ViewFetch(view
,&row
);
1866 if (rc
!= ERROR_SUCCESS
)
1868 MSI_ViewClose(view
);
1869 msiobj_release(&view
->hdr
);
1873 targetdir
= load_dynamic_stringW(row
,3);
1875 /* split src and target dir */
1876 if (strchrW(targetdir
,':'))
1878 srcdir
=strchrW(targetdir
,':');
1885 /* for now only pick long filename versions */
1886 if (strchrW(targetdir
,'|'))
1888 targetdir
= strchrW(targetdir
,'|');
1892 if (srcdir
&& strchrW(srcdir
,'|'))
1894 srcdir
= strchrW(srcdir
,'|');
1899 /* now check for root dirs */
1900 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1903 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
1908 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1909 HeapFree(GetProcessHeap(),0, package
->folders
[index
].TargetDefault
);
1910 package
->folders
[index
].TargetDefault
= dupstrW(targetdir
);
1914 package
->folders
[index
].SourceDefault
= dupstrW(srcdir
);
1916 package
->folders
[index
].SourceDefault
= dupstrW(targetdir
);
1917 HeapFree(GetProcessHeap(), 0, targetdir
);
1919 parent
= load_dynamic_stringW(row
,2);
1922 i
= load_folder(package
,parent
);
1923 package
->folders
[index
].ParentIndex
= i
;
1924 TRACE("Parent is index %i... %s %s\n",
1925 package
->folders
[index
].ParentIndex
,
1926 debugstr_w(package
->folders
[package
->folders
[index
].ParentIndex
].Directory
),
1927 debugstr_w(parent
));
1930 package
->folders
[index
].ParentIndex
= -2;
1931 HeapFree(GetProcessHeap(), 0, parent
);
1933 package
->folders
[index
].Property
= load_dynamic_property(package
, dir
,NULL
);
1935 msiobj_release(&row
->hdr
);
1936 MSI_ViewClose(view
);
1937 msiobj_release(&view
->hdr
);
1938 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),index
);
1943 LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
, BOOL source
,
1944 BOOL set_prop
, MSIFOLDER
**folder
)
1947 LPWSTR p
, path
= NULL
;
1949 TRACE("Working to resolve %s\n",debugstr_w(name
));
1951 /* special resolving for Target and Source root dir */
1952 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
1956 path
= load_dynamic_property(package
,cszTargetDir
,NULL
);
1959 path
= load_dynamic_property(package
,cszRootDrive
,NULL
);
1961 MSI_SetPropertyW(package
,cszTargetDir
,path
);
1965 for (i
= 0; i
< package
->loaded_folders
; i
++)
1967 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1970 *folder
= &(package
->folders
[i
]);
1976 path
= load_dynamic_property(package
,cszSourceDir
,NULL
);
1979 path
= load_dynamic_property(package
,cszDatabase
,NULL
);
1982 p
= strrchrW(path
,'\\');
1989 for (i
= 0; i
< package
->loaded_folders
; i
++)
1991 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1994 *folder
= &(package
->folders
[i
]);
2000 for (i
= 0; i
< package
->loaded_folders
; i
++)
2002 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2006 if (i
>= package
->loaded_folders
)
2010 *folder
= &(package
->folders
[i
]);
2012 if (!source
&& package
->folders
[i
].ResolvedTarget
)
2014 path
= dupstrW(package
->folders
[i
].ResolvedTarget
);
2015 TRACE(" already resolved to %s\n",debugstr_w(path
));
2018 else if (source
&& package
->folders
[i
].ResolvedSource
)
2020 path
= dupstrW(package
->folders
[i
].ResolvedSource
);
2023 else if (!source
&& package
->folders
[i
].Property
)
2025 path
= dupstrW(package
->folders
[i
].Property
);
2026 TRACE(" internally set to %s\n",debugstr_w(path
));
2028 MSI_SetPropertyW(package
,name
,path
);
2032 if (package
->folders
[i
].ParentIndex
>= 0)
2034 LPWSTR parent
= package
->folders
[package
->folders
[i
].ParentIndex
].Directory
;
2036 TRACE(" ! Parent is %s\n", debugstr_w(parent
));
2038 p
= resolve_folder(package
, parent
, source
, set_prop
, NULL
);
2041 TRACE(" TargetDefault = %s\n",debugstr_w(package
->folders
[i
].TargetDefault
));
2042 path
= build_directory_name(3, p
, package
->folders
[i
].TargetDefault
, NULL
);
2043 package
->folders
[i
].ResolvedTarget
= dupstrW(path
);
2044 TRACE(" resolved into %s\n",debugstr_w(path
));
2046 MSI_SetPropertyW(package
,name
,path
);
2050 path
= build_directory_name(3, p
, package
->folders
[i
].SourceDefault
, NULL
);
2051 package
->folders
[i
].ResolvedSource
= dupstrW(path
);
2053 HeapFree(GetProcessHeap(),0,p
);
2058 /* update compoennt state based on a feature change */
2059 void ACTION_UpdateComponentStates(MSIPACKAGE
*package
, LPCWSTR szFeature
)
2062 INSTALLSTATE newstate
;
2063 MSIFEATURE
*feature
;
2065 i
= get_loaded_feature(package
,szFeature
);
2069 feature
= &package
->features
[i
];
2070 newstate
= feature
->ActionRequest
;
2072 for( i
= 0; i
< feature
->ComponentCount
; i
++)
2074 MSICOMPONENT
* component
= &package
->components
[feature
->Components
[i
]];
2076 if (!component
->Enabled
)
2080 if (newstate
== INSTALLSTATE_LOCAL
)
2081 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2086 component
->ActionRequest
= newstate
;
2088 /*if any other feature wants is local we need to set it local*/
2090 j
< package
->loaded_features
&&
2091 component
->ActionRequest
!= INSTALLSTATE_LOCAL
;
2094 for (k
= 0; k
< package
->features
[j
].ComponentCount
; k
++)
2095 if ( package
->features
[j
].Components
[k
] ==
2096 feature
->Components
[i
] )
2098 if (package
->features
[j
].ActionRequest
==
2100 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2109 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
2115 LPWSTR override
= NULL
;
2116 static const WCHAR all
[]={'A','L','L',0};
2117 static const WCHAR szlevel
[] = {
2118 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2119 static const WCHAR szAddLocal
[] = {
2120 'A','D','D','L','O','C','A','L',0};
2122 /* I do not know if this is where it should happen.. but */
2124 TRACE("Checking Install Level\n");
2126 level
= load_dynamic_property(package
,szlevel
,NULL
);
2129 install_level
= atoiW(level
);
2130 HeapFree(GetProcessHeap(), 0, level
);
2135 /* ok hereis the rub
2136 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
2137 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
2138 * itnored for all the features. seems strange, epsecially since it is not
2139 * documented anywhere, but it is how it works.
2142 override
= load_dynamic_property(package
,szAddLocal
,NULL
);
2146 for(i
= 0; i
< package
->loaded_features
; i
++)
2148 if (strcmpiW(override
,all
)==0)
2150 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2151 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2155 LPWSTR ptr
= override
;
2156 LPWSTR ptr2
= strchrW(override
,',');
2161 strncmpW(ptr
,package
->features
[i
].Feature
, ptr2
-ptr
)==0)
2163 strcmpW(ptr
,package
->features
[i
].Feature
)==0))
2165 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2166 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2172 ptr2
= strchrW(ptr
,',');
2179 HeapFree(GetProcessHeap(),0,override
);
2183 for(i
= 0; i
< package
->loaded_features
; i
++)
2185 BOOL feature_state
= ((package
->features
[i
].Level
> 0) &&
2186 (package
->features
[i
].Level
<= install_level
));
2190 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2191 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2197 * now we want to enable or disable components base on feature
2200 for(i
= 0; i
< package
->loaded_features
; i
++)
2202 MSIFEATURE
* feature
= &package
->features
[i
];
2203 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2204 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2205 feature
->ActionRequest
);
2207 for( j
= 0; j
< feature
->ComponentCount
; j
++)
2209 MSICOMPONENT
* component
= &package
->components
[
2210 feature
->Components
[j
]];
2212 if (!component
->Enabled
)
2214 component
->Action
= INSTALLSTATE_ABSENT
;
2215 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
2219 if (feature
->Action
== INSTALLSTATE_LOCAL
)
2220 component
->Action
= INSTALLSTATE_LOCAL
;
2221 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
2222 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2227 for(i
= 0; i
< package
->loaded_components
; i
++)
2229 MSICOMPONENT
* component
= &package
->components
[i
];
2231 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2232 debugstr_w(component
->Component
), component
->Installed
,
2233 component
->Action
, component
->ActionRequest
);
2237 return ERROR_SUCCESS
;
2241 * A lot is done in this function aside from just the costing.
2242 * The costing needs to be implemented at some point but for now I am going
2243 * to focus on the directory building
2246 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2248 static const WCHAR ExecSeqQuery
[] = {
2249 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2250 'D','i','r','e','c','t','o','r','y',0};
2251 static const WCHAR ConditionQuery
[] = {
2252 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2253 'C','o','n','d','i','t','i','o','n',0};
2254 static const WCHAR szCosting
[] = {
2255 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2256 static const WCHAR szlevel
[] = {
2257 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2258 static const WCHAR szOne
[] = { '1', 0 };
2264 TRACE("Building Directory properties\n");
2266 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2267 if (rc
== ERROR_SUCCESS
)
2269 rc
= MSI_ViewExecute(view
, 0);
2270 if (rc
!= ERROR_SUCCESS
)
2272 MSI_ViewClose(view
);
2273 msiobj_release(&view
->hdr
);
2281 MSIRECORD
* row
= 0;
2284 rc
= MSI_ViewFetch(view
,&row
);
2285 if (rc
!= ERROR_SUCCESS
)
2292 MSI_RecordGetStringW(row
,1,name
,&sz
);
2294 /* This helper function now does ALL the work */
2295 TRACE("Dir %s ...\n",debugstr_w(name
));
2296 load_folder(package
,name
);
2297 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
2298 TRACE("resolves to %s\n",debugstr_w(path
));
2299 HeapFree( GetProcessHeap(), 0, path
);
2301 msiobj_release(&row
->hdr
);
2303 MSI_ViewClose(view
);
2304 msiobj_release(&view
->hdr
);
2307 TRACE("File calculations %i files\n",package
->loaded_files
);
2309 for (i
= 0; i
< package
->loaded_files
; i
++)
2311 MSICOMPONENT
* comp
= NULL
;
2312 MSIFILE
* file
= NULL
;
2314 file
= &package
->files
[i
];
2315 if (file
->ComponentIndex
>= 0)
2316 comp
= &package
->components
[file
->ComponentIndex
];
2318 if (file
->Temporary
== TRUE
)
2325 /* calculate target */
2326 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2328 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2330 TRACE("file %s is named %s\n",
2331 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
2333 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2335 HeapFree(GetProcessHeap(),0,p
);
2337 TRACE("file %s resolves to %s\n",
2338 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
2340 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2343 comp
->Cost
+= file
->FileSize
;
2353 static const WCHAR name
[] =
2355 static const WCHAR name_fmt
[] =
2356 {'%','u','.','%','u','.','%','u','.','%','u',0};
2357 WCHAR filever
[0x100];
2358 VS_FIXEDFILEINFO
*lpVer
;
2360 TRACE("Version comparison.. \n");
2361 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
2362 version
= HeapAlloc(GetProcessHeap(),0,versize
);
2363 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
2365 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
2367 sprintfW(filever
,name_fmt
,
2368 HIWORD(lpVer
->dwFileVersionMS
),
2369 LOWORD(lpVer
->dwFileVersionMS
),
2370 HIWORD(lpVer
->dwFileVersionLS
),
2371 LOWORD(lpVer
->dwFileVersionLS
));
2373 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2374 debugstr_w(filever
));
2375 if (strcmpiW(filever
,file
->Version
)<0)
2378 FIXME("cost should be diff in size\n");
2379 comp
->Cost
+= file
->FileSize
;
2383 HeapFree(GetProcessHeap(),0,version
);
2391 TRACE("Evaluating Condition Table\n");
2393 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2394 if (rc
== ERROR_SUCCESS
)
2396 rc
= MSI_ViewExecute(view
, 0);
2397 if (rc
!= ERROR_SUCCESS
)
2399 MSI_ViewClose(view
);
2400 msiobj_release(&view
->hdr
);
2406 WCHAR Feature
[0x100];
2407 MSIRECORD
* row
= 0;
2411 rc
= MSI_ViewFetch(view
,&row
);
2413 if (rc
!= ERROR_SUCCESS
)
2420 MSI_RecordGetStringW(row
,1,Feature
,&sz
);
2422 feature_index
= get_loaded_feature(package
,Feature
);
2423 if (feature_index
< 0)
2424 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature
));
2428 Condition
= load_dynamic_stringW(row
,3);
2430 if (MSI_EvaluateConditionW(package
,Condition
) ==
2433 int level
= MSI_RecordGetInteger(row
,2);
2434 TRACE("Reseting feature %s to level %i\n",
2435 debugstr_w(Feature
), level
);
2436 package
->features
[feature_index
].Level
= level
;
2438 HeapFree(GetProcessHeap(),0,Condition
);
2441 msiobj_release(&row
->hdr
);
2443 MSI_ViewClose(view
);
2444 msiobj_release(&view
->hdr
);
2447 TRACE("Enabling or Disabling Components\n");
2448 for (i
= 0; i
< package
->loaded_components
; i
++)
2450 if (package
->components
[i
].Condition
[0])
2452 if (MSI_EvaluateConditionW(package
,
2453 package
->components
[i
].Condition
) == MSICONDITION_FALSE
)
2455 TRACE("Disabling component %s\n",
2456 debugstr_w(package
->components
[i
].Component
));
2457 package
->components
[i
].Enabled
= FALSE
;
2462 MSI_SetPropertyW(package
,szCosting
,szOne
);
2463 /* set default run level if not set */
2464 level
= load_dynamic_property(package
,szlevel
,NULL
);
2466 MSI_SetPropertyW(package
,szlevel
, szOne
);
2468 HeapFree(GetProcessHeap(),0,level
);
2470 return SetFeatureStates(package
);
2475 * This is a helper function for handling embedded cabinet media
2477 static UINT
writeout_cabinet_stream(MSIPACKAGE
*package
, WCHAR
* stream_name
,
2485 WCHAR tmp
[MAX_PATH
];
2487 rc
= read_raw_stream_data(package
->db
,stream_name
,&data
,&size
);
2488 if (rc
!= ERROR_SUCCESS
)
2492 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp
, &write
))
2493 GetTempPathW(MAX_PATH
,tmp
);
2495 GetTempFileNameW(tmp
,stream_name
,0,source
);
2497 track_tempfile(package
,strrchrW(source
,'\\'), source
);
2498 the_file
= CreateFileW(source
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2499 FILE_ATTRIBUTE_NORMAL
, NULL
);
2501 if (the_file
== INVALID_HANDLE_VALUE
)
2503 rc
= ERROR_FUNCTION_FAILED
;
2507 WriteFile(the_file
,data
,size
,&write
,NULL
);
2508 CloseHandle(the_file
);
2509 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2511 HeapFree(GetProcessHeap(),0,data
);
2516 /* Support functions for FDI functions */
2519 MSIPACKAGE
* package
;
2524 static void * cabinet_alloc(ULONG cb
)
2526 return HeapAlloc(GetProcessHeap(), 0, cb
);
2529 static void cabinet_free(void *pv
)
2531 HeapFree(GetProcessHeap(), 0, pv
);
2534 static INT_PTR
cabinet_open(char *pszFile
, int oflag
, int pmode
)
2537 DWORD dwShareMode
= 0;
2538 DWORD dwCreateDisposition
= OPEN_EXISTING
;
2539 switch (oflag
& _O_ACCMODE
)
2542 dwAccess
= GENERIC_READ
;
2543 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_DELETE
;
2546 dwAccess
= GENERIC_WRITE
;
2547 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2550 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
2551 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2554 if ((oflag
& (_O_CREAT
| _O_EXCL
)) == (_O_CREAT
| _O_EXCL
))
2555 dwCreateDisposition
= CREATE_NEW
;
2556 else if (oflag
& _O_CREAT
)
2557 dwCreateDisposition
= CREATE_ALWAYS
;
2558 return (INT_PTR
)CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
, dwCreateDisposition
, 0, NULL
);
2561 static UINT
cabinet_read(INT_PTR hf
, void *pv
, UINT cb
)
2564 if (ReadFile((HANDLE
)hf
, pv
, cb
, &dwRead
, NULL
))
2569 static UINT
cabinet_write(INT_PTR hf
, void *pv
, UINT cb
)
2572 if (WriteFile((HANDLE
)hf
, pv
, cb
, &dwWritten
, NULL
))
2577 static int cabinet_close(INT_PTR hf
)
2579 return CloseHandle((HANDLE
)hf
) ? 0 : -1;
2582 static long cabinet_seek(INT_PTR hf
, long dist
, int seektype
)
2584 /* flags are compatible and so are passed straight through */
2585 return SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
);
2588 static INT_PTR
cabinet_notify(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
2590 /* FIXME: try to do more processing in this function */
2593 case fdintCOPY_FILE
:
2595 CabData
*data
= (CabData
*) pfdin
->pv
;
2596 ULONG len
= strlen(data
->cab_path
) + strlen(pfdin
->psz1
);
2601 LPWSTR tracknametmp
;
2602 static const WCHAR tmpprefix
[] = {'C','A','B','T','M','P','_',0};
2604 if (data
->file_name
&& strcmp(data
->file_name
,pfdin
->psz1
))
2607 file
= cabinet_alloc((len
+1)*sizeof(char));
2608 strcpy(file
, data
->cab_path
);
2609 strcat(file
, pfdin
->psz1
);
2611 TRACE("file: %s\n", debugstr_a(file
));
2613 /* track this file so it can be deleted if not installed */
2614 trackpath
=strdupAtoW(file
);
2615 tracknametmp
=strdupAtoW(strrchr(file
,'\\')+1);
2616 trackname
= HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp
) +
2617 strlenW(tmpprefix
)+1) * sizeof(WCHAR
));
2619 strcpyW(trackname
,tmpprefix
);
2620 strcatW(trackname
,tracknametmp
);
2622 track_tempfile(data
->package
, trackname
, trackpath
);
2624 HeapFree(GetProcessHeap(),0,trackpath
);
2625 HeapFree(GetProcessHeap(),0,trackname
);
2626 HeapFree(GetProcessHeap(),0,tracknametmp
);
2628 return cabinet_open(file
, _O_WRONLY
| _O_CREAT
, 0);
2630 case fdintCLOSE_FILE_INFO
:
2634 if (!DosDateTimeToFileTime(pfdin
->date
, pfdin
->time
, &ft
))
2636 if (!LocalFileTimeToFileTime(&ft
, &ftLocal
))
2638 if (!SetFileTime((HANDLE
)pfdin
->hf
, &ftLocal
, 0, &ftLocal
))
2641 cabinet_close(pfdin
->hf
);
2649 /***********************************************************************
2650 * extract_cabinet_file
2652 * Extract files from a cab file.
2654 static BOOL
extract_a_cabinet_file(MSIPACKAGE
* package
, const WCHAR
* source
,
2655 const WCHAR
* path
, const WCHAR
* file
)
2665 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source
),
2666 debugstr_w(file
), debugstr_w(path
));
2668 hfdi
= FDICreate(cabinet_alloc
,
2679 ERR("FDICreate failed\n");
2683 if (!(cabinet
= strdupWtoA( source
)))
2688 if (!(cab_path
= strdupWtoA( path
)))
2691 HeapFree(GetProcessHeap(), 0, cabinet
);
2695 data
.package
= package
;
2696 data
.cab_path
= cab_path
;
2698 file_name
= strdupWtoA(file
);
2701 data
.file_name
= file_name
;
2703 ret
= FDICopy(hfdi
, cabinet
, "", 0, cabinet_notify
, NULL
, &data
);
2706 ERR("FDICopy failed\n");
2710 HeapFree(GetProcessHeap(), 0, cabinet
);
2711 HeapFree(GetProcessHeap(), 0, cab_path
);
2712 HeapFree(GetProcessHeap(), 0, file_name
);
2717 static UINT
ready_media_for_file(MSIPACKAGE
*package
, UINT sequence
,
2718 WCHAR
* path
, WCHAR
* file
)
2722 MSIRECORD
* row
= 0;
2723 static WCHAR source
[MAX_PATH
];
2724 static const WCHAR ExecSeqQuery
[] = {
2725 's','e','l','e','c','t',' ','*',' ',
2726 'f','r','o','m',' ','M','e','d','i','a',' ',
2727 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2728 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2733 static UINT last_sequence
= 0;
2735 if (sequence
<= last_sequence
)
2737 TRACE("Media already ready (%u, %u)\n",sequence
,last_sequence
);
2738 /*extract_a_cabinet_file(package, source,path,file); */
2739 return ERROR_SUCCESS
;
2742 sprintfW(Query
,ExecSeqQuery
,sequence
);
2744 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2745 if (rc
!= ERROR_SUCCESS
)
2748 rc
= MSI_ViewExecute(view
, 0);
2749 if (rc
!= ERROR_SUCCESS
)
2751 MSI_ViewClose(view
);
2752 msiobj_release(&view
->hdr
);
2756 rc
= MSI_ViewFetch(view
,&row
);
2757 if (rc
!= ERROR_SUCCESS
)
2759 MSI_ViewClose(view
);
2760 msiobj_release(&view
->hdr
);
2763 seq
= MSI_RecordGetInteger(row
,2);
2764 last_sequence
= seq
;
2766 if (!MSI_RecordIsNull(row
,4))
2769 MSI_RecordGetStringW(row
,4,cab
,&sz
);
2770 TRACE("Source is CAB %s\n",debugstr_w(cab
));
2771 /* the stream does not contain the # character */
2774 writeout_cabinet_stream(package
,&cab
[1],source
);
2775 strcpyW(path
,source
);
2776 *(strrchrW(path
,'\\')+1)=0;
2781 if (MSI_GetPropertyW(package
, cszSourceDir
, source
, &sz
))
2783 ERR("No Source dir defined \n");
2784 rc
= ERROR_FUNCTION_FAILED
;
2788 strcpyW(path
,source
);
2789 strcatW(source
,cab
);
2790 /* extract the cab file into a folder in the temp folder */
2792 if (MSI_GetPropertyW(package
, cszTempFolder
,path
, &sz
)
2794 GetTempPathW(MAX_PATH
,path
);
2797 rc
= !extract_a_cabinet_file(package
, source
,path
,NULL
);
2799 msiobj_release(&row
->hdr
);
2800 MSI_ViewClose(view
);
2801 msiobj_release(&view
->hdr
);
2805 inline static UINT
create_component_directory ( MSIPACKAGE
* package
, INT component
)
2807 UINT rc
= ERROR_SUCCESS
;
2809 LPWSTR install_path
;
2811 install_path
= resolve_folder(package
, package
->components
[component
].Directory
,
2812 FALSE
, FALSE
, &folder
);
2814 return ERROR_FUNCTION_FAILED
;
2816 /* create the path */
2817 if (folder
->State
== 0)
2819 create_full_pathW(install_path
);
2822 HeapFree(GetProcessHeap(), 0, install_path
);
2827 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
)
2829 UINT rc
= ERROR_SUCCESS
;
2832 WCHAR uipath
[MAX_PATH
];
2835 return ERROR_INVALID_HANDLE
;
2837 /* increment progress bar each time action data is sent */
2838 ui_progress(package
,1,1,0,0);
2840 for (index
= 0; index
< package
->loaded_files
; index
++)
2842 WCHAR path_to_source
[MAX_PATH
];
2845 file
= &package
->files
[index
];
2847 if (file
->Temporary
)
2850 if (package
->components
[file
->ComponentIndex
].ActionRequest
!=
2853 ui_progress(package
,2,file
->FileSize
,0,0);
2854 TRACE("File %s is not scheduled for install\n",
2855 debugstr_w(file
->File
));
2860 if ((file
->State
== 1) || (file
->State
== 2))
2864 MSICOMPONENT
* comp
= NULL
;
2866 TRACE("Installing %s\n",debugstr_w(file
->File
));
2867 rc
= ready_media_for_file(package
,file
->Sequence
,path_to_source
,
2871 * our file table could change here because a new temp file
2872 * may have been created
2874 file
= &package
->files
[index
];
2875 if (rc
!= ERROR_SUCCESS
)
2877 ERR("Unable to ready media\n");
2878 rc
= ERROR_FUNCTION_FAILED
;
2882 create_component_directory( package
, file
->ComponentIndex
);
2884 /* recalculate file paths because things may have changed */
2886 if (file
->ComponentIndex
>= 0)
2887 comp
= &package
->components
[file
->ComponentIndex
];
2889 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2890 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2892 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2894 len
= strlenW(path_to_source
) + strlenW(file
->File
) + 2;
2895 file
->SourcePath
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
2896 strcpyW(file
->SourcePath
, path_to_source
);
2897 strcatW(file
->SourcePath
, file
->File
);
2899 TRACE("file paths %s to %s\n",debugstr_w(file
->SourcePath
),
2900 debugstr_w(file
->TargetPath
));
2903 uirow
=MSI_CreateRecord(9);
2904 MSI_RecordSetStringW(uirow
,1,file
->File
);
2905 strcpyW(uipath
,file
->TargetPath
);
2906 *(strrchrW(uipath
,'\\')+1)=0;
2907 MSI_RecordSetStringW(uirow
,9,uipath
);
2908 MSI_RecordSetInteger(uirow
,6,file
->FileSize
);
2909 ui_actiondata(package
,szInstallFiles
,uirow
);
2910 msiobj_release( &uirow
->hdr
);
2911 ui_progress(package
,2,file
->FileSize
,0,0);
2913 if (!MoveFileW(file
->SourcePath
,file
->TargetPath
))
2915 rc
= GetLastError();
2916 ERR("Unable to move file (%s -> %s) (error %d)\n",
2917 debugstr_w(file
->SourcePath
), debugstr_w(file
->TargetPath
),
2919 if (rc
== ERROR_ALREADY_EXISTS
&& file
->State
== 2)
2921 CopyFileW(file
->SourcePath
,file
->TargetPath
,FALSE
);
2922 DeleteFileW(file
->SourcePath
);
2925 else if (rc
== ERROR_FILE_NOT_FOUND
)
2927 ERR("Source File Not Found! Continueing\n");
2932 ERR("Ignoring Error and continuing...\n");
2944 inline static UINT
get_file_target(MSIPACKAGE
*package
, LPCWSTR file_key
,
2945 LPWSTR
* file_source
)
2950 return ERROR_INVALID_HANDLE
;
2952 for (index
= 0; index
< package
->loaded_files
; index
++)
2954 if (strcmpW(file_key
,package
->files
[index
].File
)==0)
2956 if (package
->files
[index
].State
>= 2)
2958 *file_source
= dupstrW(package
->files
[index
].TargetPath
);
2959 return ERROR_SUCCESS
;
2962 return ERROR_FILE_NOT_FOUND
;
2966 return ERROR_FUNCTION_FAILED
;
2969 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
)
2973 MSIRECORD
* row
= 0;
2974 static const WCHAR ExecSeqQuery
[] = {
2975 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2976 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2979 return ERROR_INVALID_HANDLE
;
2981 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2982 if (rc
!= ERROR_SUCCESS
)
2983 return ERROR_SUCCESS
;
2985 rc
= MSI_ViewExecute(view
, 0);
2986 if (rc
!= ERROR_SUCCESS
)
2988 MSI_ViewClose(view
);
2989 msiobj_release(&view
->hdr
);
2995 WCHAR file_key
[0x100];
2996 WCHAR
*file_source
= NULL
;
2997 WCHAR dest_name
[0x100];
2998 LPWSTR dest_path
, dest
;
2999 WCHAR component
[0x100];
3000 INT component_index
;
3004 rc
= MSI_ViewFetch(view
,&row
);
3005 if (rc
!= ERROR_SUCCESS
)
3012 rc
= MSI_RecordGetStringW(row
,2,component
,&sz
);
3013 if (rc
!= ERROR_SUCCESS
)
3015 ERR("Unable to get component\n");
3016 msiobj_release(&row
->hdr
);
3020 component_index
= get_loaded_component(package
,component
);
3021 if (package
->components
[component_index
].ActionRequest
!=
3024 TRACE("Skipping copy due to disabled component\n");
3026 /* the action taken was the same as the current install state */
3027 package
->components
[component_index
].Action
=
3028 package
->components
[component_index
].Installed
;
3030 msiobj_release(&row
->hdr
);
3034 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
3035 package
->components
[component_index
].Installed
= INSTALLSTATE_LOCAL
;
3038 rc
= MSI_RecordGetStringW(row
,3,file_key
,&sz
);
3039 if (rc
!= ERROR_SUCCESS
)
3041 ERR("Unable to get file key\n");
3042 msiobj_release(&row
->hdr
);
3046 rc
= get_file_target(package
,file_key
,&file_source
);
3048 if (rc
!= ERROR_SUCCESS
)
3050 ERR("Original file unknown %s\n",debugstr_w(file_key
));
3051 msiobj_release(&row
->hdr
);
3052 HeapFree(GetProcessHeap(),0,file_source
);
3056 if (MSI_RecordIsNull(row
,4))
3058 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
3063 MSI_RecordGetStringW(row
,4,dest_name
,&sz
);
3064 reduce_to_longfilename(dest_name
);
3067 if (MSI_RecordIsNull(row
,5))
3070 dest_path
= dupstrW(file_source
);
3071 p
= strrchrW(dest_path
,'\\');
3077 WCHAR destkey
[0x100];
3079 MSI_RecordGetStringW(row
,5,destkey
,&sz
);
3081 dest_path
= resolve_folder(package
, destkey
, FALSE
,FALSE
,NULL
);
3084 ERR("Unable to get destination folder\n");
3085 msiobj_release(&row
->hdr
);
3086 HeapFree(GetProcessHeap(),0,file_source
);
3091 dest
= build_directory_name(2, dest_path
, dest_name
);
3092 HeapFree(GetProcessHeap(), 0, dest_path
);
3094 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source
),
3097 if (strcmpW(file_source
,dest
))
3098 rc
= !CopyFileW(file_source
,dest
,TRUE
);
3102 if (rc
!= ERROR_SUCCESS
)
3103 ERR("Failed to copy file\n");
3105 FIXME("We should track these duplicate files as well\n");
3107 msiobj_release(&row
->hdr
);
3108 HeapFree(GetProcessHeap(),0,dest
);
3109 HeapFree(GetProcessHeap(),0,file_source
);
3111 MSI_ViewClose(view
);
3112 msiobj_release(&view
->hdr
);
3117 /* OK this value is "interpreted" and then formatted based on the
3118 first few characters */
3119 static LPSTR
parse_value(MSIPACKAGE
*package
, WCHAR
*value
, DWORD
*type
,
3123 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
3132 deformat_string(package
, &value
[2], &deformated
);
3134 /* binary value type */
3137 *size
= strlenW(ptr
)/2;
3138 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3150 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3153 HeapFree(GetProcessHeap(),0,deformated
);
3155 TRACE("Data %li bytes(%i)\n",*size
,count
);
3160 deformat_string(package
, &value
[1], &deformated
);
3163 *size
= sizeof(DWORD
);
3164 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3165 *(LPDWORD
)data
= atoiW(deformated
);
3166 TRACE("DWORD %i\n",*data
);
3168 HeapFree(GetProcessHeap(),0,deformated
);
3173 static const WCHAR szMulti
[] = {'[','~',']',0};
3182 *type
=REG_EXPAND_SZ
;
3190 if (strstrW(value
,szMulti
))
3191 *type
= REG_MULTI_SZ
;
3193 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
3198 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
3202 MSIRECORD
* row
= 0;
3203 static const WCHAR ExecSeqQuery
[] = {
3204 's','e','l','e','c','t',' ','*',' ',
3205 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
3208 return ERROR_INVALID_HANDLE
;
3210 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3211 if (rc
!= ERROR_SUCCESS
)
3212 return ERROR_SUCCESS
;
3214 rc
= MSI_ViewExecute(view
, 0);
3215 if (rc
!= ERROR_SUCCESS
)
3217 MSI_ViewClose(view
);
3218 msiobj_release(&view
->hdr
);
3222 /* increment progress bar each time action data is sent */
3223 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
3227 static const WCHAR szHCR
[] =
3228 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
3229 static const WCHAR szHCU
[] =
3230 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
3231 static const WCHAR szHLM
[] =
3232 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
3234 static const WCHAR szHU
[] =
3235 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3237 LPSTR value_data
= NULL
;
3238 HKEY root_key
, hkey
;
3240 LPWSTR value
, key
, name
, component
, deformated
;
3242 INT component_index
;
3247 rc
= MSI_ViewFetch(view
,&row
);
3248 if (rc
!= ERROR_SUCCESS
)
3253 ui_progress(package
,2,0,0,0);
3260 component
= load_dynamic_stringW(row
, 6);
3261 component_index
= get_loaded_component(package
,component
);
3263 if (package
->components
[component_index
].ActionRequest
!=
3266 TRACE("Skipping write due to disabled component\n");
3267 msiobj_release(&row
->hdr
);
3269 package
->components
[component_index
].Action
=
3270 package
->components
[component_index
].Installed
;
3275 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
3276 package
->components
[component_index
].Installed
= INSTALLSTATE_LOCAL
;
3278 /* null values have special meanings during uninstalls and such */
3280 if(MSI_RecordIsNull(row
,5))
3282 msiobj_release(&row
->hdr
);
3286 root
= MSI_RecordGetInteger(row
,2);
3287 key
= load_dynamic_stringW(row
, 3);
3289 name
= load_dynamic_stringW(row
, 4);
3291 /* get the root key */
3294 case 0: root_key
= HKEY_CLASSES_ROOT
;
3297 case 1: root_key
= HKEY_CURRENT_USER
;
3300 case 2: root_key
= HKEY_LOCAL_MACHINE
;
3303 case 3: root_key
= HKEY_USERS
;
3307 ERR("Unknown root %i\n",root
);
3314 msiobj_release(&row
->hdr
);
3318 deformat_string(package
, key
, &deformated
);
3319 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
3320 uikey
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
3321 strcpyW(uikey
,szRoot
);
3322 strcatW(uikey
,deformated
);
3324 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
3326 ERR("Could not create key %s\n",debugstr_w(deformated
));
3327 msiobj_release(&row
->hdr
);
3328 HeapFree(GetProcessHeap(),0,deformated
);
3331 HeapFree(GetProcessHeap(),0,deformated
);
3333 value
= load_dynamic_stringW(row
,5);
3334 value_data
= parse_value(package
, value
, &type
, &size
);
3336 deformat_string(package
, name
, &deformated
);
3340 TRACE("Setting value %s\n",debugstr_w(deformated
));
3341 RegSetValueExW(hkey
, deformated
, 0, type
, value_data
, size
);
3343 uirow
= MSI_CreateRecord(3);
3344 MSI_RecordSetStringW(uirow
,2,deformated
);
3345 MSI_RecordSetStringW(uirow
,1,uikey
);
3348 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
3350 MSI_RecordSetStringW(uirow
,3,value
);
3352 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
3353 msiobj_release( &uirow
->hdr
);
3355 HeapFree(GetProcessHeap(),0,value_data
);
3357 HeapFree(GetProcessHeap(),0,value
);
3358 HeapFree(GetProcessHeap(),0,deformated
);
3360 msiobj_release(&row
->hdr
);
3363 HeapFree(GetProcessHeap(),0,uikey
);
3364 HeapFree(GetProcessHeap(),0,key
);
3365 HeapFree(GetProcessHeap(),0,name
);
3366 HeapFree(GetProcessHeap(),0,component
);
3368 MSI_ViewClose(view
);
3369 msiobj_release(&view
->hdr
);
3373 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
3375 return ERROR_SUCCESS
;
3379 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
3383 static const WCHAR q1
[]={
3384 'S','E','L','E','C','T',' ','*',' ',
3385 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3388 MSIRECORD
* row
= 0;
3391 TRACE(" InstallValidate \n");
3393 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3394 if (rc
!= ERROR_SUCCESS
)
3395 return ERROR_SUCCESS
;
3397 rc
= MSI_ViewExecute(view
, 0);
3398 if (rc
!= ERROR_SUCCESS
)
3400 MSI_ViewClose(view
);
3401 msiobj_release(&view
->hdr
);
3406 rc
= MSI_ViewFetch(view
,&row
);
3407 if (rc
!= ERROR_SUCCESS
)
3414 msiobj_release(&row
->hdr
);
3416 MSI_ViewClose(view
);
3417 msiobj_release(&view
->hdr
);
3419 total
= total
+ progress
* REG_PROGRESS_VALUE
;
3420 total
= total
+ package
->loaded_components
* COMPONENT_PROGRESS_VALUE
;
3421 for (i
=0; i
< package
->loaded_files
; i
++)
3422 total
+= package
->files
[i
].FileSize
;
3423 ui_progress(package
,0,total
,0,0);
3425 return ERROR_SUCCESS
;
3428 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
3431 MSIQUERY
* view
= NULL
;
3432 MSIRECORD
* row
= 0;
3433 static const WCHAR ExecSeqQuery
[] = {
3434 'S','E','L','E','C','T',' ','*',' ',
3435 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3436 static const WCHAR title
[]=
3437 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3439 TRACE("Checking launch conditions\n");
3441 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3442 if (rc
!= ERROR_SUCCESS
)
3443 return ERROR_SUCCESS
;
3445 rc
= MSI_ViewExecute(view
, 0);
3446 if (rc
!= ERROR_SUCCESS
)
3448 MSI_ViewClose(view
);
3449 msiobj_release(&view
->hdr
);
3454 while (rc
== ERROR_SUCCESS
)
3457 LPWSTR message
= NULL
;
3459 rc
= MSI_ViewFetch(view
,&row
);
3460 if (rc
!= ERROR_SUCCESS
)
3466 cond
= load_dynamic_stringW(row
,1);
3468 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
3471 message
= load_dynamic_stringW(row
,2);
3472 deformat_string(package
,message
,&deformated
);
3473 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
3474 HeapFree(GetProcessHeap(),0,message
);
3475 HeapFree(GetProcessHeap(),0,deformated
);
3476 rc
= ERROR_FUNCTION_FAILED
;
3478 HeapFree(GetProcessHeap(),0,cond
);
3479 msiobj_release(&row
->hdr
);
3481 MSI_ViewClose(view
);
3482 msiobj_release(&view
->hdr
);
3486 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, INT
3489 MSICOMPONENT
* cmp
= &package
->components
[component_index
];
3491 if (cmp
->KeyPath
[0]==0)
3493 LPWSTR p
= resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
3496 if (cmp
->Attributes
& 0x4)
3499 MSIRECORD
* row
= 0;
3501 LPWSTR key
,deformated
,buffer
,name
,deformated_name
;
3502 static const WCHAR ExecSeqQuery
[] = {
3503 's','e','l','e','c','t',' ','*',' ',
3504 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',
3505 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '
3506 ,'`','%','s','`',0 };
3507 static const WCHAR fmt
[]={'%','0','2','i',':','%','s',0};
3508 static const WCHAR fmt2
[]={'%','0','2','i',':','%','s','\\','%','s',0};
3510 rc
= MSI_OpenQuery(package
->db
,&view
,ExecSeqQuery
,cmp
->KeyPath
);
3512 if (rc
!=ERROR_SUCCESS
)
3515 rc
= MSI_ViewExecute(view
, 0);
3516 if (rc
!= ERROR_SUCCESS
)
3518 MSI_ViewClose(view
);
3519 msiobj_release(&view
->hdr
);
3523 rc
= MSI_ViewFetch(view
,&row
);
3524 if (rc
!= ERROR_SUCCESS
)
3526 MSI_ViewClose(view
);
3527 msiobj_release(&view
->hdr
);
3531 root
= MSI_RecordGetInteger(row
,2);
3532 key
= load_dynamic_stringW(row
, 3);
3533 name
= load_dynamic_stringW(row
, 4);
3534 deformat_string(package
, key
, &deformated
);
3535 deformat_string(package
, name
, &deformated_name
);
3537 len
= strlenW(deformated
) + 5;
3538 if (deformated_name
)
3539 len
+=strlenW(deformated_name
);
3541 buffer
= HeapAlloc(GetProcessHeap(),0, len
*sizeof(WCHAR
));
3543 if (deformated_name
)
3544 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
3546 sprintfW(buffer
,fmt
,root
,deformated
);
3548 HeapFree(GetProcessHeap(),0,key
);
3549 HeapFree(GetProcessHeap(),0,deformated
);
3550 HeapFree(GetProcessHeap(),0,name
);
3551 HeapFree(GetProcessHeap(),0,deformated_name
);
3552 msiobj_release(&row
->hdr
);
3553 MSI_ViewClose(view
);
3554 msiobj_release(&view
->hdr
);
3558 else if (cmp
->Attributes
& 0x20)
3560 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3566 j
= get_loaded_file(package
,cmp
->KeyPath
);
3570 LPWSTR p
= dupstrW(package
->files
[j
].TargetPath
);
3578 * Ok further analysis makes me think that this work is
3579 * actually done in the PublishComponents and PublishFeatures
3580 * step, and not here. It appears like the keypath and all that is
3581 * resolved in this step, however actually written in the Publish steps.
3582 * But we will leave it here for now because it is unclear
3584 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
3587 WCHAR squished_pc
[GUID_SIZE
];
3588 WCHAR squished_cc
[GUID_SIZE
];
3591 HKEY hkey
=0,hkey2
=0;
3592 static const WCHAR szProductCode
[]=
3593 {'P','r','o','d','u','c','t','C','o','d','e',0};
3596 return ERROR_INVALID_HANDLE
;
3598 /* writes the Component and Features values to the registry */
3599 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
3603 rc
= MSIREG_OpenComponents(&hkey
);
3604 if (rc
!= ERROR_SUCCESS
)
3607 squash_guid(productcode
,squished_pc
);
3608 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
3609 for (i
= 0; i
< package
->loaded_components
; i
++)
3611 ui_progress(package
,2,0,0,0);
3612 if (package
->components
[i
].ComponentId
[0]!=0)
3614 WCHAR
*keypath
= NULL
;
3617 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
3618 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
3619 if (rc
!= ERROR_SUCCESS
)
3622 keypath
= resolve_keypath(package
,i
);
3625 RegSetValueExW(hkey2
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
3626 (strlenW(keypath
)+1)*sizeof(WCHAR
));
3630 uirow
= MSI_CreateRecord(3);
3631 MSI_RecordSetStringW(uirow
,1,productcode
);
3632 MSI_RecordSetStringW(uirow
,2,package
->components
[i
].
3634 MSI_RecordSetStringW(uirow
,3,keypath
);
3635 ui_actiondata(package
,szProcessComponents
,uirow
);
3636 msiobj_release( &uirow
->hdr
);
3637 HeapFree(GetProcessHeap(),0,keypath
);
3642 HeapFree(GetProcessHeap(), 0, productcode
);
3647 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3650 * OK this is a bit confusing.. I am given a _Component key and I believe
3651 * that the file that is being registered as a type library is the "key file
3652 * of that component" which I interpret to mean "The file in the KeyPath of
3657 MSIRECORD
* row
= 0;
3658 static const WCHAR Query
[] = {
3659 'S','E','L','E','C','T',' ','*',' ',
3660 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3665 return ERROR_INVALID_HANDLE
;
3667 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3668 if (rc
!= ERROR_SUCCESS
)
3669 return ERROR_SUCCESS
;
3671 rc
= MSI_ViewExecute(view
, 0);
3672 if (rc
!= ERROR_SUCCESS
)
3674 MSI_ViewClose(view
);
3675 msiobj_release(&view
->hdr
);
3681 WCHAR component
[0x100];
3685 rc
= MSI_ViewFetch(view
,&row
);
3686 if (rc
!= ERROR_SUCCESS
)
3693 MSI_RecordGetStringW(row
,3,component
,&sz
);
3695 index
= get_loaded_component(package
,component
);
3698 msiobj_release(&row
->hdr
);
3702 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
3704 TRACE("Skipping typelib reg due to disabled component\n");
3705 msiobj_release(&row
->hdr
);
3707 package
->components
[index
].Action
=
3708 package
->components
[index
].Installed
;
3713 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
3714 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
3716 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3720 msiobj_release(&row
->hdr
);
3724 res
= LoadTypeLib(package
->files
[index
].TargetPath
,&ptLib
);
3728 WCHAR helpid
[0x100];
3731 MSI_RecordGetStringW(row
,6,helpid
,&sz
);
3733 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
3734 res
= RegisterTypeLib(ptLib
,package
->files
[index
].TargetPath
,help
);
3735 HeapFree(GetProcessHeap(),0,help
);
3737 if (!SUCCEEDED(res
))
3738 ERR("Failed to register type library %s\n",
3739 debugstr_w(package
->files
[index
].TargetPath
));
3742 /* Yes the row has more fields than I need, but #1 is
3743 correct and the only one I need. Why make a new row? */
3745 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3747 TRACE("Registered %s\n",
3748 debugstr_w(package
->files
[index
].TargetPath
));
3752 ITypeLib_Release(ptLib
);
3755 ERR("Failed to load type library %s\n",
3756 debugstr_w(package
->files
[index
].TargetPath
));
3758 msiobj_release(&row
->hdr
);
3760 MSI_ViewClose(view
);
3761 msiobj_release(&view
->hdr
);
3766 static UINT
register_appid(MSIPACKAGE
*package
, LPCWSTR clsid
, LPCWSTR app
)
3768 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3771 MSIRECORD
* row
= 0;
3772 static const WCHAR ExecSeqQuery
[] =
3773 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3774 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3779 return ERROR_INVALID_HANDLE
;
3781 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, clsid
);
3782 if (rc
!= ERROR_SUCCESS
)
3785 rc
= MSI_ViewExecute(view
, 0);
3786 if (rc
!= ERROR_SUCCESS
)
3788 MSI_ViewClose(view
);
3789 msiobj_release(&view
->hdr
);
3793 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
3794 RegCreateKeyW(hkey2
,clsid
,&hkey3
);
3795 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)app
,
3796 (strlenW(app
)+1)*sizeof(WCHAR
));
3798 rc
= MSI_ViewFetch(view
,&row
);
3799 if (rc
!= ERROR_SUCCESS
)
3801 MSI_ViewClose(view
);
3802 msiobj_release(&view
->hdr
);
3806 if (!MSI_RecordIsNull(row
,2))
3808 LPWSTR deformated
=0;
3810 static const WCHAR szRemoteServerName
[] =
3811 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3812 buffer
= load_dynamic_stringW(row
,2);
3813 size
= deformat_string(package
,buffer
,&deformated
);
3814 RegSetValueExW(hkey3
,szRemoteServerName
,0,REG_SZ
,(LPVOID
)deformated
,
3816 HeapFree(GetProcessHeap(),0,deformated
);
3817 HeapFree(GetProcessHeap(),0,buffer
);
3820 if (!MSI_RecordIsNull(row
,3))
3822 static const WCHAR szLocalService
[] =
3823 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3825 buffer
= load_dynamic_stringW(row
,3);
3826 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3827 RegSetValueExW(hkey3
,szLocalService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3828 HeapFree(GetProcessHeap(),0,buffer
);
3831 if (!MSI_RecordIsNull(row
,4))
3833 static const WCHAR szService
[] =
3834 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3836 buffer
= load_dynamic_stringW(row
,4);
3837 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3838 RegSetValueExW(hkey3
,szService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3839 HeapFree(GetProcessHeap(),0,buffer
);
3842 if (!MSI_RecordIsNull(row
,5))
3844 static const WCHAR szDLL
[] =
3845 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3847 buffer
= load_dynamic_stringW(row
,5);
3848 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3849 RegSetValueExW(hkey3
,szDLL
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3850 HeapFree(GetProcessHeap(),0,buffer
);
3853 if (!MSI_RecordIsNull(row
,6))
3855 static const WCHAR szActivate
[] =
3856 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3857 static const WCHAR szY
[] = {'Y',0};
3859 if (MSI_RecordGetInteger(row
,6))
3860 RegSetValueExW(hkey3
,szActivate
,0,REG_SZ
,(LPVOID
)szY
,4);
3863 if (!MSI_RecordIsNull(row
,7))
3865 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
3866 static const WCHAR szUser
[] =
3867 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3869 if (MSI_RecordGetInteger(row
,7))
3870 RegSetValueExW(hkey3
,szRunAs
,0,REG_SZ
,(LPVOID
)szUser
,34);
3873 msiobj_release(&row
->hdr
);
3874 MSI_ViewClose(view
);
3875 msiobj_release(&view
->hdr
);
3881 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
)
3884 * Again I am assuming the words, "Whose key file represents" when referring
3885 * to a Component as to meaning that Components KeyPath file
3887 * Also there is a very strong connection between ClassInfo and ProgID
3888 * that I am mostly glossing over.
3889 * What would be more propper is to load the ClassInfo and the ProgID info
3890 * into memory data structures and then be able to enable and disable them
3891 * based on component.
3896 MSIRECORD
* row
= 0;
3897 static const WCHAR ExecSeqQuery
[] = {
3898 'S','E','L','E','C','T',' ','*',' ',
3899 'f','r','o','m',' ','C','l','a','s','s',0};
3900 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3901 static const WCHAR szProgID
[] = { 'P','r','o','g','I','D',0 };
3902 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3903 static const WCHAR szSpace
[] = {' ',0};
3904 HKEY hkey
,hkey2
,hkey3
;
3905 LPWSTR argument
,deformated
;
3908 return ERROR_INVALID_HANDLE
;
3910 rc
= RegCreateKeyW(HKEY_CLASSES_ROOT
,szCLSID
,&hkey
);
3911 if (rc
!= ERROR_SUCCESS
)
3912 return ERROR_FUNCTION_FAILED
;
3914 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3915 if (rc
!= ERROR_SUCCESS
)
3921 rc
= MSI_ViewExecute(view
, 0);
3922 if (rc
!= ERROR_SUCCESS
)
3924 MSI_ViewClose(view
);
3925 msiobj_release(&view
->hdr
);
3932 WCHAR buffer
[0x100];
3938 rc
= MSI_ViewFetch(view
,&row
);
3939 if (rc
!= ERROR_SUCCESS
)
3946 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
3948 index
= get_loaded_component(package
,buffer
);
3952 msiobj_release(&row
->hdr
);
3956 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
3958 TRACE("Skipping class reg due to disabled component\n");
3959 msiobj_release(&row
->hdr
);
3961 package
->components
[index
].Action
=
3962 package
->components
[index
].Installed
;
3967 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
3968 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
3971 MSI_RecordGetStringW(row
,1,clsid
,&sz
);
3972 RegCreateKeyW(hkey
,clsid
,&hkey2
);
3974 if (!MSI_RecordIsNull(row
,5))
3977 MSI_RecordGetStringW(row
,5,desc
,&sz
);
3979 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)desc
,
3980 (strlenW(desc
)+1)*sizeof(WCHAR
));
3986 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
3988 RegCreateKeyW(hkey2
,buffer
,&hkey3
);
3990 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3992 argument
= load_dynamic_stringW(row
,11);
3993 size
= deformat_string(package
,argument
,&deformated
);
3995 size
+=sizeof(WCHAR
);
3996 HeapFree(GetProcessHeap(),0,argument
);
3997 size
+= (strlenW(package
->files
[index
].TargetPath
))*sizeof(WCHAR
);
3999 argument
= (LPWSTR
)HeapAlloc(GetProcessHeap(),0,size
+sizeof(WCHAR
));
4000 strcpyW(argument
,package
->files
[index
].TargetPath
);
4003 strcatW(argument
,szSpace
);
4004 strcatW(argument
,deformated
);
4007 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)argument
, size
);
4008 HeapFree(GetProcessHeap(),0,deformated
);
4009 HeapFree(GetProcessHeap(),0,argument
);
4013 if (!MSI_RecordIsNull(row
,4))
4016 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4018 RegCreateKeyW(hkey2
,szProgID
,&hkey3
);
4020 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
4021 (strlenW(buffer
)+1)*sizeof(WCHAR
));
4026 if (!MSI_RecordIsNull(row
,6))
4029 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4031 RegSetValueExW(hkey2
,szAppID
,0,REG_SZ
,(LPVOID
)buffer
,
4032 (strlenW(buffer
)+1)*sizeof(WCHAR
));
4034 register_appid(package
,buffer
,desc
);
4038 if (!MSI_RecordIsNull(row
,7))
4040 FIXME("Process field 7\n");
4043 if (!MSI_RecordIsNull(row
,8))
4045 static const WCHAR szDefaultIcon
[] =
4046 {'D','e','f','a','u','l','t','I','c','o','n',0};
4048 LPWSTR FileName
= load_dynamic_stringW(row
,8);
4052 RegCreateKeyW(hkey2
,szDefaultIcon
,&hkey3
);
4053 build_icon_path(package
,FileName
,&FilePath
);
4054 if (!MSI_RecordIsNull(row
,9))
4056 static const WCHAR index_fmt
[] = {',','%','i',0};
4057 WCHAR index_buf
[20];
4058 index
= MSI_RecordGetInteger(row
,9);
4059 sprintfW(index_buf
,index_fmt
,index
);
4060 size
= strlenW(FilePath
)+strlenW(index_buf
)+1;
4061 size
*= sizeof(WCHAR
);
4062 HeapReAlloc(GetProcessHeap(),0,FilePath
,size
);
4064 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)FilePath
,
4065 (strlenW(FilePath
)+1) * sizeof(WCHAR
));
4066 HeapFree(GetProcessHeap(),0,FilePath
);
4067 HeapFree(GetProcessHeap(),0,FileName
);
4071 if (!MSI_RecordIsNull(row
,10))
4073 static const WCHAR szInproc32
[] = {
4074 'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4075 static const WCHAR szInproc
[] = {
4076 'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
4077 INT i
= MSI_RecordGetInteger(row
,10);
4078 if (i
!= MSI_NULL_INTEGER
&& i
> 0 && i
< 4)
4080 static const WCHAR ole2
[] = {'o','l','e','2','.','d','l','l',0};
4081 static const WCHAR ole32
[] = {
4082 'o','l','e','3','2','.','d','l','l',0};
4086 size
= strlenW(ole2
) * sizeof(WCHAR
);
4087 RegCreateKeyW(hkey2
,szInproc
,&hkey3
);
4088 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole2
, size
);
4092 size
= strlenW(ole32
) * sizeof(WCHAR
);
4093 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
4094 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole32
,size
);
4098 size
= strlenW(ole2
) * sizeof(WCHAR
);
4099 RegCreateKeyW(hkey2
,szInproc
,&hkey3
);
4100 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole2
, size
);
4102 size
= strlenW(ole32
) * sizeof(WCHAR
);
4103 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
4104 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole32
,size
);
4112 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
4113 argument
= load_dynamic_stringW(row
,10);
4114 reduce_to_longfilename(argument
);
4115 size
= strlenW(argument
)*sizeof(WCHAR
);
4117 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)argument
, size
);
4118 HeapFree(GetProcessHeap(),0,argument
);
4126 ui_actiondata(package
,szRegisterClassInfo
,row
);
4128 msiobj_release(&row
->hdr
);
4130 MSI_ViewClose(view
);
4131 msiobj_release(&view
->hdr
);
4138 static UINT
register_progid_base(MSIPACKAGE
* package
, MSIRECORD
* row
,
4141 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4142 static const WCHAR szDefaultIcon
[] = {
4143 'D','e','f','a','u','l','t','I','c','o','n',0};
4145 WCHAR buffer
[0x100];
4150 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
4151 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
4153 if (!MSI_RecordIsNull(row
,4))
4156 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4157 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
4161 if (!MSI_RecordIsNull(row
,3))
4165 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4166 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
4167 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
4171 strcpyW(clsid
,buffer
);
4177 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4178 return ERROR_FUNCTION_FAILED
;
4180 if (!MSI_RecordIsNull(row
,5))
4182 INT index
= MSI_RecordGetInteger(row
,6);
4183 LPWSTR FileName
= load_dynamic_stringW(row
,5);
4184 LPWSTR FilePath
,IconPath
;
4185 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
4187 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
4188 build_icon_path(package
,FileName
,&FilePath
);
4190 IconPath
= HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath
)+5)*
4193 sprintfW(IconPath
,fmt
,FilePath
,index
);
4194 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)IconPath
,
4195 (strlenW(IconPath
)+1) * sizeof(WCHAR
));
4196 HeapFree(GetProcessHeap(),0,FilePath
);
4197 HeapFree(GetProcessHeap(),0,FileName
);
4200 return ERROR_SUCCESS
;
4203 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
);
4205 static UINT
register_parent_progid(MSIPACKAGE
*package
, LPCWSTR parent
,
4210 MSIRECORD
* row
= 0;
4211 static const WCHAR Query_t
[] =
4212 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
4213 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
4217 return ERROR_INVALID_HANDLE
;
4219 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, parent
);
4220 if (rc
!= ERROR_SUCCESS
)
4223 rc
= MSI_ViewExecute(view
, 0);
4224 if (rc
!= ERROR_SUCCESS
)
4226 MSI_ViewClose(view
);
4227 msiobj_release(&view
->hdr
);
4231 rc
= MSI_ViewFetch(view
,&row
);
4232 if (rc
!= ERROR_SUCCESS
)
4234 MSI_ViewClose(view
);
4235 msiobj_release(&view
->hdr
);
4239 register_progid(package
,row
,clsid
);
4241 msiobj_release(&row
->hdr
);
4242 MSI_ViewClose(view
);
4243 msiobj_release(&view
->hdr
);
4247 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
)
4249 UINT rc
= ERROR_SUCCESS
;
4251 if (MSI_RecordIsNull(row
,2))
4252 rc
= register_progid_base(package
,row
,clsid
);
4255 WCHAR buffer
[0x1000];
4258 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4259 static const WCHAR szDefaultIcon
[] = {
4260 'D','e','f','a','u','l','t','I','c','o','n',0};
4262 /* check if already registered */
4264 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
4265 RegCreateKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, NULL
, 0,
4266 KEY_ALL_ACCESS
, NULL
, &hkey
, &disp
);
4267 if (disp
== REG_OPENED_EXISTING_KEY
)
4269 TRACE("Key already registered\n");
4275 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4276 rc
= register_parent_progid(package
,buffer
,clsid
);
4278 /* clsid is same as parent */
4279 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
4280 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)clsid
, (strlenW(clsid
)+1) *
4286 if (!MSI_RecordIsNull(row
,4))
4289 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4290 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
4291 (strlenW(buffer
)+1) * sizeof(WCHAR
));
4294 if (!MSI_RecordIsNull(row
,5))
4296 LPWSTR FileName
= load_dynamic_stringW(row
,5);
4298 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
4299 build_icon_path(package
,FileName
,&FilePath
);
4300 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)FilePath
,
4301 (strlenW(FilePath
)+1) * sizeof(WCHAR
));
4302 HeapFree(GetProcessHeap(),0,FilePath
);
4303 HeapFree(GetProcessHeap(),0,FileName
);
4312 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
4315 * Sigh, here I am just brute force registering all progids
4316 * this needs to be linked to the Classes that have been registered
4317 * but the easiest way to do that is to load all these stuff into
4318 * memory for easy checking.
4320 * Gives me something to continue to work toward.
4324 MSIRECORD
* row
= 0;
4325 static const WCHAR Query
[] = {
4326 'S','E','L','E','C','T',' ','*',' ',
4327 'F','R','O','M',' ','P','r','o','g','I','d',0};
4330 return ERROR_INVALID_HANDLE
;
4332 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4333 if (rc
!= ERROR_SUCCESS
)
4334 return ERROR_SUCCESS
;
4336 rc
= MSI_ViewExecute(view
, 0);
4337 if (rc
!= ERROR_SUCCESS
)
4339 MSI_ViewClose(view
);
4340 msiobj_release(&view
->hdr
);
4346 WCHAR clsid
[0x1000];
4348 rc
= MSI_ViewFetch(view
,&row
);
4349 if (rc
!= ERROR_SUCCESS
)
4355 register_progid(package
,row
,clsid
);
4356 ui_actiondata(package
,szRegisterProgIdInfo
,row
);
4358 msiobj_release(&row
->hdr
);
4360 MSI_ViewClose(view
);
4361 msiobj_release(&view
->hdr
);
4365 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
4369 LPWSTR SystemFolder
;
4373 static const WCHAR szInstaller
[] =
4374 {'I','n','s','t','a','l','l','e','r','\\',0};
4375 static const WCHAR szProductCode
[] =
4376 {'P','r','o','d','u','c','t','C','o','d','e',0};
4377 static const WCHAR szFolder
[] =
4378 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4380 ProductCode
= load_dynamic_property(package
,szProductCode
,&rc
);
4384 SystemFolder
= load_dynamic_property(package
,szFolder
,NULL
);
4386 dest
= build_directory_name(3, SystemFolder
, szInstaller
, ProductCode
);
4388 create_full_pathW(dest
);
4390 *FilePath
= build_directory_name(2, dest
, icon_name
);
4392 HeapFree(GetProcessHeap(),0,SystemFolder
);
4393 HeapFree(GetProcessHeap(),0,ProductCode
);
4394 HeapFree(GetProcessHeap(),0,dest
);
4395 return ERROR_SUCCESS
;
4398 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
4402 MSIRECORD
* row
= 0;
4403 static const WCHAR Query
[] = {
4404 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
4405 'S','h','o','r','t','c','u','t',0};
4411 return ERROR_INVALID_HANDLE
;
4413 res
= CoInitialize( NULL
);
4416 ERR("CoInitialize failed\n");
4417 return ERROR_FUNCTION_FAILED
;
4420 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4421 if (rc
!= ERROR_SUCCESS
)
4422 return ERROR_SUCCESS
;
4424 rc
= MSI_ViewExecute(view
, 0);
4425 if (rc
!= ERROR_SUCCESS
)
4427 MSI_ViewClose(view
);
4428 msiobj_release(&view
->hdr
);
4434 LPWSTR target_file
, target_folder
;
4435 WCHAR buffer
[0x100];
4438 static const WCHAR szlnk
[]={'.','l','n','k',0};
4440 rc
= MSI_ViewFetch(view
,&row
);
4441 if (rc
!= ERROR_SUCCESS
)
4448 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4450 index
= get_loaded_component(package
,buffer
);
4454 msiobj_release(&row
->hdr
);
4458 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
4460 TRACE("Skipping shortcut creation due to disabled component\n");
4461 msiobj_release(&row
->hdr
);
4463 package
->components
[index
].Action
=
4464 package
->components
[index
].Installed
;
4469 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
4470 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
4472 ui_actiondata(package
,szCreateShortcuts
,row
);
4474 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
4475 &IID_IShellLinkW
, (LPVOID
*) &sl
);
4479 ERR("Is IID_IShellLink\n");
4480 msiobj_release(&row
->hdr
);
4484 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
4487 ERR("Is IID_IPersistFile\n");
4488 msiobj_release(&row
->hdr
);
4493 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4494 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
4496 /* may be needed because of a bug somehwere else */
4497 create_full_pathW(target_folder
);
4500 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4501 reduce_to_longfilename(buffer
);
4502 if (!strchrW(buffer
,'.') || strcmpiW(strchrW(buffer
,'.'),szlnk
))
4503 strcatW(buffer
,szlnk
);
4504 target_file
= build_directory_name(2, target_folder
, buffer
);
4505 HeapFree(GetProcessHeap(),0,target_folder
);
4508 MSI_RecordGetStringW(row
,5,buffer
,&sz
);
4509 if (strchrW(buffer
,'['))
4512 deformat_string(package
,buffer
,&deformated
);
4513 IShellLinkW_SetPath(sl
,deformated
);
4514 HeapFree(GetProcessHeap(),0,deformated
);
4518 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4519 IPersistFile_Release( pf
);
4520 IShellLinkW_Release( sl
);
4521 msiobj_release(&row
->hdr
);
4525 if (!MSI_RecordIsNull(row
,6))
4529 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4530 deformat_string(package
,buffer
,&deformated
);
4531 IShellLinkW_SetArguments(sl
,deformated
);
4532 HeapFree(GetProcessHeap(),0,deformated
);
4535 if (!MSI_RecordIsNull(row
,7))
4538 deformated
= load_dynamic_stringW(row
,7);
4539 IShellLinkW_SetDescription(sl
,deformated
);
4540 HeapFree(GetProcessHeap(),0,deformated
);
4543 if (!MSI_RecordIsNull(row
,8))
4544 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
4546 if (!MSI_RecordIsNull(row
,9))
4552 MSI_RecordGetStringW(row
,9,buffer
,&sz
);
4554 build_icon_path(package
,buffer
,&Path
);
4555 index
= MSI_RecordGetInteger(row
,10);
4557 IShellLinkW_SetIconLocation(sl
,Path
,index
);
4558 HeapFree(GetProcessHeap(),0,Path
);
4561 if (!MSI_RecordIsNull(row
,11))
4562 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
4564 if (!MSI_RecordIsNull(row
,12))
4568 MSI_RecordGetStringW(row
,12,buffer
,&sz
);
4569 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
4570 IShellLinkW_SetWorkingDirectory(sl
,Path
);
4571 HeapFree(GetProcessHeap(), 0, Path
);
4574 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
4575 IPersistFile_Save(pf
,target_file
,FALSE
);
4577 HeapFree(GetProcessHeap(),0,target_file
);
4579 IPersistFile_Release( pf
);
4580 IShellLinkW_Release( sl
);
4582 msiobj_release(&row
->hdr
);
4584 MSI_ViewClose(view
);
4585 msiobj_release(&view
->hdr
);
4595 * 99% of the work done here is only done for
4596 * advertised installs. However this is where the
4597 * Icon table is processed and written out
4598 * so that is what I am going to do here.
4600 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
4604 MSIRECORD
* row
= 0;
4605 static const WCHAR Query
[]={
4606 'S','E','L','E','C','T',' ','*',' ',
4607 'f','r','o','m',' ','I','c','o','n',0};
4609 /* for registry stuff */
4613 static const WCHAR szProductCode
[]=
4614 {'P','r','o','d','u','c','t','C','o','d','e',0};
4615 static const WCHAR szProductName
[] = {
4616 'P','r','o','d','u','c','t','N','a','m','e',0};
4617 static const WCHAR szPackageCode
[] = {
4618 'P','a','c','k','a','g','e','C','o','d','e',0};
4621 MSIHANDLE hDb
, hSumInfo
;
4624 return ERROR_INVALID_HANDLE
;
4626 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4627 if (rc
!= ERROR_SUCCESS
)
4630 rc
= MSI_ViewExecute(view
, 0);
4631 if (rc
!= ERROR_SUCCESS
)
4633 MSI_ViewClose(view
);
4634 msiobj_release(&view
->hdr
);
4641 WCHAR
*FilePath
=NULL
;
4642 WCHAR
*FileName
=NULL
;
4645 rc
= MSI_ViewFetch(view
,&row
);
4646 if (rc
!= ERROR_SUCCESS
)
4652 FileName
= load_dynamic_stringW(row
,1);
4655 ERR("Unable to get FileName\n");
4656 msiobj_release(&row
->hdr
);
4660 build_icon_path(package
,FileName
,&FilePath
);
4662 HeapFree(GetProcessHeap(),0,FileName
);
4664 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
4666 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
4667 FILE_ATTRIBUTE_NORMAL
, NULL
);
4669 if (the_file
== INVALID_HANDLE_VALUE
)
4671 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
4672 msiobj_release(&row
->hdr
);
4673 HeapFree(GetProcessHeap(),0,FilePath
);
4681 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
4682 if (rc
!= ERROR_SUCCESS
)
4684 ERR("Failed to get stream\n");
4685 CloseHandle(the_file
);
4686 DeleteFileW(FilePath
);
4689 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
4690 } while (sz
== 1024);
4692 HeapFree(GetProcessHeap(),0,FilePath
);
4694 CloseHandle(the_file
);
4695 msiobj_release(&row
->hdr
);
4697 MSI_ViewClose(view
);
4698 msiobj_release(&view
->hdr
);
4701 /* ok there is a lot more done here but i need to figure out what */
4702 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4706 rc
= MSIREG_OpenProductsKey(productcode
,&hkey
,TRUE
);
4707 if (rc
!= ERROR_SUCCESS
)
4710 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
4711 if (rc
!= ERROR_SUCCESS
)
4715 buffer
= load_dynamic_property(package
,szProductName
,NULL
);
4716 size
= strlenW(buffer
)*sizeof(WCHAR
);
4717 RegSetValueExW(hukey
,szProductName
,0,REG_SZ
, (LPSTR
)buffer
,size
);
4718 HeapFree(GetProcessHeap(),0,buffer
);
4719 FIXME("Need to write more keys to the user registry\n");
4721 hDb
= msiobj_findhandle( &package
->db
->hdr
);
4722 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
4723 if (rc
== ERROR_SUCCESS
)
4725 WCHAR guidbuffer
[0x200];
4727 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 8, NULL
, NULL
, NULL
,
4729 if (rc
== ERROR_SUCCESS
)
4731 WCHAR squashed
[GUID_SIZE
];
4732 /* for now we only care about the first guid */
4733 LPWSTR ptr
= strchrW(guidbuffer
,';');
4735 squash_guid(guidbuffer
,squashed
);
4736 size
= strlenW(guidbuffer
)*sizeof(WCHAR
);
4737 RegSetValueExW(hukey
,szPackageCode
,0,REG_SZ
, (LPSTR
)guidbuffer
,
4743 ERR("Unable to query Revision_Number... \n");
4746 MsiCloseHandle(hSumInfo
);
4750 ERR("Unable to open Summary Information\n");
4756 HeapFree(GetProcessHeap(),0,productcode
);
4763 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
4767 MSIRECORD
* row
= 0;
4768 static const WCHAR ExecSeqQuery
[] = {'S','e','l','e','c','t',' ','*',
4769 ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0};
4770 static const WCHAR szWindowsFolder
[] =
4771 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4772 static const WCHAR szbs
[] = {'\\',0};
4774 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4775 if (rc
!= ERROR_SUCCESS
)
4777 TRACE("no IniFile table\n");
4778 return ERROR_SUCCESS
;
4781 rc
= MSI_ViewExecute(view
, 0);
4782 if (rc
!= ERROR_SUCCESS
)
4784 MSI_ViewClose(view
);
4785 msiobj_release(&view
->hdr
);
4791 LPWSTR component
,filename
,dirproperty
,section
,key
,value
,identifier
;
4792 LPWSTR deformated_section
, deformated_key
, deformated_value
;
4793 LPWSTR folder
, fullname
= NULL
;
4795 INT component_index
,action
;
4797 rc
= MSI_ViewFetch(view
,&row
);
4798 if (rc
!= ERROR_SUCCESS
)
4804 component
= load_dynamic_stringW(row
, 8);
4805 component_index
= get_loaded_component(package
,component
);
4806 HeapFree(GetProcessHeap(),0,component
);
4808 if (package
->components
[component_index
].ActionRequest
!=
4811 TRACE("Skipping ini file due to disabled component\n");
4812 msiobj_release(&row
->hdr
);
4814 package
->components
[component_index
].Action
=
4815 package
->components
[component_index
].Installed
;
4820 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
4821 package
->components
[component_index
].Installed
= INSTALLSTATE_LOCAL
;
4823 identifier
= load_dynamic_stringW(row
,1);
4824 filename
= load_dynamic_stringW(row
,2);
4825 dirproperty
= load_dynamic_stringW(row
,3);
4826 section
= load_dynamic_stringW(row
,4);
4827 key
= load_dynamic_stringW(row
,5);
4828 value
= load_dynamic_stringW(row
,6);
4829 action
= MSI_RecordGetInteger(row
,7);
4831 deformat_string(package
,section
,&deformated_section
);
4832 deformat_string(package
,key
,&deformated_key
);
4833 deformat_string(package
,value
,&deformated_value
);
4837 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
4839 folder
= load_dynamic_property(package
,dirproperty
,NULL
);
4842 folder
= load_dynamic_property(package
, szWindowsFolder
, NULL
);
4846 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
4851 fullname
= HeapAlloc(GetProcessHeap(),0,
4852 (strlenW(folder
)+strlenW(filename
)+2)*sizeof(WCHAR
));
4854 strcpyW(fullname
,folder
);
4855 if (fullname
[strlenW(folder
)] != '\\')
4856 strcatW(fullname
,szbs
);
4857 strcatW(fullname
,filename
);
4861 TRACE("Adding value %s to section %s in %s\n",
4862 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4863 debugstr_w(fullname
));
4864 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4865 deformated_value
, fullname
);
4867 else if (action
== 1)
4870 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
4871 returned
, 10, fullname
);
4872 if (returned
[0] == 0)
4874 TRACE("Adding value %s to section %s in %s\n",
4875 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4876 debugstr_w(fullname
));
4878 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4879 deformated_value
, fullname
);
4882 else if (action
== 3)
4884 FIXME("Append to existing section not yet implemented\n");
4887 uirow
= MSI_CreateRecord(4);
4888 MSI_RecordSetStringW(uirow
,1,identifier
);
4889 MSI_RecordSetStringW(uirow
,2,deformated_section
);
4890 MSI_RecordSetStringW(uirow
,3,deformated_key
);
4891 MSI_RecordSetStringW(uirow
,4,deformated_value
);
4892 ui_actiondata(package
,szWriteIniValues
,uirow
);
4893 msiobj_release( &uirow
->hdr
);
4895 HeapFree(GetProcessHeap(),0,identifier
);
4896 HeapFree(GetProcessHeap(),0,fullname
);
4897 HeapFree(GetProcessHeap(),0,filename
);
4898 HeapFree(GetProcessHeap(),0,key
);
4899 HeapFree(GetProcessHeap(),0,value
);
4900 HeapFree(GetProcessHeap(),0,section
);
4901 HeapFree(GetProcessHeap(),0,dirproperty
);
4902 HeapFree(GetProcessHeap(),0,folder
);
4903 HeapFree(GetProcessHeap(),0,deformated_key
);
4904 HeapFree(GetProcessHeap(),0,deformated_value
);
4905 HeapFree(GetProcessHeap(),0,deformated_section
);
4906 msiobj_release(&row
->hdr
);
4908 MSI_ViewClose(view
);
4909 msiobj_release(&view
->hdr
);
4913 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4917 MSIRECORD
* row
= 0;
4918 static const WCHAR ExecSeqQuery
[] = {'S','e','l','e','c','t',' ','*',' ',
4919 'f','r','o','m',' ','S','e','l','f','R','e','g',0};
4921 static const WCHAR ExeStr
[] = {
4922 'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0};
4924 PROCESS_INFORMATION info
;
4927 memset(&si
,0,sizeof(STARTUPINFOW
));
4929 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4930 if (rc
!= ERROR_SUCCESS
)
4932 TRACE("no SelfReg table\n");
4933 return ERROR_SUCCESS
;
4936 rc
= MSI_ViewExecute(view
, 0);
4937 if (rc
!= ERROR_SUCCESS
)
4939 MSI_ViewClose(view
);
4940 msiobj_release(&view
->hdr
);
4950 rc
= MSI_ViewFetch(view
,&row
);
4951 if (rc
!= ERROR_SUCCESS
)
4957 filename
= load_dynamic_stringW(row
,1);
4958 index
= get_loaded_file(package
,filename
);
4962 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4963 HeapFree(GetProcessHeap(),0,filename
);
4964 msiobj_release(&row
->hdr
);
4967 HeapFree(GetProcessHeap(),0,filename
);
4969 len
= strlenW(ExeStr
);
4970 len
+= strlenW(package
->files
[index
].TargetPath
);
4973 filename
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
4974 strcpyW(filename
,ExeStr
);
4975 strcatW(filename
,package
->files
[index
].TargetPath
);
4977 TRACE("Registering %s\n",debugstr_w(filename
));
4978 brc
= CreateProcessW(NULL
, filename
, NULL
, NULL
, FALSE
, 0, NULL
,
4979 c_collen
, &si
, &info
);
4982 WaitForSingleObject(info
.hProcess
,INFINITE
);
4984 HeapFree(GetProcessHeap(),0,filename
);
4985 msiobj_release(&row
->hdr
);
4987 MSI_ViewClose(view
);
4988 msiobj_release(&view
->hdr
);
4992 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4999 static const WCHAR szProductCode
[]=
5000 {'P','r','o','d','u','c','t','C','o','d','e',0};
5003 return ERROR_INVALID_HANDLE
;
5005 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5009 rc
= MSIREG_OpenFeaturesKey(productcode
,&hkey
,TRUE
);
5010 if (rc
!= ERROR_SUCCESS
)
5013 rc
= MSIREG_OpenUserFeaturesKey(productcode
,&hukey
,TRUE
);
5014 if (rc
!= ERROR_SUCCESS
)
5017 /* here the guids are base 85 encoded */
5018 for (i
= 0; i
< package
->loaded_features
; i
++)
5025 size
= package
->features
[i
].ComponentCount
*21;
5027 if (package
->features
[i
].Feature_Parent
[0])
5028 size
+= strlenW(package
->features
[i
].Feature_Parent
)+2;
5030 data
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5033 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
5036 memset(buf
,0,sizeof(buf
));
5037 TRACE("From %s\n",debugstr_w(package
->components
5038 [package
->features
[i
].Components
[j
]].ComponentId
));
5039 CLSIDFromString(package
->components
5040 [package
->features
[i
].Components
[j
]].ComponentId
,
5042 encode_base85_guid(&clsid
,buf
);
5043 TRACE("to %s\n",debugstr_w(buf
));
5046 if (package
->features
[i
].Feature_Parent
[0])
5048 static const WCHAR sep
[] = {'\2',0};
5050 strcatW(data
,package
->features
[i
].Feature_Parent
);
5053 size
= (strlenW(data
)+1)*sizeof(WCHAR
);
5054 RegSetValueExW(hkey
,package
->features
[i
].Feature
,0,REG_SZ
,
5056 HeapFree(GetProcessHeap(),0,data
);
5058 size
= strlenW(package
->features
[i
].Feature_Parent
)*sizeof(WCHAR
);
5059 RegSetValueExW(hukey
,package
->features
[i
].Feature
,0,REG_SZ
,
5060 (LPSTR
)package
->features
[i
].Feature_Parent
,size
);
5066 HeapFree(GetProcessHeap(), 0, productcode
);
5070 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
5072 static const WCHAR szProductCode
[]=
5073 {'P','r','o','d','u','c','t','C','o','d','e',0};
5079 static WCHAR szNONE
[] = {0};
5080 static const WCHAR szWindowsInstaler
[] =
5081 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5082 static const WCHAR szPropKeys
[][80] =
5084 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
5085 {'A','R','P','C','O','N','T','A','C','T'},
5086 {'A','R','P','C','O','M','M','E','N','T','S',0},
5087 {'P','r','o','d','u','c','t','N','a','m','e',0},
5088 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
5089 {'A','R','P','H','E','L','P','L','I','N','K',0},
5090 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
5091 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
5092 {'S','O','U','R','C','E','D','I','R',0},
5093 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
5094 {'A','R','P','R','E','A','D','M','E',0},
5095 {'A','R','P','S','I','Z','E',0},
5096 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
5097 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
5101 static const WCHAR szRegKeys
[][80] =
5103 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
5104 {'C','o','n','t','a','c','t',0},
5105 {'C','o','m','m','e','n','t','s',0},
5106 {'D','i','s','p','l','a','y','N','a','m','e',0},
5107 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
5108 {'H','e','l','p','L','i','n','k',0},
5109 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
5110 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
5111 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
5112 {'P','u','b','l','i','s','h','e','r',0},
5113 {'R','e','a','d','m','e',0},
5114 {'S','i','z','e',0},
5115 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
5116 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
5120 static const WCHAR path
[] = {
5121 'C',':','\\','W','i','n','d','o','w','s','\\',
5122 'I','n','s','t','a','l','l','e','r','\\'};
5123 static const WCHAR fmt
[] = {
5124 'C',':','\\','W','i','n','d','o','w','s','\\',
5125 'I','n','s','t','a','l','l','e','r','\\',
5126 '%','x','.','m','s','i',0};
5127 static const WCHAR szLocalPackage
[]=
5128 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
5129 WCHAR packagefile
[MAX_PATH
];
5133 return ERROR_INVALID_HANDLE
;
5135 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5139 rc
= MSIREG_OpenUninstallKey(productcode
,&hkey
,TRUE
);
5140 if (rc
!= ERROR_SUCCESS
)
5143 /* dump all the info i can grab */
5144 FIXME("Flesh out more information \n");
5147 while (szPropKeys
[i
][0]!=0)
5149 buffer
= load_dynamic_property(package
,szPropKeys
[i
],&rc
);
5150 if (rc
!= ERROR_SUCCESS
)
5152 size
= strlenW(buffer
)*sizeof(WCHAR
);
5153 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,(LPSTR
)buffer
,size
);
5159 RegSetValueExW(hkey
,szWindowsInstaler
,0,REG_DWORD
,(LPSTR
)&rc
,size
);
5161 /* copy the package locally */
5162 num
= GetTickCount() & 0xffff;
5166 sprintfW(packagefile
,fmt
,num
);
5169 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
5170 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
5171 if (handle
!= INVALID_HANDLE_VALUE
)
5173 CloseHandle(handle
);
5176 if (GetLastError() != ERROR_FILE_EXISTS
&&
5177 GetLastError() != ERROR_SHARING_VIOLATION
)
5179 if (!(++num
& 0xffff)) num
= 1;
5180 sprintfW(packagefile
,fmt
,num
);
5181 } while (num
!= start
);
5183 create_full_pathW(path
);
5184 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
5185 CopyFileW(package
->PackagePath
,packagefile
,FALSE
);
5186 size
= strlenW(packagefile
)*sizeof(WCHAR
);
5187 RegSetValueExW(hkey
,szLocalPackage
,0,REG_SZ
,(LPSTR
)packagefile
,size
);
5190 HeapFree(GetProcessHeap(),0,productcode
);
5193 return ERROR_SUCCESS
;
5196 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
5200 return ERROR_INVALID_HANDLE
;
5202 for (i
= 0; i
< package
->DeferredActionCount
; i
++)
5205 action
= package
->DeferredAction
[i
];
5206 ui_actionstart(package
, action
);
5207 TRACE("Executing Action (%s)\n",debugstr_w(action
));
5208 ACTION_CustomAction(package
,action
,TRUE
);
5209 HeapFree(GetProcessHeap(),0,package
->DeferredAction
[i
]);
5211 HeapFree(GetProcessHeap(),0,package
->DeferredAction
);
5213 package
->DeferredActionCount
= 0;
5214 package
->DeferredAction
= NULL
;
5216 return ERROR_SUCCESS
;
5219 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
5223 return ERROR_INVALID_HANDLE
;
5225 /* first do the same as an InstallExecute */
5226 ACTION_InstallExecute(package
);
5228 /* then handle Commit Actions */
5229 for (i
= 0; i
< package
->CommitActionCount
; i
++)
5232 action
= package
->CommitAction
[i
];
5233 ui_actionstart(package
, action
);
5234 TRACE("Executing Commit Action (%s)\n",debugstr_w(action
));
5235 ACTION_CustomAction(package
,action
,TRUE
);
5236 HeapFree(GetProcessHeap(),0,package
->CommitAction
[i
]);
5238 HeapFree(GetProcessHeap(),0,package
->CommitAction
);
5240 package
->CommitActionCount
= 0;
5241 package
->CommitAction
= NULL
;
5243 return ERROR_SUCCESS
;
5246 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
5248 static const WCHAR RunOnce
[] = {
5249 'S','o','f','t','w','a','r','e','\\',
5250 'M','i','c','r','o','s','o','f','t','\\',
5251 'W','i','n','d','o','w','s','\\',
5252 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5253 'R','u','n','O','n','c','e'};
5254 static const WCHAR InstallRunOnce
[] = {
5255 'S','o','f','t','w','a','r','e','\\',
5256 'M','i','c','r','o','s','o','f','t','\\',
5257 'W','i','n','d','o','w','s','\\',
5258 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5259 'I','n','s','t','a','l','l','e','r','\\',
5260 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'};
5262 static const WCHAR msiexec_fmt
[] = {
5263 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m',
5264 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5265 '\"','%','s','\"',0};
5266 static const WCHAR install_fmt
[] = {
5267 '/','I',' ','\"','%','s','\"',' ',
5268 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5269 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5273 WCHAR squished_pc
[100];
5276 static const WCHAR szProductCode
[]=
5277 {'P','r','o','d','u','c','t','C','o','d','e',0};
5278 static const WCHAR szLUS
[] = {
5279 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
5280 static const WCHAR szSourceList
[] = {
5281 'S','o','u','r','c','e','L','i','s','t',0};
5282 static const WCHAR szPackageName
[] = {
5283 'P','a','c','k','a','g','e','N','a','m','e',0};
5286 return ERROR_INVALID_HANDLE
;
5288 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5292 squash_guid(productcode
,squished_pc
);
5294 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
5295 sprintfW(buffer
,msiexec_fmt
,squished_pc
);
5297 size
= strlenW(buffer
)*sizeof(WCHAR
);
5298 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
5301 TRACE("Reboot command %s\n",debugstr_w(buffer
));
5303 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
5304 sprintfW(buffer
,install_fmt
,productcode
,squished_pc
);
5305 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
5308 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
5309 if (rc
== ERROR_SUCCESS
)
5313 RegCreateKeyW(hukey
, szSourceList
, &hukey2
);
5314 buf
= load_dynamic_property(package
,cszSourceDir
,NULL
);
5315 size
= strlenW(buf
)*sizeof(WCHAR
);
5316 RegSetValueExW(hukey2
,szLUS
,0,REG_SZ
,(LPSTR
)buf
,size
);
5317 HeapFree(GetProcessHeap(),0,buf
);
5319 buf
= strrchrW(package
->PackagePath
,'\\');
5323 size
= strlenW(buf
)*sizeof(WCHAR
);
5324 RegSetValueExW(hukey2
,szPackageName
,0,REG_SZ
,(LPSTR
)buf
,size
);
5327 RegCloseKey(hukey2
);
5329 HeapFree(GetProcessHeap(),0,productcode
);
5331 return ERROR_INSTALL_SUSPEND
;
5334 UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
5337 * we are currently doing what should be done here in the top level Install
5338 * however for Adminastrative and uninstalls this step will be needed
5340 return ERROR_SUCCESS
;
5343 /* Msi functions that seem appropriate here */
5344 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
5349 TRACE(" exteral attempt at action %s\n",szAction
);
5352 return ERROR_FUNCTION_FAILED
;
5354 return ERROR_FUNCTION_FAILED
;
5356 szwAction
= strdupAtoW(szAction
);
5359 return ERROR_FUNCTION_FAILED
;
5362 rc
= MsiDoActionW(hInstall
, szwAction
);
5363 HeapFree(GetProcessHeap(),0,szwAction
);
5367 UINT WINAPI
MsiDoActionW( MSIHANDLE hInstall
, LPCWSTR szAction
)
5369 MSIPACKAGE
*package
;
5370 UINT ret
= ERROR_INVALID_HANDLE
;
5372 TRACE(" external attempt at action %s \n",debugstr_w(szAction
));
5374 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5377 ret
= ACTION_PerformAction(package
,szAction
);
5378 msiobj_release( &package
->hdr
);
5383 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
5384 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
5390 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
5393 return ERROR_FUNCTION_FAILED
;
5395 return ERROR_FUNCTION_FAILED
;
5397 szwFolder
= strdupAtoW(szFolder
);
5400 return ERROR_FUNCTION_FAILED
;
5402 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
5404 rc
= MsiGetTargetPathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
5406 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
5407 *pcchPathBuf
, NULL
, NULL
);
5409 HeapFree(GetProcessHeap(),0,szwFolder
);
5410 HeapFree(GetProcessHeap(),0,szwPathBuf
);
5415 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
5416 szPathBuf
, DWORD
* pcchPathBuf
)
5419 UINT rc
= ERROR_FUNCTION_FAILED
;
5420 MSIPACKAGE
*package
;
5422 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
5424 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5426 return ERROR_INVALID_HANDLE
;
5427 path
= resolve_folder(package
, szFolder
, FALSE
, FALSE
, NULL
);
5428 msiobj_release( &package
->hdr
);
5430 if (path
&& (strlenW(path
) > *pcchPathBuf
))
5432 *pcchPathBuf
= strlenW(path
)+1;
5433 rc
= ERROR_MORE_DATA
;
5437 *pcchPathBuf
= strlenW(path
)+1;
5438 strcpyW(szPathBuf
,path
);
5439 TRACE("Returning Path %s\n",debugstr_w(path
));
5442 HeapFree(GetProcessHeap(),0,path
);
5448 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
5449 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
5455 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
5458 return ERROR_FUNCTION_FAILED
;
5460 return ERROR_FUNCTION_FAILED
;
5462 szwFolder
= strdupAtoW(szFolder
);
5464 return ERROR_FUNCTION_FAILED
;
5466 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
5468 rc
= MsiGetSourcePathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
5470 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
5471 *pcchPathBuf
, NULL
, NULL
);
5473 HeapFree(GetProcessHeap(),0,szwFolder
);
5474 HeapFree(GetProcessHeap(),0,szwPathBuf
);
5479 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
5480 szPathBuf
, DWORD
* pcchPathBuf
)
5483 UINT rc
= ERROR_FUNCTION_FAILED
;
5484 MSIPACKAGE
*package
;
5486 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
5488 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5490 return ERROR_INVALID_HANDLE
;
5491 path
= resolve_folder(package
, szFolder
, TRUE
, FALSE
, NULL
);
5492 msiobj_release( &package
->hdr
);
5494 if (path
&& strlenW(path
) > *pcchPathBuf
)
5496 *pcchPathBuf
= strlenW(path
)+1;
5497 rc
= ERROR_MORE_DATA
;
5501 *pcchPathBuf
= strlenW(path
)+1;
5502 strcpyW(szPathBuf
,path
);
5503 TRACE("Returning Path %s\n",debugstr_w(path
));
5506 HeapFree(GetProcessHeap(),0,path
);
5512 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
5513 LPCSTR szFolderPath
)
5516 LPWSTR szwFolderPath
;
5520 return ERROR_FUNCTION_FAILED
;
5522 return ERROR_FUNCTION_FAILED
;
5524 szwFolder
= strdupAtoW(szFolder
);
5526 return ERROR_FUNCTION_FAILED
;
5528 szwFolderPath
= strdupAtoW(szFolderPath
);
5531 HeapFree(GetProcessHeap(),0,szwFolder
);
5532 return ERROR_FUNCTION_FAILED
;
5535 rc
= MsiSetTargetPathW(hInstall
, szwFolder
, szwFolderPath
);
5537 HeapFree(GetProcessHeap(),0,szwFolder
);
5538 HeapFree(GetProcessHeap(),0,szwFolderPath
);
5543 UINT
MSI_SetTargetPathW(MSIPACKAGE
*package
, LPCWSTR szFolder
,
5544 LPCWSTR szFolderPath
)
5548 LPWSTR path2
= NULL
;
5552 TRACE("(%p %s %s)\n",package
, debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5555 return ERROR_INVALID_HANDLE
;
5557 if (szFolderPath
[0]==0)
5558 return ERROR_FUNCTION_FAILED
;
5560 if (GetFileAttributesW(szFolderPath
) == INVALID_FILE_ATTRIBUTES
)
5561 return ERROR_FUNCTION_FAILED
;
5563 path
= resolve_folder(package
,szFolder
,FALSE
,FALSE
,&folder
);
5566 return ERROR_INVALID_PARAMETER
;
5568 HeapFree(GetProcessHeap(),0,folder
->Property
);
5570 len
= strlenW(szFolderPath
);
5572 if (szFolderPath
[len
-1]!='\\')
5575 folder
->Property
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
5576 strcpyW(folder
->Property
,szFolderPath
);
5577 strcatW(folder
->Property
,cszbs
);
5580 folder
->Property
= dupstrW(szFolderPath
);
5582 if (strcmpiW(path
, szFolderPath
) == 0)
5585 * Resolved Target has not really changed, so just
5586 * set this folder and do not recalculate everything.
5588 HeapFree(GetProcessHeap(),0,folder
->ResolvedTarget
);
5589 folder
->ResolvedTarget
= NULL
;
5590 path2
= resolve_folder(package
,szFolder
,FALSE
,TRUE
,NULL
);
5591 HeapFree(GetProcessHeap(),0,path2
);
5595 for (i
= 0; i
< package
->loaded_folders
; i
++)
5597 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
5598 package
->folders
[i
].ResolvedTarget
=NULL
;
5601 for (i
= 0; i
< package
->loaded_folders
; i
++)
5603 path2
=resolve_folder(package
, package
->folders
[i
].Directory
, FALSE
,
5605 HeapFree(GetProcessHeap(),0,path2
);
5608 HeapFree(GetProcessHeap(),0,path
);
5610 return ERROR_SUCCESS
;
5613 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
5614 LPCWSTR szFolderPath
)
5616 MSIPACKAGE
*package
;
5619 TRACE("(%s %s)\n",debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5621 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5622 ret
= MSI_SetTargetPathW( package
, szFolder
, szFolderPath
);
5623 msiobj_release( &package
->hdr
);
5627 /***********************************************************************
5628 * MsiGetMode (MSI.@)
5630 * Returns an internal installer state (if it is running in a mode iRunMode)
5633 * hInstall [I] Handle to the installation
5634 * hRunMode [I] Checking run mode
5635 * MSIRUNMODE_ADMIN Administrative mode
5636 * MSIRUNMODE_ADVERTISE Advertisement mode
5637 * MSIRUNMODE_MAINTENANCE Maintenance mode
5638 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
5639 * MSIRUNMODE_LOGENABLED Log file is writing
5640 * MSIRUNMODE_OPERATIONS Operations in progress??
5641 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
5642 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
5643 * MSIRUNMODE_CABINET Files from cabinet are installed
5644 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
5645 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
5646 * MSIRUNMODE_RESERVED11 Reserved
5647 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
5648 * MSIRUNMODE_ZAWENABLED Demand installation is supported
5649 * MSIRUNMODE_RESERVED14 Reserved
5650 * MSIRUNMODE_RESERVED15 Reserved
5651 * MSIRUNMODE_SCHEDULED called from install script
5652 * MSIRUNMODE_ROLLBACK called from rollback script
5653 * MSIRUNMODE_COMMIT called from commit script
5656 * In the state: TRUE
5657 * Not in the state: FALSE
5661 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, MSIRUNMODE iRunMode
)
5663 FIXME("STUB (iRunMode=%i)\n",iRunMode
);
5668 * According to the docs, when this is called it immediately recalculates
5669 * all the component states as well
5671 UINT WINAPI
MsiSetFeatureStateA(MSIHANDLE hInstall
, LPCSTR szFeature
,
5672 INSTALLSTATE iState
)
5674 LPWSTR szwFeature
= NULL
;
5677 szwFeature
= strdupAtoW(szFeature
);
5680 return ERROR_FUNCTION_FAILED
;
5682 rc
= MsiSetFeatureStateW(hInstall
,szwFeature
, iState
);
5684 HeapFree(GetProcessHeap(),0,szwFeature
);
5689 UINT WINAPI
MsiSetFeatureStateW(MSIHANDLE hInstall
, LPCWSTR szFeature
,
5690 INSTALLSTATE iState
)
5692 MSIPACKAGE
* package
;
5695 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
5697 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5699 return ERROR_INVALID_HANDLE
;
5701 index
= get_loaded_feature(package
,szFeature
);
5703 return ERROR_UNKNOWN_FEATURE
;
5705 package
->features
[index
].ActionRequest
= iState
;
5706 ACTION_UpdateComponentStates(package
,szFeature
);
5708 return ERROR_SUCCESS
;
5711 UINT WINAPI
MsiGetFeatureStateA(MSIHANDLE hInstall
, LPSTR szFeature
,
5712 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5714 LPWSTR szwFeature
= NULL
;
5717 szwFeature
= strdupAtoW(szFeature
);
5719 rc
= MsiGetFeatureStateW(hInstall
,szwFeature
,piInstalled
, piAction
);
5721 HeapFree( GetProcessHeap(), 0 , szwFeature
);
5726 UINT
MSI_GetFeatureStateW(MSIPACKAGE
*package
, LPWSTR szFeature
,
5727 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5731 index
= get_loaded_feature(package
,szFeature
);
5733 return ERROR_UNKNOWN_FEATURE
;
5736 *piInstalled
= package
->features
[index
].Installed
;
5739 *piAction
= package
->features
[index
].Action
;
5741 TRACE("returning %i %i\n",*piInstalled
,*piAction
);
5743 return ERROR_SUCCESS
;
5746 UINT WINAPI
MsiGetFeatureStateW(MSIHANDLE hInstall
, LPWSTR szFeature
,
5747 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5749 MSIPACKAGE
* package
;
5752 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szFeature
), piInstalled
,
5755 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5757 return ERROR_INVALID_HANDLE
;
5758 ret
= MSI_GetFeatureStateW(package
, szFeature
, piInstalled
, piAction
);
5759 msiobj_release( &package
->hdr
);
5763 UINT WINAPI
MsiGetComponentStateA(MSIHANDLE hInstall
, LPSTR szComponent
,
5764 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5766 LPWSTR szwComponent
= NULL
;
5769 szwComponent
= strdupAtoW(szComponent
);
5771 rc
= MsiGetComponentStateW(hInstall
,szwComponent
,piInstalled
, piAction
);
5773 HeapFree( GetProcessHeap(), 0 , szwComponent
);
5778 UINT
MSI_GetComponentStateW(MSIPACKAGE
*package
, LPWSTR szComponent
,
5779 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5783 TRACE("%p %s %p %p\n", package
, debugstr_w(szComponent
), piInstalled
,
5786 index
= get_loaded_component(package
,szComponent
);
5788 return ERROR_UNKNOWN_COMPONENT
;
5791 *piInstalled
= package
->components
[index
].Installed
;
5794 *piAction
= package
->components
[index
].Action
;
5796 TRACE("states (%i, %i)\n",
5797 (piInstalled
)?*piInstalled
:-1,(piAction
)?*piAction
:-1);
5799 return ERROR_SUCCESS
;
5802 UINT WINAPI
MsiGetComponentStateW(MSIHANDLE hInstall
, LPWSTR szComponent
,
5803 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5805 MSIPACKAGE
* package
;
5808 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szComponent
),
5809 piInstalled
, piAction
);
5811 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5813 return ERROR_INVALID_HANDLE
;
5814 ret
= MSI_GetComponentStateW( package
, szComponent
, piInstalled
, piAction
);
5815 msiobj_release( &package
->hdr
);
5820 static UINT
ACTION_Template(MSIPACKAGE
*package
)
5824 MSIRECORD
* row
= 0;
5825 static const WCHAR ExecSeqQuery
[] = {0};
5827 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5828 if (rc
!= ERROR_SUCCESS
)
5831 rc
= MSI_ViewExecute(view
, 0);
5832 if (rc
!= ERROR_SUCCESS
)
5834 MSI_ViewClose(view
);
5835 msiobj_release(&view
->hdr
);
5841 rc
= MSI_ViewFetch(view
,&row
);
5842 if (rc
!= ERROR_SUCCESS
)
5848 msiobj_release(&row
->hdr
);
5850 MSI_ViewClose(view
);
5851 msiobj_release(&view
->hdr
);