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_RegisterExtensionInfo(MSIPACKAGE
*package
);
87 static UINT
ACTION_RegisterMIMEInfo(MSIPACKAGE
*package
);
88 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
);
89 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
);
90 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
);
91 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
);
92 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
);
93 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
);
94 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
);
95 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
);
96 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
);
97 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
);
98 static UINT
ACTION_ResolveSource(MSIPACKAGE
*package
);
102 * consts and values used
104 static const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
105 static const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
106 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
107 static const WCHAR cszTempFolder
[]= {'T','e','m','p','F','o','l','d','e','r',0};
108 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
109 static const WCHAR c_collen
[] = {'C',':','\\',0};
111 static const WCHAR cszbs
[]={'\\',0};
113 const static WCHAR szCreateFolders
[] =
114 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
115 const static WCHAR szCostFinalize
[] =
116 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
117 const static WCHAR szInstallFiles
[] =
118 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
119 const static WCHAR szDuplicateFiles
[] =
120 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
121 const static WCHAR szWriteRegistryValues
[] =
122 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
123 const static WCHAR szCostInitialize
[] =
124 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
125 const static WCHAR szFileCost
[] =
126 {'F','i','l','e','C','o','s','t',0};
127 const static WCHAR szInstallInitialize
[] =
128 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
129 const static WCHAR szInstallValidate
[] =
130 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
131 const static WCHAR szLaunchConditions
[] =
132 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
133 const static WCHAR szProcessComponents
[] =
134 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
135 const static WCHAR szRegisterTypeLibraries
[] =
136 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
138 const static WCHAR szRegisterClassInfo
[] =
139 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
140 const static WCHAR szRegisterProgIdInfo
[] =
141 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
142 const static WCHAR szCreateShortcuts
[] =
143 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
144 const static WCHAR szPublishProduct
[] =
145 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
146 const static WCHAR szWriteIniValues
[] =
147 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
148 const static WCHAR szSelfRegModules
[] =
149 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
150 const static WCHAR szPublishFeatures
[] =
151 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
152 const static WCHAR szRegisterProduct
[] =
153 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
154 const static WCHAR szInstallExecute
[] =
155 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
156 const static WCHAR szInstallExecuteAgain
[] =
157 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
158 const static WCHAR szInstallFinalize
[] =
159 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
160 const static WCHAR szForceReboot
[] =
161 {'F','o','r','c','e','R','e','b','o','o','t',0};
162 const static WCHAR szResolveSource
[] =
163 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
164 const static WCHAR szAppSearch
[] =
165 {'A','p','p','S','e','a','r','c','h',0};
166 const static WCHAR szAllocateRegistrySpace
[] =
167 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
168 const static WCHAR szBindImage
[] =
169 {'B','i','n','d','I','m','a','g','e',0};
170 const static WCHAR szCCPSearch
[] =
171 {'C','C','P','S','e','a','r','c','h',0};
172 const static WCHAR szDeleteServices
[] =
173 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
174 const static WCHAR szDisableRollback
[] =
175 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
176 const static WCHAR szExecuteAction
[] =
177 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
178 const static WCHAR szFindRelatedProducts
[] =
179 {'F','i','n','d','R','e','l','a','t','e','d','P','r','o','d','u','c','t','s',0};
180 const static WCHAR szInstallAdminPackage
[] =
181 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
182 const static WCHAR szInstallSFPCatalogFile
[] =
183 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
184 const static WCHAR szIsolateComponents
[] =
185 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
186 const static WCHAR szMigrateFeatureStates
[] =
187 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
188 const static WCHAR szMoveFiles
[] =
189 {'M','o','v','e','F','i','l','e','s',0};
190 const static WCHAR szMsiPublishAssemblies
[] =
191 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
192 const static WCHAR szMsiUnpublishAssemblies
[] =
193 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
194 const static WCHAR szInstallODBC
[] =
195 {'I','n','s','t','a','l','l','O','D','B','C',0};
196 const static WCHAR szInstallServices
[] =
197 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
198 const static WCHAR szPatchFiles
[] =
199 {'P','a','t','c','h','F','i','l','e','s',0};
200 const static WCHAR szPublishComponents
[] =
201 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
202 const static WCHAR szRegisterComPlus
[] =
203 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
204 const static WCHAR szRegisterExtensionInfo
[] =
205 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
206 const static WCHAR szRegisterFonts
[] =
207 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
208 const static WCHAR szRegisterMIMEInfo
[] =
209 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
210 const static WCHAR szRegisterUser
[] =
211 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
212 const static WCHAR szRemoveDuplicateFiles
[] =
213 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
214 const static WCHAR szRemoveEnvironmentStrings
[] =
215 {'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};
216 const static WCHAR szRemoveExistingProducts
[] =
217 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
218 const static WCHAR szRemoveFiles
[] =
219 {'R','e','m','o','v','e','F','i','l','e','s',0};
220 const static WCHAR szRemoveFolders
[] =
221 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
222 const static WCHAR szRemoveIniValues
[] =
223 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
224 const static WCHAR szRemoveODBC
[] =
225 {'R','e','m','o','v','e','O','D','B','C',0};
226 const static WCHAR szRemoveRegistryValues
[] =
227 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
228 const static WCHAR szRemoveShortcuts
[] =
229 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
230 const static WCHAR szRMCCPSearch
[] =
231 {'R','M','C','C','P','S','e','a','r','c','h',0};
232 const static WCHAR szScheduleReboot
[] =
233 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
234 const static WCHAR szSelfUnregModules
[] =
235 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
236 const static WCHAR szSetODBCFolders
[] =
237 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
238 const static WCHAR szStartServices
[] =
239 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
240 const static WCHAR szStopServices
[] =
241 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
242 const static WCHAR szUnpublishComponents
[] =
243 {'U','n','p','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
244 const static WCHAR szUnpublishFeatures
[] =
245 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
246 const static WCHAR szUnregisterClassInfo
[] =
247 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
248 const static WCHAR szUnregisterComPlus
[] =
249 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
250 const static WCHAR szUnregisterExtensionInfo
[] =
251 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
252 const static WCHAR szUnregisterFonts
[] =
253 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
254 const static WCHAR szUnregisterMIMEInfo
[] =
255 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
256 const static WCHAR szUnregisterProgIdInfo
[] =
257 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
258 const static WCHAR szUnregisterTypeLibraries
[] =
259 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
260 const static WCHAR szValidateProductID
[] =
261 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
262 const static WCHAR szWriteEnvironmentStrings
[] =
263 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
267 STANDARDACTIONHANDLER handler
;
270 static struct _actions StandardActions
[] = {
271 { szAllocateRegistrySpace
, NULL
},
272 { szAppSearch
, ACTION_AppSearch
},
273 { szBindImage
, NULL
},
274 { szCCPSearch
, NULL
},
275 { szCostFinalize
, ACTION_CostFinalize
},
276 { szCostInitialize
, ACTION_CostInitialize
},
277 { szCreateFolders
, ACTION_CreateFolders
},
278 { szCreateShortcuts
, ACTION_CreateShortcuts
},
279 { szDeleteServices
, NULL
},
280 { szDisableRollback
, NULL
},
281 { szDuplicateFiles
, ACTION_DuplicateFiles
},
282 { szExecuteAction
, NULL
},
283 { szFileCost
, ACTION_FileCost
},
284 { szFindRelatedProducts
, NULL
},
285 { szForceReboot
, ACTION_ForceReboot
},
286 { szInstallAdminPackage
, NULL
},
287 { szInstallExecute
, ACTION_InstallExecute
},
288 { szInstallExecuteAgain
, ACTION_InstallExecute
},
289 { szInstallFiles
, ACTION_InstallFiles
},
290 { szInstallFinalize
, ACTION_InstallFinalize
},
291 { szInstallInitialize
, ACTION_InstallInitialize
},
292 { szInstallSFPCatalogFile
, NULL
},
293 { szInstallValidate
, ACTION_InstallValidate
},
294 { szIsolateComponents
, NULL
},
295 { szLaunchConditions
, ACTION_LaunchConditions
},
296 { szMigrateFeatureStates
, NULL
},
297 { szMoveFiles
, NULL
},
298 { szMsiPublishAssemblies
, NULL
},
299 { szMsiUnpublishAssemblies
, NULL
},
300 { szInstallODBC
, NULL
},
301 { szInstallServices
, NULL
},
302 { szPatchFiles
, NULL
},
303 { szProcessComponents
, ACTION_ProcessComponents
},
304 { szPublishComponents
, NULL
},
305 { szPublishFeatures
, ACTION_PublishFeatures
},
306 { szPublishProduct
, ACTION_PublishProduct
},
307 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
308 { szRegisterComPlus
, NULL
},
309 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
310 { szRegisterFonts
, NULL
},
311 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
312 { szRegisterProduct
, ACTION_RegisterProduct
},
313 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
314 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
315 { szRegisterUser
, ACTION_RegisterUser
},
316 { szRemoveDuplicateFiles
, NULL
},
317 { szRemoveEnvironmentStrings
, NULL
},
318 { szRemoveExistingProducts
, NULL
},
319 { szRemoveFiles
, NULL
},
320 { szRemoveFolders
, NULL
},
321 { szRemoveIniValues
, NULL
},
322 { szRemoveODBC
, NULL
},
323 { szRemoveRegistryValues
, NULL
},
324 { szRemoveShortcuts
, NULL
},
325 { szResolveSource
, ACTION_ResolveSource
},
326 { szRMCCPSearch
, NULL
},
327 { szScheduleReboot
, NULL
},
328 { szSelfRegModules
, ACTION_SelfRegModules
},
329 { szSelfUnregModules
, NULL
},
330 { szSetODBCFolders
, NULL
},
331 { szStartServices
, NULL
},
332 { szStopServices
, NULL
},
333 { szUnpublishComponents
, NULL
},
334 { szUnpublishFeatures
, NULL
},
335 { szUnregisterClassInfo
, NULL
},
336 { szUnregisterComPlus
, NULL
},
337 { szUnregisterExtensionInfo
, NULL
},
338 { szUnregisterFonts
, NULL
},
339 { szUnregisterMIMEInfo
, NULL
},
340 { szUnregisterProgIdInfo
, NULL
},
341 { szUnregisterTypeLibraries
, NULL
},
342 { szValidateProductID
, NULL
},
343 { szWriteEnvironmentStrings
, NULL
},
344 { szWriteIniValues
, ACTION_WriteIniValues
},
345 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
350 /********************************************************
351 * helper functions to get around current HACKS and such
352 ********************************************************/
353 inline static void reduce_to_longfilename(WCHAR
* filename
)
355 LPWSTR p
= strchrW(filename
,'|');
357 memmove(filename
, p
+1, (strlenW(p
+1)+1)*sizeof(WCHAR
));
360 WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
367 if (MSI_RecordIsNull(row
,index
))
370 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
372 /* having an empty string is different than NULL */
375 ret
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
));
381 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
382 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
383 if (rc
!=ERROR_SUCCESS
)
385 ERR("Unable to load dynamic string\n");
386 HeapFree(GetProcessHeap(), 0, ret
);
392 LPWSTR
load_dynamic_property(MSIPACKAGE
*package
, LPCWSTR prop
, UINT
* rc
)
398 r
= MSI_GetPropertyW(package
, prop
, NULL
, &sz
);
399 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
406 str
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
407 r
= MSI_GetPropertyW(package
, prop
, str
, &sz
);
408 if (r
!= ERROR_SUCCESS
)
410 HeapFree(GetProcessHeap(),0,str
);
418 int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
423 for (i
= 0; i
< package
->loaded_components
; i
++)
425 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
434 int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
439 for (i
= 0; i
< package
->loaded_features
; i
++)
441 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
450 int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
455 for (i
= 0; i
< package
->loaded_files
; i
++)
457 if (strcmpW(file
,package
->files
[i
].File
)==0)
466 int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
474 for (i
=0; i
< package
->loaded_files
; i
++)
475 if (strcmpW(package
->files
[i
].File
,name
)==0)
478 index
= package
->loaded_files
;
479 package
->loaded_files
++;
480 if (package
->loaded_files
== 1)
481 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
483 package
->files
= HeapReAlloc(GetProcessHeap(),0,
484 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
486 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
488 package
->files
[index
].File
= dupstrW(name
);
489 package
->files
[index
].TargetPath
= dupstrW(path
);
490 package
->files
[index
].Temporary
= TRUE
;
492 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
497 static void remove_tracked_tempfiles(MSIPACKAGE
* package
)
504 for (i
= 0; i
< package
->loaded_files
; i
++)
506 if (package
->files
[i
].Temporary
)
508 TRACE("Cleaning up %s\n",debugstr_w(package
->files
[i
].TargetPath
));
509 DeleteFileW(package
->files
[i
].TargetPath
);
515 /* wrapper to resist a need for a full rewrite right now */
516 DWORD
deformat_string(MSIPACKAGE
*package
, LPCWSTR ptr
, WCHAR
** data
)
520 MSIRECORD
*rec
= MSI_CreateRecord(1);
523 MSI_RecordSetStringW(rec
,0,ptr
);
524 MSI_FormatRecordW(package
,rec
,NULL
,&size
);
528 *data
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
530 MSI_FormatRecordW(package
,rec
,*data
,&size
);
533 msiobj_release( &rec
->hdr
);
534 return sizeof(WCHAR
)*size
;
536 msiobj_release( &rec
->hdr
);
543 /* Called when the package is being closed */
544 void ACTION_free_package_structures( MSIPACKAGE
* package
)
548 TRACE("Freeing package action data\n");
550 remove_tracked_tempfiles(package
);
552 /* No dynamic buffers in features */
553 if (package
->features
&& package
->loaded_features
> 0)
554 HeapFree(GetProcessHeap(),0,package
->features
);
556 for (i
= 0; i
< package
->loaded_folders
; i
++)
558 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Directory
);
559 HeapFree(GetProcessHeap(),0,package
->folders
[i
].TargetDefault
);
560 HeapFree(GetProcessHeap(),0,package
->folders
[i
].SourceDefault
);
561 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
562 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedSource
);
563 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Property
);
565 if (package
->folders
&& package
->loaded_folders
> 0)
566 HeapFree(GetProcessHeap(),0,package
->folders
);
568 /* no dynamic buffers in components */
569 if (package
->components
&& package
->loaded_components
> 0)
570 HeapFree(GetProcessHeap(),0,package
->components
);
572 for (i
= 0; i
< package
->loaded_files
; i
++)
574 HeapFree(GetProcessHeap(),0,package
->files
[i
].File
);
575 HeapFree(GetProcessHeap(),0,package
->files
[i
].FileName
);
576 HeapFree(GetProcessHeap(),0,package
->files
[i
].Version
);
577 HeapFree(GetProcessHeap(),0,package
->files
[i
].Language
);
578 HeapFree(GetProcessHeap(),0,package
->files
[i
].SourcePath
);
579 HeapFree(GetProcessHeap(),0,package
->files
[i
].TargetPath
);
582 if (package
->files
&& package
->loaded_files
> 0)
583 HeapFree(GetProcessHeap(),0,package
->files
);
585 for (i
= 0; i
< package
->DeferredActionCount
; i
++)
586 HeapFree(GetProcessHeap(),0,package
->DeferredAction
[i
]);
587 HeapFree(GetProcessHeap(),0,package
->DeferredAction
);
589 for (i
= 0; i
< package
->CommitActionCount
; i
++)
590 HeapFree(GetProcessHeap(),0,package
->CommitAction
[i
]);
591 HeapFree(GetProcessHeap(),0,package
->CommitAction
);
593 HeapFree(GetProcessHeap(),0,package
->PackagePath
);
596 static void ui_progress(MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
600 row
= MSI_CreateRecord(4);
601 MSI_RecordSetInteger(row
,1,a
);
602 MSI_RecordSetInteger(row
,2,b
);
603 MSI_RecordSetInteger(row
,3,c
);
604 MSI_RecordSetInteger(row
,4,d
);
605 MSI_ProcessMessage(package
, INSTALLMESSAGE_PROGRESS
, row
);
606 msiobj_release(&row
->hdr
);
608 msi_dialog_check_messages(package
->dialog
, NULL
);
611 static void ui_actiondata(MSIPACKAGE
*package
, LPCWSTR action
, MSIRECORD
* record
)
613 static const WCHAR Query_t
[] =
614 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
615 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
616 ' ','\'','%','s','\'',0};
623 if (!package
->LastAction
|| strcmpW(package
->LastAction
,action
))
625 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, action
);
626 if (rc
!= ERROR_SUCCESS
)
629 rc
= MSI_ViewExecute(view
, 0);
630 if (rc
!= ERROR_SUCCESS
)
635 rc
= MSI_ViewFetch(view
,&row
);
636 if (rc
!= ERROR_SUCCESS
)
642 if (MSI_RecordIsNull(row
,3))
644 msiobj_release(&row
->hdr
);
646 msiobj_release(&view
->hdr
);
650 /* update the cached actionformat */
651 HeapFree(GetProcessHeap(),0,package
->ActionFormat
);
652 package
->ActionFormat
= load_dynamic_stringW(row
,3);
654 HeapFree(GetProcessHeap(),0,package
->LastAction
);
655 package
->LastAction
= dupstrW(action
);
657 msiobj_release(&row
->hdr
);
659 msiobj_release(&view
->hdr
);
662 MSI_RecordSetStringW(record
,0,package
->ActionFormat
);
664 MSI_FormatRecordW(package
,record
,message
,&size
);
666 row
= MSI_CreateRecord(1);
667 MSI_RecordSetStringW(row
,1,message
);
669 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, row
);
670 msiobj_release(&row
->hdr
);
674 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
676 static const WCHAR template_s
[]=
677 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
678 static const WCHAR format
[] =
679 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
680 static const WCHAR Query_t
[] =
681 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
682 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
683 ' ','\'','%','s','\'',0};
689 WCHAR
*ActionText
=NULL
;
691 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
693 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, action
);
694 if (rc
!= ERROR_SUCCESS
)
696 rc
= MSI_ViewExecute(view
, 0);
697 if (rc
!= ERROR_SUCCESS
)
700 msiobj_release(&view
->hdr
);
703 rc
= MSI_ViewFetch(view
,&row
);
704 if (rc
!= ERROR_SUCCESS
)
707 msiobj_release(&view
->hdr
);
711 ActionText
= load_dynamic_stringW(row
,2);
712 msiobj_release(&row
->hdr
);
714 msiobj_release(&view
->hdr
);
716 sprintfW(message
,template_s
,timet
,action
,ActionText
);
718 row
= MSI_CreateRecord(1);
719 MSI_RecordSetStringW(row
,1,message
);
721 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
722 msiobj_release(&row
->hdr
);
723 HeapFree(GetProcessHeap(),0,ActionText
);
726 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
730 static const WCHAR template_s
[]=
731 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
733 static const WCHAR template_e
[]=
734 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
735 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
736 static const WCHAR format
[] =
737 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
741 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
743 sprintfW(message
,template_s
,timet
,action
);
745 sprintfW(message
,template_e
,timet
,action
,rc
);
747 row
= MSI_CreateRecord(1);
748 MSI_RecordSetStringW(row
,1,message
);
750 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
751 msiobj_release(&row
->hdr
);
755 * build_directory_name()
757 * This function is to save messing round with directory names
758 * It handles adding backslashes between path segments,
759 * and can add \ at the end of the directory name if told to.
761 * It takes a variable number of arguments.
762 * It always allocates a new string for the result, so make sure
763 * to free the return value when finished with it.
765 * The first arg is the number of path segments that follow.
766 * The arguments following count are a list of path segments.
767 * A path segment may be NULL.
769 * Path segments will be added with a \ separating them.
770 * A \ will not be added after the last segment, however if the
771 * last segment is NULL, then the last character will be a \
774 static LPWSTR
build_directory_name(DWORD count
, ...)
781 for(i
=0; i
<count
; i
++)
783 LPCWSTR str
= va_arg(va
,LPCWSTR
);
785 sz
+= strlenW(str
) + 1;
789 dir
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
793 for(i
=0; i
<count
; i
++)
795 LPCWSTR str
= va_arg(va
,LPCWSTR
);
799 if( ((i
+1)!=count
) && dir
[strlenW(dir
)-1]!='\\')
806 /****************************************************
807 * TOP level entry points
808 *****************************************************/
810 UINT
ACTION_DoTopLevelINSTALL(MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
811 LPCWSTR szCommandLine
)
816 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
817 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
818 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
820 MSI_SetPropertyW(package
, szAction
, szInstall
);
824 LPWSTR p
, check
, path
;
826 package
->PackagePath
= dupstrW(szPackagePath
);
827 path
= dupstrW(szPackagePath
);
828 p
= strrchrW(path
,'\\');
836 HeapFree(GetProcessHeap(),0,path
);
837 path
= HeapAlloc(GetProcessHeap(),0,MAX_PATH
*sizeof(WCHAR
));
838 GetCurrentDirectoryW(MAX_PATH
,path
);
842 check
= load_dynamic_property(package
, cszSourceDir
,NULL
);
844 MSI_SetPropertyW(package
, cszSourceDir
, path
);
846 HeapFree(GetProcessHeap(), 0, check
);
848 HeapFree(GetProcessHeap(), 0, path
);
854 ptr
= (LPWSTR
)szCommandLine
;
861 TRACE("Looking at %s\n",debugstr_w(ptr
));
863 ptr2
= strchrW(ptr
,'=');
869 while (*ptr
== ' ') ptr
++;
871 prop
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
872 strncpyW(prop
,ptr
,len
);
878 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
891 val
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
892 strncpyW(val
,ptr2
,len
);
895 if (strlenW(prop
) > 0)
897 TRACE("Found commandline property (%s) = (%s)\n",
898 debugstr_w(prop
), debugstr_w(val
));
899 MSI_SetPropertyW(package
,prop
,val
);
901 HeapFree(GetProcessHeap(),0,val
);
902 HeapFree(GetProcessHeap(),0,prop
);
909 if (MSI_GetPropertyW(package
,szUILevel
,buffer
,&sz
) == ERROR_SUCCESS
)
911 if (atoiW(buffer
) >= INSTALLUILEVEL_REDUCED
)
913 rc
= ACTION_ProcessUISequence(package
);
914 if (rc
== ERROR_SUCCESS
)
915 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
918 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
921 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
925 /* install was halted but should be considered a success */
929 /* process the ending type action */
930 if (rc
== ERROR_SUCCESS
)
931 ACTION_PerformActionSequence(package
,-1);
932 else if (rc
== ERROR_INSTALL_USEREXIT
)
933 ACTION_PerformActionSequence(package
,-2);
934 else if (rc
== ERROR_FUNCTION_FAILED
)
935 ACTION_PerformActionSequence(package
,-3);
936 else if (rc
== ERROR_INSTALL_SUSPEND
)
937 ACTION_PerformActionSequence(package
,-4);
939 /* finish up running custom actions */
940 ACTION_FinishCustomActions(package
);
945 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
952 static const WCHAR ExecSeqQuery
[] = {
953 's','e','l','e','c','t',' ','*',' ',
955 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
956 'S','e','q','u','e','n','c','e',' ',
957 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
960 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
962 if (rc
== ERROR_SUCCESS
)
964 rc
= MSI_ViewExecute(view
, 0);
966 if (rc
!= ERROR_SUCCESS
)
969 msiobj_release(&view
->hdr
);
973 TRACE("Running the actions\n");
975 rc
= MSI_ViewFetch(view
,&row
);
976 if (rc
!= ERROR_SUCCESS
)
982 /* check conditions */
983 if (!MSI_RecordIsNull(row
,2))
986 cond
= load_dynamic_stringW(row
,2);
990 /* this is a hack to skip errors in the condition code */
991 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
993 HeapFree(GetProcessHeap(),0,cond
);
994 msiobj_release(&row
->hdr
);
998 HeapFree(GetProcessHeap(),0,cond
);
1003 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1004 if (rc
!= ERROR_SUCCESS
)
1006 ERR("Error is %x\n",rc
);
1007 msiobj_release(&row
->hdr
);
1011 rc
= ACTION_PerformAction(package
,buffer
);
1012 msiobj_release(&row
->hdr
);
1014 MSI_ViewClose(view
);
1015 msiobj_release(&view
->hdr
);
1023 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
1027 static const WCHAR ExecSeqQuery
[] = {
1028 's','e','l','e','c','t',' ','*',' ',
1029 'f','r','o','m',' ',
1030 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1031 'S','e','q','u','e','n','c','e',' ',
1032 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
1033 '>',' ','%','i',' ','o','r','d','e','r',' ',
1034 'b','y',' ','S','e','q','u','e','n','c','e',0 };
1035 MSIRECORD
* row
= 0;
1036 static const WCHAR IVQuery
[] = {
1037 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
1038 'f','r','o','m',' ','I','n','s','t','a','l','l',
1039 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
1040 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
1041 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
1045 /* get the sequence number */
1048 rc
= MSI_DatabaseOpenViewW(package
->db
, IVQuery
, &view
);
1049 if (rc
!= ERROR_SUCCESS
)
1051 rc
= MSI_ViewExecute(view
, 0);
1052 if (rc
!= ERROR_SUCCESS
)
1054 MSI_ViewClose(view
);
1055 msiobj_release(&view
->hdr
);
1058 rc
= MSI_ViewFetch(view
,&row
);
1059 if (rc
!= ERROR_SUCCESS
)
1061 MSI_ViewClose(view
);
1062 msiobj_release(&view
->hdr
);
1065 seq
= MSI_RecordGetInteger(row
,1);
1066 msiobj_release(&row
->hdr
);
1067 MSI_ViewClose(view
);
1068 msiobj_release(&view
->hdr
);
1071 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
1072 if (rc
== ERROR_SUCCESS
)
1074 rc
= MSI_ViewExecute(view
, 0);
1076 if (rc
!= ERROR_SUCCESS
)
1078 MSI_ViewClose(view
);
1079 msiobj_release(&view
->hdr
);
1083 TRACE("Running the actions\n");
1087 WCHAR buffer
[0x100];
1090 rc
= MSI_ViewFetch(view
,&row
);
1091 if (rc
!= ERROR_SUCCESS
)
1097 /* check conditions */
1098 if (!MSI_RecordIsNull(row
,2))
1101 cond
= load_dynamic_stringW(row
,2);
1105 /* this is a hack to skip errors in the condition code */
1106 if (MSI_EvaluateConditionW(package
, cond
) ==
1109 HeapFree(GetProcessHeap(),0,cond
);
1110 msiobj_release(&row
->hdr
);
1114 HeapFree(GetProcessHeap(),0,cond
);
1119 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1120 if (rc
!= ERROR_SUCCESS
)
1122 ERR("Error is %x\n",rc
);
1123 msiobj_release(&row
->hdr
);
1127 rc
= ACTION_PerformAction(package
,buffer
);
1129 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1132 if (rc
!= ERROR_SUCCESS
)
1134 ERR("Execution halted due to error (%i)\n",rc
);
1135 msiobj_release(&row
->hdr
);
1139 msiobj_release(&row
->hdr
);
1142 MSI_ViewClose(view
);
1143 msiobj_release(&view
->hdr
);
1151 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
1155 static const WCHAR ExecSeqQuery
[] = {
1156 's','e','l','e','c','t',' ','*',' ',
1157 'f','r','o','m',' ','I','n','s','t','a','l','l',
1158 'U','I','S','e','q','u','e','n','c','e',' ',
1159 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
1160 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
1162 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1164 if (rc
== ERROR_SUCCESS
)
1166 rc
= MSI_ViewExecute(view
, 0);
1168 if (rc
!= ERROR_SUCCESS
)
1170 MSI_ViewClose(view
);
1171 msiobj_release(&view
->hdr
);
1175 TRACE("Running the actions \n");
1179 WCHAR buffer
[0x100];
1181 MSIRECORD
* row
= 0;
1183 rc
= MSI_ViewFetch(view
,&row
);
1184 if (rc
!= ERROR_SUCCESS
)
1190 /* check conditions */
1191 if (!MSI_RecordIsNull(row
,2))
1194 cond
= load_dynamic_stringW(row
,2);
1198 /* this is a hack to skip errors in the condition code */
1199 if (MSI_EvaluateConditionW(package
, cond
) ==
1202 HeapFree(GetProcessHeap(),0,cond
);
1203 msiobj_release(&row
->hdr
);
1207 HeapFree(GetProcessHeap(),0,cond
);
1212 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
1213 if (rc
!= ERROR_SUCCESS
)
1215 ERR("Error is %x\n",rc
);
1216 msiobj_release(&row
->hdr
);
1220 rc
= ACTION_PerformUIAction(package
,buffer
);
1222 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1225 if (rc
!= ERROR_SUCCESS
)
1227 ERR("Execution halted due to error (%i)\n",rc
);
1228 msiobj_release(&row
->hdr
);
1232 msiobj_release(&row
->hdr
);
1235 MSI_ViewClose(view
);
1236 msiobj_release(&view
->hdr
);
1243 /********************************************************
1244 * ACTION helper functions and functions that perform the actions
1245 *******************************************************/
1246 BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
, UINT
* rc
)
1252 while (StandardActions
[i
].action
!= NULL
)
1254 if (strcmpW(StandardActions
[i
].action
, action
)==0)
1256 ui_actioninfo(package
, action
, TRUE
, 0);
1257 ui_actionstart(package
, action
);
1258 if (StandardActions
[i
].handler
)
1260 *rc
= StandardActions
[i
].handler(package
);
1264 FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action
));
1265 *rc
= ERROR_SUCCESS
;
1267 ui_actioninfo(package
, action
, FALSE
, *rc
);
1276 BOOL
ACTION_HandleDialogBox(MSIPACKAGE
*package
, LPCWSTR dialog
, UINT
* rc
)
1281 * for the UI when we get that working
1283 if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1285 *rc = package->CurrentInstallState;
1292 BOOL
ACTION_HandleCustomAction(MSIPACKAGE
* package
, LPCWSTR action
, UINT
* rc
)
1297 arc
= ACTION_CustomAction(package
,action
,FALSE
);
1299 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1308 * A lot of actions are really important even if they don't do anything
1309 * explicit... Lots of properties are set at the beginning of the installation
1310 * CostFinalize does a bunch of work to translate the directories and such
1312 * But until I get write access to the database that is hard, so I am going to
1313 * hack it to see if I can get something to run.
1315 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1317 UINT rc
= ERROR_SUCCESS
;
1320 TRACE("Performing action (%s)\n",debugstr_w(action
));
1322 handled
= ACTION_HandleStandardAction(package
, action
, &rc
);
1325 handled
= ACTION_HandleCustomAction(package
, action
, &rc
);
1329 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1330 rc
= ERROR_FUNCTION_NOT_CALLED
;
1333 package
->CurrentInstallState
= rc
;
1337 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1339 UINT rc
= ERROR_SUCCESS
;
1340 BOOL handled
= FALSE
;
1342 TRACE("Performing action (%s)\n",debugstr_w(action
));
1344 handled
= ACTION_HandleStandardAction(package
, action
, &rc
);
1347 handled
= ACTION_HandleCustomAction(package
, action
, &rc
);
1350 handled
= ACTION_HandleDialogBox(package
, action
, &rc
);
1352 msi_dialog_check_messages( package
->dialog
, NULL
);
1356 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1357 rc
= ERROR_FUNCTION_NOT_CALLED
;
1360 package
->CurrentInstallState
= rc
;
1364 /***********************************************************************
1367 * Recursively create all directories in the path.
1369 * shamelessly stolen from setupapi/queue.c
1371 static BOOL
create_full_pathW(const WCHAR
*path
)
1377 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
1380 strcpyW(new_path
, path
);
1382 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1383 new_path
[len
- 1] = 0;
1385 while(!CreateDirectoryW(new_path
, NULL
))
1388 DWORD last_error
= GetLastError();
1389 if(last_error
== ERROR_ALREADY_EXISTS
)
1392 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1398 if(!(slash
= strrchrW(new_path
, '\\')))
1404 len
= slash
- new_path
;
1406 if(!create_full_pathW(new_path
))
1411 new_path
[len
] = '\\';
1414 HeapFree(GetProcessHeap(), 0, new_path
);
1419 * Also we cannot enable/disable components either, so for now I am just going
1420 * to do all the directories for all the components.
1422 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1424 static const WCHAR ExecSeqQuery
[] = {
1425 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1426 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1431 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1432 if (rc
!= ERROR_SUCCESS
)
1433 return ERROR_SUCCESS
;
1435 rc
= MSI_ViewExecute(view
, 0);
1436 if (rc
!= ERROR_SUCCESS
)
1438 MSI_ViewClose(view
);
1439 msiobj_release(&view
->hdr
);
1448 MSIRECORD
*row
= NULL
, *uirow
;
1450 rc
= MSI_ViewFetch(view
,&row
);
1451 if (rc
!= ERROR_SUCCESS
)
1458 rc
= MSI_RecordGetStringW(row
,1,dir
,&sz
);
1460 if (rc
!= ERROR_SUCCESS
)
1462 ERR("Unable to get folder id \n");
1463 msiobj_release(&row
->hdr
);
1468 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1471 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1472 msiobj_release(&row
->hdr
);
1476 TRACE("Folder is %s\n",debugstr_w(full_path
));
1479 uirow
= MSI_CreateRecord(1);
1480 MSI_RecordSetStringW(uirow
,1,full_path
);
1481 ui_actiondata(package
,szCreateFolders
,uirow
);
1482 msiobj_release( &uirow
->hdr
);
1484 if (folder
->State
== 0)
1485 create_full_pathW(full_path
);
1489 msiobj_release(&row
->hdr
);
1490 HeapFree(GetProcessHeap(),0,full_path
);
1492 MSI_ViewClose(view
);
1493 msiobj_release(&view
->hdr
);
1498 static int load_component(MSIPACKAGE
* package
, MSIRECORD
* row
)
1500 int index
= package
->loaded_components
;
1503 /* fill in the data */
1505 package
->loaded_components
++;
1506 if (package
->loaded_components
== 1)
1507 package
->components
= HeapAlloc(GetProcessHeap(),0,
1508 sizeof(MSICOMPONENT
));
1510 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1511 package
->components
, package
->loaded_components
*
1512 sizeof(MSICOMPONENT
));
1514 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1517 MSI_RecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1519 TRACE("Loading Component %s\n",
1520 debugstr_w(package
->components
[index
].Component
));
1523 if (!MSI_RecordIsNull(row
,2))
1524 MSI_RecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1527 MSI_RecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1529 package
->components
[index
].Attributes
= MSI_RecordGetInteger(row
,4);
1532 MSI_RecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
1535 MSI_RecordGetStringW(row
,6,package
->components
[index
].KeyPath
,&sz
);
1537 package
->components
[index
].Installed
= INSTALLSTATE_ABSENT
;
1538 package
->components
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1539 package
->components
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1541 package
->components
[index
].Enabled
= TRUE
;
1546 static void load_feature(MSIPACKAGE
* package
, MSIRECORD
* row
)
1548 int index
= package
->loaded_features
;
1550 static const WCHAR Query1
[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1551 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1552 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1553 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1554 static const WCHAR Query2
[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1555 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1556 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1563 /* fill in the data */
1565 package
->loaded_features
++;
1566 if (package
->loaded_features
== 1)
1567 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1569 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1570 package
->loaded_features
* sizeof(MSIFEATURE
));
1572 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1575 MSI_RecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1577 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1580 if (!MSI_RecordIsNull(row
,2))
1581 MSI_RecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1584 if (!MSI_RecordIsNull(row
,3))
1585 MSI_RecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
1588 if (!MSI_RecordIsNull(row
,4))
1589 MSI_RecordGetStringW(row
,4,package
->features
[index
].Description
,&sz
);
1591 if (!MSI_RecordIsNull(row
,5))
1592 package
->features
[index
].Display
= MSI_RecordGetInteger(row
,5);
1594 package
->features
[index
].Level
= MSI_RecordGetInteger(row
,6);
1597 if (!MSI_RecordIsNull(row
,7))
1598 MSI_RecordGetStringW(row
,7,package
->features
[index
].Directory
,&sz
);
1600 package
->features
[index
].Attributes
= MSI_RecordGetInteger(row
,8);
1602 package
->features
[index
].Installed
= INSTALLSTATE_ABSENT
;
1603 package
->features
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1604 package
->features
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1606 /* load feature components */
1608 rc
= MSI_OpenQuery(package
->db
, &view
, Query1
, package
->features
[index
].Feature
);
1609 if (rc
!= ERROR_SUCCESS
)
1611 rc
= MSI_ViewExecute(view
,0);
1612 if (rc
!= ERROR_SUCCESS
)
1614 MSI_ViewClose(view
);
1615 msiobj_release(&view
->hdr
);
1621 WCHAR buffer
[0x100];
1624 INT cnt
= package
->features
[index
].ComponentCount
;
1626 rc
= MSI_ViewFetch(view
,&row2
);
1627 if (rc
!= ERROR_SUCCESS
)
1631 MSI_RecordGetStringW(row2
,1,buffer
,&sz
);
1633 /* check to see if the component is already loaded */
1634 c_indx
= get_loaded_component(package
,buffer
);
1637 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer
),
1639 package
->features
[index
].Components
[cnt
] = c_indx
;
1640 package
->features
[index
].ComponentCount
++;
1644 rc
= MSI_OpenQuery(package
->db
, &view2
, Query2
, buffer
);
1645 if (rc
!= ERROR_SUCCESS
)
1647 msiobj_release( &row2
->hdr
);
1650 rc
= MSI_ViewExecute(view2
,0);
1651 if (rc
!= ERROR_SUCCESS
)
1653 msiobj_release( &row2
->hdr
);
1654 MSI_ViewClose(view2
);
1655 msiobj_release( &view2
->hdr
);
1662 rc
= MSI_ViewFetch(view2
,&row3
);
1663 if (rc
!= ERROR_SUCCESS
)
1665 c_indx
= load_component(package
,row3
);
1666 msiobj_release( &row3
->hdr
);
1668 package
->features
[index
].Components
[cnt
] = c_indx
;
1669 package
->features
[index
].ComponentCount
++;
1670 TRACE("Loaded new component to index %i\n",c_indx
);
1672 MSI_ViewClose(view2
);
1673 msiobj_release( &view2
->hdr
);
1674 msiobj_release( &row2
->hdr
);
1676 MSI_ViewClose(view
);
1677 msiobj_release(&view
->hdr
);
1681 * I am not doing any of the costing functionality yet.
1682 * Mostly looking at doing the Component and Feature loading
1684 * The native MSI does A LOT of modification to tables here. Mostly adding
1685 * a lot of temporary columns to the Feature and Component tables.
1687 * note: Native msi also tracks the short filename. But I am only going to
1688 * track the long ones. Also looking at this directory table
1689 * it appears that the directory table does not get the parents
1690 * resolved base on property only based on their entries in the
1693 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1698 static const WCHAR Query_all
[] = {
1699 'S','E','L','E','C','T',' ','*',' ',
1700 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
1701 static const WCHAR szCosting
[] = {
1702 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1703 static const WCHAR szZero
[] = { '0', 0 };
1705 MSI_SetPropertyW(package
, szCosting
, szZero
);
1706 MSI_SetPropertyW(package
, cszRootDrive
, c_collen
);
1708 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1709 if (rc
!= ERROR_SUCCESS
)
1711 rc
= MSI_ViewExecute(view
,0);
1712 if (rc
!= ERROR_SUCCESS
)
1714 MSI_ViewClose(view
);
1715 msiobj_release(&view
->hdr
);
1722 rc
= MSI_ViewFetch(view
,&row
);
1723 if (rc
!= ERROR_SUCCESS
)
1726 load_feature(package
,row
);
1727 msiobj_release(&row
->hdr
);
1729 MSI_ViewClose(view
);
1730 msiobj_release(&view
->hdr
);
1732 return ERROR_SUCCESS
;
1735 static UINT
load_file(MSIPACKAGE
* package
, MSIRECORD
* row
)
1737 DWORD index
= package
->loaded_files
;
1741 /* fill in the data */
1743 package
->loaded_files
++;
1744 if (package
->loaded_files
== 1)
1745 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
1747 package
->files
= HeapReAlloc(GetProcessHeap(),0,
1748 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
1750 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
1752 package
->files
[index
].File
= load_dynamic_stringW(row
, 1);
1753 buffer
= load_dynamic_stringW(row
, 2);
1755 package
->files
[index
].ComponentIndex
= -1;
1756 for (i
= 0; i
< package
->loaded_components
; i
++)
1757 if (strcmpW(package
->components
[i
].Component
,buffer
)==0)
1759 package
->files
[index
].ComponentIndex
= i
;
1762 if (package
->files
[index
].ComponentIndex
== -1)
1763 ERR("Unfound Component %s\n",debugstr_w(buffer
));
1764 HeapFree(GetProcessHeap(), 0, buffer
);
1766 package
->files
[index
].FileName
= load_dynamic_stringW(row
,3);
1768 reduce_to_longfilename(package
->files
[index
].FileName
);
1770 package
->files
[index
].FileSize
= MSI_RecordGetInteger(row
,4);
1771 package
->files
[index
].Version
= load_dynamic_stringW(row
, 5);
1772 package
->files
[index
].Language
= load_dynamic_stringW(row
, 6);
1773 package
->files
[index
].Attributes
= MSI_RecordGetInteger(row
,7);
1774 package
->files
[index
].Sequence
= MSI_RecordGetInteger(row
,8);
1776 package
->files
[index
].Temporary
= FALSE
;
1777 package
->files
[index
].State
= 0;
1779 TRACE("File Loaded (%s)\n",debugstr_w(package
->files
[index
].File
));
1781 return ERROR_SUCCESS
;
1784 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1789 static const WCHAR Query
[] = {
1790 'S','E','L','E','C','T',' ','*',' ',
1791 'F','R','O','M',' ','F','i','l','e',' ',
1792 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
1795 return ERROR_INVALID_HANDLE
;
1797 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1798 if (rc
!= ERROR_SUCCESS
)
1799 return ERROR_SUCCESS
;
1801 rc
= MSI_ViewExecute(view
, 0);
1802 if (rc
!= ERROR_SUCCESS
)
1804 MSI_ViewClose(view
);
1805 msiobj_release(&view
->hdr
);
1806 return ERROR_SUCCESS
;
1811 rc
= MSI_ViewFetch(view
,&row
);
1812 if (rc
!= ERROR_SUCCESS
)
1817 load_file(package
,row
);
1818 msiobj_release(&row
->hdr
);
1820 MSI_ViewClose(view
);
1821 msiobj_release(&view
->hdr
);
1823 return ERROR_SUCCESS
;
1826 static INT
load_folder(MSIPACKAGE
*package
, const WCHAR
* dir
)
1829 static const WCHAR Query
[] =
1830 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1831 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1832 'o','r','y','`',' ','=',' ','`','%','s','`',0};
1835 LPWSTR targetdir
, parent
, srcdir
;
1836 MSIRECORD
* row
= 0;
1840 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1842 for (i
= 0; i
< package
->loaded_folders
; i
++)
1844 if (strcmpW(package
->folders
[i
].Directory
,dir
)==0)
1846 TRACE(" %s retuning on index %lu\n",debugstr_w(dir
),i
);
1851 TRACE("Working to load %s\n",debugstr_w(dir
));
1853 index
= package
->loaded_folders
++;
1854 if (package
->loaded_folders
==1)
1855 package
->folders
= HeapAlloc(GetProcessHeap(),0,
1858 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
1859 package
->folders
, package
->loaded_folders
*
1862 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
1864 package
->folders
[index
].Directory
= dupstrW(dir
);
1866 rc
= MSI_OpenQuery(package
->db
, &view
, Query
, dir
);
1867 if (rc
!= ERROR_SUCCESS
)
1870 rc
= MSI_ViewExecute(view
, 0);
1871 if (rc
!= ERROR_SUCCESS
)
1873 MSI_ViewClose(view
);
1874 msiobj_release(&view
->hdr
);
1878 rc
= MSI_ViewFetch(view
,&row
);
1879 if (rc
!= ERROR_SUCCESS
)
1881 MSI_ViewClose(view
);
1882 msiobj_release(&view
->hdr
);
1886 targetdir
= load_dynamic_stringW(row
,3);
1888 /* split src and target dir */
1889 if (strchrW(targetdir
,':'))
1891 srcdir
=strchrW(targetdir
,':');
1898 /* for now only pick long filename versions */
1899 if (strchrW(targetdir
,'|'))
1901 targetdir
= strchrW(targetdir
,'|');
1905 if (srcdir
&& strchrW(srcdir
,'|'))
1907 srcdir
= strchrW(srcdir
,'|');
1912 /* now check for root dirs */
1913 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1916 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
1921 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1922 HeapFree(GetProcessHeap(),0, package
->folders
[index
].TargetDefault
);
1923 package
->folders
[index
].TargetDefault
= dupstrW(targetdir
);
1927 package
->folders
[index
].SourceDefault
= dupstrW(srcdir
);
1929 package
->folders
[index
].SourceDefault
= dupstrW(targetdir
);
1930 HeapFree(GetProcessHeap(), 0, targetdir
);
1932 parent
= load_dynamic_stringW(row
,2);
1935 i
= load_folder(package
,parent
);
1936 package
->folders
[index
].ParentIndex
= i
;
1937 TRACE("Parent is index %i... %s %s\n",
1938 package
->folders
[index
].ParentIndex
,
1939 debugstr_w(package
->folders
[package
->folders
[index
].ParentIndex
].Directory
),
1940 debugstr_w(parent
));
1943 package
->folders
[index
].ParentIndex
= -2;
1944 HeapFree(GetProcessHeap(), 0, parent
);
1946 package
->folders
[index
].Property
= load_dynamic_property(package
, dir
,NULL
);
1948 msiobj_release(&row
->hdr
);
1949 MSI_ViewClose(view
);
1950 msiobj_release(&view
->hdr
);
1951 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),index
);
1956 LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
, BOOL source
,
1957 BOOL set_prop
, MSIFOLDER
**folder
)
1960 LPWSTR p
, path
= NULL
;
1962 TRACE("Working to resolve %s\n",debugstr_w(name
));
1964 /* special resolving for Target and Source root dir */
1965 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
1969 path
= load_dynamic_property(package
,cszTargetDir
,NULL
);
1972 path
= load_dynamic_property(package
,cszRootDrive
,NULL
);
1974 MSI_SetPropertyW(package
,cszTargetDir
,path
);
1978 for (i
= 0; i
< package
->loaded_folders
; i
++)
1980 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1983 *folder
= &(package
->folders
[i
]);
1989 path
= load_dynamic_property(package
,cszSourceDir
,NULL
);
1992 path
= load_dynamic_property(package
,cszDatabase
,NULL
);
1995 p
= strrchrW(path
,'\\');
2002 for (i
= 0; i
< package
->loaded_folders
; i
++)
2004 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2007 *folder
= &(package
->folders
[i
]);
2013 for (i
= 0; i
< package
->loaded_folders
; i
++)
2015 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2019 if (i
>= package
->loaded_folders
)
2023 *folder
= &(package
->folders
[i
]);
2025 if (!source
&& package
->folders
[i
].ResolvedTarget
)
2027 path
= dupstrW(package
->folders
[i
].ResolvedTarget
);
2028 TRACE(" already resolved to %s\n",debugstr_w(path
));
2031 else if (source
&& package
->folders
[i
].ResolvedSource
)
2033 path
= dupstrW(package
->folders
[i
].ResolvedSource
);
2036 else if (!source
&& package
->folders
[i
].Property
)
2038 path
= build_directory_name(2, package
->folders
[i
].Property
, NULL
);
2040 TRACE(" internally set to %s\n",debugstr_w(path
));
2042 MSI_SetPropertyW(package
,name
,path
);
2046 if (package
->folders
[i
].ParentIndex
>= 0)
2048 LPWSTR parent
= package
->folders
[package
->folders
[i
].ParentIndex
].Directory
;
2050 TRACE(" ! Parent is %s\n", debugstr_w(parent
));
2052 p
= resolve_folder(package
, parent
, source
, set_prop
, NULL
);
2055 TRACE(" TargetDefault = %s\n",debugstr_w(package
->folders
[i
].TargetDefault
));
2056 path
= build_directory_name(3, p
, package
->folders
[i
].TargetDefault
, NULL
);
2057 package
->folders
[i
].ResolvedTarget
= dupstrW(path
);
2058 TRACE(" resolved into %s\n",debugstr_w(path
));
2060 MSI_SetPropertyW(package
,name
,path
);
2064 path
= build_directory_name(3, p
, package
->folders
[i
].SourceDefault
, NULL
);
2065 package
->folders
[i
].ResolvedSource
= dupstrW(path
);
2067 HeapFree(GetProcessHeap(),0,p
);
2072 /* update compoennt state based on a feature change */
2073 void ACTION_UpdateComponentStates(MSIPACKAGE
*package
, LPCWSTR szFeature
)
2076 INSTALLSTATE newstate
;
2077 MSIFEATURE
*feature
;
2079 i
= get_loaded_feature(package
,szFeature
);
2083 feature
= &package
->features
[i
];
2084 newstate
= feature
->ActionRequest
;
2086 for( i
= 0; i
< feature
->ComponentCount
; i
++)
2088 MSICOMPONENT
* component
= &package
->components
[feature
->Components
[i
]];
2090 if (!component
->Enabled
)
2094 if (newstate
== INSTALLSTATE_LOCAL
)
2095 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2100 component
->ActionRequest
= newstate
;
2102 /*if any other feature wants is local we need to set it local*/
2104 j
< package
->loaded_features
&&
2105 component
->ActionRequest
!= INSTALLSTATE_LOCAL
;
2108 for (k
= 0; k
< package
->features
[j
].ComponentCount
; k
++)
2109 if ( package
->features
[j
].Components
[k
] ==
2110 feature
->Components
[i
] )
2112 if (package
->features
[j
].ActionRequest
==
2114 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2123 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
2129 LPWSTR override
= NULL
;
2130 static const WCHAR all
[]={'A','L','L',0};
2131 static const WCHAR szlevel
[] = {
2132 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2133 static const WCHAR szAddLocal
[] = {
2134 'A','D','D','L','O','C','A','L',0};
2136 /* I do not know if this is where it should happen.. but */
2138 TRACE("Checking Install Level\n");
2140 level
= load_dynamic_property(package
,szlevel
,NULL
);
2143 install_level
= atoiW(level
);
2144 HeapFree(GetProcessHeap(), 0, level
);
2149 /* ok hereis the rub
2150 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
2151 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
2152 * itnored for all the features. seems strange, epsecially since it is not
2153 * documented anywhere, but it is how it works.
2156 override
= load_dynamic_property(package
,szAddLocal
,NULL
);
2160 for(i
= 0; i
< package
->loaded_features
; i
++)
2162 if (strcmpiW(override
,all
)==0)
2164 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2165 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2169 LPWSTR ptr
= override
;
2170 LPWSTR ptr2
= strchrW(override
,',');
2175 strncmpW(ptr
,package
->features
[i
].Feature
, ptr2
-ptr
)==0)
2177 strcmpW(ptr
,package
->features
[i
].Feature
)==0))
2179 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2180 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2186 ptr2
= strchrW(ptr
,',');
2193 HeapFree(GetProcessHeap(),0,override
);
2197 for(i
= 0; i
< package
->loaded_features
; i
++)
2199 BOOL feature_state
= ((package
->features
[i
].Level
> 0) &&
2200 (package
->features
[i
].Level
<= install_level
));
2204 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2205 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2211 * now we want to enable or disable components base on feature
2214 for(i
= 0; i
< package
->loaded_features
; i
++)
2216 MSIFEATURE
* feature
= &package
->features
[i
];
2217 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2218 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2219 feature
->ActionRequest
);
2221 for( j
= 0; j
< feature
->ComponentCount
; j
++)
2223 MSICOMPONENT
* component
= &package
->components
[
2224 feature
->Components
[j
]];
2226 if (!component
->Enabled
)
2228 component
->Action
= INSTALLSTATE_ABSENT
;
2229 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
2233 if (feature
->Action
== INSTALLSTATE_LOCAL
)
2234 component
->Action
= INSTALLSTATE_LOCAL
;
2235 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
2236 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2241 for(i
= 0; i
< package
->loaded_components
; i
++)
2243 MSICOMPONENT
* component
= &package
->components
[i
];
2245 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2246 debugstr_w(component
->Component
), component
->Installed
,
2247 component
->Action
, component
->ActionRequest
);
2251 return ERROR_SUCCESS
;
2255 * A lot is done in this function aside from just the costing.
2256 * The costing needs to be implemented at some point but for now I am going
2257 * to focus on the directory building
2260 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2262 static const WCHAR ExecSeqQuery
[] = {
2263 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2264 'D','i','r','e','c','t','o','r','y',0};
2265 static const WCHAR ConditionQuery
[] = {
2266 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2267 'C','o','n','d','i','t','i','o','n',0};
2268 static const WCHAR szCosting
[] = {
2269 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2270 static const WCHAR szlevel
[] = {
2271 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2272 static const WCHAR szOne
[] = { '1', 0 };
2278 TRACE("Building Directory properties\n");
2280 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2281 if (rc
== ERROR_SUCCESS
)
2283 rc
= MSI_ViewExecute(view
, 0);
2284 if (rc
!= ERROR_SUCCESS
)
2286 MSI_ViewClose(view
);
2287 msiobj_release(&view
->hdr
);
2295 MSIRECORD
* row
= 0;
2298 rc
= MSI_ViewFetch(view
,&row
);
2299 if (rc
!= ERROR_SUCCESS
)
2306 MSI_RecordGetStringW(row
,1,name
,&sz
);
2308 /* This helper function now does ALL the work */
2309 TRACE("Dir %s ...\n",debugstr_w(name
));
2310 load_folder(package
,name
);
2311 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
2312 TRACE("resolves to %s\n",debugstr_w(path
));
2313 HeapFree( GetProcessHeap(), 0, path
);
2315 msiobj_release(&row
->hdr
);
2317 MSI_ViewClose(view
);
2318 msiobj_release(&view
->hdr
);
2321 TRACE("File calculations %i files\n",package
->loaded_files
);
2323 for (i
= 0; i
< package
->loaded_files
; i
++)
2325 MSICOMPONENT
* comp
= NULL
;
2326 MSIFILE
* file
= NULL
;
2328 file
= &package
->files
[i
];
2329 if (file
->ComponentIndex
>= 0)
2330 comp
= &package
->components
[file
->ComponentIndex
];
2332 if (file
->Temporary
== TRUE
)
2339 /* calculate target */
2340 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2342 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2344 TRACE("file %s is named %s\n",
2345 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
2347 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2349 HeapFree(GetProcessHeap(),0,p
);
2351 TRACE("file %s resolves to %s\n",
2352 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
2354 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2357 comp
->Cost
+= file
->FileSize
;
2367 static const WCHAR name
[] =
2369 static const WCHAR name_fmt
[] =
2370 {'%','u','.','%','u','.','%','u','.','%','u',0};
2371 WCHAR filever
[0x100];
2372 VS_FIXEDFILEINFO
*lpVer
;
2374 TRACE("Version comparison.. \n");
2375 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
2376 version
= HeapAlloc(GetProcessHeap(),0,versize
);
2377 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
2379 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
2381 sprintfW(filever
,name_fmt
,
2382 HIWORD(lpVer
->dwFileVersionMS
),
2383 LOWORD(lpVer
->dwFileVersionMS
),
2384 HIWORD(lpVer
->dwFileVersionLS
),
2385 LOWORD(lpVer
->dwFileVersionLS
));
2387 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2388 debugstr_w(filever
));
2389 if (strcmpiW(filever
,file
->Version
)<0)
2392 FIXME("cost should be diff in size\n");
2393 comp
->Cost
+= file
->FileSize
;
2397 HeapFree(GetProcessHeap(),0,version
);
2405 TRACE("Evaluating Condition Table\n");
2407 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2408 if (rc
== ERROR_SUCCESS
)
2410 rc
= MSI_ViewExecute(view
, 0);
2411 if (rc
!= ERROR_SUCCESS
)
2413 MSI_ViewClose(view
);
2414 msiobj_release(&view
->hdr
);
2420 WCHAR Feature
[0x100];
2421 MSIRECORD
* row
= 0;
2425 rc
= MSI_ViewFetch(view
,&row
);
2427 if (rc
!= ERROR_SUCCESS
)
2434 MSI_RecordGetStringW(row
,1,Feature
,&sz
);
2436 feature_index
= get_loaded_feature(package
,Feature
);
2437 if (feature_index
< 0)
2438 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature
));
2442 Condition
= load_dynamic_stringW(row
,3);
2444 if (MSI_EvaluateConditionW(package
,Condition
) ==
2447 int level
= MSI_RecordGetInteger(row
,2);
2448 TRACE("Reseting feature %s to level %i\n",
2449 debugstr_w(Feature
), level
);
2450 package
->features
[feature_index
].Level
= level
;
2452 HeapFree(GetProcessHeap(),0,Condition
);
2455 msiobj_release(&row
->hdr
);
2457 MSI_ViewClose(view
);
2458 msiobj_release(&view
->hdr
);
2461 TRACE("Enabling or Disabling Components\n");
2462 for (i
= 0; i
< package
->loaded_components
; i
++)
2464 if (package
->components
[i
].Condition
[0])
2466 if (MSI_EvaluateConditionW(package
,
2467 package
->components
[i
].Condition
) == MSICONDITION_FALSE
)
2469 TRACE("Disabling component %s\n",
2470 debugstr_w(package
->components
[i
].Component
));
2471 package
->components
[i
].Enabled
= FALSE
;
2476 MSI_SetPropertyW(package
,szCosting
,szOne
);
2477 /* set default run level if not set */
2478 level
= load_dynamic_property(package
,szlevel
,NULL
);
2480 MSI_SetPropertyW(package
,szlevel
, szOne
);
2482 HeapFree(GetProcessHeap(),0,level
);
2484 return SetFeatureStates(package
);
2489 * This is a helper function for handling embedded cabinet media
2491 static UINT
writeout_cabinet_stream(MSIPACKAGE
*package
, WCHAR
* stream_name
,
2499 WCHAR tmp
[MAX_PATH
];
2501 rc
= read_raw_stream_data(package
->db
,stream_name
,&data
,&size
);
2502 if (rc
!= ERROR_SUCCESS
)
2506 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp
, &write
))
2507 GetTempPathW(MAX_PATH
,tmp
);
2509 GetTempFileNameW(tmp
,stream_name
,0,source
);
2511 track_tempfile(package
,strrchrW(source
,'\\'), source
);
2512 the_file
= CreateFileW(source
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2513 FILE_ATTRIBUTE_NORMAL
, NULL
);
2515 if (the_file
== INVALID_HANDLE_VALUE
)
2517 rc
= ERROR_FUNCTION_FAILED
;
2521 WriteFile(the_file
,data
,size
,&write
,NULL
);
2522 CloseHandle(the_file
);
2523 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2525 HeapFree(GetProcessHeap(),0,data
);
2530 /* Support functions for FDI functions */
2533 MSIPACKAGE
* package
;
2538 static void * cabinet_alloc(ULONG cb
)
2540 return HeapAlloc(GetProcessHeap(), 0, cb
);
2543 static void cabinet_free(void *pv
)
2545 HeapFree(GetProcessHeap(), 0, pv
);
2548 static INT_PTR
cabinet_open(char *pszFile
, int oflag
, int pmode
)
2551 DWORD dwShareMode
= 0;
2552 DWORD dwCreateDisposition
= OPEN_EXISTING
;
2553 switch (oflag
& _O_ACCMODE
)
2556 dwAccess
= GENERIC_READ
;
2557 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_DELETE
;
2560 dwAccess
= GENERIC_WRITE
;
2561 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2564 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
2565 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2568 if ((oflag
& (_O_CREAT
| _O_EXCL
)) == (_O_CREAT
| _O_EXCL
))
2569 dwCreateDisposition
= CREATE_NEW
;
2570 else if (oflag
& _O_CREAT
)
2571 dwCreateDisposition
= CREATE_ALWAYS
;
2572 return (INT_PTR
)CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
, dwCreateDisposition
, 0, NULL
);
2575 static UINT
cabinet_read(INT_PTR hf
, void *pv
, UINT cb
)
2578 if (ReadFile((HANDLE
)hf
, pv
, cb
, &dwRead
, NULL
))
2583 static UINT
cabinet_write(INT_PTR hf
, void *pv
, UINT cb
)
2586 if (WriteFile((HANDLE
)hf
, pv
, cb
, &dwWritten
, NULL
))
2591 static int cabinet_close(INT_PTR hf
)
2593 return CloseHandle((HANDLE
)hf
) ? 0 : -1;
2596 static long cabinet_seek(INT_PTR hf
, long dist
, int seektype
)
2598 /* flags are compatible and so are passed straight through */
2599 return SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
);
2602 static INT_PTR
cabinet_notify(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
2604 /* FIXME: try to do more processing in this function */
2607 case fdintCOPY_FILE
:
2609 CabData
*data
= (CabData
*) pfdin
->pv
;
2610 ULONG len
= strlen(data
->cab_path
) + strlen(pfdin
->psz1
);
2615 LPWSTR tracknametmp
;
2616 static const WCHAR tmpprefix
[] = {'C','A','B','T','M','P','_',0};
2618 if (data
->file_name
&& strcmp(data
->file_name
,pfdin
->psz1
))
2621 file
= cabinet_alloc((len
+1)*sizeof(char));
2622 strcpy(file
, data
->cab_path
);
2623 strcat(file
, pfdin
->psz1
);
2625 TRACE("file: %s\n", debugstr_a(file
));
2627 /* track this file so it can be deleted if not installed */
2628 trackpath
=strdupAtoW(file
);
2629 tracknametmp
=strdupAtoW(strrchr(file
,'\\')+1);
2630 trackname
= HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp
) +
2631 strlenW(tmpprefix
)+1) * sizeof(WCHAR
));
2633 strcpyW(trackname
,tmpprefix
);
2634 strcatW(trackname
,tracknametmp
);
2636 track_tempfile(data
->package
, trackname
, trackpath
);
2638 HeapFree(GetProcessHeap(),0,trackpath
);
2639 HeapFree(GetProcessHeap(),0,trackname
);
2640 HeapFree(GetProcessHeap(),0,tracknametmp
);
2642 return cabinet_open(file
, _O_WRONLY
| _O_CREAT
, 0);
2644 case fdintCLOSE_FILE_INFO
:
2648 if (!DosDateTimeToFileTime(pfdin
->date
, pfdin
->time
, &ft
))
2650 if (!LocalFileTimeToFileTime(&ft
, &ftLocal
))
2652 if (!SetFileTime((HANDLE
)pfdin
->hf
, &ftLocal
, 0, &ftLocal
))
2655 cabinet_close(pfdin
->hf
);
2663 /***********************************************************************
2664 * extract_cabinet_file
2666 * Extract files from a cab file.
2668 static BOOL
extract_a_cabinet_file(MSIPACKAGE
* package
, const WCHAR
* source
,
2669 const WCHAR
* path
, const WCHAR
* file
)
2679 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source
),
2680 debugstr_w(file
), debugstr_w(path
));
2682 hfdi
= FDICreate(cabinet_alloc
,
2693 ERR("FDICreate failed\n");
2697 if (!(cabinet
= strdupWtoA( source
)))
2702 if (!(cab_path
= strdupWtoA( path
)))
2705 HeapFree(GetProcessHeap(), 0, cabinet
);
2709 data
.package
= package
;
2710 data
.cab_path
= cab_path
;
2712 file_name
= strdupWtoA(file
);
2715 data
.file_name
= file_name
;
2717 ret
= FDICopy(hfdi
, cabinet
, "", 0, cabinet_notify
, NULL
, &data
);
2720 ERR("FDICopy failed\n");
2724 HeapFree(GetProcessHeap(), 0, cabinet
);
2725 HeapFree(GetProcessHeap(), 0, cab_path
);
2726 HeapFree(GetProcessHeap(), 0, file_name
);
2731 static UINT
ready_media_for_file(MSIPACKAGE
*package
, UINT sequence
,
2732 WCHAR
* path
, WCHAR
* file
)
2736 MSIRECORD
* row
= 0;
2737 static WCHAR source
[MAX_PATH
];
2738 static const WCHAR ExecSeqQuery
[] = {
2739 's','e','l','e','c','t',' ','*',' ',
2740 'f','r','o','m',' ','M','e','d','i','a',' ',
2741 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2742 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2747 static UINT last_sequence
= 0;
2749 if (sequence
<= last_sequence
)
2751 TRACE("Media already ready (%u, %u)\n",sequence
,last_sequence
);
2752 /*extract_a_cabinet_file(package, source,path,file); */
2753 return ERROR_SUCCESS
;
2756 sprintfW(Query
,ExecSeqQuery
,sequence
);
2758 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2759 if (rc
!= ERROR_SUCCESS
)
2762 rc
= MSI_ViewExecute(view
, 0);
2763 if (rc
!= ERROR_SUCCESS
)
2765 MSI_ViewClose(view
);
2766 msiobj_release(&view
->hdr
);
2770 rc
= MSI_ViewFetch(view
,&row
);
2771 if (rc
!= ERROR_SUCCESS
)
2773 MSI_ViewClose(view
);
2774 msiobj_release(&view
->hdr
);
2777 seq
= MSI_RecordGetInteger(row
,2);
2778 last_sequence
= seq
;
2780 if (!MSI_RecordIsNull(row
,4))
2783 MSI_RecordGetStringW(row
,4,cab
,&sz
);
2784 TRACE("Source is CAB %s\n",debugstr_w(cab
));
2785 /* the stream does not contain the # character */
2788 writeout_cabinet_stream(package
,&cab
[1],source
);
2789 strcpyW(path
,source
);
2790 *(strrchrW(path
,'\\')+1)=0;
2795 if (MSI_GetPropertyW(package
, cszSourceDir
, source
, &sz
))
2797 ERR("No Source dir defined \n");
2798 rc
= ERROR_FUNCTION_FAILED
;
2802 strcpyW(path
,source
);
2803 strcatW(source
,cab
);
2804 /* extract the cab file into a folder in the temp folder */
2806 if (MSI_GetPropertyW(package
, cszTempFolder
,path
, &sz
)
2808 GetTempPathW(MAX_PATH
,path
);
2811 rc
= !extract_a_cabinet_file(package
, source
,path
,NULL
);
2816 MSI_GetPropertyW(package
,cszSourceDir
,source
,&sz
);
2817 strcpyW(path
,source
);
2819 msiobj_release(&row
->hdr
);
2820 MSI_ViewClose(view
);
2821 msiobj_release(&view
->hdr
);
2825 inline static UINT
create_component_directory ( MSIPACKAGE
* package
, INT component
)
2827 UINT rc
= ERROR_SUCCESS
;
2829 LPWSTR install_path
;
2831 install_path
= resolve_folder(package
, package
->components
[component
].Directory
,
2832 FALSE
, FALSE
, &folder
);
2834 return ERROR_FUNCTION_FAILED
;
2836 /* create the path */
2837 if (folder
->State
== 0)
2839 create_full_pathW(install_path
);
2842 HeapFree(GetProcessHeap(), 0, install_path
);
2847 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
)
2849 UINT rc
= ERROR_SUCCESS
;
2852 WCHAR uipath
[MAX_PATH
];
2855 return ERROR_INVALID_HANDLE
;
2857 /* increment progress bar each time action data is sent */
2858 ui_progress(package
,1,1,0,0);
2860 for (index
= 0; index
< package
->loaded_files
; index
++)
2862 WCHAR path_to_source
[MAX_PATH
];
2865 file
= &package
->files
[index
];
2867 if (file
->Temporary
)
2870 if (package
->components
[file
->ComponentIndex
].ActionRequest
!=
2873 ui_progress(package
,2,file
->FileSize
,0,0);
2874 TRACE("File %s is not scheduled for install\n",
2875 debugstr_w(file
->File
));
2880 if ((file
->State
== 1) || (file
->State
== 2))
2884 MSICOMPONENT
* comp
= NULL
;
2886 TRACE("Installing %s\n",debugstr_w(file
->File
));
2887 rc
= ready_media_for_file(package
,file
->Sequence
,path_to_source
,
2891 * our file table could change here because a new temp file
2892 * may have been created
2894 file
= &package
->files
[index
];
2895 if (rc
!= ERROR_SUCCESS
)
2897 ERR("Unable to ready media\n");
2898 rc
= ERROR_FUNCTION_FAILED
;
2902 create_component_directory( package
, file
->ComponentIndex
);
2904 /* recalculate file paths because things may have changed */
2906 if (file
->ComponentIndex
>= 0)
2907 comp
= &package
->components
[file
->ComponentIndex
];
2909 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2910 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2912 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2914 len
= strlenW(path_to_source
) + strlenW(file
->File
) + 2;
2915 file
->SourcePath
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
2916 strcpyW(file
->SourcePath
, path_to_source
);
2917 strcatW(file
->SourcePath
, file
->File
);
2919 TRACE("file paths %s to %s\n",debugstr_w(file
->SourcePath
),
2920 debugstr_w(file
->TargetPath
));
2923 uirow
=MSI_CreateRecord(9);
2924 MSI_RecordSetStringW(uirow
,1,file
->File
);
2925 strcpyW(uipath
,file
->TargetPath
);
2926 *(strrchrW(uipath
,'\\')+1)=0;
2927 MSI_RecordSetStringW(uirow
,9,uipath
);
2928 MSI_RecordSetInteger(uirow
,6,file
->FileSize
);
2929 ui_actiondata(package
,szInstallFiles
,uirow
);
2930 msiobj_release( &uirow
->hdr
);
2931 ui_progress(package
,2,file
->FileSize
,0,0);
2933 if (!MoveFileW(file
->SourcePath
,file
->TargetPath
))
2935 rc
= GetLastError();
2936 ERR("Unable to move file (%s -> %s) (error %d)\n",
2937 debugstr_w(file
->SourcePath
), debugstr_w(file
->TargetPath
),
2939 if (rc
== ERROR_ALREADY_EXISTS
&& file
->State
== 2)
2941 CopyFileW(file
->SourcePath
,file
->TargetPath
,FALSE
);
2942 DeleteFileW(file
->SourcePath
);
2945 else if (rc
== ERROR_FILE_NOT_FOUND
)
2947 ERR("Source File Not Found! Continueing\n");
2952 ERR("Ignoring Error and continuing...\n");
2964 inline static UINT
get_file_target(MSIPACKAGE
*package
, LPCWSTR file_key
,
2965 LPWSTR
* file_source
)
2970 return ERROR_INVALID_HANDLE
;
2972 for (index
= 0; index
< package
->loaded_files
; index
++)
2974 if (strcmpW(file_key
,package
->files
[index
].File
)==0)
2976 if (package
->files
[index
].State
>= 2)
2978 *file_source
= dupstrW(package
->files
[index
].TargetPath
);
2979 return ERROR_SUCCESS
;
2982 return ERROR_FILE_NOT_FOUND
;
2986 return ERROR_FUNCTION_FAILED
;
2989 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
)
2993 MSIRECORD
* row
= 0;
2994 static const WCHAR ExecSeqQuery
[] = {
2995 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2996 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2999 return ERROR_INVALID_HANDLE
;
3001 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3002 if (rc
!= ERROR_SUCCESS
)
3003 return ERROR_SUCCESS
;
3005 rc
= MSI_ViewExecute(view
, 0);
3006 if (rc
!= ERROR_SUCCESS
)
3008 MSI_ViewClose(view
);
3009 msiobj_release(&view
->hdr
);
3015 WCHAR file_key
[0x100];
3016 WCHAR
*file_source
= NULL
;
3017 WCHAR dest_name
[0x100];
3018 LPWSTR dest_path
, dest
;
3019 WCHAR component
[0x100];
3020 INT component_index
;
3024 rc
= MSI_ViewFetch(view
,&row
);
3025 if (rc
!= ERROR_SUCCESS
)
3032 rc
= MSI_RecordGetStringW(row
,2,component
,&sz
);
3033 if (rc
!= ERROR_SUCCESS
)
3035 ERR("Unable to get component\n");
3036 msiobj_release(&row
->hdr
);
3040 component_index
= get_loaded_component(package
,component
);
3041 if (package
->components
[component_index
].ActionRequest
!=
3044 TRACE("Skipping copy due to disabled component\n");
3046 /* the action taken was the same as the current install state */
3047 package
->components
[component_index
].Action
=
3048 package
->components
[component_index
].Installed
;
3050 msiobj_release(&row
->hdr
);
3054 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
3055 package
->components
[component_index
].Installed
= INSTALLSTATE_LOCAL
;
3058 rc
= MSI_RecordGetStringW(row
,3,file_key
,&sz
);
3059 if (rc
!= ERROR_SUCCESS
)
3061 ERR("Unable to get file key\n");
3062 msiobj_release(&row
->hdr
);
3066 rc
= get_file_target(package
,file_key
,&file_source
);
3068 if (rc
!= ERROR_SUCCESS
)
3070 ERR("Original file unknown %s\n",debugstr_w(file_key
));
3071 msiobj_release(&row
->hdr
);
3072 HeapFree(GetProcessHeap(),0,file_source
);
3076 if (MSI_RecordIsNull(row
,4))
3078 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
3083 MSI_RecordGetStringW(row
,4,dest_name
,&sz
);
3084 reduce_to_longfilename(dest_name
);
3087 if (MSI_RecordIsNull(row
,5))
3090 dest_path
= dupstrW(file_source
);
3091 p
= strrchrW(dest_path
,'\\');
3097 WCHAR destkey
[0x100];
3099 MSI_RecordGetStringW(row
,5,destkey
,&sz
);
3101 dest_path
= resolve_folder(package
, destkey
, FALSE
,FALSE
,NULL
);
3104 ERR("Unable to get destination folder\n");
3105 msiobj_release(&row
->hdr
);
3106 HeapFree(GetProcessHeap(),0,file_source
);
3111 dest
= build_directory_name(2, dest_path
, dest_name
);
3112 HeapFree(GetProcessHeap(), 0, dest_path
);
3114 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source
),
3117 if (strcmpW(file_source
,dest
))
3118 rc
= !CopyFileW(file_source
,dest
,TRUE
);
3122 if (rc
!= ERROR_SUCCESS
)
3123 ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source
), debugstr_w(dest_path
), GetLastError());
3125 FIXME("We should track these duplicate files as well\n");
3127 msiobj_release(&row
->hdr
);
3128 HeapFree(GetProcessHeap(),0,dest
);
3129 HeapFree(GetProcessHeap(),0,file_source
);
3131 MSI_ViewClose(view
);
3132 msiobj_release(&view
->hdr
);
3137 /* OK this value is "interpreted" and then formatted based on the
3138 first few characters */
3139 static LPSTR
parse_value(MSIPACKAGE
*package
, WCHAR
*value
, DWORD
*type
,
3143 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
3152 deformat_string(package
, &value
[2], &deformated
);
3154 /* binary value type */
3157 *size
= strlenW(ptr
)/2;
3158 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3170 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3173 HeapFree(GetProcessHeap(),0,deformated
);
3175 TRACE("Data %li bytes(%i)\n",*size
,count
);
3180 deformat_string(package
, &value
[1], &deformated
);
3183 *size
= sizeof(DWORD
);
3184 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3185 *(LPDWORD
)data
= atoiW(deformated
);
3186 TRACE("DWORD %i\n",*data
);
3188 HeapFree(GetProcessHeap(),0,deformated
);
3193 static const WCHAR szMulti
[] = {'[','~',']',0};
3202 *type
=REG_EXPAND_SZ
;
3210 if (strstrW(value
,szMulti
))
3211 *type
= REG_MULTI_SZ
;
3213 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
3218 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
3222 MSIRECORD
* row
= 0;
3223 static const WCHAR ExecSeqQuery
[] = {
3224 's','e','l','e','c','t',' ','*',' ',
3225 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
3228 return ERROR_INVALID_HANDLE
;
3230 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3231 if (rc
!= ERROR_SUCCESS
)
3232 return ERROR_SUCCESS
;
3234 rc
= MSI_ViewExecute(view
, 0);
3235 if (rc
!= ERROR_SUCCESS
)
3237 MSI_ViewClose(view
);
3238 msiobj_release(&view
->hdr
);
3242 /* increment progress bar each time action data is sent */
3243 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
3247 static const WCHAR szHCR
[] =
3248 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
3249 static const WCHAR szHCU
[] =
3250 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
3251 static const WCHAR szHLM
[] =
3252 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
3254 static const WCHAR szHU
[] =
3255 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3257 LPSTR value_data
= NULL
;
3258 HKEY root_key
, hkey
;
3260 LPWSTR value
, key
, name
, component
, deformated
;
3262 INT component_index
;
3267 rc
= MSI_ViewFetch(view
,&row
);
3268 if (rc
!= ERROR_SUCCESS
)
3273 ui_progress(package
,2,0,0,0);
3280 component
= load_dynamic_stringW(row
, 6);
3281 component_index
= get_loaded_component(package
,component
);
3283 if (package
->components
[component_index
].ActionRequest
!=
3286 TRACE("Skipping write due to disabled component\n");
3287 msiobj_release(&row
->hdr
);
3289 package
->components
[component_index
].Action
=
3290 package
->components
[component_index
].Installed
;
3295 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
3296 package
->components
[component_index
].Installed
= INSTALLSTATE_LOCAL
;
3298 /* null values have special meanings during uninstalls and such */
3300 if(MSI_RecordIsNull(row
,5))
3302 msiobj_release(&row
->hdr
);
3306 root
= MSI_RecordGetInteger(row
,2);
3307 key
= load_dynamic_stringW(row
, 3);
3309 name
= load_dynamic_stringW(row
, 4);
3311 /* get the root key */
3314 case 0: root_key
= HKEY_CLASSES_ROOT
;
3317 case 1: root_key
= HKEY_CURRENT_USER
;
3320 case 2: root_key
= HKEY_LOCAL_MACHINE
;
3323 case 3: root_key
= HKEY_USERS
;
3327 ERR("Unknown root %i\n",root
);
3334 msiobj_release(&row
->hdr
);
3338 deformat_string(package
, key
, &deformated
);
3339 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
3340 uikey
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
3341 strcpyW(uikey
,szRoot
);
3342 strcatW(uikey
,deformated
);
3344 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
3346 ERR("Could not create key %s\n",debugstr_w(deformated
));
3347 msiobj_release(&row
->hdr
);
3348 HeapFree(GetProcessHeap(),0,deformated
);
3351 HeapFree(GetProcessHeap(),0,deformated
);
3353 value
= load_dynamic_stringW(row
,5);
3354 value_data
= parse_value(package
, value
, &type
, &size
);
3356 deformat_string(package
, name
, &deformated
);
3360 TRACE("Setting value %s\n",debugstr_w(deformated
));
3361 RegSetValueExW(hkey
, deformated
, 0, type
, value_data
, size
);
3363 uirow
= MSI_CreateRecord(3);
3364 MSI_RecordSetStringW(uirow
,2,deformated
);
3365 MSI_RecordSetStringW(uirow
,1,uikey
);
3368 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
3370 MSI_RecordSetStringW(uirow
,3,value
);
3372 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
3373 msiobj_release( &uirow
->hdr
);
3375 HeapFree(GetProcessHeap(),0,value_data
);
3377 HeapFree(GetProcessHeap(),0,value
);
3378 HeapFree(GetProcessHeap(),0,deformated
);
3380 msiobj_release(&row
->hdr
);
3383 HeapFree(GetProcessHeap(),0,uikey
);
3384 HeapFree(GetProcessHeap(),0,key
);
3385 HeapFree(GetProcessHeap(),0,name
);
3386 HeapFree(GetProcessHeap(),0,component
);
3388 MSI_ViewClose(view
);
3389 msiobj_release(&view
->hdr
);
3393 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
3395 return ERROR_SUCCESS
;
3399 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
3403 static const WCHAR q1
[]={
3404 'S','E','L','E','C','T',' ','*',' ',
3405 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3408 MSIRECORD
* row
= 0;
3411 TRACE(" InstallValidate \n");
3413 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3414 if (rc
!= ERROR_SUCCESS
)
3415 return ERROR_SUCCESS
;
3417 rc
= MSI_ViewExecute(view
, 0);
3418 if (rc
!= ERROR_SUCCESS
)
3420 MSI_ViewClose(view
);
3421 msiobj_release(&view
->hdr
);
3426 rc
= MSI_ViewFetch(view
,&row
);
3427 if (rc
!= ERROR_SUCCESS
)
3434 msiobj_release(&row
->hdr
);
3436 MSI_ViewClose(view
);
3437 msiobj_release(&view
->hdr
);
3439 total
= total
+ progress
* REG_PROGRESS_VALUE
;
3440 total
= total
+ package
->loaded_components
* COMPONENT_PROGRESS_VALUE
;
3441 for (i
=0; i
< package
->loaded_files
; i
++)
3442 total
+= package
->files
[i
].FileSize
;
3443 ui_progress(package
,0,total
,0,0);
3445 return ERROR_SUCCESS
;
3448 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
3451 MSIQUERY
* view
= NULL
;
3452 MSIRECORD
* row
= 0;
3453 static const WCHAR ExecSeqQuery
[] = {
3454 'S','E','L','E','C','T',' ','*',' ',
3455 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3456 static const WCHAR title
[]=
3457 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3459 TRACE("Checking launch conditions\n");
3461 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3462 if (rc
!= ERROR_SUCCESS
)
3463 return ERROR_SUCCESS
;
3465 rc
= MSI_ViewExecute(view
, 0);
3466 if (rc
!= ERROR_SUCCESS
)
3468 MSI_ViewClose(view
);
3469 msiobj_release(&view
->hdr
);
3474 while (rc
== ERROR_SUCCESS
)
3477 LPWSTR message
= NULL
;
3479 rc
= MSI_ViewFetch(view
,&row
);
3480 if (rc
!= ERROR_SUCCESS
)
3486 cond
= load_dynamic_stringW(row
,1);
3488 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
3491 message
= load_dynamic_stringW(row
,2);
3492 deformat_string(package
,message
,&deformated
);
3493 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
3494 HeapFree(GetProcessHeap(),0,message
);
3495 HeapFree(GetProcessHeap(),0,deformated
);
3496 rc
= ERROR_FUNCTION_FAILED
;
3498 HeapFree(GetProcessHeap(),0,cond
);
3499 msiobj_release(&row
->hdr
);
3501 MSI_ViewClose(view
);
3502 msiobj_release(&view
->hdr
);
3506 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, INT
3509 MSICOMPONENT
* cmp
= &package
->components
[component_index
];
3511 if (cmp
->KeyPath
[0]==0)
3513 LPWSTR p
= resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
3516 if (cmp
->Attributes
& 0x4)
3519 MSIRECORD
* row
= 0;
3521 LPWSTR key
,deformated
,buffer
,name
,deformated_name
;
3522 static const WCHAR ExecSeqQuery
[] = {
3523 's','e','l','e','c','t',' ','*',' ',
3524 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',
3525 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '
3526 ,'`','%','s','`',0 };
3527 static const WCHAR fmt
[]={'%','0','2','i',':','%','s',0};
3528 static const WCHAR fmt2
[]={'%','0','2','i',':','%','s','\\','%','s',0};
3530 rc
= MSI_OpenQuery(package
->db
,&view
,ExecSeqQuery
,cmp
->KeyPath
);
3532 if (rc
!=ERROR_SUCCESS
)
3535 rc
= MSI_ViewExecute(view
, 0);
3536 if (rc
!= ERROR_SUCCESS
)
3538 MSI_ViewClose(view
);
3539 msiobj_release(&view
->hdr
);
3543 rc
= MSI_ViewFetch(view
,&row
);
3544 if (rc
!= ERROR_SUCCESS
)
3546 MSI_ViewClose(view
);
3547 msiobj_release(&view
->hdr
);
3551 root
= MSI_RecordGetInteger(row
,2);
3552 key
= load_dynamic_stringW(row
, 3);
3553 name
= load_dynamic_stringW(row
, 4);
3554 deformat_string(package
, key
, &deformated
);
3555 deformat_string(package
, name
, &deformated_name
);
3557 len
= strlenW(deformated
) + 5;
3558 if (deformated_name
)
3559 len
+=strlenW(deformated_name
);
3561 buffer
= HeapAlloc(GetProcessHeap(),0, len
*sizeof(WCHAR
));
3563 if (deformated_name
)
3564 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
3566 sprintfW(buffer
,fmt
,root
,deformated
);
3568 HeapFree(GetProcessHeap(),0,key
);
3569 HeapFree(GetProcessHeap(),0,deformated
);
3570 HeapFree(GetProcessHeap(),0,name
);
3571 HeapFree(GetProcessHeap(),0,deformated_name
);
3572 msiobj_release(&row
->hdr
);
3573 MSI_ViewClose(view
);
3574 msiobj_release(&view
->hdr
);
3578 else if (cmp
->Attributes
& 0x20)
3580 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3586 j
= get_loaded_file(package
,cmp
->KeyPath
);
3590 LPWSTR p
= dupstrW(package
->files
[j
].TargetPath
);
3598 * Ok further analysis makes me think that this work is
3599 * actually done in the PublishComponents and PublishFeatures
3600 * step, and not here. It appears like the keypath and all that is
3601 * resolved in this step, however actually written in the Publish steps.
3602 * But we will leave it here for now because it is unclear
3604 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
3607 WCHAR squished_pc
[GUID_SIZE
];
3608 WCHAR squished_cc
[GUID_SIZE
];
3611 HKEY hkey
=0,hkey2
=0;
3612 static const WCHAR szProductCode
[]=
3613 {'P','r','o','d','u','c','t','C','o','d','e',0};
3616 return ERROR_INVALID_HANDLE
;
3618 /* writes the Component and Features values to the registry */
3619 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
3623 rc
= MSIREG_OpenComponents(&hkey
);
3624 if (rc
!= ERROR_SUCCESS
)
3627 squash_guid(productcode
,squished_pc
);
3628 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
3629 for (i
= 0; i
< package
->loaded_components
; i
++)
3631 ui_progress(package
,2,0,0,0);
3632 if (package
->components
[i
].ComponentId
[0]!=0)
3634 WCHAR
*keypath
= NULL
;
3637 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
3638 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
3639 if (rc
!= ERROR_SUCCESS
)
3642 keypath
= resolve_keypath(package
,i
);
3645 RegSetValueExW(hkey2
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
3646 (strlenW(keypath
)+1)*sizeof(WCHAR
));
3650 uirow
= MSI_CreateRecord(3);
3651 MSI_RecordSetStringW(uirow
,1,productcode
);
3652 MSI_RecordSetStringW(uirow
,2,package
->components
[i
].
3654 MSI_RecordSetStringW(uirow
,3,keypath
);
3655 ui_actiondata(package
,szProcessComponents
,uirow
);
3656 msiobj_release( &uirow
->hdr
);
3657 HeapFree(GetProcessHeap(),0,keypath
);
3662 HeapFree(GetProcessHeap(), 0, productcode
);
3667 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3670 * OK this is a bit confusing.. I am given a _Component key and I believe
3671 * that the file that is being registered as a type library is the "key file
3672 * of that component" which I interpret to mean "The file in the KeyPath of
3677 MSIRECORD
* row
= 0;
3678 static const WCHAR Query
[] = {
3679 'S','E','L','E','C','T',' ','*',' ',
3680 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3685 return ERROR_INVALID_HANDLE
;
3687 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3688 if (rc
!= ERROR_SUCCESS
)
3689 return ERROR_SUCCESS
;
3691 rc
= MSI_ViewExecute(view
, 0);
3692 if (rc
!= ERROR_SUCCESS
)
3694 MSI_ViewClose(view
);
3695 msiobj_release(&view
->hdr
);
3701 WCHAR component
[0x100];
3705 rc
= MSI_ViewFetch(view
,&row
);
3706 if (rc
!= ERROR_SUCCESS
)
3713 MSI_RecordGetStringW(row
,3,component
,&sz
);
3715 index
= get_loaded_component(package
,component
);
3718 msiobj_release(&row
->hdr
);
3722 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
3724 TRACE("Skipping typelib reg due to disabled component\n");
3725 msiobj_release(&row
->hdr
);
3727 package
->components
[index
].Action
=
3728 package
->components
[index
].Installed
;
3733 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
3734 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
3736 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3740 msiobj_release(&row
->hdr
);
3744 res
= LoadTypeLib(package
->files
[index
].TargetPath
,&ptLib
);
3748 WCHAR helpid
[0x100];
3751 MSI_RecordGetStringW(row
,6,helpid
,&sz
);
3753 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
3754 res
= RegisterTypeLib(ptLib
,package
->files
[index
].TargetPath
,help
);
3755 HeapFree(GetProcessHeap(),0,help
);
3757 if (!SUCCEEDED(res
))
3758 ERR("Failed to register type library %s\n",
3759 debugstr_w(package
->files
[index
].TargetPath
));
3762 /* Yes the row has more fields than I need, but #1 is
3763 correct and the only one I need. Why make a new row? */
3765 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3767 TRACE("Registered %s\n",
3768 debugstr_w(package
->files
[index
].TargetPath
));
3772 ITypeLib_Release(ptLib
);
3775 ERR("Failed to load type library %s\n",
3776 debugstr_w(package
->files
[index
].TargetPath
));
3778 msiobj_release(&row
->hdr
);
3780 MSI_ViewClose(view
);
3781 msiobj_release(&view
->hdr
);
3786 static UINT
register_appid(MSIPACKAGE
*package
, LPCWSTR clsid
, LPCWSTR app
)
3788 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3791 MSIRECORD
* row
= 0;
3792 static const WCHAR ExecSeqQuery
[] =
3793 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3794 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3799 return ERROR_INVALID_HANDLE
;
3801 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, clsid
);
3802 if (rc
!= ERROR_SUCCESS
)
3805 rc
= MSI_ViewExecute(view
, 0);
3806 if (rc
!= ERROR_SUCCESS
)
3808 MSI_ViewClose(view
);
3809 msiobj_release(&view
->hdr
);
3813 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
3814 RegCreateKeyW(hkey2
,clsid
,&hkey3
);
3815 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)app
,
3816 (strlenW(app
)+1)*sizeof(WCHAR
));
3818 rc
= MSI_ViewFetch(view
,&row
);
3819 if (rc
!= ERROR_SUCCESS
)
3821 MSI_ViewClose(view
);
3822 msiobj_release(&view
->hdr
);
3826 if (!MSI_RecordIsNull(row
,2))
3828 LPWSTR deformated
=0;
3830 static const WCHAR szRemoteServerName
[] =
3831 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3832 buffer
= load_dynamic_stringW(row
,2);
3833 size
= deformat_string(package
,buffer
,&deformated
);
3834 RegSetValueExW(hkey3
,szRemoteServerName
,0,REG_SZ
,(LPVOID
)deformated
,
3836 HeapFree(GetProcessHeap(),0,deformated
);
3837 HeapFree(GetProcessHeap(),0,buffer
);
3840 if (!MSI_RecordIsNull(row
,3))
3842 static const WCHAR szLocalService
[] =
3843 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3845 buffer
= load_dynamic_stringW(row
,3);
3846 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3847 RegSetValueExW(hkey3
,szLocalService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3848 HeapFree(GetProcessHeap(),0,buffer
);
3851 if (!MSI_RecordIsNull(row
,4))
3853 static const WCHAR szService
[] =
3854 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3856 buffer
= load_dynamic_stringW(row
,4);
3857 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3858 RegSetValueExW(hkey3
,szService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3859 HeapFree(GetProcessHeap(),0,buffer
);
3862 if (!MSI_RecordIsNull(row
,5))
3864 static const WCHAR szDLL
[] =
3865 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3867 buffer
= load_dynamic_stringW(row
,5);
3868 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3869 RegSetValueExW(hkey3
,szDLL
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3870 HeapFree(GetProcessHeap(),0,buffer
);
3873 if (!MSI_RecordIsNull(row
,6))
3875 static const WCHAR szActivate
[] =
3876 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3877 static const WCHAR szY
[] = {'Y',0};
3879 if (MSI_RecordGetInteger(row
,6))
3880 RegSetValueExW(hkey3
,szActivate
,0,REG_SZ
,(LPVOID
)szY
,4);
3883 if (!MSI_RecordIsNull(row
,7))
3885 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
3886 static const WCHAR szUser
[] =
3887 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3889 if (MSI_RecordGetInteger(row
,7))
3890 RegSetValueExW(hkey3
,szRunAs
,0,REG_SZ
,(LPVOID
)szUser
,34);
3893 msiobj_release(&row
->hdr
);
3894 MSI_ViewClose(view
);
3895 msiobj_release(&view
->hdr
);
3901 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
)
3904 * Again I am assuming the words, "Whose key file represents" when referring
3905 * to a Component as to meaning that Components KeyPath file
3907 * Also there is a very strong connection between ClassInfo and ProgID
3908 * that I am mostly glossing over.
3909 * What would be more propper is to load the ClassInfo and the ProgID info
3910 * into memory data structures and then be able to enable and disable them
3911 * based on component.
3916 MSIRECORD
* row
= 0;
3917 static const WCHAR ExecSeqQuery
[] = {
3918 'S','E','L','E','C','T',' ','*',' ',
3919 'f','r','o','m',' ','C','l','a','s','s',0};
3920 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3921 static const WCHAR szProgID
[] = { 'P','r','o','g','I','D',0 };
3922 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3923 static const WCHAR szSpace
[] = {' ',0};
3924 HKEY hkey
,hkey2
,hkey3
;
3925 LPWSTR argument
,deformated
;
3928 return ERROR_INVALID_HANDLE
;
3930 rc
= RegCreateKeyW(HKEY_CLASSES_ROOT
,szCLSID
,&hkey
);
3931 if (rc
!= ERROR_SUCCESS
)
3932 return ERROR_FUNCTION_FAILED
;
3934 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3935 if (rc
!= ERROR_SUCCESS
)
3941 rc
= MSI_ViewExecute(view
, 0);
3942 if (rc
!= ERROR_SUCCESS
)
3944 MSI_ViewClose(view
);
3945 msiobj_release(&view
->hdr
);
3952 WCHAR buffer
[0x100];
3958 rc
= MSI_ViewFetch(view
,&row
);
3959 if (rc
!= ERROR_SUCCESS
)
3966 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
3968 index
= get_loaded_component(package
,buffer
);
3972 msiobj_release(&row
->hdr
);
3976 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
3978 TRACE("Skipping class reg due to disabled component\n");
3979 msiobj_release(&row
->hdr
);
3981 package
->components
[index
].Action
=
3982 package
->components
[index
].Installed
;
3987 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
3988 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
3991 MSI_RecordGetStringW(row
,1,clsid
,&sz
);
3992 RegCreateKeyW(hkey
,clsid
,&hkey2
);
3994 if (!MSI_RecordIsNull(row
,5))
3997 MSI_RecordGetStringW(row
,5,desc
,&sz
);
3999 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)desc
,
4000 (strlenW(desc
)+1)*sizeof(WCHAR
));
4006 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4008 RegCreateKeyW(hkey2
,buffer
,&hkey3
);
4010 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
4012 argument
= load_dynamic_stringW(row
,11);
4013 size
= deformat_string(package
,argument
,&deformated
);
4015 size
+=sizeof(WCHAR
);
4016 HeapFree(GetProcessHeap(),0,argument
);
4017 size
+= (strlenW(package
->files
[index
].TargetPath
))*sizeof(WCHAR
);
4019 argument
= (LPWSTR
)HeapAlloc(GetProcessHeap(),0,size
+sizeof(WCHAR
));
4020 strcpyW(argument
,package
->files
[index
].TargetPath
);
4023 strcatW(argument
,szSpace
);
4024 strcatW(argument
,deformated
);
4027 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)argument
, size
);
4028 HeapFree(GetProcessHeap(),0,deformated
);
4029 HeapFree(GetProcessHeap(),0,argument
);
4033 if (!MSI_RecordIsNull(row
,4))
4036 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4038 RegCreateKeyW(hkey2
,szProgID
,&hkey3
);
4040 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
4041 (strlenW(buffer
)+1)*sizeof(WCHAR
));
4046 if (!MSI_RecordIsNull(row
,6))
4049 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4051 RegSetValueExW(hkey2
,szAppID
,0,REG_SZ
,(LPVOID
)buffer
,
4052 (strlenW(buffer
)+1)*sizeof(WCHAR
));
4054 register_appid(package
,buffer
,desc
);
4058 if (!MSI_RecordIsNull(row
,7))
4060 FIXME("Process field 7\n");
4063 if (!MSI_RecordIsNull(row
,8))
4065 static const WCHAR szDefaultIcon
[] =
4066 {'D','e','f','a','u','l','t','I','c','o','n',0};
4068 LPWSTR FileName
= load_dynamic_stringW(row
,8);
4072 RegCreateKeyW(hkey2
,szDefaultIcon
,&hkey3
);
4073 build_icon_path(package
,FileName
,&FilePath
);
4074 if (!MSI_RecordIsNull(row
,9))
4076 static const WCHAR index_fmt
[] = {',','%','i',0};
4077 WCHAR index_buf
[20];
4078 index
= MSI_RecordGetInteger(row
,9);
4079 sprintfW(index_buf
,index_fmt
,index
);
4080 size
= strlenW(FilePath
)+strlenW(index_buf
)+1;
4081 size
*= sizeof(WCHAR
);
4082 HeapReAlloc(GetProcessHeap(),0,FilePath
,size
);
4084 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)FilePath
,
4085 (strlenW(FilePath
)+1) * sizeof(WCHAR
));
4086 HeapFree(GetProcessHeap(),0,FilePath
);
4087 HeapFree(GetProcessHeap(),0,FileName
);
4091 if (!MSI_RecordIsNull(row
,10))
4093 static const WCHAR szInproc32
[] = {
4094 'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4095 static const WCHAR szInproc
[] = {
4096 'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
4097 INT i
= MSI_RecordGetInteger(row
,10);
4098 if (i
!= MSI_NULL_INTEGER
&& i
> 0 && i
< 4)
4100 static const WCHAR ole2
[] = {'o','l','e','2','.','d','l','l',0};
4101 static const WCHAR ole32
[] = {
4102 'o','l','e','3','2','.','d','l','l',0};
4106 size
= strlenW(ole2
) * sizeof(WCHAR
);
4107 RegCreateKeyW(hkey2
,szInproc
,&hkey3
);
4108 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole2
, size
);
4112 size
= strlenW(ole32
) * sizeof(WCHAR
);
4113 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
4114 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole32
,size
);
4118 size
= strlenW(ole2
) * sizeof(WCHAR
);
4119 RegCreateKeyW(hkey2
,szInproc
,&hkey3
);
4120 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole2
, size
);
4122 size
= strlenW(ole32
) * sizeof(WCHAR
);
4123 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
4124 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)ole32
,size
);
4132 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
4133 argument
= load_dynamic_stringW(row
,10);
4134 reduce_to_longfilename(argument
);
4135 size
= strlenW(argument
)*sizeof(WCHAR
);
4137 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)argument
, size
);
4138 HeapFree(GetProcessHeap(),0,argument
);
4146 ui_actiondata(package
,szRegisterClassInfo
,row
);
4148 msiobj_release(&row
->hdr
);
4150 MSI_ViewClose(view
);
4151 msiobj_release(&view
->hdr
);
4158 static UINT
register_progid_base(MSIPACKAGE
* package
, MSIRECORD
* row
,
4161 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4162 static const WCHAR szDefaultIcon
[] = {
4163 'D','e','f','a','u','l','t','I','c','o','n',0};
4165 WCHAR buffer
[0x100];
4170 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
4171 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
4173 if (!MSI_RecordIsNull(row
,4))
4176 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4177 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
4181 if (!MSI_RecordIsNull(row
,3))
4185 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4186 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
4187 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
4191 strcpyW(clsid
,buffer
);
4197 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4198 return ERROR_FUNCTION_FAILED
;
4200 if (!MSI_RecordIsNull(row
,5))
4202 INT index
= MSI_RecordGetInteger(row
,6);
4203 LPWSTR FileName
= load_dynamic_stringW(row
,5);
4204 LPWSTR FilePath
,IconPath
;
4205 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
4207 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
4208 build_icon_path(package
,FileName
,&FilePath
);
4210 IconPath
= HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath
)+5)*
4213 sprintfW(IconPath
,fmt
,FilePath
,index
);
4214 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)IconPath
,
4215 (strlenW(IconPath
)+1) * sizeof(WCHAR
));
4216 HeapFree(GetProcessHeap(),0,FilePath
);
4217 HeapFree(GetProcessHeap(),0,FileName
);
4220 return ERROR_SUCCESS
;
4223 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
);
4225 static UINT
register_parent_progid(MSIPACKAGE
*package
, LPCWSTR parent
,
4230 MSIRECORD
* row
= 0;
4231 static const WCHAR Query_t
[] =
4232 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
4233 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
4237 return ERROR_INVALID_HANDLE
;
4239 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, parent
);
4240 if (rc
!= ERROR_SUCCESS
)
4243 rc
= MSI_ViewExecute(view
, 0);
4244 if (rc
!= ERROR_SUCCESS
)
4246 MSI_ViewClose(view
);
4247 msiobj_release(&view
->hdr
);
4251 rc
= MSI_ViewFetch(view
,&row
);
4252 if (rc
!= ERROR_SUCCESS
)
4254 MSI_ViewClose(view
);
4255 msiobj_release(&view
->hdr
);
4259 register_progid(package
,row
,clsid
);
4261 msiobj_release(&row
->hdr
);
4262 MSI_ViewClose(view
);
4263 msiobj_release(&view
->hdr
);
4267 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
)
4269 UINT rc
= ERROR_SUCCESS
;
4271 if (MSI_RecordIsNull(row
,2))
4272 rc
= register_progid_base(package
,row
,clsid
);
4275 WCHAR buffer
[0x1000];
4278 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
4279 static const WCHAR szDefaultIcon
[] = {
4280 'D','e','f','a','u','l','t','I','c','o','n',0};
4282 /* check if already registered */
4284 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
4285 RegCreateKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, NULL
, 0,
4286 KEY_ALL_ACCESS
, NULL
, &hkey
, &disp
);
4287 if (disp
== REG_OPENED_EXISTING_KEY
)
4289 TRACE("Key already registered\n");
4295 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4296 rc
= register_parent_progid(package
,buffer
,clsid
);
4298 /* clsid is same as parent */
4299 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
4300 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)clsid
, (strlenW(clsid
)+1) *
4306 if (!MSI_RecordIsNull(row
,4))
4309 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4310 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
4311 (strlenW(buffer
)+1) * sizeof(WCHAR
));
4314 if (!MSI_RecordIsNull(row
,5))
4316 LPWSTR FileName
= load_dynamic_stringW(row
,5);
4318 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
4319 build_icon_path(package
,FileName
,&FilePath
);
4320 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)FilePath
,
4321 (strlenW(FilePath
)+1) * sizeof(WCHAR
));
4322 HeapFree(GetProcessHeap(),0,FilePath
);
4323 HeapFree(GetProcessHeap(),0,FileName
);
4332 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
4335 * Sigh, here I am just brute force registering all progids
4336 * this needs to be linked to the Classes that have been registered
4337 * but the easiest way to do that is to load all these stuff into
4338 * memory for easy checking.
4340 * Gives me something to continue to work toward.
4344 MSIRECORD
* row
= 0;
4345 static const WCHAR Query
[] = {
4346 'S','E','L','E','C','T',' ','*',' ',
4347 'F','R','O','M',' ','P','r','o','g','I','d',0};
4350 return ERROR_INVALID_HANDLE
;
4352 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4353 if (rc
!= ERROR_SUCCESS
)
4354 return ERROR_SUCCESS
;
4356 rc
= MSI_ViewExecute(view
, 0);
4357 if (rc
!= ERROR_SUCCESS
)
4359 MSI_ViewClose(view
);
4360 msiobj_release(&view
->hdr
);
4366 WCHAR clsid
[0x1000];
4368 rc
= MSI_ViewFetch(view
,&row
);
4369 if (rc
!= ERROR_SUCCESS
)
4375 register_progid(package
,row
,clsid
);
4376 ui_actiondata(package
,szRegisterProgIdInfo
,row
);
4378 msiobj_release(&row
->hdr
);
4380 MSI_ViewClose(view
);
4381 msiobj_release(&view
->hdr
);
4385 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
4389 LPWSTR SystemFolder
;
4393 static const WCHAR szInstaller
[] =
4394 {'I','n','s','t','a','l','l','e','r','\\',0};
4395 static const WCHAR szProductCode
[] =
4396 {'P','r','o','d','u','c','t','C','o','d','e',0};
4397 static const WCHAR szFolder
[] =
4398 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4400 ProductCode
= load_dynamic_property(package
,szProductCode
,&rc
);
4404 SystemFolder
= load_dynamic_property(package
,szFolder
,NULL
);
4406 dest
= build_directory_name(3, SystemFolder
, szInstaller
, ProductCode
);
4408 create_full_pathW(dest
);
4410 *FilePath
= build_directory_name(2, dest
, icon_name
);
4412 HeapFree(GetProcessHeap(),0,SystemFolder
);
4413 HeapFree(GetProcessHeap(),0,ProductCode
);
4414 HeapFree(GetProcessHeap(),0,dest
);
4415 return ERROR_SUCCESS
;
4418 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
4422 MSIRECORD
* row
= 0;
4423 static const WCHAR Query
[] = {
4424 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
4425 'S','h','o','r','t','c','u','t',0};
4431 return ERROR_INVALID_HANDLE
;
4433 res
= CoInitialize( NULL
);
4436 ERR("CoInitialize failed\n");
4437 return ERROR_FUNCTION_FAILED
;
4440 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4441 if (rc
!= ERROR_SUCCESS
)
4442 return ERROR_SUCCESS
;
4444 rc
= MSI_ViewExecute(view
, 0);
4445 if (rc
!= ERROR_SUCCESS
)
4447 MSI_ViewClose(view
);
4448 msiobj_release(&view
->hdr
);
4454 LPWSTR target_file
, target_folder
;
4455 WCHAR buffer
[0x100];
4458 static const WCHAR szlnk
[]={'.','l','n','k',0};
4460 rc
= MSI_ViewFetch(view
,&row
);
4461 if (rc
!= ERROR_SUCCESS
)
4468 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4470 index
= get_loaded_component(package
,buffer
);
4474 msiobj_release(&row
->hdr
);
4478 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
4480 TRACE("Skipping shortcut creation due to disabled component\n");
4481 msiobj_release(&row
->hdr
);
4483 package
->components
[index
].Action
=
4484 package
->components
[index
].Installed
;
4489 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
4490 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
4492 ui_actiondata(package
,szCreateShortcuts
,row
);
4494 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
4495 &IID_IShellLinkW
, (LPVOID
*) &sl
);
4499 ERR("Is IID_IShellLink\n");
4500 msiobj_release(&row
->hdr
);
4504 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
4507 ERR("Is IID_IPersistFile\n");
4508 msiobj_release(&row
->hdr
);
4513 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4514 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
4516 /* may be needed because of a bug somehwere else */
4517 create_full_pathW(target_folder
);
4520 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4521 reduce_to_longfilename(buffer
);
4522 if (!strchrW(buffer
,'.') || strcmpiW(strchrW(buffer
,'.'),szlnk
))
4523 strcatW(buffer
,szlnk
);
4524 target_file
= build_directory_name(2, target_folder
, buffer
);
4525 HeapFree(GetProcessHeap(),0,target_folder
);
4528 MSI_RecordGetStringW(row
,5,buffer
,&sz
);
4529 if (strchrW(buffer
,'['))
4532 deformat_string(package
,buffer
,&deformated
);
4533 IShellLinkW_SetPath(sl
,deformated
);
4534 HeapFree(GetProcessHeap(),0,deformated
);
4538 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4539 IPersistFile_Release( pf
);
4540 IShellLinkW_Release( sl
);
4541 msiobj_release(&row
->hdr
);
4545 if (!MSI_RecordIsNull(row
,6))
4549 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4550 deformat_string(package
,buffer
,&deformated
);
4551 IShellLinkW_SetArguments(sl
,deformated
);
4552 HeapFree(GetProcessHeap(),0,deformated
);
4555 if (!MSI_RecordIsNull(row
,7))
4558 deformated
= load_dynamic_stringW(row
,7);
4559 IShellLinkW_SetDescription(sl
,deformated
);
4560 HeapFree(GetProcessHeap(),0,deformated
);
4563 if (!MSI_RecordIsNull(row
,8))
4564 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
4566 if (!MSI_RecordIsNull(row
,9))
4572 MSI_RecordGetStringW(row
,9,buffer
,&sz
);
4574 build_icon_path(package
,buffer
,&Path
);
4575 index
= MSI_RecordGetInteger(row
,10);
4577 IShellLinkW_SetIconLocation(sl
,Path
,index
);
4578 HeapFree(GetProcessHeap(),0,Path
);
4581 if (!MSI_RecordIsNull(row
,11))
4582 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
4584 if (!MSI_RecordIsNull(row
,12))
4588 MSI_RecordGetStringW(row
,12,buffer
,&sz
);
4589 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
4590 IShellLinkW_SetWorkingDirectory(sl
,Path
);
4591 HeapFree(GetProcessHeap(), 0, Path
);
4594 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
4595 IPersistFile_Save(pf
,target_file
,FALSE
);
4597 HeapFree(GetProcessHeap(),0,target_file
);
4599 IPersistFile_Release( pf
);
4600 IShellLinkW_Release( sl
);
4602 msiobj_release(&row
->hdr
);
4604 MSI_ViewClose(view
);
4605 msiobj_release(&view
->hdr
);
4615 * 99% of the work done here is only done for
4616 * advertised installs. However this is where the
4617 * Icon table is processed and written out
4618 * so that is what I am going to do here.
4620 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
4624 MSIRECORD
* row
= 0;
4625 static const WCHAR Query
[]={
4626 'S','E','L','E','C','T',' ','*',' ',
4627 'f','r','o','m',' ','I','c','o','n',0};
4629 /* for registry stuff */
4633 static const WCHAR szProductCode
[]=
4634 {'P','r','o','d','u','c','t','C','o','d','e',0};
4635 static const WCHAR szProductName
[] = {
4636 'P','r','o','d','u','c','t','N','a','m','e',0};
4637 static const WCHAR szPackageCode
[] = {
4638 'P','a','c','k','a','g','e','C','o','d','e',0};
4641 MSIHANDLE hDb
, hSumInfo
;
4644 return ERROR_INVALID_HANDLE
;
4646 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4647 if (rc
!= ERROR_SUCCESS
)
4650 rc
= MSI_ViewExecute(view
, 0);
4651 if (rc
!= ERROR_SUCCESS
)
4653 MSI_ViewClose(view
);
4654 msiobj_release(&view
->hdr
);
4661 WCHAR
*FilePath
=NULL
;
4662 WCHAR
*FileName
=NULL
;
4665 rc
= MSI_ViewFetch(view
,&row
);
4666 if (rc
!= ERROR_SUCCESS
)
4672 FileName
= load_dynamic_stringW(row
,1);
4675 ERR("Unable to get FileName\n");
4676 msiobj_release(&row
->hdr
);
4680 build_icon_path(package
,FileName
,&FilePath
);
4682 HeapFree(GetProcessHeap(),0,FileName
);
4684 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
4686 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
4687 FILE_ATTRIBUTE_NORMAL
, NULL
);
4689 if (the_file
== INVALID_HANDLE_VALUE
)
4691 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
4692 msiobj_release(&row
->hdr
);
4693 HeapFree(GetProcessHeap(),0,FilePath
);
4701 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
4702 if (rc
!= ERROR_SUCCESS
)
4704 ERR("Failed to get stream\n");
4705 CloseHandle(the_file
);
4706 DeleteFileW(FilePath
);
4709 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
4710 } while (sz
== 1024);
4712 HeapFree(GetProcessHeap(),0,FilePath
);
4714 CloseHandle(the_file
);
4715 msiobj_release(&row
->hdr
);
4717 MSI_ViewClose(view
);
4718 msiobj_release(&view
->hdr
);
4721 /* ok there is a lot more done here but i need to figure out what */
4722 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4726 rc
= MSIREG_OpenProductsKey(productcode
,&hkey
,TRUE
);
4727 if (rc
!= ERROR_SUCCESS
)
4730 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
4731 if (rc
!= ERROR_SUCCESS
)
4735 buffer
= load_dynamic_property(package
,szProductName
,NULL
);
4736 size
= strlenW(buffer
)*sizeof(WCHAR
);
4737 RegSetValueExW(hukey
,szProductName
,0,REG_SZ
, (LPSTR
)buffer
,size
);
4738 HeapFree(GetProcessHeap(),0,buffer
);
4739 FIXME("Need to write more keys to the user registry\n");
4741 hDb
= msiobj_findhandle( &package
->db
->hdr
);
4742 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
4743 if (rc
== ERROR_SUCCESS
)
4745 WCHAR guidbuffer
[0x200];
4747 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 8, NULL
, NULL
, NULL
,
4749 if (rc
== ERROR_SUCCESS
)
4751 WCHAR squashed
[GUID_SIZE
];
4752 /* for now we only care about the first guid */
4753 LPWSTR ptr
= strchrW(guidbuffer
,';');
4755 squash_guid(guidbuffer
,squashed
);
4756 size
= strlenW(guidbuffer
)*sizeof(WCHAR
);
4757 RegSetValueExW(hukey
,szPackageCode
,0,REG_SZ
, (LPSTR
)guidbuffer
,
4763 ERR("Unable to query Revision_Number... \n");
4766 MsiCloseHandle(hSumInfo
);
4770 ERR("Unable to open Summary Information\n");
4776 HeapFree(GetProcessHeap(),0,productcode
);
4783 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
4787 MSIRECORD
* row
= 0;
4788 static const WCHAR ExecSeqQuery
[] = {'S','e','l','e','c','t',' ','*',
4789 ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0};
4790 static const WCHAR szWindowsFolder
[] =
4791 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4793 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4794 if (rc
!= ERROR_SUCCESS
)
4796 TRACE("no IniFile table\n");
4797 return ERROR_SUCCESS
;
4800 rc
= MSI_ViewExecute(view
, 0);
4801 if (rc
!= ERROR_SUCCESS
)
4803 MSI_ViewClose(view
);
4804 msiobj_release(&view
->hdr
);
4810 LPWSTR component
,filename
,dirproperty
,section
,key
,value
,identifier
;
4811 LPWSTR deformated_section
, deformated_key
, deformated_value
;
4812 LPWSTR folder
, fullname
= NULL
;
4814 INT component_index
,action
;
4816 rc
= MSI_ViewFetch(view
,&row
);
4817 if (rc
!= ERROR_SUCCESS
)
4823 component
= load_dynamic_stringW(row
, 8);
4824 component_index
= get_loaded_component(package
,component
);
4825 HeapFree(GetProcessHeap(),0,component
);
4827 if (package
->components
[component_index
].ActionRequest
!=
4830 TRACE("Skipping ini file due to disabled component\n");
4831 msiobj_release(&row
->hdr
);
4833 package
->components
[component_index
].Action
=
4834 package
->components
[component_index
].Installed
;
4839 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
4840 package
->components
[component_index
].Installed
= INSTALLSTATE_LOCAL
;
4842 identifier
= load_dynamic_stringW(row
,1);
4843 filename
= load_dynamic_stringW(row
,2);
4844 dirproperty
= load_dynamic_stringW(row
,3);
4845 section
= load_dynamic_stringW(row
,4);
4846 key
= load_dynamic_stringW(row
,5);
4847 value
= load_dynamic_stringW(row
,6);
4848 action
= MSI_RecordGetInteger(row
,7);
4850 deformat_string(package
,section
,&deformated_section
);
4851 deformat_string(package
,key
,&deformated_key
);
4852 deformat_string(package
,value
,&deformated_value
);
4856 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
4858 folder
= load_dynamic_property(package
,dirproperty
,NULL
);
4861 folder
= load_dynamic_property(package
, szWindowsFolder
, NULL
);
4865 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
4869 fullname
= build_directory_name(3, folder
, filename
, NULL
);
4873 TRACE("Adding value %s to section %s in %s\n",
4874 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4875 debugstr_w(fullname
));
4876 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4877 deformated_value
, fullname
);
4879 else if (action
== 1)
4882 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
4883 returned
, 10, fullname
);
4884 if (returned
[0] == 0)
4886 TRACE("Adding value %s to section %s in %s\n",
4887 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4888 debugstr_w(fullname
));
4890 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4891 deformated_value
, fullname
);
4894 else if (action
== 3)
4896 FIXME("Append to existing section not yet implemented\n");
4899 uirow
= MSI_CreateRecord(4);
4900 MSI_RecordSetStringW(uirow
,1,identifier
);
4901 MSI_RecordSetStringW(uirow
,2,deformated_section
);
4902 MSI_RecordSetStringW(uirow
,3,deformated_key
);
4903 MSI_RecordSetStringW(uirow
,4,deformated_value
);
4904 ui_actiondata(package
,szWriteIniValues
,uirow
);
4905 msiobj_release( &uirow
->hdr
);
4907 HeapFree(GetProcessHeap(),0,identifier
);
4908 HeapFree(GetProcessHeap(),0,fullname
);
4909 HeapFree(GetProcessHeap(),0,filename
);
4910 HeapFree(GetProcessHeap(),0,key
);
4911 HeapFree(GetProcessHeap(),0,value
);
4912 HeapFree(GetProcessHeap(),0,section
);
4913 HeapFree(GetProcessHeap(),0,dirproperty
);
4914 HeapFree(GetProcessHeap(),0,folder
);
4915 HeapFree(GetProcessHeap(),0,deformated_key
);
4916 HeapFree(GetProcessHeap(),0,deformated_value
);
4917 HeapFree(GetProcessHeap(),0,deformated_section
);
4918 msiobj_release(&row
->hdr
);
4920 MSI_ViewClose(view
);
4921 msiobj_release(&view
->hdr
);
4925 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4929 MSIRECORD
* row
= 0;
4930 static const WCHAR ExecSeqQuery
[] = {'S','e','l','e','c','t',' ','*',' ',
4931 'f','r','o','m',' ','S','e','l','f','R','e','g',0};
4933 static const WCHAR ExeStr
[] = {
4934 'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0};
4936 PROCESS_INFORMATION info
;
4939 memset(&si
,0,sizeof(STARTUPINFOW
));
4941 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4942 if (rc
!= ERROR_SUCCESS
)
4944 TRACE("no SelfReg table\n");
4945 return ERROR_SUCCESS
;
4948 rc
= MSI_ViewExecute(view
, 0);
4949 if (rc
!= ERROR_SUCCESS
)
4951 MSI_ViewClose(view
);
4952 msiobj_release(&view
->hdr
);
4962 rc
= MSI_ViewFetch(view
,&row
);
4963 if (rc
!= ERROR_SUCCESS
)
4969 filename
= load_dynamic_stringW(row
,1);
4970 index
= get_loaded_file(package
,filename
);
4974 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4975 HeapFree(GetProcessHeap(),0,filename
);
4976 msiobj_release(&row
->hdr
);
4979 HeapFree(GetProcessHeap(),0,filename
);
4981 len
= strlenW(ExeStr
);
4982 len
+= strlenW(package
->files
[index
].TargetPath
);
4985 filename
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
4986 strcpyW(filename
,ExeStr
);
4987 strcatW(filename
,package
->files
[index
].TargetPath
);
4989 TRACE("Registering %s\n",debugstr_w(filename
));
4990 brc
= CreateProcessW(NULL
, filename
, NULL
, NULL
, FALSE
, 0, NULL
,
4991 c_collen
, &si
, &info
);
4994 msi_dialog_check_messages(package
->dialog
, info
.hProcess
);
4996 HeapFree(GetProcessHeap(),0,filename
);
4997 msiobj_release(&row
->hdr
);
4999 MSI_ViewClose(view
);
5000 msiobj_release(&view
->hdr
);
5004 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
5011 static const WCHAR szProductCode
[]=
5012 {'P','r','o','d','u','c','t','C','o','d','e',0};
5015 return ERROR_INVALID_HANDLE
;
5017 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5021 rc
= MSIREG_OpenFeaturesKey(productcode
,&hkey
,TRUE
);
5022 if (rc
!= ERROR_SUCCESS
)
5025 rc
= MSIREG_OpenUserFeaturesKey(productcode
,&hukey
,TRUE
);
5026 if (rc
!= ERROR_SUCCESS
)
5029 /* here the guids are base 85 encoded */
5030 for (i
= 0; i
< package
->loaded_features
; i
++)
5037 size
= package
->features
[i
].ComponentCount
*21;
5039 if (package
->features
[i
].Feature_Parent
[0])
5040 size
+= strlenW(package
->features
[i
].Feature_Parent
)+2;
5042 data
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5045 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
5048 memset(buf
,0,sizeof(buf
));
5049 TRACE("From %s\n",debugstr_w(package
->components
5050 [package
->features
[i
].Components
[j
]].ComponentId
));
5051 CLSIDFromString(package
->components
5052 [package
->features
[i
].Components
[j
]].ComponentId
,
5054 encode_base85_guid(&clsid
,buf
);
5055 TRACE("to %s\n",debugstr_w(buf
));
5058 if (package
->features
[i
].Feature_Parent
[0])
5060 static const WCHAR sep
[] = {'\2',0};
5062 strcatW(data
,package
->features
[i
].Feature_Parent
);
5065 size
= (strlenW(data
)+1)*sizeof(WCHAR
);
5066 RegSetValueExW(hkey
,package
->features
[i
].Feature
,0,REG_SZ
,
5068 HeapFree(GetProcessHeap(),0,data
);
5070 size
= strlenW(package
->features
[i
].Feature_Parent
)*sizeof(WCHAR
);
5071 RegSetValueExW(hukey
,package
->features
[i
].Feature
,0,REG_SZ
,
5072 (LPSTR
)package
->features
[i
].Feature_Parent
,size
);
5078 HeapFree(GetProcessHeap(), 0, productcode
);
5082 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
5084 static const WCHAR szProductCode
[]=
5085 {'P','r','o','d','u','c','t','C','o','d','e',0};
5091 static WCHAR szNONE
[] = {0};
5092 static const WCHAR szWindowsInstaler
[] =
5093 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5094 static const WCHAR szPropKeys
[][80] =
5096 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
5097 {'A','R','P','C','O','N','T','A','C','T'},
5098 {'A','R','P','C','O','M','M','E','N','T','S',0},
5099 {'P','r','o','d','u','c','t','N','a','m','e',0},
5100 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
5101 {'A','R','P','H','E','L','P','L','I','N','K',0},
5102 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
5103 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
5104 {'S','O','U','R','C','E','D','I','R',0},
5105 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
5106 {'A','R','P','R','E','A','D','M','E',0},
5107 {'A','R','P','S','I','Z','E',0},
5108 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
5109 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
5113 static const WCHAR szRegKeys
[][80] =
5115 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
5116 {'C','o','n','t','a','c','t',0},
5117 {'C','o','m','m','e','n','t','s',0},
5118 {'D','i','s','p','l','a','y','N','a','m','e',0},
5119 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
5120 {'H','e','l','p','L','i','n','k',0},
5121 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
5122 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
5123 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
5124 {'P','u','b','l','i','s','h','e','r',0},
5125 {'R','e','a','d','m','e',0},
5126 {'S','i','z','e',0},
5127 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
5128 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
5132 static const WCHAR path
[] = {
5133 'C',':','\\','W','i','n','d','o','w','s','\\',
5134 'I','n','s','t','a','l','l','e','r','\\'};
5135 static const WCHAR fmt
[] = {
5136 'C',':','\\','W','i','n','d','o','w','s','\\',
5137 'I','n','s','t','a','l','l','e','r','\\',
5138 '%','x','.','m','s','i',0};
5139 static const WCHAR szLocalPackage
[]=
5140 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
5141 WCHAR packagefile
[MAX_PATH
];
5145 return ERROR_INVALID_HANDLE
;
5147 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5151 rc
= MSIREG_OpenUninstallKey(productcode
,&hkey
,TRUE
);
5152 if (rc
!= ERROR_SUCCESS
)
5155 /* dump all the info i can grab */
5156 FIXME("Flesh out more information \n");
5159 while (szPropKeys
[i
][0]!=0)
5161 buffer
= load_dynamic_property(package
,szPropKeys
[i
],&rc
);
5162 if (rc
!= ERROR_SUCCESS
)
5164 size
= strlenW(buffer
)*sizeof(WCHAR
);
5165 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,(LPSTR
)buffer
,size
);
5171 RegSetValueExW(hkey
,szWindowsInstaler
,0,REG_DWORD
,(LPSTR
)&rc
,size
);
5173 /* copy the package locally */
5174 num
= GetTickCount() & 0xffff;
5178 sprintfW(packagefile
,fmt
,num
);
5181 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
5182 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
5183 if (handle
!= INVALID_HANDLE_VALUE
)
5185 CloseHandle(handle
);
5188 if (GetLastError() != ERROR_FILE_EXISTS
&&
5189 GetLastError() != ERROR_SHARING_VIOLATION
)
5191 if (!(++num
& 0xffff)) num
= 1;
5192 sprintfW(packagefile
,fmt
,num
);
5193 } while (num
!= start
);
5195 create_full_pathW(path
);
5196 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
5197 CopyFileW(package
->PackagePath
,packagefile
,FALSE
);
5198 size
= strlenW(packagefile
)*sizeof(WCHAR
);
5199 RegSetValueExW(hkey
,szLocalPackage
,0,REG_SZ
,(LPSTR
)packagefile
,size
);
5202 HeapFree(GetProcessHeap(),0,productcode
);
5205 return ERROR_SUCCESS
;
5208 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
5212 return ERROR_INVALID_HANDLE
;
5214 for (i
= 0; i
< package
->DeferredActionCount
; i
++)
5217 action
= package
->DeferredAction
[i
];
5218 ui_actionstart(package
, action
);
5219 TRACE("Executing Action (%s)\n",debugstr_w(action
));
5220 ACTION_CustomAction(package
,action
,TRUE
);
5221 HeapFree(GetProcessHeap(),0,package
->DeferredAction
[i
]);
5223 HeapFree(GetProcessHeap(),0,package
->DeferredAction
);
5225 package
->DeferredActionCount
= 0;
5226 package
->DeferredAction
= NULL
;
5228 return ERROR_SUCCESS
;
5231 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
5235 return ERROR_INVALID_HANDLE
;
5237 /* first do the same as an InstallExecute */
5238 ACTION_InstallExecute(package
);
5240 /* then handle Commit Actions */
5241 for (i
= 0; i
< package
->CommitActionCount
; i
++)
5244 action
= package
->CommitAction
[i
];
5245 ui_actionstart(package
, action
);
5246 TRACE("Executing Commit Action (%s)\n",debugstr_w(action
));
5247 ACTION_CustomAction(package
,action
,TRUE
);
5248 HeapFree(GetProcessHeap(),0,package
->CommitAction
[i
]);
5250 HeapFree(GetProcessHeap(),0,package
->CommitAction
);
5252 package
->CommitActionCount
= 0;
5253 package
->CommitAction
= NULL
;
5255 return ERROR_SUCCESS
;
5258 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
5260 static const WCHAR RunOnce
[] = {
5261 'S','o','f','t','w','a','r','e','\\',
5262 'M','i','c','r','o','s','o','f','t','\\',
5263 'W','i','n','d','o','w','s','\\',
5264 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5265 'R','u','n','O','n','c','e'};
5266 static const WCHAR InstallRunOnce
[] = {
5267 'S','o','f','t','w','a','r','e','\\',
5268 'M','i','c','r','o','s','o','f','t','\\',
5269 'W','i','n','d','o','w','s','\\',
5270 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5271 'I','n','s','t','a','l','l','e','r','\\',
5272 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'};
5274 static const WCHAR msiexec_fmt
[] = {
5275 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m',
5276 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5277 '\"','%','s','\"',0};
5278 static const WCHAR install_fmt
[] = {
5279 '/','I',' ','\"','%','s','\"',' ',
5280 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5281 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5285 WCHAR squished_pc
[100];
5288 static const WCHAR szProductCode
[]=
5289 {'P','r','o','d','u','c','t','C','o','d','e',0};
5290 static const WCHAR szLUS
[] = {
5291 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
5292 static const WCHAR szSourceList
[] = {
5293 'S','o','u','r','c','e','L','i','s','t',0};
5294 static const WCHAR szPackageName
[] = {
5295 'P','a','c','k','a','g','e','N','a','m','e',0};
5298 return ERROR_INVALID_HANDLE
;
5300 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5304 squash_guid(productcode
,squished_pc
);
5306 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
5307 sprintfW(buffer
,msiexec_fmt
,squished_pc
);
5309 size
= strlenW(buffer
)*sizeof(WCHAR
);
5310 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
5313 TRACE("Reboot command %s\n",debugstr_w(buffer
));
5315 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
5316 sprintfW(buffer
,install_fmt
,productcode
,squished_pc
);
5317 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
5320 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
5321 if (rc
== ERROR_SUCCESS
)
5325 RegCreateKeyW(hukey
, szSourceList
, &hukey2
);
5326 buf
= load_dynamic_property(package
,cszSourceDir
,NULL
);
5327 size
= strlenW(buf
)*sizeof(WCHAR
);
5328 RegSetValueExW(hukey2
,szLUS
,0,REG_SZ
,(LPSTR
)buf
,size
);
5329 HeapFree(GetProcessHeap(),0,buf
);
5331 buf
= strrchrW(package
->PackagePath
,'\\');
5335 size
= strlenW(buf
)*sizeof(WCHAR
);
5336 RegSetValueExW(hukey2
,szPackageName
,0,REG_SZ
,(LPSTR
)buf
,size
);
5339 RegCloseKey(hukey2
);
5341 HeapFree(GetProcessHeap(),0,productcode
);
5343 return ERROR_INSTALL_SUSPEND
;
5346 UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
5349 * we are currently doing what should be done here in the top level Install
5350 * however for Adminastrative and uninstalls this step will be needed
5352 return ERROR_SUCCESS
;
5356 static UINT
ACTION_RegisterExtensionInfo(MSIPACKAGE
*package
)
5360 MSIRECORD
* row
= 0;
5361 static const WCHAR ExecSeqQuery
[] = {
5362 'S','E','L','E','C','T',' ','*',' ',
5363 'f','r','o','m',' ','E','x','t','e','n','s','i','o','n',0};
5364 static const WCHAR szContentType
[] =
5365 { 'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
5369 return ERROR_INVALID_HANDLE
;
5371 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5372 if (rc
!= ERROR_SUCCESS
)
5378 rc
= MSI_ViewExecute(view
, 0);
5379 if (rc
!= ERROR_SUCCESS
)
5381 MSI_ViewClose(view
);
5382 msiobj_release(&view
->hdr
);
5388 WCHAR buffer
[0x100];
5389 WCHAR extension
[257];
5394 rc
= MSI_ViewFetch(view
,&row
);
5395 if (rc
!= ERROR_SUCCESS
)
5402 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
5404 index
= get_loaded_component(package
,buffer
);
5408 msiobj_release(&row
->hdr
);
5412 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
5414 TRACE("Skipping extension reg due to disabled component\n");
5415 msiobj_release(&row
->hdr
);
5417 package
->components
[index
].Action
=
5418 package
->components
[index
].Installed
;
5423 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
5424 package
->components
[index
].Installed
= INSTALLSTATE_LOCAL
;
5426 exten
= load_dynamic_stringW(row
,1);
5429 strcatW(extension
,exten
);
5430 HeapFree(GetProcessHeap(),0,exten
);
5432 RegCreateKeyW(HKEY_CLASSES_ROOT
,extension
,&hkey
);
5434 if (!MSI_RecordIsNull(row
,4))
5436 LPWSTR mime
= load_dynamic_stringW(row
,4);
5437 RegSetValueExW(hkey
,szContentType
,0,REG_SZ
,(LPVOID
)mime
,
5438 (strlenW(mime
)+1)*sizeof(WCHAR
));
5439 HeapFree(GetProcessHeap(),0,mime
);
5442 if (!MSI_RecordIsNull(row
,3))
5444 static const WCHAR szSN
[] =
5445 {'\\','S','h','e','l','l','N','e','w',0};
5448 LPWSTR progid
= load_dynamic_stringW(row
,3);
5450 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)progid
,
5451 (strlenW(progid
)+1)*sizeof(WCHAR
));
5453 newkey
= HeapAlloc(GetProcessHeap(),0,
5454 (strlenW(progid
)+strlenW(szSN
)+1) * sizeof(WCHAR
));
5456 strcpyW(newkey
,progid
);
5457 strcatW(newkey
,szSN
);
5458 RegCreateKeyW(hkey
,newkey
,&hkey2
);
5461 HeapFree(GetProcessHeap(),0,progid
);
5462 HeapFree(GetProcessHeap(),0,newkey
);
5468 ui_actiondata(package
,szRegisterExtensionInfo
,row
);
5470 msiobj_release(&row
->hdr
);
5472 MSI_ViewClose(view
);
5473 msiobj_release(&view
->hdr
);
5479 static UINT
ACTION_RegisterMIMEInfo(MSIPACKAGE
*package
)
5483 MSIRECORD
* row
= 0;
5484 static const WCHAR ExecSeqQuery
[] = {
5485 'S','E','L','E','C','T',' ','*',' ',
5486 'f','r','o','m',' ','M','I','M','E',0};
5487 static const WCHAR szExten
[] =
5488 { 'E','x','t','e','n','s','i','o','n',0 };
5492 return ERROR_INVALID_HANDLE
;
5494 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5495 if (rc
!= ERROR_SUCCESS
)
5501 rc
= MSI_ViewExecute(view
, 0);
5502 if (rc
!= ERROR_SUCCESS
)
5504 MSI_ViewClose(view
);
5505 msiobj_release(&view
->hdr
);
5511 WCHAR extension
[257];
5514 static const WCHAR fmt
[] =
5515 {'M','I','M','E','\\',
5516 'D','a','t','a','b','a','s','e','\\',
5517 'C','o','n','t','e','n','t',' ','T','y','p','e','\\',
5521 rc
= MSI_ViewFetch(view
,&row
);
5522 if (rc
!= ERROR_SUCCESS
)
5528 mime
= load_dynamic_stringW(row
,1);
5529 exten
= load_dynamic_stringW(row
,2);
5532 strcatW(extension
,exten
);
5533 HeapFree(GetProcessHeap(),0,exten
);
5535 key
= HeapAlloc(GetProcessHeap(),0,(strlenW(mime
)+strlenW(fmt
)+1) *
5537 sprintfW(key
,fmt
,mime
);
5538 RegCreateKeyW(HKEY_CLASSES_ROOT
,key
,&hkey
);
5539 RegSetValueExW(hkey
,szExten
,0,REG_SZ
,(LPVOID
)extension
,
5540 (strlenW(extension
)+1)*sizeof(WCHAR
));
5542 HeapFree(GetProcessHeap(),0,mime
);
5543 HeapFree(GetProcessHeap(),0,key
);
5545 if (!MSI_RecordIsNull(row
,3))
5547 FIXME("Handle non null for field 3\n");
5552 ui_actiondata(package
,szRegisterMIMEInfo
,row
);
5554 msiobj_release(&row
->hdr
);
5556 MSI_ViewClose(view
);
5557 msiobj_release(&view
->hdr
);
5563 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
5565 static const WCHAR szProductCode
[]=
5566 {'P','r','o','d','u','c','t','C','o','d','e',0};
5567 static const WCHAR szProductID
[]=
5568 {'P','r','o','d','u','c','t','I','D',0};
5576 static const WCHAR szPropKeys
[][80] =
5578 {'P','r','o','d','u','c','t','I','D',0},
5579 {'U','S','E','R','N','A','M','E',0},
5580 {'C','O','M','P','A','N','Y','N','A','M','E',0},
5584 static const WCHAR szRegKeys
[][80] =
5586 {'P','r','o','d','u','c','t','I','D',0},
5587 {'R','e','g','O','w','n','e','r',0},
5588 {'R','e','g','C','o','m','p','a','n','y',0},
5593 return ERROR_INVALID_HANDLE
;
5595 productid
= load_dynamic_property(package
,szProductID
,&rc
);
5597 return ERROR_SUCCESS
;
5599 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
5603 rc
= MSIREG_OpenUninstallKey(productcode
,&hkey
,TRUE
);
5604 if (rc
!= ERROR_SUCCESS
)
5608 while (szPropKeys
[i
][0]!=0)
5610 buffer
= load_dynamic_property(package
,szPropKeys
[i
],&rc
);
5611 if (rc
== ERROR_SUCCESS
)
5613 size
= strlenW(buffer
)*sizeof(WCHAR
);
5614 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,(LPSTR
)buffer
,size
);
5620 HeapFree(GetProcessHeap(),0,productcode
);
5621 HeapFree(GetProcessHeap(),0,productid
);
5624 return ERROR_SUCCESS
;
5627 /* Msi functions that seem appropriate here */
5628 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
5633 TRACE(" exteral attempt at action %s\n",szAction
);
5636 return ERROR_FUNCTION_FAILED
;
5638 return ERROR_FUNCTION_FAILED
;
5640 szwAction
= strdupAtoW(szAction
);
5643 return ERROR_FUNCTION_FAILED
;
5646 rc
= MsiDoActionW(hInstall
, szwAction
);
5647 HeapFree(GetProcessHeap(),0,szwAction
);
5651 UINT WINAPI
MsiDoActionW( MSIHANDLE hInstall
, LPCWSTR szAction
)
5653 MSIPACKAGE
*package
;
5654 UINT ret
= ERROR_INVALID_HANDLE
;
5656 TRACE(" external attempt at action %s \n",debugstr_w(szAction
));
5658 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5661 ret
= ACTION_PerformAction(package
,szAction
);
5662 msiobj_release( &package
->hdr
);
5667 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
5668 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
5674 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
5677 return ERROR_FUNCTION_FAILED
;
5679 return ERROR_FUNCTION_FAILED
;
5681 szwFolder
= strdupAtoW(szFolder
);
5684 return ERROR_FUNCTION_FAILED
;
5686 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
5688 rc
= MsiGetTargetPathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
5690 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
5691 *pcchPathBuf
, NULL
, NULL
);
5693 HeapFree(GetProcessHeap(),0,szwFolder
);
5694 HeapFree(GetProcessHeap(),0,szwPathBuf
);
5699 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
5700 szPathBuf
, DWORD
* pcchPathBuf
)
5703 UINT rc
= ERROR_FUNCTION_FAILED
;
5704 MSIPACKAGE
*package
;
5706 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
5708 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5710 return ERROR_INVALID_HANDLE
;
5711 path
= resolve_folder(package
, szFolder
, FALSE
, FALSE
, NULL
);
5712 msiobj_release( &package
->hdr
);
5714 if (path
&& (strlenW(path
) > *pcchPathBuf
))
5716 *pcchPathBuf
= strlenW(path
)+1;
5717 rc
= ERROR_MORE_DATA
;
5721 *pcchPathBuf
= strlenW(path
)+1;
5722 strcpyW(szPathBuf
,path
);
5723 TRACE("Returning Path %s\n",debugstr_w(path
));
5726 HeapFree(GetProcessHeap(),0,path
);
5732 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
5733 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
5739 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
5742 return ERROR_FUNCTION_FAILED
;
5744 return ERROR_FUNCTION_FAILED
;
5746 szwFolder
= strdupAtoW(szFolder
);
5748 return ERROR_FUNCTION_FAILED
;
5750 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
5752 rc
= MsiGetSourcePathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
5754 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
5755 *pcchPathBuf
, NULL
, NULL
);
5757 HeapFree(GetProcessHeap(),0,szwFolder
);
5758 HeapFree(GetProcessHeap(),0,szwPathBuf
);
5763 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
5764 szPathBuf
, DWORD
* pcchPathBuf
)
5767 UINT rc
= ERROR_FUNCTION_FAILED
;
5768 MSIPACKAGE
*package
;
5770 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
5772 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5774 return ERROR_INVALID_HANDLE
;
5775 path
= resolve_folder(package
, szFolder
, TRUE
, FALSE
, NULL
);
5776 msiobj_release( &package
->hdr
);
5778 if (path
&& strlenW(path
) > *pcchPathBuf
)
5780 *pcchPathBuf
= strlenW(path
)+1;
5781 rc
= ERROR_MORE_DATA
;
5785 *pcchPathBuf
= strlenW(path
)+1;
5786 strcpyW(szPathBuf
,path
);
5787 TRACE("Returning Path %s\n",debugstr_w(path
));
5790 HeapFree(GetProcessHeap(),0,path
);
5796 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
5797 LPCSTR szFolderPath
)
5800 LPWSTR szwFolderPath
;
5804 return ERROR_FUNCTION_FAILED
;
5806 return ERROR_FUNCTION_FAILED
;
5808 szwFolder
= strdupAtoW(szFolder
);
5810 return ERROR_FUNCTION_FAILED
;
5812 szwFolderPath
= strdupAtoW(szFolderPath
);
5815 HeapFree(GetProcessHeap(),0,szwFolder
);
5816 return ERROR_FUNCTION_FAILED
;
5819 rc
= MsiSetTargetPathW(hInstall
, szwFolder
, szwFolderPath
);
5821 HeapFree(GetProcessHeap(),0,szwFolder
);
5822 HeapFree(GetProcessHeap(),0,szwFolderPath
);
5827 UINT
MSI_SetTargetPathW(MSIPACKAGE
*package
, LPCWSTR szFolder
,
5828 LPCWSTR szFolderPath
)
5832 LPWSTR path2
= NULL
;
5835 TRACE("(%p %s %s)\n",package
, debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5838 return ERROR_INVALID_HANDLE
;
5840 if (szFolderPath
[0]==0)
5841 return ERROR_FUNCTION_FAILED
;
5843 if (GetFileAttributesW(szFolderPath
) == INVALID_FILE_ATTRIBUTES
)
5844 return ERROR_FUNCTION_FAILED
;
5846 path
= resolve_folder(package
,szFolder
,FALSE
,FALSE
,&folder
);
5849 return ERROR_INVALID_PARAMETER
;
5851 HeapFree(GetProcessHeap(),0,folder
->Property
);
5852 folder
->Property
= build_directory_name(2, szFolderPath
, NULL
);
5854 if (strcmpiW(path
, folder
->Property
) == 0)
5857 * Resolved Target has not really changed, so just
5858 * set this folder and do not recalculate everything.
5860 HeapFree(GetProcessHeap(),0,folder
->ResolvedTarget
);
5861 folder
->ResolvedTarget
= NULL
;
5862 path2
= resolve_folder(package
,szFolder
,FALSE
,TRUE
,NULL
);
5863 HeapFree(GetProcessHeap(),0,path2
);
5867 for (i
= 0; i
< package
->loaded_folders
; i
++)
5869 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
5870 package
->folders
[i
].ResolvedTarget
=NULL
;
5873 for (i
= 0; i
< package
->loaded_folders
; i
++)
5875 path2
=resolve_folder(package
, package
->folders
[i
].Directory
, FALSE
,
5877 HeapFree(GetProcessHeap(),0,path2
);
5880 HeapFree(GetProcessHeap(),0,path
);
5882 return ERROR_SUCCESS
;
5885 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
5886 LPCWSTR szFolderPath
)
5888 MSIPACKAGE
*package
;
5891 TRACE("(%s %s)\n",debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5893 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5894 ret
= MSI_SetTargetPathW( package
, szFolder
, szFolderPath
);
5895 msiobj_release( &package
->hdr
);
5899 /***********************************************************************
5900 * MsiGetMode (MSI.@)
5902 * Returns an internal installer state (if it is running in a mode iRunMode)
5905 * hInstall [I] Handle to the installation
5906 * hRunMode [I] Checking run mode
5907 * MSIRUNMODE_ADMIN Administrative mode
5908 * MSIRUNMODE_ADVERTISE Advertisement mode
5909 * MSIRUNMODE_MAINTENANCE Maintenance mode
5910 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
5911 * MSIRUNMODE_LOGENABLED Log file is writing
5912 * MSIRUNMODE_OPERATIONS Operations in progress??
5913 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
5914 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
5915 * MSIRUNMODE_CABINET Files from cabinet are installed
5916 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
5917 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
5918 * MSIRUNMODE_RESERVED11 Reserved
5919 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
5920 * MSIRUNMODE_ZAWENABLED Demand installation is supported
5921 * MSIRUNMODE_RESERVED14 Reserved
5922 * MSIRUNMODE_RESERVED15 Reserved
5923 * MSIRUNMODE_SCHEDULED called from install script
5924 * MSIRUNMODE_ROLLBACK called from rollback script
5925 * MSIRUNMODE_COMMIT called from commit script
5928 * In the state: TRUE
5929 * Not in the state: FALSE
5933 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, MSIRUNMODE iRunMode
)
5935 FIXME("STUB (iRunMode=%i)\n",iRunMode
);
5940 * According to the docs, when this is called it immediately recalculates
5941 * all the component states as well
5943 UINT WINAPI
MsiSetFeatureStateA(MSIHANDLE hInstall
, LPCSTR szFeature
,
5944 INSTALLSTATE iState
)
5946 LPWSTR szwFeature
= NULL
;
5949 szwFeature
= strdupAtoW(szFeature
);
5952 return ERROR_FUNCTION_FAILED
;
5954 rc
= MsiSetFeatureStateW(hInstall
,szwFeature
, iState
);
5956 HeapFree(GetProcessHeap(),0,szwFeature
);
5961 UINT WINAPI
MsiSetFeatureStateW(MSIHANDLE hInstall
, LPCWSTR szFeature
,
5962 INSTALLSTATE iState
)
5964 MSIPACKAGE
* package
;
5967 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
5969 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5971 return ERROR_INVALID_HANDLE
;
5973 index
= get_loaded_feature(package
,szFeature
);
5975 return ERROR_UNKNOWN_FEATURE
;
5977 package
->features
[index
].ActionRequest
= iState
;
5978 ACTION_UpdateComponentStates(package
,szFeature
);
5980 return ERROR_SUCCESS
;
5983 UINT WINAPI
MsiGetFeatureStateA(MSIHANDLE hInstall
, LPSTR szFeature
,
5984 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5986 LPWSTR szwFeature
= NULL
;
5989 szwFeature
= strdupAtoW(szFeature
);
5991 rc
= MsiGetFeatureStateW(hInstall
,szwFeature
,piInstalled
, piAction
);
5993 HeapFree( GetProcessHeap(), 0 , szwFeature
);
5998 UINT
MSI_GetFeatureStateW(MSIPACKAGE
*package
, LPWSTR szFeature
,
5999 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
6003 index
= get_loaded_feature(package
,szFeature
);
6005 return ERROR_UNKNOWN_FEATURE
;
6008 *piInstalled
= package
->features
[index
].Installed
;
6011 *piAction
= package
->features
[index
].Action
;
6013 TRACE("returning %i %i\n",*piInstalled
,*piAction
);
6015 return ERROR_SUCCESS
;
6018 UINT WINAPI
MsiGetFeatureStateW(MSIHANDLE hInstall
, LPWSTR szFeature
,
6019 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
6021 MSIPACKAGE
* package
;
6024 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szFeature
), piInstalled
,
6027 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
6029 return ERROR_INVALID_HANDLE
;
6030 ret
= MSI_GetFeatureStateW(package
, szFeature
, piInstalled
, piAction
);
6031 msiobj_release( &package
->hdr
);
6035 UINT WINAPI
MsiGetComponentStateA(MSIHANDLE hInstall
, LPSTR szComponent
,
6036 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
6038 LPWSTR szwComponent
= NULL
;
6041 szwComponent
= strdupAtoW(szComponent
);
6043 rc
= MsiGetComponentStateW(hInstall
,szwComponent
,piInstalled
, piAction
);
6045 HeapFree( GetProcessHeap(), 0 , szwComponent
);
6050 UINT
MSI_GetComponentStateW(MSIPACKAGE
*package
, LPWSTR szComponent
,
6051 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
6055 TRACE("%p %s %p %p\n", package
, debugstr_w(szComponent
), piInstalled
,
6058 index
= get_loaded_component(package
,szComponent
);
6060 return ERROR_UNKNOWN_COMPONENT
;
6063 *piInstalled
= package
->components
[index
].Installed
;
6066 *piAction
= package
->components
[index
].Action
;
6068 TRACE("states (%i, %i)\n",
6069 (piInstalled
)?*piInstalled
:-1,(piAction
)?*piAction
:-1);
6071 return ERROR_SUCCESS
;
6074 UINT WINAPI
MsiGetComponentStateW(MSIHANDLE hInstall
, LPWSTR szComponent
,
6075 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
6077 MSIPACKAGE
* package
;
6080 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szComponent
),
6081 piInstalled
, piAction
);
6083 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
6085 return ERROR_INVALID_HANDLE
;
6086 ret
= MSI_GetComponentStateW( package
, szComponent
, piInstalled
, piAction
);
6087 msiobj_release( &package
->hdr
);
6092 static UINT
ACTION_Template(MSIPACKAGE
*package
)
6096 MSIRECORD
* row
= 0;
6097 static const WCHAR ExecSeqQuery
[] = {0};
6099 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6100 if (rc
!= ERROR_SUCCESS
)
6103 rc
= MSI_ViewExecute(view
, 0);
6104 if (rc
!= ERROR_SUCCESS
)
6106 MSI_ViewClose(view
);
6107 msiobj_release(&view
->hdr
);
6113 rc
= MSI_ViewFetch(view
,&row
);
6114 if (rc
!= ERROR_SUCCESS
)
6120 msiobj_release(&row
->hdr
);
6122 MSI_ViewClose(view
);
6123 msiobj_release(&view
->hdr
);